Refactoring Retreat

Just finished my third (and hopefully final for this year) road-trip to Atlanta and back.  Flights were crazy expensive over Memorial Weekend, so I opted to take a day off work and drive my daughter to her drum corps camp.  While there, I followed my usual practice of major refactoring (since I’ve got little else to do on Saturday).

Amongst the things I accomplished:

  • defined a MagicAugment adjunct for enhancing weapons and armor, replacing a rather loosely defined “IsDependent” property of base adjuncts
  • allowed natural weapons to be augmented (and included ability to have +0 augmentation to overcome damage reduction)
  • excluded species from the species selection list if the constructor has arguments (such as a Skeleton, which needs a source creature to work)
  • fixed some icons on menus by going through the resource manager instead of directly at the package
  • Traits became adjuncts
  • changed some magic-styles back to match OGL names
  • created an UndeadClass
  • defined BaseMonsterClass as an IPowerClass (so it can source powers)
  • removed GetTraits (which just enumerated strings)
  • did some housecleaning on power classes and fractional power dice
  • defined body cloning (for skeleton/zombie at the very least)

Since I got back, I did a few more things:

  • refactored PowerDefs and PowerSources (and their interfaces) to have non-action oriented versions in support of qualities that do not have actions associated with them (think: magical damage reduction).  My goal here is to get all power sources running as adjuncts so that anti-magic fields (and such) can shut down everything magical without having to write tons of specialized code
  • made the PickUpHandler check load limits

Next:

Finish equipment and natural weapon transfer for skeleton, follow similar pattern for zombie (possibly generalize).

Advertisements

Creature Templates

Reading the SRD, one might think there are only two types of creature templates (changes that can be applied to a creature to make it more powerful).  These are: acquired and inherited templates.

Acquired templates are supposed to be templates that are added to a creature well after it has acted as a a non-templated version of the creature, and includes such things as lycanthropes (were-wolves, were-rats, etc), ghosts, zombies, skeletons, liches and vampires.

Inherited templates are supposed to be templates that are part of the creature make-up from the beginning, such as fiendish, celestial, half-fiend, half-celestial and half-dragon (but which may also include lycanthropes!)

When attempting to program these, I can identify four semi-distinct categories:

Altered Species

Fiendish, half-fiend, celestial, half-celestial and half-dragon fall into this category.  Typically used for creatures that do not progress by character class (or have some progression with “racial power dice”).  Rather than use the standard species traits and progressions, the altered progressions and traits are used instead.

Replacement Creature

Ghost, skeleton and zombie fall into this category.  There is a base creature instance which is used to build out the replacement creature.  The original creature needs to be tracked in case the template is removed (that is, the condition that made the replacement creature is undone).

Replacement Creature with Advancement Alterations

Liches and vampires use this style.  The base creature instance is used to build a replacement creature, but the creature can advance in character class.  Any subsequent character class advancement may be altered from its normal class features (typically power dice size), but also may include strengths of special powers such as spell resistance.

Advancement Class Analog

Lycanthropes gain a number of “racial power dice” indicated by the type of lycanthropy.  These act like a character class, but care needs to be taken in removing the “affliction” (class and power dice) since it is possible to advance in character class level after gaining the “affliction”.


Object: Animated

I had tagged my son with creating an adventure module (for low level characters) a little while back, and he got back to me telling me had included animated objects and zombies.  Zombies (in the OGL world) are created by templates, so I knew I’d have to tackle them eventually.  Animated objects seemed like a relatively simple thing, but the more I dug into it, the murkier it became.

So far, the only “species” I had worked on were a gaggle of humanoid-type classes suitable for player characters (including the goblin), and a gargoyle, since he’s a good testbed for flight, increased size by power-dice, and can take class levels.

In all of these I had a single abstract method that had to be overridden when connecting the species to a creature, and another when disconnecting the species.  I refactored this into a whole slew of overridable functions, one for each major area, like body construction, abilities, requirements, senses, and movements (etc. etc.)

I also defined a Slam natural weapon and a slam item slot (animated objects use slam).  So far, this was some simple refactoring to help guide future species construction, but then the oddities set in…

Animated Objects have no Constitution score, they do not gain feats or skill points per power die (in fact they don’t really “gain” anything, as they are almost like a template applied to objects).  While not as obvious, it was just as simple to make them not gain ability boosts every 4 power die.

The lack of CON and the immunities required some validation and creation of lots of little handlers and filters to block interactions from things like poison, or handle the absence of non-lethal damage.  Also I defined some adjuncts that can filter out other adjuncts by explicit type, source magic type or source magic power descriptor and prevent them from anchoring to the creature.  I revamped the way adjuncts bind and defined that adjunct binding was an interaction so that it could use the HandleInteraction-style of monitoring, prevention and alteration.  Previously I used a ChangeMonitor class that allowed other things to connect and signal their intention to veto the change.

Also, the size-ranges for animated objects as they “progress” in power dice don’t work like the standard set, so I had to factor in custom size ranges.  The ability scores and natural armor follow their own path for animated objects.  Weapon damage for animated objects also doesn’t follow any normal weapon progression, so I had to virtualize the roller lookup and retain the standard as a default when no custom lookup by size is supplied.

And…animated objects come in different forms, materials and aspect ratios (tall versus long), exposing some weaknesses in my original model of dealing with reach squares upon size changes.  I had to provide level 1 advancement requirements for some of these, but some others (such as aspect ratio and partial power die) I deemed reusable enough to be in the BaseMonsterClass.  Dealing with a creature that can have a fractional power die proved a bit problematic, but ultimately resolved (as a level 1 requirement flag that prevents advancement past 1 until the flag is set to non-fractional).  This also led me to having the functions to “count” creature power dice accounting for fractions when the number of power-dice affected becomes relevant to a magic power.

I also cleaned up some code that made refreshing the character sheet in WPF workshop a bit easier (except for attack modifiers which are still a bit wonky right now).

Not quite “done” with the animated object, but definitely past the bulk of it.