Difference between revisions of "Adding Hindrances (Savage)"
Latest revision as of 20:13, 17 December 2008
Now that all of the mechanics are in place for hindrances, it's possible to actually define them. To keep them all together as a group, we create a new "thing_hindrances.dat" file where they will be added. When adding hindrances, be mindful of using the correct "#traitroll" or "#traitbonus" macro, since the two have important differences in their behavior.
Some hindrances apply penalties that are situational. When the situation may persist for an extended period, the user may want to toggle the effects on and leave them that way for a period of time. To support this, appropriate hindrances should be designated as able to be user-activated by assigning the "User.Activation" tag. This will display the hindrance as something the user can toggle on and off within the "In-Play" tab. A script that applies the effects can then check the actual activation state of the hindrance and apply the effects when appropriate.
If you need to reference a trait from a script of some sort (e.g. within a pre-requisite test), be careful to handle it properly. If the trait is a skill or something else the user can optionally add to the character, the trait might not exist on the character. If that's possible, be sure to use the "#traitfound" macro instead of "#trait", else you will receive run-time errors from HL that you're trying to access picks that don't exist.
Adding all the hindrances is a straightforward process of going through and entering all of the details accurately. We'll select a few representative samples to cover in the sections below, pointing out key facets of each.
We'll start with the "Delusional" hindrance, since it's relatively basic in nature. This hindrance can be either minor or major in severity, so we assign it an initial severity of minor (via the field) and then assign it the "User.UserSelect" tag to indicate the user can select the ultimate severity level. Other than that, there is nothing to do, since the hindrance's effects are something the GM must adjudicate. The result is a simple hindrance as shown below.
<thing id="hinDelude" name="Delusional" compset="Hindrance" isunique="yes" description="Description goes here"> <fieldval field="hinMajor" value="0"/> <tag group="User" tag="UserSelect"/> </thing>
Now we'll look at the "Bloodthirsty" hindrance, since it will demonstrate user-activated behaviors. This hindrance is always major in severity, so we set the field value accordingly. The effects of the hindrance don't always apply, so we allow the user to control when to apply them by assigning the "User.Activation" tag. In the script that applies the effects, we then check whether the activation state is on or off, applying the effects only if activated. The net result is the definition below.
<thing id="hinBloodth" name="Bloodthirsty" compset="Hindrance" isunique="yes" description="Description goes here"> <fieldval field="hinMajor" value="1"/> <tag group="User" tag="Activation"/> <eval index="1" phase="PreTraits" priority="5000"> <before name="Calc trtFinal"/><![CDATA[ ~if activated, suffer -4 on Charisma if (field[abilActive].value <> 0) then #traitbonus[trCharisma] -= 4 endif ]]></eval> </thing>
The "Phobia" hindrance is a perfect example of when the user needs to specify a suitable domain, in this case identifying what the character is afraid of. As far as the mechanics are concerned here, requiring the user to specify a domain is as simple as assigning the "User.NeedDomain" tag. So that's all we need to do besides allowing the user to designate the severity, and the results can be seen below.
<thing id="hinPhobia" name="Phobia" compset="Hindrance" isunique="yes" description="Description goes here"> <fieldval field="hinMajor" value="0"/> <tag group="User" tag="UserSelect"/> <tag group="User" tag="NeedDomain"/> </thing>
Dynamic Control Over User Activation
Now we'll switch to the "Bad Eyes" hindrance, since it demonstrates how to combine many of the mechanics involved and throws an interesting wrinkle into the mix. This hindrance can be either minor or major, so we assign it an appropriate field value and tag. When the hindrance is minor, the user can toggle the penalties on and off based on whether the character has temporarily lost his glasses, so we should probably assign the "User.Activation" tag to give the user control. But when the hindrance is major, the penalties always apply, in which case we don't want the user to have control. So what we really need to do is have the hindrance be user controlled only when it is minor. This requires that we change the behavior dynamically, which can be done within the script by assigning the tag only when the hindrance is minor. Putting it all together yields the following definition:
<thing id="hinBadEyes" name="Bad Eyes" compset="Hindrance" isunique="yes" description="Description goes here"> <fieldval field="hinMajor" value="0"/> <tag group="User" tag="UserSelect"/> <eval index="1" phase="PreTraits" priority="5000"> <before name="Calc trtFinal"/><![CDATA[ ~if this is a minor hindrance, allow the user to activate it if (field[hinMajor].value = 0) then perform assign[User.Activation] endif ~if this is a major hindrance or the user has activated it, apply the effects if (field[hinMajor].value + field[abilActive].value <> 0) then #traitroll[skShooting] -= 2 #traitroll[skNotice] -= 2 endif ]]></eval> </thing>
In rare cases, a hindrance will have pre-requisites that need to be properly handled. For example, the "Bad Luck" hindrance can't be taken at the same time as the "Luck" or "Great Luck" edges. For situations like this, we need to define an appropriate pre-requisite test that checks the state of the character and reports whether the pre-requisite conditions are satisfied. If not satisfied during selection display, the invalid choice can be highlighted appropriately. However, if an invalid selection is actually added to the character, then a validation message is displayed to the user. We can also designate the tab panel corresponding to the hindrance as invalid to highlight it to the user. We can put it all together into something that looks like the following:
<thing id="hinBadLuck" name="All Thumbs" compset="Hindrance" isunique="yes" description="Description goes here"> <fieldval field="hinMajor" value="1"/> <eval index="1" phase="PreTraits" priority="5000"> <before name="Calc trtFinal"/><![CDATA[ #trkmax[trkBennies] -= 1 ]]></eval> <!-- <pickreq ispreclude="yes" thing="edgLuck"/> <pickreq ispreclude="yes" thing="edgLuck2"/> --> </thing>
NOTE! In the above "pickreq" elements, we check for the existence of one of the two Luck edges. However, these things won't exist until we actually define the edges, so the compiler will reject the above thing as invalid. For now, we'll comment out the two XML elements, as shown above, and make a note to put these back into place when we actually add the edges later.
Acknowledging Our Limitations
Every now and then, you'll come across an incredibly specialized requirement for a particular thing that will require an inordinate amount of work to properly verify within the data files. When this happens, you can either spend many hours to handle the special case situation or you can defer the special case to the user. A perfect example of this within the Savage Worlds data files is the "Elderly" hindrance, which dictates that the extra skill points it confers must be spent on skills based on the "Smarts" attribute. It is simple to increase the number of skill points available to be spent, but requiring them to all be spent on a subset of skills requires that the additional skills be purchased and tracked separately from the standard pool of skills. While possible, it's a lot of work to implement properly, and all for a lone special case that is probably not very frequently used by players. In situations like this, it's often best to simply acknowledge the special case as a limitation of the data files and flag it to the user within the description text for the thing. That's what we're going to do with the "Elderly" hindrance.