Character Creation Logic (Savage)

From HLKitWiki
Revision as of 07:35, 11 February 2009 by Rob (talk | contribs) (→‎Races)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

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

Overview

With all the basics now in place, it's a perfect time for us to get all of the basic character creation logic fully tested and operational. This entails tracking the allocation of attribute points and skill points, as well as the selection of races, edges, hindrances, and rewards.

Attribute Points

We'll focus on attribute points first. We already have a resource in place to track those points, so we need to properly consume those points. This can be most easily handled by adding a script to the "Attribute" component that spends the resource appropriately. The Skeleton files provide such a script for us already, so all we need to do is adapt it for our needs. The d4 rating for an attribute costs no points, but each increment beyond that costs one point. So we'll employ a component script that behaves accordingly, which should look similar to the one shown below.

<eval index="2" phase="Traits" priority="10000">
  <before name="Calc resLeft"/>
  <after name="Bound trtUser"/><![CDATA[
  ~since the base starting value for each attribute is two, we add only the extras
  perform #resspent[resAttrib,+,field[trtUser].value - 2,field[name].text]
  ]]></eval> 

Skill Points

Skill points behave much like attributes, except that we have to treat the initial purchase of the skill as one skill point and all subsequent increases as either one or two additional skill points. We already have a resource in place to track the points, and the Skeleton files already provide a "Skill" component script that we can easily adapt to our needs.

The interesting logic here has to do with determining whether each die type for a skill costs one or two points. We can start by assuming that each notch counts at least one point. So we'll first calculate the total number of notches. We must also subtract one from our total, since the base values for skills is two, which costs the first point.

The extra skill point cost is incurred for each level that a skill exceeds its linked attribute. We can access the linked attribute and get its value via the "linkage" transition. Once we have that value, we can compare the two and add an extra skill point for each level of difference between them.

The net script that we need should look something like the following:

<eval index="2" phase="Traits" priority="10000">
  <before name="Calc resLeft"/>
  <after name="Bound trtUser"/><![CDATA[
  ~if this skill is not added directly to the hero (i.e. an advance), skip it entirely
  if (origin.ishero = 0) then
    done
    endif

  ~the base value for skills is two, so we need to adjust by one to get the proper cost
  var points as number
  points = field[trtUser].value - 1

  ~add an extra point for every level we exceed our linked attribute
  var attrib as number
  attrib = linkage[attribute].field[trtUser].value
  if (field[trtUser].value > attrib) then
    points += field[trtUser].value - attrib
    endif

  ~accrue the total points spent on this skill
  hero.child[resSkill].field[resSpent].value += points
  ]]></eval>  

Races

Try choosing all of the different races for the character and verify whether everything is behaving correctly. This includes racial bonuses to attributes, skills, and derived traits, plus other facets such as the extra edge conferred by the "Human" and "Half-Elven" races. After a quick check, everything looks correct, except for one facet.

The issue is with the tallying of skill points. If the "Elven" race is selected, it confers a free bonus level to the "Agility" attribute. That bonus needs to be considered part of the base die type for the attribute. Otherwise, skills based on Agility will cost an extra skill point unless they are lower than the attribute.

Taking a look at the Eval script we created a few moments ago, we can easily accommodate this fix. The bonus die level tracked within the "trtBonus" field, so all we need to do is add the bonus to the user value and we'll have the net value we need. Note that we do not want to use the "trtFinal" field value, since that value also includes in-play adjustments, which are temporary and must be excluded from consideration here.

The code fragment below shows the effected lines within the Eval script and what they should now look like.

~get the level of our linked attribute and factor in bonuses due to races and such
var attrib as number
attrib = linkage[attribute].field[trtUser].value
attrib += linkage[attribute].field[trtBonus].value

~add an extra point for every level we exceed our linked attribute
if (field[trtUser].value > attrib) then
  points += field[trtUser].value - attrib
  endif

Hindrances

Add a variety of hindrances of different severities. Also add hindrances that have a user-controlled severity and toggle that severity. While doing so, watch the total points of rewards that are available for selection on the right. The total should go up one point for each minor hindrance and two points for each major hindrance. In addition, when hindrances are added that confer negative effects, verify that the effects are being applied properly. If a hindrance has user-controlled effects that can be toggled on and off, make sure the option appears properly on the "In-Play" tab and that it all behaves correctly.

Everything is working as it should, with one exception. The rules stipulate that a character may choose a maximum of one major hindrance and two minor hindrances, but this restriction is not being validated anywhere. We need to add a new validation rule that will enforce this restriction and report when a character exceeds the limits. To do that, we need to add a new thing whose sole purpose is performing this validation. By convention, we add these "validation" things to the file "thing_validate.dat". So open up the file and we'll add a new validation thing whose sole purpose is to invoke our validation rule to verify hindrances. We derive the thing from the "Simple" component set, and we must make sure it's added to every character so that the validation is always performed. The net result looks like the following.

<thing
  id="valHinders"
  name="Hindrances"
  compset="Simple">
  <tag group="Helper" tag="Bootstrap"/> 
  <evalrule index="1" phase="Validate" priority="8000" 
    message="Maximum of one major and two minor hindrances allowed"
    summary="Limit exceeded"><![CDATA[
    ~iterate through all hindrances and tally up the number of majors and minors
    var major as number
    var minor as number
    foreach pick in hero where "component.Hindrance"
      if (each.field[hinMajor].value = 0) then
        minor += 1
      else
        major += 1
        endif
      nexteach 

    ~if we have no more than one major and two minor, we're good
    if (major <= 1) then
      if (minor <= 2) then
        @valid = 1
        done
        endif
      endif 

    ~mark associated tabs as invalid
    container.panelvalid[edges] = 0
    ]]></evalrule>
  </thing>

After making the above changes, validation is now working as it should. However, it would be better if the title above the hindrances table appeared in red to clearly identify where to fix the problem on the tab. This can be achieved by having the above EvalRule assign a tag to the hero, which can be checked by the table portal. So we start by defining a new "Hero.BadHinders" tag within the file "tags.1st". Add the following tag to the "Hero" tag group.

<value id="BadHinders"/>  <!-- Indicates that the hindrances selected don't comply with the rules -->

Once that's in place, we can assign the tag within the above EvalRule script by adding the line below if the rule is failed.

perform hero.assign[Hero.BadHinders]

The final step is to check for and properly handle the tag within the table portal. Locate the "edHinders" portal within the file "tab_edges.dat" and then find the HeaderTitle script. This script returns the title to be displayed, which currently amounts to simply "Hindrances". We can change the script to detect if the tag is present and change the color to red when it is. The new script should look similar to the one below.

@text = ""
if (hero.tagis[Hero.BadHinders] <> 0) then
  @text = "{text ff0000}"
  endif
@text &= "Hindrances"  

Rewards

Add a variety of rewards and verify that the available number of resources is being properly adjusted. Some rewards are worth two points and some are worth one. Also verify that the effects of each reward are being applied correctly. Everything seems to check out fine.

Edges

The final thing that we need to test on this tab is edges. Add a variety of edges and make sure that the appropriate resources are being adjusted. For edges that confer bonuses, verify that the effects are being applied properly. If an edge has user-controlled effects that can be toggled on and off, make sure the option appears properly on the "In-Play" tab and that it all behaves correctly. Once that's handled, we're ready to move on with our development.