Final Cleanup Continued (Savage)

From HLKitWiki
Revision as of 07:36, 11 February 2009 by Rob (talk | contribs) (→‎Next)
Jump to navigationJump to search

Context: HL Kit … Authoring Examples … Savage Worlds Walk-Through 

Overview

Identify Hindrance Severity in Sheet Output

The list of hindrances that are output within the character sheet use the same mechanism as edges and racial abilities. However, hindrances can be taken in both major and minor forms, and that aspect of each hindrance is important to the player.

We can modify the Label script currently in use within the "oAbilPick" template to detect the presence of a hindrance and output it specially. We'll only flag major hindrances, and we'll do it by including a special symbol. This will keep the space requirements to an absolute minimum. We can pick a suitable character from the "Wingdings" font, resulting in the following revised Label script.

var major as string
if (tagis[component.Hindrance] <> 0) then
  if (field[hinMajor].value <> 0) then
    major = " {font Wingdings}" & chr(181) & "{revert}"
    endif
  endif
@text = field[shortname].text & major & "{/b}  {size 32}" & field[summary].text

Add Drawbacks to Character Sheet

It seems that we overlooked including the details of arcane drawbacks on the character sheet. Since it's something the player should not forget, we should probably include a reminder. One solution would be to show the drawback like a hindrance. Another would be to include the name of the drawback within the title above the table of arcane powers. And a third would be to add a new table that listed the drawback just like an edge or hindrance.

None of these options is ideal, and they each have their trade-offs. Treating drawbacks as hindrances would entail a fair amount of work to revise the data files. Since all we need is to display them, the extra work probably isn't worth it. Including the drawback within the title above the arcane powers table would not show its summary, plus it would result in a very cramped title area. Adding a new table is quick and easy, but the downside is that we'll consume additional vertical space on the sheet.

We'll go with the new table for the sake of simplicity. Our table portal can be adapted from the edges table, giving us the following.

<portal
  id="oDrawback"
  style="outNormal">
  <output_table
    component="Drawback"
    showtemplate="oDrawPick">
    <headertitle><![CDATA[
      @text = "Arcane Drawbacks"
      ]]></headertitle>
    </output_table>
  </portal>

The template can be readily adapted from the one used for special abilities. This results in the template shown below.

<template
  id="oDrawPick"
  name="Output Drawbacks Table"
  compset="Drawback"
  marginvert="2">

  <portal
    id="details"
    style="outMedLt">
    <output_label>
      <labeltext><![CDATA[
        @text = field[name].text & "{/b}  {size 32}" & field[summary].text
        ]]></labeltext>
      </output_label>
    </portal>

  <position><![CDATA[
    ~our details width spans the entire template width
    portal[details].width = width

    ~our height is the height of our portal
    height = portal[details].bottom
    ]]></position>
  </template>

The last step is to integrate the portal into a layout. We'll add it to the "oRightSide" layout and place immediately above the table of arcane powers. If we include it above the powers, it will always be prominently visible and immediately adjacent to the list of powers. All we need to do is add the "portalref" element and then auto-place the portal immediately beneath the continuation of the edges output.

Ignoring Wound Penalties

There are two edges that allow the character to ignore wound penalties (Nerves of Steel and the improved version). Since HL automatically applies the effects of all wounds penalties to rolls, users will assume the effects of these edges are properly factored in. We'd better make good on that assumption.

The wound and fatigue penalties are all handled via the "acNetPenal" field on the "Actor" component. We can add a new field to track the number of wound penalties that are ignored, and then we can factor that value into the final calculation for "acNetPenal". Our new field is shown below.

<field
  id="acIgnWound"
  name="Ignored Wound Penalties"
  type="derived">
  </field>

We can now modify the Calculate script on the "acNetPenal" field to take the ignored wounds into account. The revised script should look like the following.

@value = -field[acFatigue].value
if (field[acWounds].value > field[acIgnWound].value) then
  @value -= field[acWounds].value - field[acIgnWound].value
  endif

All the mechanics are in place. Our two edges can now use a simple Eval script to adjust the "acIgnWound" field, and everything works exactly as we want.

<eval index="1" phase="Setup" priority="5000"><![CDATA[
  herofield[acIgnWound].value += 1
  ]]></eval>

Dependencies on Load Limit

The "Acrobat" edge exposes a timing issue with our data files. The edge confers a +1 to a character's Parry if the character has no encumbrance penalty. To implement this, we need to have the encumbrance penalty determined before we act, and we need to act before the final value for the Parry trait is resolved. Our current script timing does not work this way, although we should be able to do this.

