<--Rethink ^--xmld20--^ Rethink, part 3-->

xmld20 - an XML Schema for d20 gaming systems - rethink, continued

Character sheets

Optimally, a data-driven character sheet should only contain the choices that a player made at each level up, and perhaps any effects gained through play (whether permanent or transient during play).

The previous monster entries that we worked with, as mentioned before, were an intermediate representation: they had already gone through the "level ups" (from the monster progression tables that we haven't yet created), but hadn't gotten to the final form (monster statblock, character sheet, etc.).

If we're going to work from basics, and have everything calculatable, then we should only record, in a minimalistic fashion, that information that isn't calculatable.

Here's an attempt at our fighter character that we're making:

<Characters>
  <Character>
    <Bio>
	<Name>Placide deMorgan</Name>
	<Race>human</Race>
	<Player>Wayne Pearson</Player>
    </Bio>
    <Levels>
	<Level number="1" class="fighter">
		<Increase type="Skill" name="Climb">4</Increase>
		<Increase type="Skill" name="Jump">4</Increase>
		<Increase type="Skill" name="Swim">4</Increase>
		<Add type="Feat" name="Cleave"/>
		<Add type="Feat" name="Dodge"/>
		<Add type="Feat" name="Power Attack"/>
	</Level>
	<Level number="2" class="fighter">
		<Increase type="Skill" name="Climb">1</Increase>
		<Increase type="Skill" name="Jump">1</Increase>
		<Increase type="Skill" name="Swim">1</Increase>
		<Add type="Feat" name="Mobility"/>
	</Level>
    </Levels>
  </Character>
</Characters>
This has done a lot. First of all, I separated things that are decided at creation time (name, race, etc.) from the things decided at level gain time. Perhaps the creation items should be a "level 0" set of items? While it may not make sense for Name, it does for something like the initial abilities, which I've left out (for precisely this reason).

Also note that I've changed the Increase element to use type instead of name, because at this point, we have further information to provide, and name seemed like a good name for that attribute.

In the same way as feats and skills have a "type" and a "name", I think saves and abilities should as well. At this point some might say that I'm overgeneralizing things a bit, and they might be right. But, this does lend itself well to extending the software to work on more than d20 rules (or if d20 changes to add a new ability or saving throw). Also, keeping everything in the same schema of type/name/(subname) allows the code to be written more generally, both for my ease and debugging purposes.

Let's take a look at what we have for now, for our progression table and our character. And just to entertain the idea, let's use "level 0" for now, to make things look a bit symmetrical. Also, when doing the previous work I kept wavering on whether or not to use the short names for things (Str, Wiz, Fort) or long (Strength, Wizard, Fortitude) and whether or not to capitalize them or not.

Time to make a stand: long names, no capitalization!

<Class name="fighter">
  <Levels>
    <Level number="1">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="fortitude">2</Increase>
	<Increase type="SavingThrow" name="reflex">0</Increase>
	<Increase type="SavingThrow" name="will">0</Increase>
	<Increase type="Skill">2</Increase>
	<Add type="Feat" subtype="fighter"/>
    </Level>
    <Level number="2">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="fortitude">1</Increase>
	<Increase type="Skill">2</Increase>
	<Add type="Feat" subtype="fighter"/>
    </Level>
  </Levels>
</Class>
<Characters>
  <Character>
    <Bio>
	<Name>Placide deMorgan</Name>
	<Race>human</Race>
	<Player>Wayne Pearson</Player>
    </Bio>
    <Levels>
	<Level number="0">
		<Set type="Ability" name="strength">12</Set>
		<Set type="Ability" name="intelligence">10</Set>
		<Set type="Ability" name="dexterity">14</Set>
		<Set type="Ability" name="constitution">14</Set>
		<Set type="Ability" name="wisdom">12</Set>
		<Set type="Ability" name="charisma">12</Set>
	</Level>
	<Level number="1" class="fighter">
		<Increase type="Skill" name="climb">4</Increase>
		<Increase type="Skill" name="jump">4</Increase>
		<Increase type="Skill" name="swim">4</Increase>
		<Add type="Feat" name="cleave"/>
		<Add type="Feat" name="dodge"/>
		<Add type="Feat" name="power attack"/>
	</Level>
	<Level number="2" class="fighter">
		<Increase type="Skill" name="climb">1</Increase>
		<Increase type="Skill" name="jump">1</Increase>
		<Increase type="Skill" name="swim">1</Increase>
		<Add type="Feat" name="mobility"/>
	</Level>
    </Levels>
  </Character>
</Characters>
For this to work properly, the processing system still has to do a bit of work. First, it has to "prep" the character by loading in all of the level 0 items. Then for each level after that, it must decide if there are race-specific benefits (such as the human's extra feat and extra skill points); it must check the class benefits, as listed in our table above; and it must check for any character level benefits (such as the start feat at first level or the fact that you get four times the skill points at first level - a real pain to have to code).

So what should be the end result of our blackbox that processes the above data? Perhaps something like this:

<Character>
	<Name>Placide deMorgan</Name>
	<Race>human</Race>
	<Player>Wayne Pearson</Player>
	<Ability name="strength">12</Ability>
	<Ability name="intelligence">12</Ability>
	<Ability name="dexterity">12</Ability>
	<Ability name="constitution">12</Ability>
	<Ability name="wisdom">12</Ability>
	<Ability name="charisma">12</Ability>
	<HD>2</HD>
	<hp>18</hp>
	<BAB>2</BAB>
	<SavingThrow name="fortitude">3</SavingThrow>
	<SavingThrow name="reflex">0</SavingThrow>
	<SavingThrow name="wisdom">0</SavingThrow>
	<Skill name="climb">5</Skill>
	<Skill name="jump">5</Skill>
	<Skill name="swim">5</Skill>
	<Feat name="cleave"/>
	<Feat name="dodge"/>
	<Feat name="power attack"/>
	<Feat name="mobility"/>
</Character>
This looks pretty good so far, especially from the point-of-view of a statblock generator or a character sheet generator. even a combat simulator has easy access to the values needed.

A few things to note, that are going to be a problem. The four-times skill points at first level is going to be something a bit awkward to code, and thus should probably just be one of those hard-coded ideas. The same goes with the maximum hitpoints for a character's first hitdice. If we're trying to represent a generic monster, we'll also need a way to say so, because they don't get a max HD, but rather average.

Something else that isn't clear from what we've created so far is when the software might need to ask for input. In the above, we've already said what feats and skills this character takes at each level, but how does the code know that when it sees

	<Add type="Feat" subtype="fighter"/>
that it has to refer back to the character sheet to find out what feat was chosen? Do we hard-code the fact that feats are always chosen from the character sheet? No, because some classes give you specific feats (Track for a ranger, Evasion for a rogue, etc.)

Perhaps we can say that an "empty" element, like above, means that nothing is supplied by the progression table, and thus must be filled in by the character sheet? So we would have

	<Add type="Feat">track</Add>
in the ranger table? This looks pretty good, but requires us to rework the way we have the Skill points being handled, going from
	<Increase type="Skill">2</Increase>
to
	<Increase type="Skill" count="2"/>
This allows us to say (if any class has such a thing), that at a given level, the character gains a few ranks in a specific skill:
	<Increase type="Skill" count="1">climb</Increase>
The problem with this is that it doesn't allow us to specify a subname, for those skills or feats that need it, such as Knowledge (the planes) or Weapon Focus (katana).

Since we have the name and subname attributes already slated for use in the character sheet, perhaps we can use them in the progression table as well:

	<Add type="Feat" name="track"/>
	<Increase type="Skill" name="climb" count="1"/>
At this point, I wonder if we needed to use the count attribute at all, now that the element body is freed, so we could go back to
	<Add type="Feat" name="track"/>
	<Increase type="Skill" name="climb">1</Increase>
I like this way better, because it doesn't restrict the value of the Increase to just numeric ones (or ones that make sense with a "count" attribute), such as the monk's Ki Strike ability. We could generalize the Increase idea to be an additive effect for numbers, but a concatenative effect for other things. Note then, that it's the presence or absence of the name attribute that tells us whether we've specifically stated which skill, feat, or whatever was taken, or whether we need to consult the character sheet (or perhaps the user interface) for more information.

Choices

It's the choices in d20, and character progression, that make the game so appealing, because no two characters are likely to end up the same. But it's that availability of choices that leads to headaches for those trying to code the rules. While choosing a feat might not be so bad, and even restricting it to those that have a subtype of "fighter" is handlable, what happens when the restrictions are even more refined?

The pre-requisites for feats seem to be something suited for the code to handle. If the character sheet says that a character has a feat, we just assume that it got there legitimately, and render or otherwise process that character without worrying about it. But if we're writing the code that generates the character sheet, interactively with the user, then we want it to follow the rules.

The Mobility feat has a pre-requisite, which is the Dodge feat. This is something that can easily be stored in our feat list, and checked against the current character. But what happens if a class progression table says that the character gets the feat, even if they do not meet the pre-requisites? This happens surprisingly often, and thus we need a way to handle this. Is it as simple as having a prereq="ignore" attribute in our level table? Are pre-requisites the only rules that are bent by entries in a progression table? At this point, it's hard to say, but it's good to keep at least this one idea in mind before we go further.

so far

At this point, we have two elements that exist in a level progression, Increase and Add; these two can have a handful of attributes, type, subtype, name, subname; and they can also contain test in the element, representing values chosen or specified.

Is this enough to codify a whole progression table? Let's try:

<Class name="fighter">
  <Levels>
    <Level number="1">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="fortitude">2</Increase>
	<Increase type="Skill">2</Increase>
	<Add type="Feat" subtype="fighter"/>
    </Level>
    <Level number="2">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="fortitude">1</Increase>
	<Increase type="Skill">2</Increase>
	<Add type="Feat" subtype="fighter"/>
    </Level>
    <Level number="3">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="reflex">1</Increase>
	<Increase type="SavingThrow" name="will">1</Increase>
	<Increase type="Skill">2</Increase>
    </Level>
    <Level number="4">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="fortitude">1</Increase>
	<Increase type="Skill">2</Increase>
	<Add type="Feat" subtype="fighter"/>
    </Level>
    <Level number="5">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="Skill">2</Increase>
    </Level>
    <Level number="6">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="fortitude">1</Increase>
	<Increase type="SavingThrow" name="reflex">1</Increase>
	<Increase type="SavingThrow" name="will">1</Increase>
	<Increase type="Skill">2</Increase>
	<Add type="Feat" subtype="fighter"/>
    </Level>
    <Level number="7">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="Skill">2</Increase>
    </Level>
    <Level number="8">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="fortitude">1</Increase>
	<Increase type="Skill">2</Increase>
	<Add type="Feat" subtype="fighter"/>
    </Level>
    <Level number="9">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="reflex">1</Increase>
	<Increase type="SavingThrow" name="will">1</Increase>
	<Increase type="Skill">2</Increase>
    </Level>
    <Level number="10">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="fortitude">1</Increase>
	<Increase type="Skill">2</Increase>
	<Add type="Feat" subtype="fighter"/>
    </Level>
    <Level number="11">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="Skill">2</Increase>
    </Level>
    <Level number="12">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="fortitude">1</Increase>
	<Increase type="SavingThrow" name="reflex">1</Increase>
	<Increase type="SavingThrow" name="will">1</Increase>
	<Increase type="Skill">2</Increase>
	<Add type="Feat" subtype="fighter"/>
    </Level>
    <Level number="13">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="Skill">2</Increase>
    </Level>
    <Level number="14">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="fortitude">1</Increase>
	<Increase type="Skill">2</Increase>
	<Add type="Feat" subtype="fighter"/>
    </Level>
    <Level number="15">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="reflex">1</Increase>
	<Increase type="SavingThrow" name="will">1</Increase>
	<Increase type="Skill">2</Increase>
    </Level>
    <Level number="16">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="fortitude">1</Increase>
	<Increase type="Skill">2</Increase>
	<Add type="Feat" subtype="fighter"/>
    </Level>
    <Level number="17">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="Skill">2</Increase>
    </Level>
    <Level number="18">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="fortitude">1</Increase>
	<Increase type="SavingThrow" name="reflex">1</Increase>
	<Increase type="SavingThrow" name="will">1</Increase>
	<Increase type="Skill">2</Increase>
	<Add type="Feat" subtype="fighter"/>
    </Level>
    <Level number="19">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="Skill">2</Increase>
    </Level>
    <Level number="20">
	<Increase type="HD">10</Increase>
	<Increase type="BAB">1</Increase>
	<Increase type="SavingThrow" name="fortitude">1</Increase>
	<Increase type="Skill">2</Increase>
	<Add type="Feat" subtype="fighter"/>
    </Level>
  </Levels>
</Class>
Looking pretty good! So what's missing? What can't we represent with our current implementation?
<--Rethink ^--xmld20--^ Rethink, part 3-->
©2002-2017 Wayne Pearson