Implementing the Character Sheet (Savage): Difference between revisions

From HLKitWiki
Jump to navigationJump to search
Line 211: Line 211:


===Derived Traits===
===Derived Traits===
Moving down the left column, the next section is the derived traits. The Skeleton files provide this section already, and all we need to do is adapt it appropriately. The table portal has the id "oDerived", so we'll start there. We want to use the standard style for the table instead of the grid-based one used in the Skeleton files, so we first change the style to "outNormal". Then we can change the component to the more restrictive "Derived" and switch to a two-column table. The final change is to the List tag expression, which needs to omit any traits that are specifically hidden. This yields a table portal like the one shown below.
<pre>
<portal
  id="oDerived"
  style="outNormal">
  <output_table
    component="Derived"
    showtemplate="oDerivPick"
    showsortset="explicit"
    columns="2">
    <list>!Hide.Trait</list>
    <headertitle><![CDATA[
      @text = "Derived Traits"
      ]]></headertitle>
    </output_table>
  </portal>
</pre>
We now shift our focus to the template, which has the id "oDerivPick". We'll start with margins that are designed for a single-column table that needs to leave room for the grid around each item. We'll eliminate the horizontal margin, since we're packing the derived traits into two columns. We'll also reduce the vertical margin to zero for now, leaving ourselves the option to increase it again later.
The existing template simply shows a name and value, with dots between. For Savage Worlds, we need this same behavior, plus we also need to provide an empty box next to each value where the user can note adjustments to the value during play. For this, we'll add a new portal that contains just a blank space (we have to specify something, else the compiler will complain). We'll use the "outGreyBox" style to put a box around the portal, thereby providing a place where the user can note adjustments.
Instead of positioning the portals at the left and right edges, we'll just align them from left to right. This yields the following revised template.
<pre>
<template
  id="oDerivPick"
  name="Output Derived Traits Table"
  compset="Trait"
  marginvert="8">
  <portal
    id="name"
    style="outNameLg">
    <output_label
      field="name">
      </output_label>
    </portal>
  <portal
    id="value"
    style="outValueLg">
    <output_label
      field="trtDisplay">
      </output_label>
    </portal>
  <portal
    id="adjust"
    style="outGreyBox">
    <output_label
      text=" ">
      </output_label>
    </portal>
  <portal
    id="dots"
    style="outDots">
    <output_dots>
      </output_dots>
    </portal>
  <position><![CDATA[
    ~our height is based on the tallest portal (they should all be the same)
    height = portal[name].height
    if (issizing <> 0) then
      done
      endif
    ~setup appropriate widths for the various portals
    portal[adjust].width = 100
    ~center everything vertically
    perform portal[name].centervert
    perform portal[value].centervert
    perform portal[adjust].centervert
    perform portal[dots].centervert
    ~position everything horizontally
    portal[name].left = 45
    portal[value].left = 355
    perform portal[adjust].alignrel[ltor,value,30]
    ~extend the dots from the right of the name across to the value on the right
    perform portal[dots].alignrel[ltor,name,0]
    portal[dots].width = portal[value].left - 5 - portal[dots].left
    ]]></position>
  </template>
</pre>
After reloading the files and taking a look at the character sheet, this looks pretty good, except for one glaring problem. The boxes for the user to write in adjustments are touching, so we need to insert a bit of spacing. We can go back to the vertical margins and increase them a bit. If we increase the margin to a value of 5, everything looks great.


===Skills===
===Skills===

Revision as of 22:00, 16 January 2009

Context: HL Kit &#133; Authoring Examples &#133; Savage Worlds Walk-Through 

Overview

Our design is in place, so it's time to start actually implementing our new character sheet. Since we're adapting the sheet provided by the Skeleton files, we'll find what we need in the file "sheet_standard1.dat".

Before We Get Started

We're going to be using this sheet both as our starting point for our changes and as a source of examples for how to do various tasks. As such, we should make a copy of this file somewhere (not within our data file folder). We can keep the copy around for use as a reference or guide on how to do things. We can then freely change the file in our game system folder to morph it into our new character sheet for Savage Worlds.

During the development of our character sheet, we're going to be taking a look at how things behave dozens of times. There is generally no need to print anything during our testing. Instead, you can use the Print Preview mechanism within HL, which can be accessed quickly via the keystroke sequence <Alt+F><V>. After doing a quick-reload, you'll find yourself following with these keystrokes on a regular basis.

