The Savage Worlds data files are starting to come together nicely now. However, we still have a few significant tasks left to complete. The most obvious one at this point is that we haven't dealt with equipment yet. We'll start with equipment in general and simple gear in particular.
As with previous stages in the development of our data files, the first step is to assess the differences between the Savage Worlds game system and the default mechanisms provided by the Skeleton files. In general, the Skeleton files provide the majority of what we'll need. There are only a small number of core differences between what's provided and what we need. The sections below will address each of those areas.
The first thing we must handle for Savage Worlds is the notion of a time period. The Savage Worlds rulebook presents a small number of basic time periods, and different assortments of gear are available within each of those time periods. Given that there are a growing number of Savage Settings supplements for the game, and since each setting can establish its own array of available gear, our solution should be something that can be readily expanded to support those settings. The Kit's "sources" mechanism is exactly what we need.
The sources mechanism allows an author to define an assortment of different configuration settings that the user can control via the "Configure Hero" form. Each source is presented to the user as a different setting that can be toggled on and off, and the sources can be organized into an hierarchical structure if you wish. We can then associate sources to things, making those things dependent on whether the user enables the corresponding source(s). We'll setup a "Time Period" source that is not user-selectable, and then we'll create a variety of user-selectable sources as children beneath it for each time period.
To add our sources, open the file "control.1st" and locate the "Optional" source that is pre-defined. Delete that source and replace it with the new sources that we'll be using. We assign an explicit sort order to each time period so that they are sorted chronologically when displayed instead of using the default alphabetical order. We also need to designate one source as the default. The net result should look similar to the source definitions shown below.
<source id="TimePeriod" name="Time Period" selectable="no" description="Time periods and Savage Settings that govern the availability of equipment"> </source> <source id="TimeMedi" name="Medieval" parent="TimePeriod" sortorder="1" default="yes" description="Enables the availability of equipment from the Medieval time period"> </source> <source id="TimePowder" name="Black Powder" parent="TimePeriod" sortorder="2" description="Enables the availability of equipment from the Black Powder time period"> </source> <source id="TimeModern" name="Modern" parent="TimePeriod" sortorder="3" description="Enables the availability of equipment from the Modern time period"> </source> <source id="TimeFuture" name="Futuristic" parent="TimePeriod" sortorder="4" description="Enables the availability of equipment from the Futuristic time period"> </source>
Once the sources are defined, we can associate a thing with a particular source via the "usesource" element. This element specifies the unique id of the source to which the thing is linked. If a given thing should be available for multiple sources, such as Medieval hand weapons also being available during the Black Powder time period, then the thing should be assigned both sources. If either source is enabled by the user, the thing will be available for selection. For example, an Umbrella from the "Modern Items" list within the rulebook would be associated with the "Modern" time period much like the following example.
<thing id="eqUmbrella" name="Umbrella" compset="Equipment" description="Description goes here"> <fieldval field="grCost" value="5"/> <fieldval field="grWeight" value="2"/> <usesource id="TimeModern"/> </thing>
A variety of equipment in Savage Worlds is assigned a cost of "Military", which indicates that the item cannot be purchased and is only available to military troops. There are two basic ways that we can support this behavior within our data files. The first option is to designate a special cost value that, when assigned to a piece of equipment, indicates the equipment should be treated as having a cost of "Military". If we use a value of zero, then we aren't able to have any piece of equipment that properly has a zero cost, so that's not a good idea. However, if we use a non-zero value, then we have to do special handling everywhere when buying and selling equipment to treat that special value as actually having a zero cost, and that's not a very good idea either. The other option is to leave the actual cost as zero for military equipment and assign a special tag to designate the equipment appropriately. This is a better approach, since the only thing we have to do specially is ensure that any piece of equipment with the special tag is displayed as having a cost of "Military".
We start by defining our new tag. Since this is a tag the user will be able to control via the Editor, we'll add it to the "User" tag group. To make things as obvious as possible, we'll simply name the tag "Military". Open the file "tags.1st" and locate the "User" tag group, then define the new tag. It should look similar to the one below.
<value id="Military"/> <!-- Identifies a piece of equipment with a cost of "Military" -->
Now that the tag is defined, we need to recognize it properly and display our cost. This is most easily accomplished by the introduction of a Finalize script for the "grCost" field of equipment. We need to allocate suitable space for the finalized value, and then we simply check for the tag within the script. If the tag is present, the value is "Military", else the value is the numeric default. Open the file "equipment.str" and locate the "Gear" component, then find the "grCost" field. It seems that the field already has a Finalize script that formats the monetary cost appropriately. So all we need to do is revise the script to handle the special case of the tag before doing anything else. The net result should look similar to the script below.
~if we have a military cost, report that fact if (tagis[User.Military] <> 0) then @text = "Mil" done endif ~if this is a thing, we have to determine the value for use below; if we ~have a non-zero lot cost, override our value based on the lot cost, else ~use multiply the unit code by the lot size. See the Calculate script ~comments for more details. if (ispick = 0) then if (field[grLotCost].value > 0) then @value = field[grLotCost].value else @value = field[grCost].value * field[lotsize].value endif endif ~convert the cost to a value for display appropriately if (@value = 0) then @text = chr(150) else var moneyvalue as number var money as string moneyvalue = @value call Money @text = money endif
Basic Gear Categories
The final wrinkle in the way basic gear is handled for Savage Worlds is that the gear is broken up into categories for improved organization. In order to parallel this, we need to define a new tag group for tracking the type of gear. We can then define the appropriate types as tags within the group. Once defined, the appropriate tag can be assigned to each piece of gear.
For consistency with the rulebook, we want to sort gear by type, so we need to designate the tag group as having an "explicit" sequence behavior. Once we do that, we need to assign an "order" attribute to each tag so that HL knows the order in which to sequence the various groupings. We assign values that are in keeping with the rulebook.
In order to allow users to extend the set of gear types without having to modify the core files, we'll also designate the tag group as being "dynamic". Putting it all together yields a tag group specification similar to the one below, which must be defined within the file "tags.1st".
<group id="GearType" dynamic="yes" sequence="explicit"> <value id="Custom" order="0"/> <value id="Adventure" name="Adventuring Gear" order="1"/> <value id="Clothing" order="2"/> <value id="Food" order="3"/> <value id="Animals" name="Animals & Tack" order="4"/> <value id="Computers" order="5"/> <value id="Surveil" name="Surveillance" order="6"/> <value id="Ammo" name="Ammunition" order="7"/> </group>
Add Basic Gear
All the pieces are in place so that we can now define all of the basic gear within the Savage Worlds core rulebook. A couple of sample items are defined below for reference. You can either define the rest yourself or pull them out of the completed Savage Worlds data files that are included.
<thing id="eqBackpack" name="Backpack" compset="Equipment" description="Description goes here"> <fieldval field="grCost" value="50"/> <fieldval field="grWeight" value="2"/> <usesource id="TimeMedi"/> <usesource id="TimePowder"/> <tag group="GearType" tag="General"/> <tag group="thing" tag="holder"/> </thing> <thing id="eqTorch" name="Torch" compset="Equipment" stacking="merge" description="Description goes here"> <fieldval field="grCost" value="5"/> <fieldval field="grWeight" value="1"/> <usesource id="TimeMedi"/> <usesource id="TimePowder"/> <tag group="GearType" tag="General"/> </thing>
Revise Gear Tab
All the gear is in place, so let's look at how it's added and managed by the user on the Gear tab. All of the mechanisms associated with the Gear tab will be found in the file "tab_gear.dat", and the Skeleton files provide a solid starting point for our needs, but we'll refine everything a little bit for Savage Worlds. If we go to add a piece of gear, the first thing we'll notice is that the description area on the right for the selected piece of gear is rather narrow for a meaningful description. We can widen that region via use of the "descwidth" attribute within the "table_dynamic" element of the table portal. The default width is 250 pixels, so try increasing it to 275 and 300 to see which you prefer.
The next thing we'll notice is that the various gear options are sorted alphabetically, but they are not grouped like they are within the rulebook. As we discussed earlier, all tables list their contents alphabetically by default, but we can customize that behavior if we wish via the use of a "sort set". Open the file "control.1st" and you'll find a variety of "sortset" elements near the bottom. We need to add a new one that will sort the gear first by its type/category and then by name within each category. Each sort key within a sort set can be either a field or a tag group, specified by its unique id, and the order of the sort keys dictates the ultimate ordering of the items. We want our gear to be sorted by the type and then the name, so we'll need two sort keys. Putting it all together yields a sort set that looks similar to the one shown below.
<sortset id="Gear" name="Gear By Type and Name"> <sortkey isfield="no" id="GearType"/> <sortkey isfield="no" id="_Name_"/> </sortset>
Once the sort set is defined, we can reference it from the table portal so that all gear is shown to the user in the order dictated by the sort set. This is accomplished by adding the "choosesortset" attribute to the "table_dynamic" element of the table portal and specifying the id of our new sort set. With both the "descwidth" and "choosesortset" attributes added, the resulting "table_dynamic" element should look like below.
<table_dynamic component="Gear" showtemplate="grGrPick" choosetemplate="grGrThing" choosesortset="Gear" buytemplate="BuyCash" selltemplate="SellCash" descwidth="275">
There is one thing we've overlooked, though. If a thing does not possess a tag from a tag group specified in a sort set, that thing is sorted to the end of the list. This means that the three custom gear things are all sorted last now, but they should remain at the top of the list. The solution is to add a new "GearType" tag called "Custom" that is assigned an order value to put it first, after which the tag can be assigned to the three custom gear things. Once this is done, our gear is behaving the way we want it to behave.