What's the best way to separate logic from data, when some of the data *is* logic?
I'm working on a hobby project. For context, it's a Dungeons & Dragons 3.5e character generator.
For those who don't know, there's lot's of rules and options when generating the characters. End result is a Character which really just consists of a bunch of statistics (Stats). Some of these stats are numbers, others are information.
One of the steps during this process is selecting a "Class" for your character. "Barbarian" for example, or "Cleric". These classes determine a list of "Feats" that your character gets at different character levels.
The important part of all this is the "Feats". These feats can modify the character's data in many different ways, for example:
- One feat will grant you Uncanny Dodge (which is itself a Feat), unless you already have Uncanny Dodge, in which case it gives you Improved Uncanny Dodge
- Uncanny Dodge retains your DEX bonus to AC when flat-footed
- Normally, flat-footed AC is calculated by adding a series of other stats together
- Improved Uncanny Dodge has some other effects but has a prerequisite that you already have Uncanny Dodge
- Another feat might grant you a +2 to SPOT checks, but only when such checks relate to a specific condition
To make sense of all this, I see:
- A feat's effect on a character can include IF/ELSE logic
- Feat that grants Uncanny Dodge if you don't already have it, or Improved Uncanny Dodge if you do
- A feat can grant you another feat
- Feat grants you Uncanny Dodge (or Improved Uncanny Dodge)
- A feat can change the logic used to calculate other stats
- Uncanny Dodge adds your DEX bonus to AC where it normally doesn't apply
- A feat can add a note to a stat, but not change the stat
- Add a note to the SPOT checks there there's an additional +2 under a specific condition
There are hundreds of Feats. I don't want to hard code them all, or rather, I could, but it seems madness. Instead, I want to keep them all in data files and load them that way.
But there's no consistent way to store the effects feats have in data files. I'm using standard CSV files at the moment, which leads me to:
(incomplete example)
Name | Effect |
---|---|
Barbarian Uncanny Dodge | IF Character.Feats.Contains(Uncanny Dodge) THEN ADD_FEAT Improved Uncanny Dodge ELSE Uncanny Dodge ENDIF |
Uncanny Dodge | Character.AC.FlatFooted += Character.DEX |
Spotting Feat | Character.Skills.SPOT.notes += "+2 when the moon is out" |
I've no problem writing a tokeniser and parser for this; but the number of possibilities means I basically need to expose everything (stats and logic calculations) to manipulation via these options in the data files.
In my mind, I'm circling back to hard-coding everything and adding an even harder to use "programming language" to the data files. Sure, it would be useful to allow users to add their own custom Feats to my data files, but at that point if the user can do that, they could probably just download the source code and compile their own.
So what's the best way to do this? No matter which way I cut this, it doesn't seem sensible.
I'm doing this to learn Qt, which is going great, so I selected C++ for the flair, but in all honesty, this isn't much of a language specific question I guess.