Entity Attributes

The attributes features are designed for use with Entity types. For an Entity to have attributes it should implement IHasAttributes.

Basic Concepts

Core Attributes

These represent primary aspects of your entity, with values that change over the implementor's lifetime. How these values change is up to you. You might allow the player to set them upon leveling up. You might automatically increment them based on the player's activity. For non-players (like monsters) you might set them when you initialize the instance and never touch them again. In typical roleplaying games these are usually things like Strength, Agility, Intellect, etc.

The main point is that they can be set to specific values.

Derived Attributes

These represent corollary aspects of your entity, and their values are calculated. Good examples of derived attributes are things like Health, Mana, and Energy. You provide a formula - say, Mana is derived as the implementor's Vitality multiplied by half their Willpower. The result of this formula is the value of the derived attribute.

The main point is that they are never directly set to specific values, but derive their values from a formula that may include Core Attributes and other input.

Instantiating a DerivedAttribute

The DerivedAttribute class contains a nested class, Function. This is used to carry the function a DerivedAttribute uses to calculate its value, and provides a means of clamping the result to a range regardless of the actual function result value. You can call either the raw or clamped value.

The func parameter of type Func<IHasCoreAttributes, IHasDerivedAttributes, IHasSkills, IHasInventory, ushort> allows you to access members in those references within your function definition, giving you a lot of flexibility in how you calculate the result.

Of course you don't have to target members in all the interfaces in your function definition but they're available if you need them. The constructor does, however, require that the implementing type implements IHasDerivedAttributes (because implementing this is a given in this case), whereas that instance must implement skills and inventory only if you use those respective members in the function.

The Initialize method (which you'll likely call from your implementor's constructor) also ensures that all references are to the same implementor instance (meaning you cannot calculate one implementor's members against another's).

In the FigmentShare singleton instance you define what attributes exist in your game, and then in your implementing types, which of those attributes they will use.

Initializing an implementor

The following scenario assumes an instance of FigmentShare (which stores the CoreAttributes and DerivedAttributes you have defined for your game) named Share.

var myChar = new Character(Share, "Joe", "Blow");

// Character loadout

var attrVitality = Share.GetCoreAttribute("Vitality");
var attrStrength = Share.GetCoreAtrribute("Strength");
var attrIntellect = Share.GetCoreAttribute("Intellect");
var attrWillpower = Share.GetCoreAttribute("Willpower");

var attrHp = Share.GetDerivedAttribute("Health");
var attrMp = Share.GetDerivedAttribute("Mana");

// Temp collection representing a CoreAttribute and the value we want the character to have for it

var coreAttr = new Dictionary<CoreAttribute, ushort>();

coreAttr.Add(attrVitality, 10);
coreAttr.Add(attrStrength, 10);
...

// Temp collection representing a DerivedAttribute and the function we want the character to use to determine the value for it

var dervAttr = new Dictionary<DerivedAttribute, Func<IHasCoreAttributes, IHasDerivedAttributes, IHasSkills, IHasInventory, ushort>>();

dervAttr.Add(AttrHp, (c, d, s, i) => (ushort)(a.CoreAttributes[attrVitality] + a.CoreAttributes[attrWillpower]));
dervAttr.Add(AttrMp, (c, d, s, i) => (ushort)(a.CoreAttributes[attrIntellect] + a.CoreAttributes[attrWillpower]));

// Now we can initialize our character:

foreach (var kv in coreAttr) myChar.CoreAttributes.Add(kv.Key, kv.Value);
foreach (var kv in dervAttr) myChar.DerivedAttributes.Add(kv.Key, kv.Value); 

Last edited Aug 25, 2011 at 9:33 PM by Furiant, version 16