We also want to see a meaningful character being displayed when testing our character sheet. If you haven't done so already, create a character for testing. It's probably best to have the character be invalid and have more capabilities than a starting character normally should. This way, you really see how all the different facets of the character sheet will work. For example, give the character an arcane background and powers to see how that stuff works. Give him an assortment of skills, hindrances, edges, weapons, armor, and gears. That way, when you're testing things, you'll get a good sense of how everything looks by just using the existing character. The entire process goes much more quickly this way.

Character Basics

The provided character sheet that we using as our template places the basic information in the top left corner. We'll start there for simplicity and then develop our character sheet in a systematic fashion by proceeding down the left column and then down the right column.

The character name is placed within the header bar for the section, so that's a nice prominent place that works well for us. Beneath that, the Skeleton files have three visible sections of information, with each being less prominent than the one above. The first shows the player name in a large bold font. The official character sheets don't include this and it takes up valuable space when we're trying to keep things compact, so we'll just omit that from our sheet. The second section shows the character points in bold, which don't apply to Savage Worlds, and the third shows basic character details. Having two sections ought to work nicely for us, with one in bold and one not, but we need to re-apportion the information and add some details.

In the first section, we should show the two most important facets of the character that will be included in the character basics. Those are the character's race and rank (with XP). If we do this, that leaves the physical characteristics for display beneath. We could include the hair, eyes, and skin tone in this section, but that would generally require a second line of text on the character sheet and we're trying to keep everything compact. So we'll leave that information out and switch to centering the remaining details on the line.

All of this information is managed via the "oHeroInfo" portal, so we'll adapt it for our purposes. The text is simply synthesized by a single script. Once we finish revising it, the result should look similar to the new script below.

~start with the character's race
var temp as string
temp = hero.firstchild["component.Race"].field[name].text
if (empty(temp) <> 0) then
  temp = "Unknown"
  endif
@text &= "{size 36}Race: " & temp

