The PCGen LST format: Part 2 – Races
Posted: , Updated: Category: GamesSuppose we wanted to define a new race. How would we go about defining something like the Halfling from the d20 SRD?
Halflings
- +2 Dexterity, -2 Strength.
- Small: As a Small creature, a halfling gains a +1 size bonus to Armor Class, a +1 size bonus on attack rolls, and a +4 size bonus on Hide checks, but she uses smaller weapons than humans use, and her lifting and carrying limits are three-quarters of those of a Medium character.
- Halfling base land speed is 20 feet.
- +2 racial bonus on Climb, Jump, Listen, and Move Silently checks.
- +1 racial bonus on all saving throws.
- +2 morale bonus on saving throws against fear: This bonus stacks with the halfling’s +1 bonus on saving throws in general.
- … (list of traits continues)
The PCGen Documentation > List Files > LST File Classes, Lessons 3 through 6, Fundamentals of Race Building, walks through the construction of example races. These lessons are enough to learn the basics.
My concern with the LST File Classes is that they were written many years ago, and don’t always show the “modern” way of doing things. e.g. the use of the SAB
tag where the ASPECT
tag would be preferred for new code. I would prefer to learn the language by dissecting the Pathfinder and DnD 3.5 data files, which are the most up-to-date available in the PCGen project.
↞※↠
In this article, I will dissect the Pathfinder data files cr_races.lst
and cr_abilities_race.lst
files to determine how the Dwarf
race is defined, and trace back the code responsible for implementing the Dwarf ~ Defensive Training
ability (one of a half-dozen abilities making up the Dwarf
.)
In dissecting these files, I have discovered that the Pathfinder and DnD 3.5e data files are made quite complicated by the need to support sub-races (i.e. Hill Dwarf, Aquatic Dwarf, Desert Dwarf…).
Home-brew races don’t need this complexity, and are therefore much easier to implement. I will write a separate article walking through the coding of a home-brew race. Those who are only interested in simple home-brew code may await that article.
For the time being, let us press on with the dissection of the PCGen data files.
Files where races are defined
In PCGen, the races for the Pathfinder system are defined in the following files, all found in /data/pathfinder/paizo/roleplaying_game/core_rulebook
:
cr_races.lst
- basic statistical information for each race, such as:SIZE:
- small, medium, large, hugeTYPE:
-Humanoid
,Undead
MOVE:
-Walk,30
,Swim,60
- …
cr_abilities_race.lst
- a collection ofABILITY
records which define each race’s traits and abilities, such as:- stat bonuses (+2 CON, -2 CHA)
- skill bonuses (+2 to Open Lock)
- saving throw bonuses (+1 Luck bonus to all saves)
- …
cr_abilitycategories.lst
- a small file - defines the categories of abilities ,such asDwarf Racial Trait
,Fighter Bonus Feat
, etc. which are used when codingcr_abilities_race.lst
. The most obvious use of this file is to group abilities for the player to choose amongst, i.e. the categoryFighter Bonus Feat
which contains all the feats that Fighter-class characters are allowed to take at 1st, 2nd, 4th, etc. levels.
Note the file-names all start with cr
standing for the [Pathfinder] core rulebook.
The 3.5ed files are similarly named rsrd
for the Revised System Reference Document - look in data/35e/wizards_of_the_coast/rsrd/basics/
.
The filenames [x]_races.lst
etc. are standardised according to the Data LST standards.
Basic race information: cr_races.lst
The definition of the Dwarf race in cr_races.lst
is fairly straightforward.
|
|
This is mainly basic information like the creature’s size (M, medium), the race’s type (Humanoid) and subtype (Dwarf), and so on.
Before moving on, note two features here:
- The
SORTKEY
ofa_base_pc
is alphabetically first in the list of all race names, so it appears at the top of the list in the PCGen GUI. This means that you don’t have to wade through the hundreds of monster races (ape, bear, cheetah, deep one, earth elemental…) to get to the PC races (human, dwarf, elf, etc.) STARTFEATS:1
grants the race one bonus feat at first level. All PC races get a feat at 1st, but monster races don’t, so we have to be explicit about whether we want a given race to get a free feat at 1st, or not.
The real meat of the race definition is called out by the tag ABILITY:Internal|AUTOMATIC|Race Traits ~ Dwarf
. This calls into the record called Race Traits ~ Dwarf
in cr_abilities_race.lst
.
Race ability definitions: cr_abilities_race.lst
This is an ability .lst
file. Each record (line) in this file defines an ability.
If we search for Race Traits ~ Dwarf
we find the following, apparently empty, ability record:
|
|
The record has a CATEGORY
tag, but nothing else.
What’s going on here?
A bit more searching shows more lines matching Race Traits ~ Dwarf
:
|
|
These lines CATEGORY=Internal|Race Traits ~ Dwarf.MOD
are modifying the “empty” record Race Traits ~ Dwarf
. This is a trick for breaking up a long record into multiple lines, which is explained in my earlier post Exploring the PCGen file format – Part 1: Really long lines.
After the .MOD
lines have modified the existing Race Traits ~ Dwarf
record, the end result is:
|
|
The Race Traits ~ Dwarf
ability record now contains ten ABILITY
tags within it. That is, the Race Traits ~ Dwarf
ability is coded to grant ten more sub-abilities. These include Dwarf ~ Defensive Training
, Dwarf ~ Greed
, Dwarf ~ Hatred
, and so on.
Actual ability definitions
We have seen that the Race Traits ~ Dwarf
ability is just an in-direct handle to a number of sub-abilities, like:
|
|
The actual mechanical effects of the Dwarf ~ Defensive Training
ability are defined in a separate record, further down in the file, as:
|
|
From this, we conclude that the cr_abilities_race.lst
file works like this:
In
cr_abilities_race.lst
, a blank definition is written for theRace Traits ~ Dwarf
ability.The details of the Dwarf racial abilities are defined in individual records, one per sub-ability, like
Dwarf ~ Defensive Training
,Dwarf ~ Greed
,Dwarf ~ Hatred
, and so on.The
CATEGORY=Internal|Race Traits ~ Dwarf.MOD...
syntax is used to add pointers from theRace Traits ~ Dwarf
ability to each of the sub-abilities,Dwarf ~ Defensive Training
,Dwarf ~ Greed
, and so on.The
cr_races.lst
defines theDwarf
race as having just the one ability,Race Traits ~ Dwarf
. Since this points to all the sub-abilities, grantingRace Traits ~ Dwarf
automatically grants all the sub-abilities, without needing to refer to each one individually inraces.lst
.
!PREABILITY?
One thing remains un-explained.
If it was only required to use the Race Traits ~ Dwarf
ability as a handle onto the ten sub-abilities, then this would suffice:
|
|
However the actual code looks like this:
|
|
Recall that PREABILITY
is used to implement conditional logic. If the PREABILITY
condition evaluates ‘True’, the tag is applied. If the PREABILITY
condition evaluates ‘False’, the tag is ignored.
Adding !
to the front inverts the logic. !PREABILITY
will cause the tag to be applied if the condition evaluates ‘False’ and vice-versa.
Having recalled how PREABILITY
and !PREABILITY
operate, we ask: Why would we ever want to remove any of the Dwarf racial abilities? Surely all dwarves have Dwarf ~ Defensive Training
? (+4 Dodge AC vs. Giant).
The answer is: No, only the default kind of Dwarf (the ‘Hill Dwarf’) has +4 Dodge AC vs. Giants. There are multiple subtypes of dwarf, and these subtypes have different bonuses.
Searching through the entire Pathfinder data file directory for DwarfDefensiveTraining
reveals:
- The
Ouat
class (a type of Monk from the Inner Sea Combat book) is made up of dwarves who have rejected the traditional Dwarf training vs. Giants, so they don’t have +4 AC vs anything. (isc_abilities_class.lst
.) - The
Saltbeard
from the Advanced Races Guide is a sub-race of dwarves who live on the high seas. There are no giants in the ocean, so a Saltbeard loses the +4 AC vs. giants, but gains +2 AC vs. any creature of the Water or Aquatic subtypes. (arg_abilities_race.lst
.)
This indicates that all the !PREABILITY
logic is there to support racial sub-types.
The logic looks like:
|
|
which is read as NOT having an ability of TYPE = DwarfDefensiveTraining.
If the default Dwarf is used, then there will be no pre-existing abilities of the type DwarfDefensiveTraining
, so the logic will evaluate to ‘True’. The ABILITY:Dwarf Racial Trait|AUTOMATIC|Dwarf ~ Defensive Training
tag will be applied, granting the Dwarf ~ Defensive Training
ability.
If a racial sub-type defines an ability of the type DwarfDefensiveTraining
(in the ability category Special Ability
), then the !PREABILITY
logic will evaluate to ‘False’. The ABILITY:Dwarf Racial Trait|AUTOMATIC|Dwarf ~ Defensive Training
will be ignored.
Conclusion
Racial abilities are implemented by adding references from the race definition in _races.lst
to one (or more) abilities in _abilities_race.lst
.
A smart way of doing this is to make one reference from _races.lst
to a ‘master’ ability in _abilities_race.lst
, like Race Traits ~ Dwarf
, and then add further references from the ‘master’ ability to multiple sub-abilities.
Advanced !PREABILITY logic for sub-races
The Pathfinder and DnD 3.5 data files contain some advanced logic in the racial ability definitions:
|
|
The logic is in there to support sub-races, i.e. Dwarf → Saltbeard, which requires the ‘default’ racial abilities to be disabled in favour of the sub-race’s abilities.
The happy news is that most home-brewers won’t be interested in sub-races, and so won’t need to implement anything with this level of complexity.
The simpler code:
|
|
will be quite sufficient for most home-brew.
Previously: Exploring the PCGen file format – Part 1: Really long lines
From Andrew Maitland (2015-07-06) we have the below comment, and another more detailed forum post.
Only two “sub races”? I wouldn’t have coded up that crazy advanced logic if the issue was simply two subraces (which tend to be ignored in pathfinder).
That code is invoked quite a bit, thanks to the Advanced Player’s Guide giving new rules to swap Racial Traits – that is when I coded up those up (took three distinctive iterations before I finally got the correct method – first pass involved kits, it wasn’t pretty… numerous bugs for having elf traits as a halfling). Each race trait beyond the originals has a COST:0 plus an exclusion “PC cannot possess TYPE=x, or in your example “DwarfDefensiveTraining” – which the original trait does not include to avoid circular logic, the exclusion is to avoid taking two traits that affect the same racial trait. For 3.5e the Unearthed Arcana book introduced OGL subrace options, which is why the logic exists in the RSRD. Otherwise the RSRD code support would have only been to support homebrew options beyond our official releases.
You are correct about empty records. Much easier to debug issues over multiple lines. You should have seen the race files before I made that change… complicated doesn’t begin to describe it. If you want a trip down memory lane, I can get you a copy of them.
For the SORTKEY, that is overkill to be honest. TYPE:PC places it at the top of the race list already. But most people wouldn’t know that TYPE:PC actually does that, so shrug I included it. Class sorting has the same logic – “Base” = top, “Prestige” next and then everything else in alpha order after.
One correction I see – STARTFEATS is absolutely required IF the race/class ever acquires feats. Non-Intelligent beings, such as Oozes, mindless undead and mindless constructs, never gain skills or feats, hence they will lack that entry.
As to ye olde documentation. Yes, those are over ten years old easily. The problem with keeping those updated is lack of volunteers. Do you want new books, or updated documentation? Most people ask for books.
I would say you’d make a great documentation monkey. We have openings
Cheers, Andrew Maitland