Our goal is to be able to adjust the Parry trait prior to its final resolution. Derived traits are officially calculated at a timing of Traits/6000. So we need to get the encumbrance penalty resolved before then if at all possible.

The encumbrance penalty is tracked by the "resEncumb" resource. The final value is currently calculated at a timing of Final/500. The only timing requirements for this calculation are the accrual of weight carried (which occurs at Effects/10000) and the load limit (which occurs at Traits/7000). The weight accrual occurs long before we need to act for the "Acrobat" edge, so we can move the timing of the penalty if we can move the timing of the load limit calculation.

The load limit is tracked by the "resLoadLim" resource and it calculates its maximum (the value we need for the encumbrance penalty) at a timing of Traits/7000. This calculation depends on the "acLoadMult" field, which is nailed down very early in the evaluation cycle, so that's not a problem. It also depends on the final value of the Strength attribute. Attributes are finalized within the "trtFinal" field, which is calculated at a timing of Traits/3000. This means we can move the load limit calculation to a timing of Traits/4000 without any problems.

Once we move the load limit calculation, we can then safely move the encumbrance penalty calculation. We'll move that to a timing of Traits/4500. This leaves nice gap in the evaluation cycle where we can inspect the encumbrance and adjust the Parry trait based on it. We'll schedule the Eval script for the edge at Traits/5000.

Since we've gone through and analyzed all these dependencies, we'll do one additional thing. Each of the various scripts we identified should be named. Then we can specify appropriate timing dependencies between these scripts. Now we can let the compiler safety check our timing dependencies for us all the time. If we need to adjust the timing of one of these scripts in the future, we can rely on the compiler to let us know if we messed something up.

Edges Need Domain Support

When we implemented edges, we identified all the ones that looked to be special in some way and added appropriate handling for them. We missed one. The "Connections" edge requires that the user specify the organization with which the connections exist. This means we have to add domain support for edges. Fortunately, we've already done that a couple times, so it should not be complicated. In fact, it's rather simple.

The first thing we need to do is add the "Domain" component to the "Edge" component set. This will integrate domain handling internally into edges. The "Domain" component handles modifying the name, so all the mechanics we need are provided.

Next, we need to add support for domains to the interface. We can copy the two portals dealing with domains from the "edHinder" template and add them to the "edEdge" template. Then we can copy the positioning code for those portals, which we can drop into place with a single change. The "lbldomain" portal can be aligned directly relative to the "name" portal instead of using the non-existent "edge" variable.

Domain support is fully operational for edges now. All that remains to be done is assign the "User.NeedDomain" tag to the "Connections" edge. Once we do that, the edge will prompt the user for a domain and integrate into the name for display.

Background Edges are Creation-Only

All background edges are generally only valid for selection during character creation. The Skeleton files provide built-in support for designating abilities as creation-only (via the "User.CreateOnly" tag). However, adding the tag individually to all background edges is error-prone. It would be best if we automatically treated all background edges as creation-only.

Doing this is easy. We can clone the pre-requisite used for this purpose within the "Ability" component and add it to the "Edge" component. We can then adapt it to only apply to background edges. Since GMs can allow the selection of background edges after creation, we'll only flag an error when showing things. Once an edge is added, we'll assume the player did so with the GM's approval. The resulting pre-requisite should look like below.

<prereq message="Background edges are only available at character creation">
  <!-- This pre-req is only applicable to background edges -->
  <match><![CDATA[
    EdgeType.Background
    ]]></match>

  <validate><![CDATA[
    ~we only report a failure on things (once added, we assume the user knows best)
    if (@ispick <> 0) then
      @valid = 1
      done
      endif

    ~if the mode is creation, we're valid
    if (state.iscreate <> 0) then
      @valid = 1
      endif
    ]]></validate>
  </prereq>

Buying Off Hindrances

  • use an advancement to buy off a hindrance

Injuries As Advancements

  • treating injuries as advancements makes them inaccessible to NPCs and makes it difficult to heal them at a later date, so they must be handled separately on the Personal tab

Hiding Equipment

Various creatures define their own custom equipment, such as the "Goblin" and "Lich". This gear needs to be private to the particular creature and not make public for general selection by the user. To solve this, we need to define a new "Hide.Equipment" tag and then assign that tag to all such gear.

Once the tags are assigned, we need to modify all of the table portals on the "Armory" tab. This new tag must be integrated into the Candidate tag expression of each portal so that equipment with the tag is not shown for selection. In each case, the revised element should look like the one shown below.

<candidate inheritlist="yes"><![CDATA[
  !Equipment.Natural & !Hide.Equipment
  ]]></candidate>

Show Linked Attributes on Skills

Next