Let’s build a Dungeon Crawler with Hollywood-MAL! (part 2, Designing the game)

I’m going to discuss deeply the character’s class data structure, it’s a core game element and must be planned carefully, so let’s go.

 

LEVEL AND EXPTABLE

Every character, friend or foe, has a level: basically it’s a number that allow the player to have an idea of how strong the character is. To gain levels the player must performs actions in order to gain experience points, when he reach a certain experience value he get a new level and the ability to distribute some bonus points to his main attributes.

In this kind of games, the character’s level determines how many spells and abilities the character is able to learn, moreover spells and abilities may have some requirements based on the level and/or attributes.

In this article we are going to discuss the class attributes and how I will implement them in the game.

Usually the higher is the character’s level and the more experience points are needed to reach the next level.

Writing down all experience points for each level and for each class is extremely boring so I thought to use the following table to describe how a given character’s class grows:

 expTable =                                  ; Defines how the class grows
   { firstExpLevel = -1,                     ; Set the level 1 experience needed
     increase = -1,                          ; A % value to compute the experience
                                             ; needed for the next level
     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.
     },

Let’s expand the concept:

  • firstExpLevel
    We set here the experience points needed to reach the level 2
  • increase
    This is a multiplier that determines the formula to calculate all the subsequent levels, the formula is :
      nextLevelExp = previousLevelExp * increase

    For example, let’s say we set level 2 (firstExpLevel) at 1000 Exp points and we increase it using 0.75 as multiplier, here is how we are going to calculate experience points for each level:

    • Level 2 Needed Exp = 1000
    • Level 3 Needed Exp = 1000 + 1000 * 0.75 = 1750
    • Level 4 Needed Exp = 1750 + 1750 * 0.75 = 3062
    • Level 5 Needed Exp = 3062 + 3062 * 0.75 = 5358
    • Level 6 Needed Exp = 5358 + 5358 * 0.75 = 9376
    • and so on…
  • levelCap
    It’s the maximum level this class can reach
  • levels
    It’s a table that will be populated with all needed experience points for each level, as I have showed above.
  • attributePoints
    Here we have to specify how many bonus points the player gains when he get a new level, this points can be freely added on the main chatracter’s attributes.

 

PRIMARY ATTRIBUTES

If you are an RPG fan you already know what attributes are: basically an attribute is a value that represent a character trait, the most common are Intelligence, Dexterity, Strenght, and so on… so I will put the most common attributes in our class template like this:

 attributes =
   { level = 1,                               ; Current character level
     experience = 0,                          ; Current character experience
     attributesCap = 100,                     ; Max attribute value
     rollPoints = 10,                         ; How many points for the initial roll
     
     primary =
       { strenght = 20,
         intelligence = 20,
         dexterity = 20,
         constitution = 20,
         knowledge = 20,
         luck = 20 },

     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
         },
       }
    }

As you can see, it’s a basic and very common definition, but no one stop us from adding more attributes or change them for our very own custom design. For now let’s stick with this basic design:

  • Level
    It holds the current level of a character, it must be compatible with the experience point specified below
  • experience
    It hold the current character’s experience points
  • attributesCap
    We must set the maximun value each attribute can reach
  • rollPoints
    At creation time we can decide to roll the specified points into the primary attributes, this points can also be assigned by the player when he creates his characters.

And now it’s time for the primary attributes, they are called this way because almost any secondary attribute is calculated starting from these values, they describe several aspects of a characters like his ability with weapons, ability with magic and so on.

Here are what I’ve defined as a starting point, it’s a very common template:

  • strength
    Measures how physicallly strong the character is, this can determine, for example, transportable weight,  the maximum weight of a weapon that can be wielded, how much additional damage it can deal with a weapon, and so on…
  • intelligence
    Intelligence determines if the character can cast a spell or not and with what proficiency. This value is often used to determine how many spells a character can “memorize” and have ready to be casted.
  • dexterity
    This attribute is used to determine how a character is able to avoid incoming attacks and traps, but is also used as a requirement for some complex weapons like a crossbow, bow, or anything more complex than a sword. Dexterity also means agility and it could be used as a requiremenet to pass a certain obstacole in a passage, for example. Dexterity, along with Intelligence and or Knoledge, could be used to determine the ability to disarm traps.
  • constitution
    Constitution determines the general physical health of the character, it’s mostly used to calculate the hit points and the health regeneration rate (healing rate), or the ability to resist poisons, etc…
  • knowledge
    This attribute determines how much knowledge the character have and can influence several aspects like the ability to identify and use an item, the ability to understand foreign languages, the ability to recognize certain dangerous situations, etc…
  • luck
    Finally we have the luck: it should have a small impact on any character action, but can be very important to put the hands on shiny loot or to save him from a deadly trap.

 

SECONDARY ATTRIBUTES

As I have anticipated, secondary attributes are values calculated using primary attributes, now we have to face the first problem : how can we store a formula to calculate each secondary attribute easily and fast?

My solution is very simple : for each formula we will use a table indexed with the primary attribute we want to use, while the value will be the attribute’s multiplier, all specified values will be calculated and added together.

Here is a practical example : suppose we want to calculate the secondary attribute Health and we want to influence this value using mainly the Constitution attribute and, with a less impact, the Strength attribute:

   ; This is just an example to make it clear how it works
   primary =
   { Constitution = 30,
     Strength = 27,
     ... }

   ; The formula table
   Health_formula = 
     { Constitution = 12.7,
       Strength = 3.2 }

   ; Here is how the Health is calculated
   Health = 0
   
   ; For each attribute specified in the formula table...
   For i, v In Pairs(Health_formula)
     ; i = index, in this case the attribute's name
     ; v = value, in this case the specified multiplier

     ; Check if the attribute specified in the formula exists
     ; in the primary attributes table
     If HaveItem(primary, i)
       ; Exists, calculate the health for this attribute
       Health = Health + primary[i]*v
     Else
       ; If not exists we may print a warning or we can look in other
       ; places.
     EndIf
   Next

   ; Done!
   ; Calculated Health will be :
   ; 30*12.7 + 27*3.2 = 467

This method is very fast, and using negative multipliers you can add penalties to your formulas. I will use the same method to store and calculate (with some variations) all the formulas we need.

It’s very important to keep in mind the attribute’s cap values while writing secondary attribute formulas to have balanced results between classes.

I think it’s important to avoid hardcoded stuff as much as possible, it may be a little faster when you run your programs but you will lose a lot in configurability and flexibility.

That’s all for this episode! Next time we will go on with the secondary attributes one by one, you can have a look at them in the meanwhile, name and descriptions are quite intuitive.

 

WHAT ABOUT THE NEXT STEPS?

Next episode : Secondary attributes and Wearable Item slots and Wearable items

 

Previous Episodes : 1

 

Stay tuned and if you like this project support me on Patreon!

Leave a Reply

Your email address will not be published.Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: