Let’s build a Dungeon Crawler with Hollywood-MAL! (part 3, Designing the game)
Let’s go on with the secondary attributes.
As you have seen in the previous article, I have defined the following secondary attributes :
- Health
The “so called” hit points, a value that represent the character’s life points, when they go down to zero the character dies. Health is regenerated over time using the self-healing capabilities of the character. - Mana
It’s a value that represent the magic “fuel” a charatcer have to cast spells, almost all spells requires mana and if the character does not have enough mana he can’t cast the spell. If mana go down to zero nothing happen. Mana is regenerated over time depending on the magical predisposition of the character. - Weight
Indicates the maximum weight a character can carry, it includes all the stuff he is wearing and what he is carrying in his bags (inventory). Often this value is determined by the character’s strength. - Attack
Describes the attack skills of the character, both physical and magical. Each character has a percentual chance to hit his target and a percentual chance to inflict a critical hit. We defines here also the base physical damage the character can inflict to an enemy with his bare hands (no weapons equipped). - Defence
Any character can have an innate resistance to physical and/or magical attacks, we define here this damage reduction for both. We also define here the ability to dodge an enemy attack, both physical and/or magical. - LearnSpell & LearnAbility
Something not seen often: I want my character has a chance to learn an enemy’s spell or an enemy’s ability simply facing him, of course the character must meet some requirements described in the spell or in the ability to learn. - Steal
It’s a percentual value that influence the ability to steal an item from the enemy during the battle. - Escape
It’s a percentual value that determine the success of an escape attempt from the battle.
We will compute these values using the formula described in the previous episode.
Health and Mana have almost the same structure, here is the health one:
<code>health =
{ maxValue_formula = { },
RegenValue_formula = { },
currentValue = -1,
maxValue = -1,
regenValue = -1 }</code>
- maxValue_formula
The formula that determines the maximum health a character can have. - regenValue_formula
The formula that determines how much health is recovered for each turn - currentValue
The current character’s health - maxValue
The result of the maxValue_formula is stored here - regenValue
The result of the regenValue_formula is stored here
I’m going tp skip the Mana and Weight definitions since, they are almost identical to the Health one, instead I’ll go on with the other secondary attributes.
Attack includes three attributes : bareHands attack, which is physical, Critical chance and Hit chance. These values are obvious and do not need further description but you may wonder why there is no base attack damage defined here.
Well, I think that the best and more flexible approach is to define, in each weapon and each spell a base damage value which will be influenced by one or more character’s attributes (we will use the formulas described earlier), for example we could define a sword with a base cutting damage of 6 which is influenced by both the character’s strength and by the sword proficiency (ability) if any.
Practical example:
<code> Sword's base Cutting Damage : 6
Sword's damage modifiers : strength = 0.06
Character's Strength : 20
Sword's final damage : 6 * (20*0.06) = 7</code>
Later, when the character will get, for example, a strenght of 35:
<code>Sword's final damage : 6 * (35*0.06) = 12</code>
If the characters has the Sword Proficiency ability we could raise further the final damage.
It’s just an example so you know how I’m going to implement the character’s attack and how data will be calculated.
Defence instead defines two parameters: the innate ability to resist and reduce damage of both physical and magical attacks and the ability to dodge an incoming attack and avoid completely the possible damage.
The damage reduction will be added to the reductions made by worn items, what we are defining here is the base secondary attributes a naked character’s has.
Think about a race with a fighter class that has a natural stone skin, that’s why I thought to implement things in this way. Obviously we could have defined races with their own characteristics and then hooked them to the various classes, but I wouldn’t want to complicate the structure of the game too much, it’s quite complicated in this way 😀
I want that the characters are able to learn both spells and abilities from the enemies they are facing, It is normal thing to look at someone and learn from them certain techniques so I’ve included two formulas to determine the chance a character has to learn a seen ability and/or spell: when we will defines those two things we will see that we have to include requisites that a character must have in order to learn and use them, those requisites must be declared inside any spell or ability we are going to create.
To conclude the secondary attributes we have the chance to escape from a battle: if the character encounter an enemy too strong for him he can try to escape, the escape success is determined by the formula defined by the escape_formula.
WEARABLE ITEMS
As said in the previous episodes I’ve decided to use six slots where the character can equip items, these are:
- Helmet
- Vest
- Boots
- Ring
- Left Hand
- Right Hand
Technically we will put on these slots only a reference to the item stored and described in a separate database. These items (we will see them later) should provide several things that defines the item itself and modify the character’s attributes, they also can add modifiers to the character (think about a cursed or a blessed item to have an idea).
INVENTORY
The inventory represent the character’s bag, again, to keep the project simple, I will not manage the space taken by the objects, but only their weight since we have defined the maximum weight a character can carry.
The inventory is essentially a table where we will store the item references defined into another separate database.
LEARNED / MEMORIZED
In this section we will store all the spells and abilities a character has learned, we also have two formulas that determines how many spells and how many abilities the character can learn. For example we could write the following maxSpells_formula to determine how many spells a character can learn:
<code> maxSpells_formula = { intelligence = 0.1, knowledge = 0.05 }</code>
Suppose that our character has the following attributes:
<code> intelligence = 20
knowledge = 15</code>
We will have :
<code> maxSpells_formula = 20*0.1 + 15*0.05 = 2.75 rounded to 2</code>
Later when the character will increase (if the player wants) intelligence to 23:
<code> maxSpells_formula = 23*0.1 + 15*0.05 = 3.05 rounded to 3</code>
RESISTANCES
In the defence secondary attributes we have defined innate resistances to physical and magical damages, all physical damages and all magical damages. Here we are adding more details because we can specify which resistance we have for each physical damage type (piercing, slashing, bludgeoning, etc…) and for each magical damage type (fire, darkness, holy, etc…).
It’s a fact that skeletons are almost immune to piercing attacks!
Again we will need an external database where we will define all magical and physical damage types, so that we can put here only a reference.
For example, if we want to set a resisteance to the fire magic the definition will be stored like this:
<code> resistances =
{ magicalTypes =
{ fire = 0.2 }
}</code>
The above definition means that whenever the character gets a damage from fire magic, he will benefit from a damage reduction of 20%.
WEAKNESSES
It’s the same as the resistances, but in this case the character will get a penalty. If we use the previous example we will have:
<code> weaknesses=
{ magicalTypes =
{ fire = 0.2 }
}</code>
It means that when the character gets a damage from fire magic, he will get an additional damage by 20% of the initial damage.
Talking again about skeletons, it is well known that they are very sensible to clubs and hammers (blunt damage).
MODIFIERS
Modifiers is used to store temporary (or permanent) alterations on the character status, think about a character being on fire: we have to find a way to inflict a fire damage to the chatacter at each turn. This status may vanish after some time or may be permanent until the character uses a certain potion (think about poisons).
Modifiers can also change attributes, for example receiving a bless could raise one or more primary attributes for some turns,
This system is flexible enough to define hundreds of alterated states and DOT (damage over time) effects.
POSITION
We need to store where every character is located on our map, here we will store its horizontal coordinate, vertical coordinate and the direction where he is facing. The direction is important to determine what a character can see.
LET’S RECAP
So, we have started from a core game element which is the character’s class, from it we will build all the characters who lives in the dungeon, including our hero.
We have also seen that the character’s class needs more databases as following:
- ITEMS
- Wearable items (helmet, vest, …)
- Weapons (left and/or right hand)
- Shields (left and/or right hand)
- Consumable items (potions, food, …)
- Treasures (items we can sell for money: diamond, gems, …)
- Books (to learn new spells and abilities)
- MAGICAL STUFF
- Types of magic (Fire, Ice, Holy, …)
- Spells (All available spells)
- PHYSICAL STUFF
- Types of physical damage (piercing, slash, …)
- Abilities (All available abilities)
- ALTERED STATUSES
- Statuses (All possible altered statuses for the character’s modifiers: poison, burn, paralisys, blind, …)
I think it’s a good starting point! We will probably need more additional databases, but we will talk about them when needed 🙂
Here is the complete character’s class data structure, remember that this is just a templete and that we will create and setup classes using methods (for those not familiar with OOP – Object Oriented Programming, I will make a brief summary on the subject in the next episode).
<code>class =
{ name = "empty", ; Class name (Druid, Priest, ...)
description = "empty", ; A brief class description
; Experience & Levels
expTable = ; Defines how the class grows
{ firstExpLevel = -1, ; Set the level 2 experience needed
increase = -1, ; A % value to compute the experience
; needed for the next level, example:
; .firstExpLevel = 1000
; .increase = 0.75
; Level 2 -> 1000+1000*.75 = 1750 Exp
; Level 3 -> 1750+1750*.75 = 3062 Exp
levelCap = -1, ; Level cap, max level allowed
levels = { }, ; This table will be precalculated at
; creation time, will be populated with
; Exp needed for each level.
attributePoints = -1, ; How many main attributes point can be
; assigned freely at each level up.
},
; Primary
attributes = ; -- Primary Attributes --
{ level = 1, ; Current character level
experience = 0, ; Current character experience
attributesCap = 100, ; Attributes cap, the max level each attributes can reach
rollPoints = 10, ; How many points are rolled into the attributes when
; a character is created.
primary =
{ strength = 20, ; Strenght (usually used to determine the
; effectiveness of brandished weapons)
intelligence = 20, ; Intelligence (usually used to determine the
; effectiveness of magical spells)
dexterity = 20, ; Dexterity (usually used to calculate the
; ability to avoid attacks or to use ranged
; weapons)
constitution = 20, ; Constitution (usually used to determine the
; health state and the hit points)
knowledge = 20, ; Knowledge (usually used to determine if an
; object can be used or identified)
luck = 20 ; Luck (small influence on character actions)
},
; Secondary
secondary =
{ health =
{ maxValue_formula = { }, ; List of attribute multipliers
RegenValue_formula = { }, ; List of attribute multipliers
currentValue = -1, ; Character's current health
maxValue = -1, ; Character's max health
regenValue = -1 }, ; Health regen value at each turn
mana =
{ maxValue_formula = { }, ; List of attribute multipliers
regenValue_formula = { }, ; List of attribute multipliers
currentValue = -1, ; Character's current mana
maxValue = -1, ; Character's max mana
regenValue = -1 }, ; Mana regen value at each turn
weight =
{ maxValue_formula = { }, ; List of attributes multipliers
currentValue = -1, ; Character's current weight
maxValue = -1 }, ; Character's max transportable weight
attack =
{ bareHands_formula = { }, ; Physical attack with bare hands
physicalCrit_formula = { }, ; % of a physical critical hit
magicalCrit_formula = { }, ; % of magical critical hit
physicalHit_formula = { }, ; % to hit with a physical attack
magicalHit_formula = { } }, ; % to hit with a magical attack
defence =
{ physical_formula = { }, ; % Physical damage reduction
magical_formula = { }, ; % Magical damage reduction
physicalDodge_formula = { }, ; % to dodge a physical attack
magicalDodge_formula = { } },; % to dodge a magical attack
learnSpell_formula = { }, ; % to learn an enemy spell
learnAbility_formula = { }, ; % to learn an enemy ability
steal_formula = { }, ; % to steal an enemy item
escape_formula = { }, ; % to leave the battle at each turn
},
}
; Wearable slots
wearable =
{ helmet = -1, ; Helmet slot
vest = -1, ; Vest slot
boots = -1, ; Boots slot
ring = -1, ; Rign slot
leftHand = -1, ; Left hand slot
rightHand = -1 ; Right hand slot
},
; Inventory
inventory = { }, ; A place holder for the character's inventory
; Spells
spells = { }, ; All allowed spells for this class
abilities = { }, ; All allowed abilities for this class
; Learned
memorized =
{ maxSpells_formula = { },
spells = { }, ; A place holder for the character's learned spells
maxAbilities_formula = { },
abilities = { } ; A place holder for the character's learned abilities
},
; Resistances
resistances =
{ magicType = { }, ; A list of resistances in % for each magic type
physicalType = { } ; A list of resistances in % for each physical type
},
; Weaknesses
weaknesses =
{ magicType = { }, ; A list of weaknesses in % for each magic type
physicalType = { } ; A list of weaknesses in % for each physical type
},
; Modifiers
modifiers = { }, ; A place holder for character's active modifiers
; Position & Facing
position =
{ x = -1, ; Horizontal coordinate in the current map
y = -1, ; Vertical coordinate in the current map
facing = -1 } ; The direction in which the character is looking
}
</code>
Pretty nice! 😀
WHAT’S NEXT ?
Next episode : In the next episode we will write down a little piece of code to setup the databases, we will add the magical and physical types and we will discuss about altered states (statuses) and how we can we manage this fundamental part of any RPG.
Stay tuned and if you like this project support me on Patreon!
Any feedback is really appreciated!