Revise Journal Tab (Savage)

From HLKitWiki
Jump to: navigation, search

Context: HL KitAuthoring Examples … Savage Worlds Walk-Through 

Overview

We've got advancements in place, but advancements are dependent upon the accumulation of experience points (XP). The Skeleton files provide a reasonable starting point for tracking XP and finances, along with a suitable tab where the user can manage these details. However, we can probably tailor it better for Savage Worlds. So the next thing we'll tackle is the Journal tab.

Assess Each Journal Entry

The first thing we need to do is look at the individual journal entries provided by the Skeleton files and assess what needs to be added, deleted, or changed. Savage Worlds uses a rather common approach for handling money and XP, so we don't really need to track anything additional for each journal entry. Some games employ complex currencies with multiple types of coins that must be tracked independently, and those games will require some re-work of each journal entry to allow the user to properly manage those currencies. Fortunately, Savage Worlds isn't such a game, so we can avoid that work.

Assess the Header

While the individual journal entries are fine as they are, the header information at the top only shows the total cash on hand and total accrued XP. It would probably be helpful to the user to also show the character's current rank, since that has implications on the various edges and arcane powers that can be selected. We could even include the number of XP needed to reach the next rank, but each rank is an even 20 XP, so it's something a user can instantly determine and therefore makes little sense for us to add.

This will be the third time we need to convert the character rank from a numeric value to the corresponding name. So we really need to resolve this before we proceed with our changes to the header.

Converting Rank from Value to Text

We need to convert the character rank from the numeric value used to track it internally to a string for display. Typically, when a field is involved, this can be done by simply defining a Finalize script that performs the conversion. However, we also need to convert the rank requirement used within the pre-requisite test for minimum character rank, and the Finalize script won't work for that, so we need to devise a different approach. The technique we'll use is to write a procedure that will receive the rank value to be converted in one variable and place the result in a separate variable for use by the caller.

This procedure has an interesting wrinkle to it, though. This procedure needs to be able to be called from within both a Label script and a Validate script. The Label script starts with an initial context of a pick/thing, while the Validate script starts with an initial context of a container. As such, the two script types have nothing in common, so there is no procedure context we can use that the two can share. The solution is to define a procedure with a script type of "none". This results in a procedure that has no context whatsoever, which means there is no initial script context for the procedure (implied or otherwise). Since we only need to convert a numeric value to a string, there is no context required, so we can use this technique.

Open the file "procedures.dat", where we can now add the new procedure that we'll call "RankName". We can steal the logic out of the file "tab_basics.dat" for use within our procedure. The net result is something that should look like the definition below.

<procedure id="RankName" scripttype="none"><![CDATA[
  ~declare variables that are used to communicate with our caller
  var rankvalue as number
  var ranktext as string 
  ~map the value to the corresponding string
  if (rankvalue = 0) then
    ranktext = "Novice"
  elseif (rankvalue = 1) then
    ranktext = "Seasoned"
  elseif (rankvalue = 2) then
    ranktext = "Veteran"
  elseif (rankvalue = 3) then
    ranktext = "Heroic"
  elseif (rankvalue = 4) then
    ranktext = "Legendary"
  else
    ranktext = "Invalid Value: " & rankvalue
    endif
  ]]></procedure>

Once the procedure is in place, we need to go back and convert the two existing references to rank over to call the new procedure. We'll start with the Label script for showing the rank on the Basics tab. Open the file "tab_basics.dat" and locate the "baRank" portal. We change the Label script to call the "RankName" procedure to perform the conversion, which yields a new script that mirrors the one below.

var rankvalue as number
var ranktext as string
rankvalue = herofield[acRank].value
call RankName
@text = ranktext & " (" & hero.child[resXP].field[resMax].value & " XP)"

Next, we'll revise the logic within the "MinRank" component. Open up the file "components.core" and locate the "MinRank" component, then find its "prereq" element. We replace the if/then/else block with a suitable call to the "RankName" procedure, resulting in a new Validate script that looks like the one below.

<prereq iserror="yes" message="Minimum Rank required.">
  <valid><![CDATA[
    var rankvalue as number
    var ranktext as string

    ~get the minimum rank required for the thing to be valid
    rankvalue = altthing.field[rnkMinRank].value

    ~if the minimum rank is satisfied, we're good to go
    if (herofield[acRank].value >= rankvalue) then
      @valid = 1
      done
      endif

    ~mark the panel as invalid
    altthing.linkvalid = 0

    ~synthesize an appropriate validation error message
    call RankName
    @message = ranktext & " rank required."
    ]]></valid>
  </prereq> 

Revise the Header

Now that we've got the new "RankName" procedure in place, we can put it to use within the header of the Journal tab. Open the file "tab_journal.dat" and locate the "jrHeader" template, then find its "info" portal. This portal contains a Label script that synthesizes the text to be shown within the header. We'll amend it to add a new entry that shows the character's rank, yielding a revised script similar to the following.

var rankvalue as number
var ranktext as string
rankvalue = herofield[acRank].value
call RankName
@text = "{text a0a0a0}Total $: " & herofield[acCashNet].value
@text &= "{horz 40} Total XP: " & #resmax[resXP]
@text &= "{horz 40} Rank: " & ranktext