Integrated Editor Support (Savage)
Context: HL Kit … Authoring Examples … Savage Worlds Walk-Through
Overview
Our data files are basically complete. Our focus now shifts to the final steps necessary to prepare the data files for release to others. The first of these final steps is setting things up so that users can leverage the integrated Editor provided within HL.
Most gamers will have their own custom tweaks that they employ within their gaming group or that are unique to a particular game world. The goal is to enable them to easily add that material. You've invested quite a bit of time in creating your data files, so spending a small amount more to maximize the ability of others to use your files is a worthwhile investment.
Using the Editor
We assume that you're at least moderately familiar with using the Editor for a different game system. If you haven't done so yet, take the time to review the documentation for one our licensed game systems and familiarize yourself with how the Editor works. After a little bit of experimenting, you should be able to appreciate how much simpler the Editor is to use than manually editing XML files. Our new objective is to wrap our data files up in a way that allows users to quickly and easily create new content via the Editor.
Editor Basics
Internally, the Editor is driven by an assortment of "editthing" XML elements. Every "thing" is derived from a component set. Every type of thing that you want users to be able to create must have an "editthing" defined for it. Consequently, you'll need to define a separate "editthing" for every component set that users can create things for.
Within each "editthing", you must define one or more "inputthing" elements. Each "inputthing" corresponds to exactly one specific facet of a particular thing. For example, the value of a field is controlled via an "inputthing". So is whether a particular tag is assigned to the thing.
In an effort to keep everything as simple as possible for users, the Editor uses only a handful of simple mechanisms. These include checkboxes, picking an option from a list, entering a value, and a few others. Each "inputthing" specifies the exact user-interface mechanism to be used for customizing a single facet of the thing being edited. Along with the mechanism, it must also provide the internal details for how to map the visual mechanism to something concrete in the data files.
Let's look at an example. Skills can optionally require the user to specify a domain. Internally, this detail is controlled for skills via the "User.NeedDomain" tag. Within the Editor, we want the user to simply specify whether the skill requires the domain or not. The best way to handle an either-or situation like this is by showing the user a checkbox. So we would define an "inputthing" that uses the "tagcheck" mechanism. This mechanism presents a checkbox to the user and assigns a tag to the thing based on whether the checkbox is checked. If we specified the "User.NeedDomain" tag for the "tagcheck", that tag would be added to the thing if the checkbox is checked and omitted if unchecked.
The contents of an "editthing" are primarily just a list of "inputthing" elements. The order of the "inputthing" elements dictates the order in which everything is presented to the user within the Editor. This gives us complete control and allows us to incrementally get our data files to fully utilize the Editor. In the sections below, we'll be looking at this process in detail, with concrete examples. Through the process, you'll be exposed to most of the different "inputthing" mechanisms and how to use them.
Use Tags Whenever Practical
Before we start implementing Editor support, we need to first address an important detail. The majority of the "inputthing" mechanisms center on the use of tags. The reason for this is that tags provide a critical benefit that simple values and text fields do not. Tags offer a restricted set of inputs that the user can select from.
In most situations, the data files for any game system will be designed around various small groupings of options. In Savage Worlds, all attributes and skills use a die type that ranges from "d4" to "d12". Hindrances can be either minor or major in severity, thereby having a cost of 1 or 2 points. The character's rank ranges through five levels, and edges can specify a dependency on the rank level. The list goes on and on.
If we present the user with an empty field to enter a value into, we have no way of knowing that the user entered something valid. For example, if we present a field for the user to specify the minimum strength requirement for a ranged weapon, there is nothing to stop the user from entering a value of 42. Even if the user means well, the question arises whether he should be entering a value of 10 for a "d10" or a value of 5 to correspond with the technique we use internally. However, if we present a list of tags containing only the five valid die types, there is no opportunity for confusion and no opportunity for error.
There are still a variety of places where an arbitrary text or value field is exactly what we need. However, we will strive to use them only when they are truly appropriate. Keep this in mind as you're working on your own data files. We'll be running into a few situations below where we need to change our data files to leverage tags instead of fields.
Taking Inventory
The final thing we should do before starting on our implementation is take inventory of our data files. We need to go through all the different files to identify which component sets we want to expose to users within the Editor. In general, this list should consist of any objects that we expect users will want to customize for their own games. Once we have the list culled out, we should then organize it into a reasonable sequence that will be easiest to implement.
The list we can identify for Savage Worlds is presented below, showing the component set id and the corresponding group of objects the user will be operating upon. With this list, we have a clear path for getting full Editor integration operational.
- Attribute - Attributes
- Skill - Skills
- Trait - Derived Traits
- RaceAbil - Racial Abilities
- Edge - Edges
- Hindrance - Hindrances
- Reward - Hindrance Rewards
- Equipment - Mundane Items
- Melee - Hand Weapons
- Ranged - Ranged Weapons
- SpecWeap - Special Weapons
- Armor - Armor
- Shield - Shields
- Vehicle - Vehicles
- Arcane - Arcane Backgrounds
- Power - Arcane Powers
- Drawback - Arcane Drawbacks
- Injury - Injuries
- Race - Races
- Creature - Creatures
- Simple - Simple (used for validation rules and such)
- Mechanic - Mechanics (used for auto-bootstrapped behaviors)
Changes Needed
Since we want to utilize tags whenever possible within the Editor, we need to go through each of the identified component sets above and look for places where we must make revisions. There are a total of four changes we need to make to the mechanics to streamline Editor integration.
The first change we'll notice is within the "Edge" component. The "edgIsWild" field is a simple "yes" or "no" situation. As such, it must be changed to the use of a tag, with the tag indicating a wildcard is required. To handle this, we'll define a "User.NeedWild" tag. We can then delete the field and go through all edges to assign the tag whenever the edge requires a wildcard. The final modification is within the "prereq" element on the "Edge" component, where the test of the field value must instead test the presence of the tag.
The second change is within the "MinRank" component, which will impact both edges and arcane powers. The minimum rank is specified via a field value, but it should be handled via a tag. We'll define a new "MinRank" tag group with tags corresponding to each rank level, as shown below.
<group id="MinRank"> <value id="0" name="Novice"/> <value id="1" name="Seasoned"/> <value id="2" name="Veteran"/> <value id="3" name="Heroic"/> <value id="4" name="Legendary"/> </group>
With the tag group in place, we can delete the field and then tweak the "prereq" element on the component so that it checks for the tag instead of the field value (just like we did above). We can then go through all edges and arcane powers, converting all use of the "rnkMinRank" field over to the appropriate "MinRank" tag.
The third change is required within the "Hindrance" component. The "hinMajor" field has a simple "yes" or "no" behavior, so we can change it to key on the presence of a tag. We'll define a new "User.HindMajor" tag that indicates a hindrance starts out as a major one. Then we can go through all hindrances and assign the tag whenever a hindrance starts out as major.
This situation is a bit different from the wildcard field, though. The user can select the severity for some hindrances. Consequently, we cannot delete the field, since we need it to store the user-selected severity rating. What we'll do instead is configure the initial state of the field based on the presence of the tag. Since the field is user-modifiable, we can't do this in an Eval script, because we would end up clobbering the user-assigned state with our script every time. Instead, we'll handle it within a Creation script, since we can setup the initial state in the Creation script and then allow the user to adjust the field thereafter. Our script should look like below.
<creation><![CDATA[ field[hinMajor].value = tagis[User.HindMajor] ]]></creation>
The final change we need to make is with weapons. The minimum strength requirement is currently handled via a field value. We need to change it in exactly the same way we handled the weapon die previously. If the tag is present, the corresponding requirement exists. The only caveat is that we must continue handling the presence of the weapon die as a strength requirement, with the separate requirement only applying when no weapon is given. Our new tag group should look like below.
<group id="StrReqDie" name="Strength Req Die"> <value id="2" name="d4"/> <value id="3" name="d6"/> <value id="4" name="d8"/> <value id="5" name="d10"/> <value id="6" name="d12"/> </group>
Upon closer examination of the files, we'll find it difficult to actually delete the field. This means we'll need to use the tag to set the field value appropriately. Since it's not user-adjustable, we can change the field from "static" to "derived", then we can define an Eval script that maps the tag to the field value. The mapping is easy due to the proper use of the value possessed by each tag, resulting in the Eval script below.
<eval index="3" phase="Setup" priority="1000"><![CDATA[ if (tagis[StrReqDie.?] <> 0) then field[wpStrReq].value = tagvalue[StrReqDie.?] endif ]]></eval>
The change impacts both the "WeapMelee" and "WeapRange" components, and all weapons based upon them. Any weapon that specifies the "wpStrReq" field must be modified to specify the corresponding tag instead. Beyond that, the only remaining change is within the "prereq" element on the "WeaponBase" component, which must change the tag instead of the field value on things.
At this point, we've got everything converted that must be converted. We can now begin define entries for Editor integration.
Starting Simple
All the pieces are in place, so it should be relatively straightforward for us to begin hooking everything into the Editor. We'll start with something simple, such as attributes. While few users will want to actually define a new attribute, there's no reason they can't, and making it possible is easy. All of our internal mechanisms just display a list of attributes, so adding a new one will merely increase the space needed to show all of them.
We must now take a look at the "Attribute" component set. There are three components that comprise the compset. The first is the "Attribute" component, which has nothing interesting that must be configured for a new attribute. The last is the "CanAdvance" component, which also has no behaviors that must be tailored for individual attributes. That leaves the "Trait" component, for which the only interesting field is the abbreviation ("trtAbbrev").
Now let's take a look at all of the attributes we've defined so far. There are six of them, including the one we added for super power skills. In assessing the attributes, there are two tags that we define on one or more of them. Each of these tags should be made customizable by the user when creating a new attribute. Combining that with the field identified above, we have the following three special pieces of information that we want the user to configure.
- Abbreviation - This will be a simple field where the user can enter the text he chooses. We can use a "field" input to capture the field value with the Editor.
- Hide from User - The super power attribute is hidden, so we must allow users to hide any new attribute that they may add. This state is controlled through the presence of a tag. We'll use the "tagcheck" input for Editor integration, since the tag will be assigned if the user checks the box.
- Display Sequence - The order in which attributes is shown depends on an explicit sequence defined by the author, which is dictated via a tag assignment. The user will need to assign a proper tag from a specific tag group, but the user can choose any tag that he wants to control the order. For this, we'll use a "tagpick" input for Editor integration, which presents the user with the option to select a tag from a specified tag group.
We can now define our "editthing". We'll specify the appropriate prefix to be used on all attributes ("attr"), along with a suitable description text and summary information. For each input, we'll provide a suitable name that tells the user what he's editing, as well as a information about how the input is used and what the implications are of any particular values or selections. Putting it all together yields an "editthing" that looks like the following.
<editthing compset="Attribute" name="Attribute" prefix="attr" description="Attributes are incredibly simple. They only have an optional abbreviation." summary="Defines an Attribute to which starting attribute points can be allocated by a character."> <inputthing name="Abbreviation" helptext="Specify a very short abbreviation for use in displaying the attribute via its abbreviation (max 5 characters)."> <it_field field="trtAbbrev"/> </inputthing> <inputthing name="Hide from User?" helptext="Specify whether this attribute is hidden from the user and for internal use only."> <it_tagcheck group="Hide" tag="Attribute"/> </inputthing> <inputthing name="Display Sequence" helptext="Specify the sequence in which this attribute should be shown to the user within lists of attributes. The unique id of the tag must be an integer value."> <it_tagpick group="explicit" tag="?" require="yes" deftag="1"/> </inputthing> </editthing>
Editor support for attributes should now be in place, so reload the data files and let's test it. Launch the Editor via the "Tools" menu, then create a new data file. Click on the "Attribute" tab and then click on the "New (Copy)" button to create an attribute. Pick any of the standard five attributes and make a copy. Within the list of inputs below, you should see all three inputs we specified, with each having the proper behavior we expected.
Change the name to something conspicuous (e.g. "Zebra") and assign the thing a suitable unique id. Then specify a display sequence value of 10. Save the new attribute and click the button to test it now. Since we added an attribute, it's not user-selectable and doesn't appear automatically. We need to perform a quick-reload, after which it should appear everywhere it's supposed to. On the "Basics" tab, in the summary panel, on the character sheet, etc. Our attribute is working and we've got things integrated smoothly with the Editor.
The Next Few Objects
Next on our list is skills. By looking through all the skills that we've defined, we can assess what mechanics we need to expose within the Editor. There are five items that we identify.
- Abbreviation - This is identical to attributes.
- Linked Attribute - Every skill must specify the attribute it is associated with. For linkages, the special "linkage" input is utilized, which will prompt the user appropriately based on the definition within the component.
- Focus Requirement - Some skills require a focus to be specified, which is controlled via a tag, so we'll use the "tagcheck" input.
- Arcane Background - Skills associated with arcane powers are tied to the proper arcane background. If a skill requires a background association, the user must be able to select it, so we'll use a "tagpick" input.
- Show on TacCon - Various skills are shown on the Tactical Console, and the user should be able to designate a skill for display. Such skills are identified via a tag, so we can use a "tagcheck" input for them.
This above analysis results in the following "editthing" definition.
<editthing compset="Skill" name="Skill" prefix="sk" description="Skills must specify a linked attribute that they are based upon. Additional options can be specified, depending on the behavior of the skill." summary="Defines a Skill to which starting skill points can be allocated by a character."> <inputthing name="Abbreviation" helptext="Specify a very short abbreviation for use in displaying the skill via its abbreviation (max 5 characters)."> <it_field field="trtAbbrev"/> </inputthing> <inputthing name="Linked Attribute for Skill" helptext="Select the attribute used to calculate the net attack for this skill."> <it_linkage compset="Attribute" linkage="attribute"/> </inputthing> <inputthing name="Focus Required?" helptext="Specify whether this skill requires the user to specify a focus (e.g. Knowledge)."> <it_tagcheck group="User" tag="NeedDomain"/> </inputthing> <inputthing name="Arcane Background" helptext="Specify the arcane background that this skill is associated with (for arcane skills only)."> <it_tagpick group="Arcane" tag="?"/> </inputthing> <inputthing name="Non-Combat on TacCon?" helptext="Specify whether this skill is shown on the Tactical Console when out of combat."> <it_tagcheck group="DashTacCon" tag="NonCombat"/> </inputthing> </editthing>
After skills, we have derived traits, for which we'll identify six facets that need to be customizable via the Editor. Mapping these to the corresponding "inputthing" elements is easy.
- Abbreviation - Same as above.
- Base Value - Traits like Parry and Toughness start with a base value of two, so we need a "field" input for this value.
- Dashboard and TacCon Visibility - There are three separate areas where the trait can be listed, and each is governed by a separate tag, so we'll setup three different "tagcheck" inputs.
- Display Sequence - Same as for attributes.
We continue onward with racial abilities. These are very different from the traits we've been handling thus far, but they are extremely simple and have only five facets that require customization. All of them are handled via use of a "tagcheck" input.
- User Activation - Some abilities have in-play effects that the user can turn on or off, and they must identified via the "User.Activation" tag.
- Selectable by Creatures - Many abilities can be selected for use when customizing creatures, and they are identified via a tag.
- User Text - Some user-added abilities require the user to specify text, which is dictated by a tag.
- User Value - Same as for text above, except a different tag is used.
- Printable - A few abilities must be omitted from inclusion in character sheet output, and they are identified via a tag.
Edges
As with the objects covered above, edges are actually rather simple to define for Editor integration. However, there are many facets to edges that need to be addressed. In the interest of providing one last complete example, we'll fully assess edges here.
- Type of Edge - Every edge has a type, which must be selected from the list of possible tags via a "tagpick" input.
- Minimum Rank - Every edge has a minimum rank requirement, which is dictated by a tag selection using "tagpick".
- Wild Card Requirement - If an edge is only valid for wild cards, it can be assigned a tag via a "tagcheck" input.
- User Activation - If an edge has in-play effects that the user can turn on or off, it is flagged via a tag using a "tagcheck" input.
- Creation Only - Some edges are only selected at character creation and are identified via a tag using a "tagcheck" input.
- Arcane Background - If an edge confers an arcane background, it must specify the proper tag via a "tagpick" input.
- Printable - If an edge should be omitted from character output, it is designated with a tag via a "tagcheck" input.
- Auto-Naming - Edges automatically have their name customized if user-selected facets exist, but it can be turned off via a tag controlled by a "tagcheck" input.
- Domain Requirement - If an edge requires a domain from the user, a "tagcheck" input allows the tag to be assigned.
- Domain Term - If an edge requires a domain, the term shown is controlled via a tag using a "tagpick" input. Since the user can specify any term they want, the input is marked as "dynamic", allowing the user to create a new tag with a custom name.
- Menu Sources - If an edge requires the user to select customizations via a menu, the source from which to pull the menu options is specified via a tag using a "tagpick" input.
- Menu Tag Expressions - Edges using menu selection must specify a tag expression to dictate the items shown in the menu, which can only be handled via a "field" input.
Distilling all of the above into an "editthing" results in the following.
<editthing compset="Edge" name="Edge" prefix="edg" description="Edges have lots of facets, from requirements to user activation to user customization.{br}The customization options cannot be combined - you can use menus or a domain." summary="Defines an edge that can be selected for a character by the user."> <inputthing name="Type of Edge" helptext="Specify the category this edge gets classified in."> <it_tagpick group="EdgeType" tag="?" require="yes" deftag="Background"/> </inputthing> <inputthing name="Minimum Rank Required" helptext="Specify the minimum rank a character must possess to take this edge."> <it_tagpick group="MinRank" tag="?" require="yes" deftag="0"/> </inputthing> <inputthing name="Wild Card Required?" helptext="Specify whether this edge is only selectable for wild card characters."> <it_tagcheck group="User" tag="NeedWild"/> </inputthing> <inputthing name="Activated by User?" helptext="Specify whether this edge has an effect that can be activated by the user via the In-Play tab."> <it_tagcheck group="User" tag="Activation"/> </inputthing> <inputthing name="Creation Only?" helptext="Specify whether this edge can only be selected for a character during creation."> <it_tagcheck group="User" tag="CreateOnly"/> </inputthing> <inputthing name="Arcane Background" helptext="Specify any arcane background conferred by the edge."> <it_tagpick group="Arcane" tag="?"/> </inputthing> <inputthing name="Omit from Printouts?" helptext="Specify whether this edge should be omitted from character sheet output."> <it_tagcheck group="Print" tag="NoPrint"/> </inputthing> <inputthing name="Disable Auto-Naming?" helptext="Specify whether the automatic synthesis of names for this edge should be disabled."> <it_tagcheck group="User" tag="NoAutoName"/> </inputthing> <inputthing name="Require Domain Specification?" helptext="Specify whether the edge requires the user to specify a domain."> <it_tagcheck group="User" tag="NeedDomain"/> </inputthing> <inputthing name="Domain Term" helptext="Specify the term to use as a label for the domain. If empty, the term 'Domain' is used."> <it_tagpick group="DomainTerm" tag="?" dynamic="yes"/> </inputthing> <inputthing name="Menu #1 Source" helptext="Specify the source from which to retrieve choices for display in the first menu."> <it_tagpick group="ChooseSrc1" tag="?"/> </inputthing> <inputthing name="Menu #1 Tag Expression" helptext="Specify the tag expression used to identify choices for display in the first menu. If empty, no first menu is shown."> <it_field field="usrCandid1"/> </inputthing> <inputthing name="Menu #2 Source" helptext="Specify the source from which to retrieve choices for display in the second menu."> <it_tagpick group="ChooseSrc2" tag="?"/> </inputthing> <inputthing name="Menu #2 Tag Expression" helptext="Specify the tag expression used to identify choices for display in the second menu. If empty, no second menu is shown."> <it_field field="usrCandid2"/> </inputthing> </editthing>
Other Interesting Facets
The remaining objects can be defined by following the same logic as above and using the same mechanisms, so we won't be covering them here. There are are a few special situations, though, that we'll identify and discuss briefly.
There are a variety of component sets that derived from the "Gear" component. For things that are gear, there are two different cost behaviors that can be specified. There is both a "grCost" field and a "grLotCost" field. Users must have the distinction clearly explained to them within the Editor, else confusion will likely ensue. The difference is that the "grCost" field allows you to specify the cost for an individual item, while the "grLotCost" field allows you to specify the cost for a full "lot" of the item, as dictated by the "lotsize" attribute. Some game systems will list the cost for individual items, while others list the cost per lot-size purchases, and this allows users to enter the cost information either way.
Another facet of gear is that some items can be designated as "holders" of other gear. By default, all gear can be held within a backpack or other holder. However, users can also specify that a piece of gear can hold other items. There are two additional options. One allows a piece of gear to both be held within other holders and to hold items itself, as would be appropriate for a backpack or sack. The second option is for gear that can hold other items but cannot be held itself, as would be appropriate for a vehicle. Gear must allow the user to specify the holder behavior via a "tagpick" input that selects the appropriate tag.
Both weapons and vehicles possess an arbitrary assortment of special traits, such as "heavy weapon", "double tap", or "four-wheel drive". All of these traits are dictated via tags belonging to the same group, and any number of these traits can be assigned to a given thing. Handling this requires the use of the "taglist" input, which allows the user to select as many tags as he wishes from the specified tag group.
The final special behavior involves arcane backgrounds. There are a number of situations where an "Arcane" tag must be specified within the Editor, and these situations should generally require the user to select a tag that already exists. The exception is the "Arcane Background" thing, which should allow the user to define a new tag corresponding to the arcane background. This is achieved by setting the "dynamic" attribute to "yes" for the input, which tells the Editor to allow the user to add new tags.