Part of an item's stats can include a reference to the behavior of the item when it is consumed or used. This can be represented in the item's structure as a delegate/function pointer/closure/et cetera based on language.
In C#, you could do it with an Action
delegate. So your item structure would look like:
class Item {
int value;
int weight;
// ...other stats...
Action<Item, Character> onUseEffect;
};
onUseEffect
is a (possibly-null) reference to a function that takes an Item
and a Character
, which at runtime will be the item being used and the character using the item, respectively. You can naturally have more (or fewer) parameters as needed.
So now, when using an item you look up it's Item
object as you do now to get the stats of the item. And if that Item
has a non-null onUseEffect
, you call that function:
void UseItem(string name) {
Item item = m_itemDatabase[name]; // look up the item...
if (item.onUseEffect != null) {
item.onUseEffect(item, thisCharacter); // use the item...
}
}
You'd bind these actions when you create each item in the database:
Item potionItem = new Item();
// ...other initialization...
potionItem.onUseEffect = (item, user) => {
// Potions heal 50 HP for the user.
user.Health += 50;
};
m_itemDatabase.Add("Potion", potionItem);
All of this allows you to define your item behavior in code without having to subclass Item
for each new type or behavior. It's also a useful building block towards allowing your item's behavior to be defined in scripts (the onUseEffect
delegate simply becomes a call to the item's script), as you proposed in your question. Using scripts (e.g., data) to describe the behavioral effects of your items is a good idea in general, although it might be overkill depending on the size of your game and data set. And whether or not you already have a scripting mechanism built.