Ah, we’re back to the numbers again.
In particular, I’ve implemented Attributes
, which is the system that I’ve used to manage most values belonging to an actor (e.g. the player).
An RPG has many numeric values that are important to the player.
Usually there are some major attributes like Strenght
that determines for example how hard the player can hit, Perception
to represent how perceptive the player is, etc.
Additionally, there could be skills which measure particular skills and crafts that the player can perform such as Weaponsmithing
, Weaving
, etc.
And sometimes there are also hidden attributes, these are not always directly shown to the player but very important for the experience.
For example Damage
to measure the players damage, Critital Rate
how effective/common critial hits are, Defense Rating
how well the player is defended. These are often based on the other properties such as what the player is wearing, how strong they are, etc.
Design
In my current design all of the values mentioned above are Attributes
.
An Attribute
is simply a value belonging to an actor, and it’s backed by an AttributeState
for each actor that owns such an attribute.
Additionally, each Attribute
can be associated with one or more tags.
This makes it easier for me to treat these different attributes in different ways. For example all attributes with the major
tag will be shown separetely from attributes with the skill
tag.
Implementation
Most of it is simple implemented using a straight-forward object-oriented approach.
ConstantAttribute(State)
A ConstantAttribute
is a simple numeric value that is stored in the player’s save file.
These are generally used for major attributes since they are simple values.
ExpressionAttribute(State)
An ExpressionAttribute
is a special kind of calculated property that uses an expression to resolve it’s value. These are great for hidden attributes since they can use the values of other attributes in a flexible manner.
ExpressionAttribute.new({
'id': 'max_health',
'name': 'Max. Health',
'expression': '(strength + endurance) / 2',
'dependencies': ['strength', 'endurance'],
'show': true,
'labels': ['dynamic'],
}),
DamageAttribute(State)
A DamageAttribute
is an example of how code could be used to create custom attributes.
The major benefit of using a custom attribute is that they could then also be used in ExpressionAttribute
.
In this particular case I just implemented a custom attribute because of some legacy code I didn’t move to the attributes system yet.
In the implementation I ask the EquipmentManager
for the weapon rating of the player
and add the players strength to it.
func value():
return EquipmentManager.get_weapon_rating('player') + Attributes.get_attribute('player', 'strength').value()
Conclusion
Using this system I’ve managed to implement all of the attributes that I’ve needed so far.
Since all of these actor related numeric values are now using one system and are defined in one place it allows me to design a generic buff/debuff system that can affect any attribute from Weapon Damage
to Carpentry
.