~append the rank and XP, showing any unspent advances
var rankvalue as number
var ranktext as string
rankvalue = herofield[acRank].value
call RankName
@text &= "; " & ranktext & "  ("
@text &= hero.child[resXP].field[resMax].text & " XP)"
if (#resleft[resAdvance] > 0) then
  @text &= "; " & #resleft[resAdvance] & " Advance(s)"
  endif

~sart a new line and turn off bold
@text &= "{br}{/b}"

~append the gender, age, height, and weight
if (hero.child[mscPerson].field[perGender].value = 0) then
  @text &= "Male"
else
  @text &= "Female"
  endif
@text &= "; Age: " & hero.child[mscPerson].field[perAge].text
@text &= "; Height: " & hero.child[mscPerson].field[perHeight].text
@text &= "; Weight: " & hero.child[mscPerson].field[perWeight].text

Attributes

Moving downward, the next section we want to include is the attributes, and they conveniently happen to be next in the provided files. However, the way attributes are handled in the Skeleton files is a bit different from how we're going to be handling them. In the Skeleton files, attributes have a header across the top and a bunch of pieces for display. For our purposes, all we need is a basic title at the top and relatively simple display elements for each attribute. So we've got a bit of work to do in revamping how attributes work.

The first thing we need to do is revise the attributes table portal appropriately, which has the id "oAttribute". We'll eliminate the use of a header template and designate that we'll be using a two-column table. We then need to add our simple header by adding a suitable "headertitle" element. Lastly, we need to accommodate the hidden attribute for super powers appropriately, which requires we define a List tag expression that omits hidden attributes. This results in a revised portal that looks similar to the one below.

<portal
  id="oAttribute"
  style="outNormal">
  <output_table
    component="Attribute"
    showtemplate="oAttrPick"
    showsortset="explicit"
    columns="2">
    <list>!Hide.Attribute</list>
    <headertitle><![CDATA[
      @text = "Attributes"
      ]]></headertitle>
    </output_table>
  </portal>

We next shift our focus to the "oAttrPick" template used for displaying each attribute. We'll start by changing the vertical margin to zero, and we can increase it later if want. The next step is to eliminate all of the existing portals that are used as the header, since we won't be using them. We can also eliminate the Header script that is no longer needed. This leaves us with six portals that we need to deal with. We obviously want to keep the name portal, and we'll also need portals for both the final die-type and any adjustment that applies (just like we did on the Basics tab). So we can delete all the portals we don't need and add new ones for what we do need.

We can look at the approach we used on the Basics panel for guidance on how to define our two new portals. The portal showing the adjustment can be essentially copied, with the caveat that we need to convert it over to be an output portal with a corresponding output style. We could do the same for the attribute value itself, except that we'd end up with very poor results. The problem is that the fields that are automatically generated for our traits to contain display bitmaps are tailored for on-screen display. So we get colored bitmaps that are going to be very poor quality on printers that are comparatively very high resolution.

We need to come up with a different approach for displaying the attribute die-type bitmaps. Fortunately, the Skeleton files include a separate assortment of bitmaps for the various die-types that are specifically intended for use within character sheet output. We'll need to identify the proper bitmap to use in each case, just like we did within the "FinalRoll" procedure that we defined earlier. In fact, we might as well implement this logic in a new procedure as well, since we're going to need the same logic when we display skills.

Open the file "procedures.dat" and locate the existing "FinalRoll" procedure. We need a similar procedure that synthesizes the proper die-type bitmap for printed output. The Kit provides two sets of bitmaps for printed die-type output, one for showing an "active" die and the other for showing an "inactive" die. This makes it possible to show a sequence of die-type bitmaps, with the proper one shown prominently as "active" and the others shown more faintly as "inactive". In the interest of keeping things compact, we won't be using that approach for our character sheet, but you can easily do it for your own sheet if you want. All we'll be using is the proper "active" bitmap, which results in the new procedure shown below.

<procedure id="OutputDie" scripttype="none"><![CDATA[
  ~declare variables that are used to communicate with our caller
  var dietype as number
  var dietext as string

  ~bound our final die type appropriately
  var final as number
  final = dietype
  if (final < 2) then
    final = 2
  elseif (final > 6) then
    final = 6
    endif

  ~convert the final value for the trait to the proper die type bitmap for output
  ~Note: Be sure to scale the bitmap appropriately for the size we want.
  final *= 2
  dietext = "{bmpscale 9 d" & final & "_outputactive}"
  ]]></procedure>

Now that we've got our procedure in place, we can easily define our portals and tailor the Position script accordingly. This yields a revised template that looks like the following.

<template
  id="oAttrPick"
  name="Output Attributes Table"
  compset="Attribute"
  marginvert="0">

  <portal
    id="name"
    style="outNameLg">
    <output_label
      field="name">
      </output_label>
    </portal>

  <portal
    id="value"
    style="outValueLg">
    <output_label>
      <labeltext><![CDATA[
        var dietype as number
        var dietext as string
        dietype = field[trtFinal].value
        call OutputDie
        @text = dietext
        ]]></labeltext>
      </output_label>
    </portal>

  <portal
    id="adjust"
    style="outNameLg">
    <output_label>
      <labeltext><![CDATA[
        if (field[trtNetRoll].value = 0) then
          @text = ""
        else
          @text = signed(field[trtNetRoll].value)
          endif
        ]]></labeltext>
      </output_label>
    </portal>

  <position><![CDATA[
    ~our height is driven by the tallest portal
    height = portal[value].height
    if (issizing <> 0) then
      done
      endif

    ~center everything vertically within the template
    perform portal[name].centervert
    perform portal[value].centervert
    perform portal[adjust].centervert
    perform portal[dots].centervert

    ~position everything horizontally
    portal[name].left = 65
    portal[value].left = 340
    perform portal[adjust].alignrel[ltor,value,5]
    ]]></position>

  </template>

Reload the data files and take a look at our character sheet. It looks reasonable, but the empty gap between the attribute names and the die-type bitmaps makes some of the pieces seem rather isolated from one another, especially when the attribute name is short. Visually associating the attribute name and value would be an immense help in making our character sheet look attractive. Fortunately, the Kit provides a convenient way of accomplishing this objective.

There is a special output portal that is specifically designed for use in situations like this ("output_dots"). It places a series of dots between two portals, and you can see it in use within the derived traits, weapons, and skills within the provided character sheet. We're going to use this technique for displaying our attributes. Doing so requires that we add a new portal for the dots and then position and size it appropriately. At the bottom of the list of portals, add the new portal shown below. In addition, add the lines of script code at the end of the Position script to integrate the portal properly.

<portal
  id="dots"
  style="outDots">
  <output_dots>
    </output_dots>
  </portal>
~extend the dots from the right of the name across to the value on the right
perform portal[dots].alignrel[ltor,name,0]
portal[dots].width = portal[value].left - 5 - portal[dots].left

Reload everything and take a look at the character sheet. This looks much better. In fact, we'll use this technique in additional tables below, which will both visually associate elements better and give our character sheet a consistent look.

Health and Power

Within the provided Skeleton files, this is a section where you can include important resources that need to be tracked, such as health. Savage Worlds traditionally uses a different approach to these resources, so we don't need this section in the character. We'll add different handling later when we reach that point in our development.

Deleting the section from the character sheet entails a few steps, since there are multiple pieces involved.

  1. First of all, this section is handled via the "oPower" table portal, so we can start by deleting that portal.
  2. The portal referenced the "oPowerPick" template, so we next delete that template.
  3. The portal is utilized within the "oLeftSide" layout, so we need to delete it from there. This includes removing the "portalref" element and the line of code in the Position script that places the portal.

That should cover it. Reload the file and preview the character sheet. The section is now eliminated.

Derived Traits

Moving down the left column, the next section is the derived traits. The Skeleton files provide this section already, and all we need to do is adapt it appropriately. The table portal has the id "oDerived", so we'll start there. We want to use the standard style for the table instead of the grid-based one used in the Skeleton files, so we first change the style to "outNormal". Then we can change the component to the more restrictive "Derived" and switch to a two-column table. The final change is to the List tag expression, which needs to omit any traits that are specifically hidden. This yields a table portal like the one shown below.

<portal
  id="oDerived"
  style="outNormal">
  <output_table
    component="Derived"
    showtemplate="oDerivPick"
    showsortset="explicit"
    columns="2">
    <list>!Hide.Trait</list>
    <headertitle><![CDATA[
      @text = "Derived Traits"
      ]]></headertitle>
    </output_table>
  </portal>

We now shift our focus to the template, which has the id "oDerivPick". We'll start with margins that are designed for a single-column table that needs to leave room for the grid around each item. We'll eliminate the horizontal margin, since we're packing the derived traits into two columns. We'll also reduce the vertical margin to zero for now, leaving ourselves the option to increase it again later.

The existing template simply shows a name and value, with dots between. For Savage Worlds, we need this same behavior, plus we also need to provide an empty box next to each value where the user can note adjustments to the value during play. For this, we'll add a new portal that contains just a blank space (we have to specify something, else the compiler will complain). We'll use the "outGreyBox" style to put a box around the portal, thereby providing a place where the user can note adjustments.

Instead of positioning the portals at the left and right edges, we'll just align them from left to right. This yields the following revised template.

<template
  id="oDerivPick"
  name="Output Derived Traits Table"
  compset="Trait"
  marginvert="8">

  <portal
    id="name"
    style="outNameLg">
    <output_label
      field="name">
      </output_label>
    </portal>

  <portal
    id="value"
    style="outValueLg">
    <output_label
      field="trtDisplay">
      </output_label>
    </portal>

  <portal
    id="adjust"
    style="outGreyBox">
    <output_label
      text=" ">
      </output_label>
    </portal>

  <portal
    id="dots"
    style="outDots">
    <output_dots>
      </output_dots>
    </portal>

  <position><![CDATA[
    ~our height is based on the tallest portal (they should all be the same)
    height = portal[name].height
    if (issizing <> 0) then
      done
      endif

    ~setup appropriate widths for the various portals
    portal[adjust].width = 100

    ~center everything vertically
    perform portal[name].centervert
    perform portal[value].centervert
    perform portal[adjust].centervert
    perform portal[dots].centervert

    ~position everything horizontally
    portal[name].left = 45
    portal[value].left = 355
    perform portal[adjust].alignrel[ltor,value,30]

    ~extend the dots from the right of the name across to the value on the right
    perform portal[dots].alignrel[ltor,name,0]
    portal[dots].width = portal[value].left - 5 - portal[dots].left
    ]]></position>

  </template>

After reloading the files and taking a look at the character sheet, this looks pretty good, except for one glaring problem. The boxes for the user to write in adjustments are touching, so we need to insert a bit of spacing. We can go back to the vertical margins and increase them a bit. If we increase the margin to a value of 5, everything looks great.

Skills

Racial Abilities

Hindrances

Edges