Final Cleanup (Savage)

From HLKitWiki
Revision as of 01:45, 8 February 2009 by Rob (Talk | contribs)

Jump to: navigation, search

Context: HL KitAuthoring Examples … Savage Worlds Walk-Through 

Overview

Our data files are complete. It's time to do a final round of cleanup. We'll be eliminating any extraneous mechanisms that we inherited from the Skeleton files. After that, we'll do another round of testing so we can fix anything that has slipped past us.

Skeleton File Remnants

The Skeleton files provided us with a working set of functionality, and we used the vast majority of it. However, there are some bits left over that we didn't use. Before we consider our files complete, we should prune that material out, leaving ourselves with only material that is associated with our game system.

WARNING! Deleting information from the data files will result in lots of warnings about orphaned material when you load saved portfolios. This is normal and can be ignored, since we are intentionally deleting the information. If you encounter errors like this when you aren't intentionally deleting material, be sure to verify that you haven't made an inadvertent mistake.

We'll focus our attention first on the various things that are defined. That's because any internal mechanisms we might eliminate or change will impact these things, so it's much easier to remove the dependencies before removing the mechanisms that are depended upon. All of these things will be defined within the data files that start with the prefix "thing_". The Skeleton files included a variety of thing definitions that we're no longer using. Those we can readily identify and delete.

We'll start with any things defined for the purpose of validation. Using the logic above, validation rules often build on other things, so we eliminate them before eliminating the things they depend on. All validation rules are found in the file "thing_validate.dat", so we'll go through the each thing defined in the file and determine if we're still using it. There appears to be only one, the "valCP" thing used for testing character points. We can delete that and move on.

Proceeding down the dependency hierarchy, the next group of things to focus on are any resources or trackers, which are defined in the file "thing_miscellaneous.dat". There are two resources in this file that we inherited from the Skeleton files are no longer using. These are the "resCP" and "resAbility" things, so we'll delete them.

Once we do that, we'll discover a couple of old dependencies on those two things within the "resXP" thing. We're definitely using the "resXP" resource, but the Eval script that adjusts the available quantity of those resources based on the XP is extraneous. Once we delete that, this file is cleaned.

However, there is a second dependency. The "Ability" component we inherited from the Skeleton files has an Eval script that accrues the usage of ability points. With the elimination of the "resAbility" thing, we must also eliminate the script.

We can now go through all the other data files in which we defined things. Our goal is to eliminate any sample things that were provided or that we copied, adapted, and left hanging around. The list below spells out the various places we need to check.

  • Sample attributes
  • Sample skills
  • Sample abilities
  • Sample adjustments
  • Sample advances
  • Sample weapons
  • Sample armor
  • Sample gear
  • Sample races
  • Sample edges
  • Sample hindrances

After going through the data files in search of the above items, there should only be one file left that we haven't assessed and in which things are defined. That's the file "thing_traits.dat". The Skeleton files provided us with a number of traits that we didn't use, and there should no longer be any references to them. Consequently, we can now delete them easily. The set of things to remove are "trHealth", "trInit", "trDefense", and "trPowerPts".

Our data files should no longer have extraneous things lurking within them, so we can shift our focus to the internals. In general, we don't really need to worry much about mechanisms built into the various components. Most of those mechanisms have been fully adapted to our purposes for Savage Worlds. The few exceptions are causing no trouble and will require a fair amount of work to isolate and remove. So it's best to just leave them alone, unless they are either obvious or a source of potential problems.

In our case, there are two places that are worth addressing. The first is the "Ability" component. We changed this component so that it provides a number of shared behaviors, but the Skeleton files originally defined it without that in mind. As such, there is an important behavior provided by the component that is either redundant or a potential problem. The component defines an identity tag group and assigns a corresponding tag to the hero for every ability. Each separate type of ability already does this with its own identity group, so we can delete the identity group definition and the Eval script that forwards the tag to the actor.

The final cleanup task we should do is review the contents of the "Actor" component. For many game systems, at least a few mechanisms provided in this component will be unused. Since this component is rather extensive, keeping it pruned of unnecessary logic will simply make our data files easier to maintain. We can go through the list of fields and identify those that are now orphaned. This consists of the fields "acStartCP" and "acStartAbi", which we can delete. Scanning through the rest of the component, everything else is being used.

At this point, our data files have been properly cleaned of any unused remnants of the Skeleton files.

NOTE! If our game system did not use the advancements mechanism, we could also delete the data files specific to advancements and all the associated references.

New Characters Report Wrong Attribute Points

When we create a new character, the number of attribute points is being displayed as "-12 of 5" above the table of attributes. The moment that we make any change at all to the character, everything behaves correctly. We obviously have a timing problem.

The value "-12" is quite suspicious, too. We have a total of six attributes defined (including the hidden one for super powers). That translates to a difference of two points per attribute. It appears that we broke this when we changed the default value of each attribute from two to zero.

The attribute values are being properly bounded to two, as evidenced by everything being corrected by making any change to the character. A change triggers a new evaluation pass. This means that the field on the resource that contains the message for display is probably being synthesized before the bounding of the field value is occurring. Unfortunately, the message is being synthesized during the Render phase, so that's not the case.

Looking a bit more closely, the message being synthesized is using the "resLeft" field. That field is being calculated at a timing of Final/1000. However, the bounding is occurring at a timing of Final/10000. We've uncovered the source of the problem.

We need to change the timing of one or both actions. Before we can do that, though, we must first assess what other timing dependencies exist on these two actions. The calculation of the "resLeft" field is named, so we need to assess what other scripts depend on it. There are two, but both of them must occur before the calculation, so we are free to move the calculation later if we wish.

The bounding script is also named, and there is one dependency. The calculation of the delta must occur before the bounding is performed, and the delta depends on the fields "trtBonus" and "trtInPlay". Both of those fields must be in their final state before they are used to calculate the "trtFinal" value, and that happens at a timing of Traits/3000. This means that we can freely move the delta calculation to substantially earlier if we wish.

The pieces of the puzzle are now in place. The best solution is probably to change the timing of all three scripts. We'll calculate the delta for "trtUser" at a timing of Final/1000. Then we can move the timing of the bounding to Final/5000. Lastly, we can move the timing of the "resLeft" calculation to Final/7000. We'll also specify an "after" timing dependency of the "resLeft" calculation upon the bounding so that we don't run into this problem again in the future.

Once we make these changes, everything should work properly again. Unfortunately, the problem remains. We found a piece of the problem, but there is something else amiss still.

After adding some "debug" statements to our scripts, we'll confirm that "resLeft" calculation is yielding the wrong results. So we need to focus on the information that the "resLeft" calculation depends upon. This would be the "resMax" value and the "resSpent" value. Doing a quick search of where the "resMax" field is referenced in the data files confirms that the "resMax" value is not the culprit, so that leaves the "resSpent" field. Doing another scan of where the "resSpent" field is referenced uncovers that it is being tallied for attributes via an Eval script at a timing of Setup/5000. That's way before the bounding occurs, which explains the problem. If we change the timing to Final/6000 (i.e. after the bounding), everything starts to work correctly.

To make sure this problem doesn't arise again, we'll add a timing dependency to the erroneous Eval script. We'll ensure that this script always occurs after the bounding of the "trtUser" field.

But wait a minute. The script we fixed only applies to attributes. A similar script exists to tally the points spent for skills. Since skills are traits, they also need to be tallied after the bounding is performed. Skills start with a default "trtUser" value of zero, so we aren't noticing the error. However, if we changed the default value, we would see the same problem. The solution is to make sure that the Eval script on the "Skill" component is also changed to the same timing and that a suitable timing dependency is also added.

The only other use of the "Trait" component is with derived traits. Since there is no resource being tallied for derived traits, there are no other places where this problem could be lurking.

Rank and XP Shown for Creatures

There are a number of places where XP and rank are being shown for creatures. We eliminated this from a few obvious spots, but we overlooked some as well. We need to go through these locations and verify that the XP and rank are omitted for creatures. We can identify all the places that we need to check by doing a search for references to the "acRankName" field name.

The first instance we find is within the LeadSummary script in the definition file. We can wrap the logic for including the XP within an if/then block, as shown below.

~append the rank and XP (only for non-creatures)
if (hero.tagis[Hero.Creature] = 0) then
  @text &= " - " & herofield[acRankName].text & " - " & herofield[acFinalXP].value & " XP"
  endif

The next instance is within the Eval script that synthesizes the ally recap within the "Actor" component. We can use the same technique and wrap the code within an if/then block. However, this instance requires a little more tweaking than just an if/then block, since the punctuation output assumes the XP is always included. The revised logic should look like the code below.

~output any race
recap &= field[acRaceName].text

~output the XP and rank (only for non-creatures)
if (hero.tagis[Hero.Creature] = 0) then
  recap &= ", " & field[acRankName].text & "  (" & field[acFinalXP].value & " XP)"
  endif

There are two instances within character sheet output that need to be addressed. One is on the first page, where the character details are synthesized in the "oHeroInfo" portal. We can again wrap the logic within an if/then block, as shown below.

~append the rank and XP (only for non-creatures)
if (hero.tagis[Hero.Creature] = 0) then
  @text &= "; " & herofield[acRankName].text & "  ("
  @text &= herofield[acFinalXP].text & " XP)"
  endif

The other instance within the character sheet output is on the second page, within the output for allies. We can use an if/then block again, although we need to be sure to keep the newline outside of the conditional block. The resulting code is below.

~output the rank and XP (only for non-creatures)
if (hero.tagis[Hero.Creature] = 0) then
  @text &= "; {b}" & herofield[acRankName].text & "{/b} ("
  @text &= herofield[acFinalXP].text & " XP)"
  endif

~insert a newline before continuing our output
@text &= "{br}"

The XP and rank are also shown within the "Basics" and "Journal" tabs. However, we have already dealt with both. On the "Basics" tab, the portal with the information is hidden for creatures. Similarly, the entire "Journal" tab is hidden for creatures.

Derived Traits Positioning Within Sheets

Show XP and Rank on Basics Summary Panel

Next