Armour as a Modifier
In a game I am working on. I need to make an armour system that can boost and hinder the player. I will use a similar system to how Risk of Rain 2 handles items. Each armour will contain a percentage modifier that will either boost or hinder a select stat. Armour also belongs to different slots and weight classes which will change the impact on weight.
Armour is mostly a data class and it’s main purpose is just to provide these numbers to the players stats. It needs these variables to work:
- Slots
- Types
- Level
- Rarity
- Health modifier
- Resistance modifier
- Agility modifier
- Stamina modifier
- Attack Speed modifier
- Weight modifier
Slots
Armour will need an enum to differentiate which slot it goes on. This will be necessary for the inventory system and weight calculations.
# Define which slot this armour takes up
enum Armour_Slots {HEAD, TORSO, LEGS}
# Allow it to be set in inspector
@export var armour_slot: Armour_Slots
Types
Armour is split into different armour types (Light, Medium and Heavy) These will work with armour_slot
to determine the weight impact.
# Armour Types
enum Armour_Types {LIGHT, MEDIUM, HEAVY}
@export var armour_type: Armour_Types
Level
Level is easy to implement but very important for working with the other modifiers. We don’t need to set this in the inspector but we will for now so we can debug later. It is also a value that will be shared by other items later on so it will change later.
@export var level: int = 1 # Default to lvl 1
Rarity
Rarity is similar to level where there will be more than just armour rarity. This will end up in a higher class eventually but for now its fine in the armour script.
# Create a temp rarity enum
enum Rarity_Types {ONE_STAR, TWO_STAR, THREE_STAR}
# Set an armour pieces rarity in inspector
@export var rarity: Rarity_Types
Modifiers
Health, resistance, agility, stamina and attack speed will all function similarly to how risk of rain 2 handles items. Each modifier adds a percentage increase on top of the players base stats.
## Warning! Going below 1 will decrease the players health
@export var health_modifier: float = 1
## Warning! Going below 1 will decrease the players resistance
@export var resistance_modifier: float = 1
## Warning! Going below 1 will decrease the players agility
@export var agility_modifier: float = 1
## Warning! Going below 1 will decrease the players stamina
@export var stamina_modifier: float = 1
## Warning! Going below 1 will increase the players attack speed
@export var attack_speed_modifier: float = 1
The warnings are for future me (who will mess this up)
A basic example of how these would be used is:
player_health=base_health * armour_head.health_modifier * armour_torso.health_modifier *
armour_legs.health_modifier
Each piece of armour individually contributes to the players max health.
Weight
Weight is a modifier that is dependant on the slot and type of the armour. The combination of these two variables applies a different modifier to the players overall speed. However we may want two different armours of the same class to weigh different amounts based on their slot.
One way to do this is to have a two key array system where we store a default modifier that gets looked up based on the class and slot:
# Example
weight_modifier = weights[armour_type][armour_slot]
This should work well but the values are set and cannot be changed easily. A fix for this could be to have an override variable that will only have an effect if it is not some specific value (e.g. -100). This is known as a sentinel value and while not typically intended for this purpose it still works.
This does mean we have to hand make the weights array. We can visualise the array very easily with a table:
As you can see, if we wanted to get the default Medium Torso weight modifier we can access it by weight_table[armour_type][armour_slot]
In code this table looks like:
## Input the armour type then the slot
const weight_table = [[1.0, 1.0, 1.0], # Light
[1.1, 1.3, 1.3], # Medium
[1.3, 1.5, 1.5],] # Heavy
Now that the table is created we need to make the modifier and find the right number:
var weight_modifier
const WEIGHT_OVERRIDE_SENTINEL = -100
@export var weight_override: float = WEIGHT_OVERRIDE_SENTINEL
func _ready():
if weight_override != WEIGHT_OVERRIDE_SENTINEL:
weight_modifier = weight_table[armour_type][armour_slot]
else:
weight_modifier = weight_override
This is majority of what the armour needs to function. You’ll notice that it is only actually running code to determine the weight_modifier
variable. The rest are variables we want to set in the inspector that will be read by our player’s stat controller.
Conclusion
This is all working towards an inventory system that works in multiplayer and is one of three components. The two left to implement are:
-
Weapons
: This will be what the player has equipped (sword, bow, etc). This may have slots for each hand -
Pickups
: Any object that can be carried. This includes equipment, tools and quest related goodies
If you made it this far, thanks! If you think something is incorrect with what I’ve written or I missed a typo please feel free to message me on discord @ precipire.