Edge Support (Savage)
In Savage Worlds, edges represent the beneficial counterparts of hindrances, and we now need to get them working.
Component and Component Set
As with hindrances, edges have a lot of behaviors in common with the existing "Ability" component set, but they also introduce new behaviors that we must manage. To that end, we'll define an "Edge" component and a corresponding component set. The new component will be evolved in the following sections, so we start here with a simple component that does nothing and add the component set on top of it, incorporating the "Ability" and "SpecialTab" components as well. Since edges can be selected through advancements, we'll also include the "CanAdvance" component that we'll need later. The net result is the following, which we'll add to the file "traits.str":
<component id="Edge" name="Edge" autocompset="no" panellink="abilities"> <compset id="Edge"> <compref component="Edge"/> <compref component="Ability"/> <compref component="SpecialTab"/> <compref component="CanAdvance"/> </compset>
Inclusion on "Special" Tab
The influence of edges will be important during play, so we need to make sure they appear on the "Special" tab. The basic appearance is handled by inclusion of the "SpecialTab" component in the component set, but we need to customize the behavior appropriately. We first need to define a new classification tag for ordering the display of edges on the "Special" tab. To do this, we add an "Edge" tag to the "SpecialTab" tag group within the file "tags.1st" with a suitable order value to sequence everything appropriately.
<value id="Edge" order="40"/>
Once the tag is defined, we need to make sure that all edges are assigned the tag. We do that within the component by adding the line below:
<tag group="SpecialTab" tag="Edge"/>
The Savage Worlds rulebook breaks edges up into an assortment of categories. In keeping with that approach, the data files should do the same. The solution is to create a new tag group for the edge category and populate it with tags corresponding to each category. So we create an "EdgeType" tag group and define the appropriate tags, as shown below. Every edge should be assigned one of these tags.
<group id="EdgeType"> <value id="Background"/> <value id="Combat"/> <value id="Leadership"/> <value id="Power"/> <value id="Profession" name="Professional"/> <value id="Social"/> <value id="Weird"/> <value id="Wildcard" name="Wild Card"/> <value id="Legendary"/> </group>
Identification for Pre-Requisites
There are numerous situations where one edge precludes or depends upon another edge. The most common example is the various "levels" of an edge, where there is a basic version of an edge and one or two advanced versions that require the lesser versions to already be taken. For example, the "Very Attractive" edge requires the "Attractive" edge as a pre-requisite. To support this, we must track the edges that have been added to the character in a centralized way. This is most easily accomplished by designating an "identity" tag group for edges and then forwarding the identity tag of each selected edge to the hero. The net result is that the hero will always possess tags for each edge chosen for the character, which we can then test against.
We can designate an identity tag group on a component by adding a single line, which automatically defines and assigns the tag to each thing. Forwarding the identity tag to the hero is achieved with a one-line script. Both pieces should look like the following:
<identity group="Edge"/> <eval index="1" phase="Setup" priority="5000"><![CDATA[ perform forward[Edge.?] ]]></eval>
There is one last facet of edges that we haven't addressed yet. Every edge has a minimum character rank specified, and the character must be at least that rank in order to select the edge. So we need to track the minimum rank, and the easiest way to do it is to treat the rank as a numeric value and use a field to specify the value. As we established previously, character ranks range from 0-4, with zero corresponding to a Novice and four indicating a Legendary character. So we need to add a field for the minimum rank, as shown below.
<field id="edgMinRank" name="Minimum Rank" type="static"> </field>
Once we have the field in place, we then need to verify that the character satisfies the minimum rank as a pre-requisite. This is accomplished by defining a shared pre-requisite on the component that will be inherited by all things derived from the component. Within the Valid script for the pre-requisite, we do not need to differentiate between whether it is testing a thing prior to selection or a pick that has been added by the user. The field that dictates the requirement is "static", so it cannot be changed for a pick. Consequently, we can always utilize the state of the thing instead of having to distinguish between picks and things. We also need to synthesize an appropriate validation error message to report to the user. Putting it all together yields the following pre-requisite:
<prereq iserror="yes" message="Minimum Rank required."> <valid><![CDATA[ ~get the minimum rank required for the edge to be valid var rank as number rank = altthing.field[edgMinRank].value ~if the minimum rank is satisfied, we're good to go if (herofield[acRank].value >= rank) then @valid = 1 done endif ~mark the panel as invalid altthing.linkvalid = 0 ~synthesize an appropriate validation error message if (rank = 1) then @message = "Seasoned" elseif (rank = 2) then @message = "Veteran" elseif (rank = 3) then @message = "Heroic" elseif (rank = 4) then @message = "Legendary" endif @message &= " rank required." ]]></valid> </prereq>
Wild Card Restrictions
A fair number of edges are limited for use only with "wild card" characters, such as PCs and pivotal NPCs in the story. We could implement a separate pre-requisite test for each of these edges, but the number is significant and it is much easier to handle everything in a very generic way within the component. We start by defining a new field for the component that indicates whether the character is required to be a "wild card", as shown below. A non-zero value indicates that a wild card is required and the default value is zero to indicate no requirement unless explicitly specified otherwise.
<field id="edgIsWild" name="Is Wild Card Needed?" type="static"> </field>
We can now define a pre-requisite on the component that compares the requirement field against the field we added earlier on the character that indicates whether the character actually is a "wild card". We do not need to differentiate between picks and things within the Valid script, since the wild card requirement field is static and cannot change for a pick. The net result is shown below.
<prereq iserror="yes" message="Wild Card required."> <valid><![CDATA[ ~if the hero is a wild card, then we know we're going to be valid if (herofield[acIsWild].value <> 0) then @valid = 1 done endif ~we're valid if the edge does NOT require a wild card if (altthing.field[edgIsWild].value = 0) then @valid = 1 done endif ~we're not valid, so mark the panel as invalid altthing.linkvalid = 0 ]]></valid> </prereq>
Every character has a dynamic number of edges that he is allowed to select, as dictated by the "resEdge" resource that we defined earlier. Whenever an edge is selected for a character, one slot must be spent from the resource. We can perform this automatically for each edge via a script on the component, and the script should look something like the one shown below.
<eval index="2" phase="Setup" priority="5000"><![CDATA[ #resspent[resEdge] += 1 ]]></eval>