in an RPG, there are many different things that can affect your stats. your stats may be used in many calculations in many different places, so its nice to have an easy way to find out the value of a particular stat.
the simplest idea would be to add to your stats when you equip an item, and subtract from your stats when you remove an item. strange things may happen (ex: you lose an item but it doesn't get unequipped) which can cause your stats to have the wrong value.
also, equipping items is not the only thing that increases your stats. a magic spell may increase your health by 200 for a limited time. this is not something you equip/remove. how would you store the +200 health effect, and how would you know when to remove it?
to solve some of these problems i came up with this, the Buff datum:
bonus is a string which stores the information for all of the effects of the buff. so, in the example of the spell that increases your health by 200, bonus would be "health=200". suppose that spell increased your health by 200 and increased your strength by 100, then bonus would be "health=200&strength=100". you could also have the buff subtract from a stat, such as "strength=-50". like when you're writing numbers, if you don't put a minus sign its treated as a positive number.
l_bonus is a list which has all the same data as the bonus string. we can use the params2list() function to convert the bonus string into a list, such that the bonus string of "health=200" would result in a list where l_bonus["health"] = 200.
Note: params2list() probably treats all values as text strings, so that the health value in that example would actually be the string "200", and not the number 200. you can use text2num() to convert the string to a number.
the bonus variable is not even necessary, as all the information is stored in l_bonus. however, there may be some cases where you'd like the buff object to have a backup copy of this data in case something were to happen to the list.
the benefit of keeping the bonuses in a list is that you can easily look up the bonus for any given stat. that task, coincidentally, is what get_value() does. so, calling Buff.get_value("health") would return 200. this way you can easily check if a player gets a bonus from a buff, and if so, what the bonus is.
A datum is the most basic object in DM. its more basic than a mob, a turf, an obj, or even an area. you don't place them on the map, so you may not be sure exactly where to put them.
since a player may have several buffs on them at once, a list makes a nice place to store them. this way, you can give the player more buffs, or take some away as you need to. and, since they are in one list, you can easily cycle through all of them and check for certain bonuses.
the get_bonus() function takes a stat name and returns your bonus for that stat. if you recall, buff objects have a similiar function, get_value(). get_value() returns a single buff's bonus to a stat. that's the best that get_value() can do, because its only one buff. it doesn't know how to find the other buffs. however, get_bonus() belongs to the mob, and the mob has a list of all of its buffs. it can loop through all of its buffs, call get_value() for each buff, and sum up those values. the get_bonus() function gives us a simple way to check all bonuses the mob has for a given stat.
if you've been paying close attention, you'll have noticed that i skipped something. well, i didn't skip it. i wanted to cover it last, seriously. and that thing which i did not forget about is the check() proc. what i've shown here is the bare bones of a buff object. this is the minimum requirement for the object to be able to function as a buff. as i said earlier, you could rely on equip/remove events adding or subtracting the proper amounts from your stats. however, there might be circumstances which would make relying on equip/remove events unreliable.
the check() proc is a poorly named function which checks if the buff should still exist. ideally, check performs no complex tasks, so its harmless for you to call at key times. for example, you might want to call check() at the start of get_value(), because if the buff shouldn't exist anymore, it shouldn't return its value. the function may require checking some conditions that may seem impossible to check. the buff object that i've shown you knows nothing of its owner. so, if you wanted to check anything involving the player, you'd need to give the buff object another variable which is a reference to its owner, and set that reference properly when the buff is created. i did not include variables like that because not all buffs would require that.
you can also use check to do some more interesting things. for example, you can give the buff a variable which stores the time at which the buff will expire. then, check can compare that saved time to the current time, and if its expired, the buff will delete itself.
Note: on second thought, maybe i should include a reference to the owner in the example. because, in the buff's destructor it would be nice for it to remove itself from its owner's buff list.