Refining Arcane Backgrounds and Powers (Savage)

From HLKitWiki
Revision as of 08:23, 18 December 2008 by Rob (talk | contribs)
Jump to navigationJump to search

Context: HL Kit … Authoring Examples … Savage Worlds Walk-Through 

Overview

There are a variety of special restrictions and handling that need to be performed for arcane backgrounds and powers. Now that we've got the "Arcane" tab in place and working, we can add and test the remaining logic.

Arcane Background Drawbacks

Certain arcane backgrounds possess drawbacks that occur when the character rolls poorly when activating an arcane power (e.g. backlash, brainburn, etc.). These drawbacks are fundamental to the character, so they need to be shown on the "Special" tab. This entails we take a number of steps.

The first thing we need to do is define a new component and component set for drawbacks. The component set will integrate both the new "Drawback" component and the "SpecialTab" component so that all derived things appear properly on the "Special" tab. Drawbacks don't have any fields, but they need to have a unique "SpecialTab" tag to control their positioning on the "Special" tab, so we define the tag within the file "tags.1st" and then the component can assign that appropriate tag. The net result is something similar to the following.

<component
  id="Drawback"
  name="Drawback for Arcane Background"
  autocompset="no">
  <tag group="SpecialTab" tag="Drawback"/>
  </component>

<compset
  id="Drawback">
  <compref component="Drawback"/>
  <compref component="SpecialTab"/>
  </compset>

Once the component and component set are in place, we need to define each of the drawbacks. They are all extremely simple, requiring nothing special at all. We define them in the file "thing_arcane.dat", along with all the other arcane mechanics. We should also define them close to each of the arcane backgrounds to which they correspond. The following is an example of a drawback.

<thing
  id="drwMagic"
  name="Backlash"
  compset="Drawback"
  isunique="yes"
  description="Description goes here">
  </thing>

The final step we need to do is to automatically add the proper drawback whenever the corresponding arcane background is added. This is accomplished by specifying a "bootstrap" element within the arcane background. The "bootstrap" element automatically adds the designated thing whenever HL creates the thing it is assigned for. So the revised "Magic" arcane background would look something like the following.

<thing
  id="arcMagic"
  name="Magic"
  compset="Arcane"
  isunique="yes"
  description="Description goes here">
  <fieldval field="arcPowers" value="3"/>
  <fieldval field="arcPoints" value="10"/>
  <tag group="Arcane" tag="Magic"/>
  <bootstrap thing="drwMagic"/>
  </thing> 

Non-Available Powers

Various arcane powers are not suitable for use with certain arcane backgrounds. Since the rules outline these restrictions as suggestions, it would be inappropriate for the data files to prohibit arcane powers for arcane backgrounds. Instead, we'll use the Kit's pre-requisites mechanism to flag arcane powers as improper, which will still allow them to be taken and simply present a validation error. 

The simplest and most obvious way to handle this is to write separate pre-requisites for every arcane power, specifically testing against the precluded arcane backgrounds. But that requires that we define a lot of very similar pre-requisites. It also means that any supplements that introduce new arcane powers will similarly have to define all the separate pre-requisites. That's a lot of work that we can avoid by writing a single pre-requisite test on the component that is shared by all arcane powers.

Doing this requires that we devise a way to conveniently identify the various combinations of arcane powers and backgrounds that are either valid or invalid. Since most powers are available to each background, the list of exceptions will be much easier to maintain. Then the question becomes whether it's easier to track the precluded powers for each background or the precluded backgrounds for each power. The rules present the list of precluded powers for each background, so this would make sense, as it follows the presentation of the rulebook. However, stop and think for a moment about how this would be implemented. It would require that every arcane power be sanity checked against information that is part of the arcane background, and that would require a good amount of extra work to manage in the data files. In contrast, having each arcane power identify the arcane backgrounds to which it doesn't apply would be easy to implement, since the character already has a suitable arcane background tag assigned that can be checked against. So we'll go with this latter approach.

With our design in mind, we need a way to designate an arcane power as being invalid for a particular arcane background. Tags are the obvious solution, and we already have an "Arcane" tag group that we could use. However, the "Arcane" tag group is already used to identify what something is, so it would be confusing to use it at other times to indicate what something is not. The easiest way to solve this is to create a new tag group that indicates an arcane background that a power is not allowed to be. We'll call the new tag group "ArcaneDeny" and define the exact same set of tags as for the "Arcane" tag group, resulting in something like below.

<group
  id="ArcaneDeny"
  dynamic="yes">
  <value id="Magic"/>
  <value id="Miracles"/>
  <value id="Psionics"/>
  <value id="SuperPower"/>
  <value id="WeirdSci"/>
  </group>

Now we can assign the appropriate "ArcaneDeny" tags to all of our powers. For example, the rulebook states that the "Magic" arcane background does not usually have access to "Healing" or "Greater Healing". Consequently, we'll need to assign the "ArcaneDeny.Magic" tag to both of those powers. The "Healing" power is shown below as an example.

<thing
  id="powHealing"
  name="Healing"
  compset="Power"
  isunique="yes"
  description="Description goes here">
  <fieldval field="rnkMinRank" value="0"/>
  <fieldval field="powPoints" value="3"/>
  <fieldval field="powRange" value="Touch"/>
  <fieldval field="powLength" value="Instant"/>
  <fieldval field="powMaint" value=""/>
  <fieldval field="powTraps" value="Laying on hands, touching the victim with a holy symbol, prayer"/>
  <tag group="ArcaneDeny" tag="Magic"/>
  <tag group="ArcaneDeny" tag="SuperPower"/>
  <tag group="ArcaneDeny" tag="WeirdSci"/>
  </thing>

At this point, every power should properly identify the arcane background(s) for which it is not valid. The final thing we need to do is define the appropriate pre-requisite test to verify whether a given power is valid. Since each power identifies any backgrounds that it is invalid for, the pre-requisite must determine if the list of forbidden backgrounds matches the active background for the character. If it does, then the power is considered invalid. This can be accomplished via use of the "tagmatch" target reference in the Validate script, which can be used to check whether the "Arcane" tag on the character (i.e. the arcane background) matches any corresponding "ArcaneDeny" tags on the power. The resulting pre-requisite should look something like the following.

<prereq message="Not suitable for character's arcane background.">
  <valid><![CDATA[
    ~look for an "Arcane" tag in the initial context (character); if found, look for
    ~a corresponding "ArcaneDeny" tag in the power; if a matching tag is found, it
    ~means the power is invalid, so a result of zero indicates we're valid
    var result as number
    result = altthing.tagmatch[Arcane,ArcaneDeny,initial]
    if (result = 0) then
      @valid = 1
      done
      endif
    ~mark the linked panel as invalid
    altthing.linkvalid = 0
    ]]></valid>
  </prereq> 

Precluded Edges

The rules for Weird Scientists explicitly preclude the ability to select the "Soul Drain" edge. This means that the two require a suitable pre-requisite to deny the other. The pre-requisite for each needs to simply verify that the other edge has not already been selected, which can be handled via the "pickreq" element. The pre-requisite for the "Weird Science" arcane background edge will look something like the following, with the one for the "Soul Drain" edge looking very similar. [Remember: This is applied to the edge and not the arcane background.]

<pickreq ispreclude="yes" thing="edgSoulDrn"/>

Super Powers

The "Super Powers" arcane background doesn't have a corresponding arcane skill. Instead, every single arcane power has its own separate arcane skill when used as a super power. This requires that we define a suitable arcane skill for every arcane power. We also need to make sure these arcane skills are only visible when the corresponding power is possessed by the character and the arcane background employed is "Super Powers". We can use the same technique employed for normal arcane skills (i.e. a ContainerReq test), although we now need to test for a specific arcane power. There is no indication on the character of which arcane powers are possessed, so we'll need to add that. 

The easiest way to identify which arcane powers have been chosen on the character involves the use of identity tags. The "Power" component can define identity tags for each individual power. Then a component-based Eval script can forward the identity tags of added powers up to the character. Once the tags are on the character, they can be readily tested by the ContainerReq test. The code below shows what must be added to the "Power" component. Note that we've scheduled the script to occur at the same timing as the script that forwards the "Arcane" tag for arcane backgrounds (Initialize/1000). Since we'll be depending on these tags within ContainerReq tests using the same logic, it's easiest to keep our timing consistent within the data files.

<identity group="Power"/>

<eval index="2" phase="Initialize" priority="1000"><![CDATA[
  perform forward[Power.?]
  ]]></eval> 

We're now ready to define the arcane skills for each power. Or are we? It seems we have a problem, because arcane skills for super powers do not have an associated linked attribute. However, we've defined skills such that they require a linked attribute. One obvious solution would be to eliminate the requirement that skills always have a linked attribute. However, that would make it easy for anyone adding a new skill to inadvertently forget to add the linkage and we'd have to handle missing linkages. A less obvious (but better) solution would be to define a special attribute that was always hidden from the user. This provides us with a linked attribute for which we can control the value, ensuring that skills linked to it are always treated appropriately with regards to advancement costs. This is a little bit more work, but it provides greater safety, so we'll use this approach.

Adding the new attribute entails a number of minor tasks. First of all, the attribute needs to be hidden, so we'll assign it the pre-defined "Hide.Attribute" tag for this purpose. Next, we need to setup the value of the attribute appropriately so that the skills properly determine whether they are less than the linked attribute. Although the rulebook isn't clear on this point, the Savage Worlds designers have confirmed that skills for super powers are always considered greater than or equal to the linked attribute, which means that we can safely leave the attribute at its default value. Lastly, the attribute itself must be defined in the file "thing_attributes.dat", as shown below.

<thing
  id="attrSup"
  name="Super Power"
  compset="Attribute"
  isunique="yes"
  description="Used for arcane skills based on powers for characters with the Super Powers arcane background.">
  <tag group="Hide" tag="Attribute"/>
  </thing> 

Once we have the new attribute in place, we can finally define our new arcane skills tied to the arcane powers. All of the skills will be handled the same way, so only one is presented below as an example. The skill needs to perform a ContainerReq test that verifies both the arcane background and the proper arcane power.

<thing
  id="skpArmor"
  name="Armor (Power)"
  compset="Skill"
  isunique="yes"
  description="Description goes here">
  <tag group="Arcane" tag="SuperPower"/>
  <containerreq phase="Initialize" priority="2000"><![CDATA[
    Arcane.SuperPower & Power.powArmor
    ]]></containerreq>
  <link linkage="attribute" thing="attrSup"/>
  </thing>