I use a system similiar to this to create simple or complex character systems. This is based off of a tutorial by LummoxJr, modified for my own needs over time.
For those unfamiliar with a datum, it is an "blank slate" so to speak. An atom that has no real qualities of it's own except what you give it.
This is by no means the only use for datums, this is just a use that I've adopted and would like to share.
To create a datum you simply decide what you'd like to call it.
MyDatum//datum type declared
From there it's like using any other atom, you can apply procs, variables and such as needed. Moving on we will use datums to create a basic character that could be used in an rpg type game.
MainStat
var
current=100
maximum=100
Attribute
var
current=10
This creates two datums which shall be used for the health and magic, as well as any attributes for our character.
To apply them to the character they are used like this:
mob
var
MainStat/Health=new
MainStat/Mana=new
Attribute/Strength=new
Attribute/Defense=new
The code above gives all mobs a datum variable called Health, Mana, Strength and Defense.
Which you can then use like so.
mob.Health.current-=5
mob.Strength.current=5
How is this any different from just declaring a normal variable? Well read on.
Let's get into the procs needed for our adventure. Let's start with some basic ones for Losing health, gaining attributes and the like.
Normally you would have to write a proc for each , lose health, lose mana, and so on- with datum based character development you no longer have to do that.
mob
var
MainStat/Health=new
MainStat/Mana=new
Attribute/Strength=new
Attribute/Defense=new
proc
LoseMS(var/MainStat/M,var/amt)
M.current=max(0,M.current-amt)
GainMS(var/MainStat/M,var/amt)
M.current=min(M.maximum,M.current+amt)
GainAttr(var/Attribute/A,var/amt)
A.current+=amt
As you can see the code now has 3 new procs which will handled losing health, mana and gaining strength and defense altogether which saves a bit of typing and simplifies things.
To use them you would do something like this-
mob.GainMS(Health,200)
mob.GainMS(Mana,50)
mob.GainAttr(Defense,2)
For ease of use you can wrap them up into a proc like this in a very common example.
LevelUp()
GainAttr(Strength,2)
GainAttr(Defense,2)
This also reaches to examples of dealing damage, you could also easily expand this, by editting the datums. Let's say you want to do away with traditional levelling, and apply stats that level up independent of one another. You could easily do that with a datum based character.
MainStat
var
current=100
maximum=100
experience=0
exp_needed=100
Attribute
var
current=10
experience=0
exp_needed=100
mob
var
MainStat/Health=new
MainStat/Mana=new
Attribute/Strength=new
Attribute/Defense=new
proc
LoseMS(var/MainStat/M,var/amt)
M.current=max(0,M.current-amt)
GainMS(var/MainStat/M,var/amt)
M.current=min(M.maximum,M.current+amt)
GainAttr(var/Attribute/A,var/amt)
A.current+=amt
LevelUp()
GainAttr(Strength,2)
GainAttr(Defense,2)
IncreaseMS(var/MainStat/M,var/amt)
M.maximum+=amt
GainMSExp(var/MainStat/M,var/amt)
M.experience+=amt
if(M.experience>=M.exp_needed)
LevelMS(M)
GainAttrExp(var/Attribute/A,var/amt)
A.experience+=amt
while(A.experience>=A.exp_needed)
A.experience-=A.exp_needed
GainAttr(A,1)
sleep(1)
LevelMS(var/MainStat/M)
while(M.experience>=M.exp_needed)
M.experience-=M.exp_needed
M.maximum+=10
sleep(1)
In this updated code you can now apply experience points to individual attributes and main stats, allowing you to create health that raises as you take damage, or strength that increases as you attack foes or shatter rocks for example.
The benefits of this type of system can be applied to many things, skills like blacksmithing, potion making or as you have seen here. If you expanded this to give your character more than two main stats and 7 to 8 different attributes, you'd still only need to use the base procs that are declared here to manipulate them, or you could continue to add even more functionality to them by elaborating on the datums.
An example of that would be using it to hold buff/debuff values, regeneration rate specific to each main stat or modifiers to the effect of each attribute to name a few.
As many benefits as there are to using something like this there some things to look out for:
If you fail to create a new /datum when you attach it to a mob it will give an error thus when you apply a datum as a variable, or any atom for that matter, you always need to check if it exists using isnull() or initialize it by doing like above:
mob
var
MainStat/Stamina=new
One other thing of note is that when handling more than one mob, you must be observant that you don't mix them up and apply unwanted effects.
verb
SmackYaOne()//this would hit yourself.
for(var/mob/M in oview(1))
M.LoseMS(Health,55)
SmackYaOneV1()//this would hit anyone in view of 1.
for(var/mob/M in oview(1))
M.LoseMS(M.Health,55)
I'd also let the stat know what mob it's attached to, which also lets you do things like: