Difference between revisions of "More Cleanup (Savage)"

From HLKitWiki
Jump to: navigation, search
(Next)
(Damage and Non-Wildcards)
Line 33: Line 33:
 
   name="Maximum Wounds"
 
   name="Maximum Wounds"
 
   type="derived">
 
   type="derived">
   <calculate phase="Initialize" priority="1000"><![CDATA[
+
   <calculate phase="Setup" priority="1000"><![CDATA[
 
     ~if we're a wildcard, we can take 4 wounds, else only one
 
     ~if we're a wildcard, we can take 4 wounds, else only one
 
     if (field[acIsWild].value <> 0) then
 
     if (field[acIsWild].value <> 0) then

Revision as of 05:42, 4 February 2009

Context: HL KitAuthoring Examples … Savage Worlds Walk-Through 

Overview

Our list of things we came up with previously is almost fully addressed. Let's take this opportunity to do another round of testing everything and see if there's anything we missed last time. Then we can knock off the remaining little things on our list. The sections below identify the various issues we can spot and the fixes that we need to make.

Another Assessment

-add menu tracking and selection for Scholar and Profesional/Expert/Master edges

   -add to character sheet

-Parry must handle a Fighting stat of "d12+X", which adds half of X, rounded down

-Toughness must handle a Vigor stat of "d12+X" the same way

-build in editor support for users to add custom material

-cleanup of all unused mechanisms from Skeleton files

-delete stuff from files that is not needed for SW

-add all creatures from the bestiary as a stock portfolio - see page 125

Damage and Non-Wildcards

On the "In-Play" tab, we make the assumption that all characters can take four levels of damage. However, this only applies to wildcards. Non-wildcards take one hit and go down. After looking into this a little bit further, it seems that we've made this assumption through the data files. We need to properly handle the situation where a character has a different maximum number of wounds based on the wildcard designation.

The first thing we need to do is setup a new field into which we can save the appropriate maximum number of wounds. Since the field value is based solely on the wildcard state of the character, we can use a Calculate script on the field to easily determine the value. We need to be sure to schedule the script early, since other scripts will rely on this value. This yields a field that looks like the following.

<field
  id="acMaxWound"
  name="Maximum Wounds"
  type="derived">
  <calculate phase="Setup" priority="1000"><![CDATA[
    ~if we're a wildcard, we can take 4 wounds, else only one
    if (field[acIsWild].value <> 0) then
      @value = 4
    else
      @value = 1
      endif
    ]]></calculate>
  </field>

With the field in place, we can now go through the data files and identify places where the field needs to be utilized. We'll do a search for references to the "acWounds" field to locate places where a change may be needed. It turns out there are three places within the "Actor" component and another two places within the "In-Play" tab.

The Finalize script for the "acDmgSumm" field uses a hard-coded value of four when determining whether to show the wounds as "Inc". We can replace the four with a reference to the "acMaxWound" field. The new line of code should look like below.

if (wounds <= -field[acMaxWound].value) then

Similar logic is utilized within the Finalize script for the "acDmgTac" field. Again, we replace the four with a reference to the field. The third reference is in the Eval script that assigns the "Hero.Dead" tag. Simply swapping out the literal value for the field is all we need to do.

Shifting our focus to the "In-Play" tab, both the "wounds" and "wndsustain" portals reference a hard-coded value of four. Both of these references need to be replaced with the field. The new line of code for the Label script in the "wounds" portal is shown below.

if (wounds > -field[acMaxWound].value) then

All of the handling for wounds is now properly differentiating between wildcards and non-wildcards.

Lead Summary Script

When a lead character is saved out to a portfolio, a summary of that character is synthesized and stored in the portfolio. This summary is displayed along with the name when the user attempts to import characters from that portfolio. The summary is synthesized via the LoadSummary script, whose purpose is to provide a brief (but useful) synopsis of the character.

The LoadSummary script is defined in the file "definition.def", and the Skeleton files provide us with a basic implementation. We'll adapt the one provided for Savage Worlds. The question is what information we should include. Savage Worlds characters have no clear role (such as classes), so there's really nothing definitive we can say about a character beyond its race and rank/XP. This leaves us with a script implementation that looks like the following.

~start with the race
var txt as string
txt = hero.firstchild["Race.?"].field[name].text
if (empty(txt) <> 0) then
  txt = "No Race"
  endif
@text &= txt

~append the rank and XP
var rankvalue as number
var ranktext as string
rankvalue = herofield[acRank].value
call RankName
@text &= " - " & ranktext & " - " & herofield[acFinalXP].value & " XP"

Arcane Power Totals

If a character with an arcane background adds a foreign gizmo on the "Gear" tab, that gizmo is being counted towards the total number of arcane powers selected by that character. Foreign gizmos need to be ignored when tallying up the number of powers chosen for the character.

The tallying of each arcane power is performed within an Eval script on the "Power" copmonent. This script always consumes one power slot for each power. We need to modify the script to skip any power with the "Helper.Foreign" tag. The revised script should look like below.

if (tagis[Helper.Foreign] = 0) then
  perform #resspent[resPowers,+,1,field[name].text]
  endif

Show Arcane Powers Resource

The "Basics" tab contains all of the various resources that a user will want to monitor during character creation, except for one. If the character has an arcane background, the list of resources does not include the one for arcane powers.

We can add the resource to the list by assigning it the "Helper.Creation" tag. We can then control its position in the list by assigning it an appropriate "explicit" tag. We'll put it at the end, after "Skills", so we'll assign it the tag "explicit.6".

The only problem now is that the resource shows up for characters with no arcane background. What we want is for the resource to only show up when an arcane background is possessed. There are a number of ways we can solve this, but the best is to recognize that the resource serves no purpose unless we an arcane background is selected. As such, we can use the same approach as with the "Advances" resource, except that pre-condition changes. We can assign a ContainerReq test to the "resPowers" resource and make the thing dependent upon the hero possessing any tag from the "Arcane" group, which will assigned if any arcane background is chosen. This results in the revised "resPowers" thing below.

<thing
  id="resPowers"
  name="Arcane Powers"
  compset="Resource">
  <fieldval field="resObject" value="Arcane Power"/>
  <tag group="Helper" tag="Bootstrap"/>
  <tag group="Helper" tag="Creation"/>
  <tag group="explicit" tag="6"/>

  <containerreq phase="Initialize" priority="2000">
    Arcane.?
    </containerreq>

  </thing>

Starting Bennies

Normal player characters receive three Bennies at the start of each game. However, NPCs that are wildcards only receive two personal Bennies and non-wildcards receive zero. We have the necessary information to setup everything properly, so let's add this in properly.

Bennies are managed via a tracker that is defined in the file "thing_miscellaneous.dat". This tracker starts with a fixed range of zero to three. By defining an Eval script for the thing, we can customize the starting values based on the characteristics assigned to the hero. The new Eval script should look similar to the one below.

<eval index="1" phase="Initialize" priority="2000"><![CDATA[
  ~if we're not a wildcard, we get zero starting Bennies
  if (herofield[acIsWild].value = 0) then
    field[trkMax].value = 0

  ~if we're an NPC, we get two starting Bennies
  elseif (hero.tagis[Hero.NPC] <> 0) then
    field[trkMax].value = 2

  ~otherwise, we're a normal character and get three starting Bennies
  else
    field[trkMax].value = 3
    endif
  ]]></eval>

Super Power Skill Names

The character sheet output makes the assumption that all skills that lack a domain can safely fit within the narrow width of the two-column table. While this is true for all normal skills, the skills associated with super powers have comparatively much longer names. As such, they are shrunk as far as possible and still cut off.

A simple solution is to handle super power skills the same way we handle skills with domains, moving them into the single-column table beneath the two-column table. Since all super skills possess an "Arcane.?" tag, we can readily identify such skills. This makes it easy to integrate them into the second table instead.

The first step is to revise the List tag expression for the skills shown in the two-column table, omitting the super skills. The second step is to revise the List tag expression of the other table to include the super skills. The two revised List tag expressions should look like below. Note the addition of the "CDATA" block around the first one due to the use of the '&' character.

<list><![CDATA[!User.NeedDomain & !Arcane.?]]></list>

<list>User.NeedDomain | Arcane.?</list>

Once the tag expressions are defined, we then need to refine the "oSkillPick" template. The template bases the sizes for its contents based on the same criteria used in the List tag expressions for the tables. This means all we need to do is change the one line in the Position script that identifies whether the pick belongs in the narrow or wide table. The revised line of code should look like the following.

if (tagis[User.NeedDomain] + tagis[Arcane.?] = 0) then

Alternate Pace Values

There are some abilities that necessitate having two values for the "Pace" trait. All characters possess a ground-based speed, which is the standard value for "Pace". However, some abilities confer swimming or flying speeds. We need a way to track and convey that information to the user.

The easiest solution is to add a new field to the "Derived" component. This one field will serve to track a generic alternate value, and we can integrate the field value into the display for the trait. If there is no alternate value needed, then it can be left at a default value of zero, in which case it will be omitted from display. For the "Pace" trait, this field will identify whichever alternate speed is appropriate (flying or swimming). There is currently no need for this field on other derived traits.

The new field is extremely simple. We'll designate it as a "special" value, since it's actual purpose will value from one trait to another. The definition below is all we need.

<field
  id="trtSpecial"
  name="Special Value"
  type="derived">
  </field>

With the field defined, we then need to decide how to integrate it into the displayed value for the trait, which is stored in the "trtDisplay" field. An Eval script on the "Trait" component currently handles this, so we'll need to break up the logic. We'll modify the existing Eval script on the "Trait" component to do nothing for a "Derived" trait. Then we'll add a new Eval script on the "Derived" component to synthesize the proper display contents. The new Eval script should look like the following.

<eval index="2" phase="Render" priority="5000" name="Calc trtDisplay"><![CDATA[
  ~our display text is the final value, plus any "special" value given
  field[trtDisplay].text = field[trtFinal].value
  if (field[trtSpecial].value <> 0) then
    field[trtDisplay].text &= "/" & field[trtSpecial].value
    endif
  ]]></eval>

If a particular ability confers a non-standard value for "Pace", it can assign that value to the "trtSpecial" field. That field will then be integrated into the displayed value for the trait.

Natural Armor

The Skeleton files provide an entry for "Natural Armor". This thing can be used for any situation where an actor has an innate (or natural) defensive protection that behaves like armor. For example, an extra thick hide or scaly skin might confer the equivalent defense of armor.

When this situation presents itself, you can bootstrap the "armNatural" thing onto the character. As part of the bootstrap, you can specify the level of defensive protection that is afforded by the natural armor via the "defDefense" field. If not specified, the default defensive rating is "1". The sample "bootstrap" element below shows the assignment of natural armor with a defensive rating of "3".

<bootstrap thing="armNatural">
  <assignval field="defDefense" value="2"/>
  </bootstrap>

Since natural armor covers the entire body, we need to assign all of the various "ArmorLoc" tags to the thing. We also need to assign an appropriate armor type, which means we need to define an appropriate tag in the "ArmorType" group. When we're done, the revised thing should look like below.

<thing
  id="armNatural"
  name="Natural Armor"
  compset="Armor"
  description="Description goes here"
  isunique="yes"
  holdable="no">
  <fieldval field="defDefense" value="1"/>
  <tag group="Equipment" tag="Natural"/>
  <tag group="Equipment" tag="AutoEquip"/>
  <tag group="ArmorType" tag="Natural"/>
  <tag group="ArmorLoc" tag="Torso"/>
  <tag group="ArmorLoc" tag="Arms"/>
  <tag group="ArmorLoc" tag="Legs"/>
  <tag group="ArmorLoc" tag="Head"/>
  </thing>

Revise "Configure Hero" Form

The "Configure Hero" form currently shows the starting cash, followed by the starting XP, and then the checkboxes to designate a wildcard and an NPC. The result is a sequence where toggling the NPC checkbox causes the portals for starting XP to appear and disappear above it. This behavior is rather disorienting to the user, as the checkbox portal just toggled moves under the mouse.

What we need is a sequence that allows the visibility change in an intuitive manner. That sequence should be the NPC checkbox, followed by the wildcard checkbox, then the starting cash, and lastly the starting XP. Since the concept of starting cash really doesn't make any sense for NPCs, we'll also hide the starting cash for an NPC.

We'll first re-order the portals within the template to this new sequence. This will ensure that attempts by the user to use the <Tab> key to move through the portals will work smoothly.

We now need to revise the Position script logic to orchestrate the display properly. We start by determining the visibility of the starting cash and XP. After that, we'll position the label at the top, with the NPC checkbox beneath it. We'll allow for the remaining portals to be optionally visible, tracking our vertical position as we proceed downward through the template. This results in the following revised Position script.

~set the width of the template to something we like
width = 185

~determine whether the starting cash is visible based on whether we're a pc
portal[cash].visible = hero.tagis[Hero.PC]
portal[lblcash].visible = portal[cash].visible

~determine whether the starting xp is visible based on if we're a pc
portal[xp].visible = hero.tagis[Hero.PC]
portal[lblxp].visible = portal[xp].visible

~position the title at the top
perform portal[label].centerhorz

~position the npc checkbox beneath the title
portal[isnpc].width = width
perform portal[isnpc].centerhorz
perform portal[isnpc].alignrel[ttob,label,15]

~start tracking our vertical position because portals may not be visible
var y as number
y = portal[isnpc].bottom

~if visible, position the wildcard checkbox beneath the character type
if (portal[iswild].visible <> 0) then
  perform portal[iswild].centerhorz
  portal[iswild].top = y + 15
  y = portal[iswild].bottom
  endif

~if visible, position the starting cash next
if (portal[cash].visible <> 0) then
  portal[cash].top = y + 15
  portal[cash].width = 50
  perform portal[lblcash].centeron[vert,cash]
  portal[lblcash].left = (width - portal[lblcash].width - portal[cash].width - 10) / 2
  perform portal[cash].alignrel[ltor,lblcash,10]
  y = portal[cash].bottom
  endif

~if visible, position the starting xp beneath the wildcard checkbox
if (portal[xp].visible <> 0) then
  portal[xp].top = y + 15
  portal[xp].width = 50
  perform portal[lblxp].centeron[vert,xp]
  portal[lblxp].left = (width - portal[lblxp].width - portal[xp].width - 10) / 2
  perform portal[xp].alignrel[ltor,lblxp,10]
  y = portal[xp].bottom
  endif

~set the height of the template based on the extent of the portals
~Note: Include a little extra space at the bottom for borders and such.
height = y + 3

The final thing we'll do is change the label at the top of the template. It currently says "Starting Resources", but the NPC state is not a resource, so the name is misleading. We'll change it to "Starting Characteristics". This requires simply changing the literal text for the "label" portal, and we're done.

Next