Difference between revisions of "Evolving the "Edges" Tab (Savage)"

From HLKitWiki
Jump to: navigation, search
(Customizing Hindrances)
 
(2 intermediate revisions by the same user not shown)
Line 159: Line 159:
 
   endif  
 
   endif  
 
</pre>
 
</pre>
 +
 +
With the integration of domain handling, we discover that we have the same problem we encountered previously for skills. The domain name is automatically synthesized into the name of the hindrance, which results in the domain being shown in the name and within the edit portal. We should omit it from the name. To accomplish that, we change the "name" portal to utilize the "thingname" field instead of the "name" field. Once that change is made, everything behaves as it should.
  
 
===Adding Rewards===
 
===Adding Rewards===
Line 172: Line 174:
 
     showtemplate="SimpleItem"
 
     showtemplate="SimpleItem"
 
     choosetemplate="SimpleItem"
 
     choosetemplate="SimpleItem"
     addthing="resHinder"
+
     addpick="resHinder"
    addspace="2"
+
 
     columns="2">
 
     columns="2">
 
     <titlebar><![CDATA[
 
     <titlebar><![CDATA[
Line 187: Line 188:
 
         done
 
         done
 
         endif
 
         endif
 +
 
       ~get the color-highlighted "add" text
 
       ~get the color-highlighted "add" text
 
       @text = field[resAddItem].text
 
       @text = field[resAddItem].text
Line 211: Line 213:
 
We now have all three tables in place, but their positioning logic is incredibly crude. If enough edges are added, both the hindrances and rewards table could completely disappear beyond the bottom of the tab. So we need to change to logic that is more intelligent.
 
We now have all three tables in place, but their positioning logic is incredibly crude. If enough edges are added, both the hindrances and rewards table could completely disappear beyond the bottom of the tab. So we need to change to logic that is more intelligent.
  
We start by establishing suitable minimum heights for the tables of hindrances and rewards, calculating the vertical space remaining. We then allow the edges table to use as much vertical space as remains when those minimums are factored in. If the edge table doesn't need all the space, then the hindrances table is first allowed to expand as much as necessary. Lastly, if there is still unused space remaining, the rewards table is given an opportunity to expand. This logic ensures that we optimize our use of the vertical space, giving preference to edges and then hindrances, while we also ensure that the maximum amount of edge table is kept visible at all times. The net result is the Position script shown below.  
+
We start by establishing suitable minimum heights for the tables of hindrances and rewards, then calculating the vertical space remaining. Next, we allow the edges table to use as much vertical space as remains when those minimums are factored in. If the edge table doesn't need all the space, then the hindrances table is first allowed to expand as much as necessary. Lastly, if there is still unused space remaining, the rewards table is given an opportunity to expand. This logic ensures that we optimize our use of the vertical space, giving preference to edges and then hindrances, while we also ensure that the maximum amount of the edges table is kept visible at all times. The net result is the Position script shown below.  
  
 
<pre>
 
<pre>
Line 221: Line 223:
 
   portal[edRewards].freeze = 1
 
   portal[edRewards].freeze = 1
 
   endif  
 
   endif  
 +
 +
~determine the vertical gap we want to use between tables
 +
var gap as number
 +
gap = 15
  
 
~size all tables to span the full layout width
 
~size all tables to span the full layout width
Line 230: Line 236:
 
portal[edHinders].maxrows = 3
 
portal[edHinders].maxrows = 3
 
portal[edRewards].maxrows = 1  
 
portal[edRewards].maxrows = 1  
 
~determine the vertical gap we want to use between tables
 
var gap as number
 
gap = 15
 
  
 
~position the rewards table at the bottom
 
~position the rewards table at the bottom
Line 256: Line 258:
 
===Reporting Errors===
 
===Reporting Errors===
  
Earlier in the evolution process of our data files, we established panel linkages to the "basics" panel for edges, rewards, and hindrances. Consequently, if we add one of those three items to the character and the item is invalid in some way, the "Basics" panel will turn red to highlight the error to the user. Now that we have an appropriate panel in place for those three objects, we need to highlight the proper panel when errors are encountered. This is simply a matter of opening the file "traits.pri" and changing the "panellink" attribute of the "Edge", "Hindrance", and "Reward" components. Change the attribute to associate the new "edges" panel with the component and everything is hooked up properly.
+
Earlier in the evolution process of our data files, we established panel linkages to the "basics" panel for edges, rewards, and hindrances. Consequently, if we add one of those three items to the character and the item is invalid in some way, the "Basics" panel will turn red to highlight the error to the user. Now that we have an appropriate panel in place for those three objects, we need to highlight the proper panel when errors are encountered. This is simply a matter of opening the file "traits.str" and changing the "panellink" attribute of the "Edge", "Hindrance", and "Reward" components. Change the attribute to associate the new "edges" panel with the component and everything will be hooked up properly.

Latest revision as of 06:46, 8 February 2009

Context: HL KitAuthoring Examples … Savage Worlds Walk-Through 

Overview

Once we have a basic tab in place that contains the "Edges" table, we need to add tables for selection of hindrances and rewards.

Adding Hindrances

We'll handle hindrances next, since we should place those immediately below the table of edges. We put them below, because the list of edges will evolve as the character advances, while the hindrances will generally be fixed after character creation.

Our first step is to add a table portal in which we can manage the hindrances. Since hindrances have a number of complexities we have to deal with, we will need our own custom template instead of being able to use the "SimpleItem" template. However, using the "SimpleItem" template on an interim basis makes it easy for us to get the table added, so that's what we'll do.

We copy the table portal for edges, then we adapt it for our needs. This amounts to changing all edge references over to hindrances. Hindrances don't have a resource associated with them, so we must also revise a few of the scripts slightly to eliminate references to the resource. The net result is the portal below.

<portal
  id="edHinders"
  style="tblNormal">
  <table_dynamic
    component="Hindrance"
    showtemplate="SimpleItem"
    choosetemplate="SimpleItem"> 
    <titlebar><![CDATA[
      @text = "Add a Hindrance"
      ]]></titlebar>
    <headertitle><![CDATA[
      @text = "Hindrances"
      ]]></headertitle> 
    <additem><![CDATA[
      ~if we're in advancement mode, we've been frozen, so display accordingly
      if (state.iscreate = 0) then
        @text = "{text a0a0a0}Cannot Add Hindrances After Creation"
        done
        endif 
      ~be sure to use a suitable color for a purely optional choice
      @text = "{text a0a0a0}Add New Hindrance"
      ]]></additem>
    </table_dynamic>
  </portal> 

Our portal has now been added to the data files, but nothing is actually being done with it. We still need to integrate it into the layout and position it properly. Adding it to the layout is simple. We add a new "portalref" element that references the table portal. Since the table will be beneath the edges table, we'll assign a suitable tab order to ensure the flow proceeds from edges to hindrances. This results in the new element shown below.

<portalref portal="edHinders" taborder="20"/>

The next step is positioning the table portal properly. We'll reconcile the concerns of juggling three tables within the panel once they are all defined. For now, we'll simply position the new table beneath the table of edges. That can be achieved by adding the following lines of code to the Position script in the layout.

portal[edHinders].width = width
portal[edHinders].top = portal[edEdges].bottom + 10 

Customizing Hindrances

Now that the hindrances table portal is in place, we can customize how hindrances are displayed and behave. Although some hindrances are simple and involve only a name, there are some for which the user can selectively choose whether it is major or minor in impact. In addition, some hindrances need to specify a domain, just like skills. We need to provide our own template in order to support these behaviors.

Before we do anything, we need to get a new template that we can customize. We're currently using the "SimpleItem" template, and it would be an excellent starting point for our purposes. The template used for skills would also be an excellent starting point, so you could just as easily start with either one. We'll use the "SimpleItem" template, since that's what you will probably be using most often for this purpose. Open the file "visual.dat" and locate the "SimpleItem" template. Copy it into the file "tab_edges.dat", where we can adapt it.

Change the unique id to something suitable, such as "edHinder", and the component set to "Hindrance". Eliminate the extra logic in the Position script that is expressly for use when showing things, since we're always showing picks. Lastly, we need to hook the new template into the table portal, so go to the "edHinders" portal and change the "choosetemplate" to reference our new "edHinder" template. At this point, you should be able to re-compile and load, with no visible change in behavior.

We can now adapt the template to our needs. Many hindrances have a fixed severity rating, and we should be sure to display that clearly to the user. The name of each hindrance is currently shown as a field-based label that simply shows the value of the field. We'll change that to a script-based label, wherein we'll start with the name and append an indication of whether the hindrance is major or minor. If the hindrance has a user-controlled severity, we'll leave the name unchanged and show the state differently, as outlined further below. The net result is a revised "name" portal that should look something like the following.

<portal
  id="name"
  style="lblNormal"
  showinvalid="yes">
  <label>
    <labeltext><![CDATA[
      @text = field[name].text
      if (tagis[User.UserSelect] = 0) then
        if (field[hinMajor].value = 0) then
          @text &= " (Minor)"
        else
          @text &= " (Major)"
          endif
        endif
      ]]></labeltext>
    </label>
  </portal>

For user-controlled hindrances, we need to add a new portal of some sort that allows the user to designate the severity. One option is to use a checkbox portal. A traditional checkbox would probably look quite poor, so we won't consider that further. However, we could also use a bitmap-based checkbox. With a bitmap-based checkbox, we select two separate bitmaps to indicate the two different states and rely on the bitmaps indicating the state to the user. This technique is used in a few places for different game systems and can be very useful. The problem with this approach is that we need to clearly convey "major" versus "minor" to the user via bitmaps - that's not an easy proposition.

Fortunately, we can also use a menu, just like we do for the character's gender on the "Personal" tab. We'll start by opening the file "tab_personal.dat", locating the "gender" portal, and copying it into the template we're working with so we can adapt it. We'll change the id to "severity" and hook it up to the "hinMajor" field. Then we can change the list of choices that the user is shown, making sure that the value zero reflects "minor" and one reflects "major", since that's the convention we've already established for the "hinMajor" field.

<portal
  id="severity"
  style="menuNormal">
  <menu_literal
    field="hinMajor">
    <choice value="0" display="Minor"/>
    <choice value="1" display="Major"/>
    </menu_literal>
  </portal>

The portal is added, so we now need to position it properly and control when it is made visible. We'll add the appropriate logic to the Position script for the template, keying on the presence of the "User.UserSelect" tag and positioning the severity to the right of the hindrance name. The additions made to the Position script should look similar to the code below.

~center the portal vertically
perform portal[severity].centervert

~if we don't need a menu, hide the portal
var edge as number
if (tagis[User.UserSelect] = 0) then
  portal[severity].visible = 0
  edge = portal[name].right

~otherwise, position the menu portal to the right of the name/domain
else
  perform portal[severity].alignrel[ltor,name,15]
  portal[severity].width = 55
  edge = portal[severity].right
  endif

In addition to the severity menu, some portals also require a user-specified domain, just like certain skills. To support this, we need to add two portals that are virtually identical to the ones we used in the table of skills. So open the file "tab_skills.dat" and locate the "lbldomain" and "domain" portals within the "skPick" template. Copy them into the "edHinder" template that we're working on. The only aspect we need to change is the field associated with the "domain" edit portal, which needs to be hooked up to the "domDomain" field for hindrances. At this point, the two new portals should look similar to the ones below.

<portal
  id="lbldomain"
  style="lblSecond">
  <label
    text="Domain:">
    </label>
  </portal>

<portal
  id="domain"
  style="editNormal">
  <edit
    field="domDomain">
    </edit>
  </portal>

Once the portals are properly defined, we need to position them and control their visibility. If the domain is not needed, we simply hide it, else we position the domain to the right of the name - or the severity menu, if any. The new logic required in the Position script should look like below.

~center the portals vertically
perform portal[domain].centervert
perform portal[lbldomain].alignrel[btob,domain,0]

~if we don't need a domain, hide the portals
if (tagis[User.NeedDomain] = 0) then
  portal[lbldomain].visible = 0
  portal[domain].visible = 0

~otherwise, position the domain portals next to the name, making sure the
~domain edit portal doesn't run beyond the available space
else
  portal[lbldomain].left = edge + 15
  perform portal[domain].alignrel[ltor,lbldomain,5]
  portal[domain].width = minimum(150,portal[info].left - portal[domain].left - 10)
  endif 

With the integration of domain handling, we discover that we have the same problem we encountered previously for skills. The domain name is automatically synthesized into the name of the hindrance, which results in the domain being shown in the name and within the edit portal. We should omit it from the name. To accomplish that, we change the "name" portal to utilize the "thingname" field instead of the "name" field. Once that change is made, everything behaves as it should.

Adding Rewards

The one remaining table we need is for selecting rewards, which we'll place beneath hindrances. Rewards are very simple, consisting of only a name for display. As such, they don't need to take up the full width of the tab and we can display them in two columns instead of just one. We'll start by adding a table portal in which we can manage the rewards, and we'll configure it for two columns of display. Due to the simplicity of rewards, we can re-use the "SimpleItem" template and avoid having to define a new template. So we copy the table portal for edges and adapt it for our needs. This amounts to changing all references to edges over to rewards, as well as changing the edges resource over to the hindrance resource for tracking how many rewards are left to be selected by the user. Except for changing to two columns, everything else remains the same, resulting in the portal shown below.

<portal
  id="edRewards"
  style="tblNormal">
  <table_dynamic
    component="Reward"
    showtemplate="SimpleItem"
    choosetemplate="SimpleItem"
    addpick="resHinder"
    columns="2">
    <titlebar><![CDATA[
      @text = "Add an Reward - " & hero.child[resHinder].field[resSummary].text
      ]]></titlebar>
    <headertitle><![CDATA[
      @text = "Rewards - " & hero.child[resHinder].field[resSummary].text
      ]]></headertitle>
    <additem><![CDATA[
      ~if we're in advancement mode, we've been frozen, so display accordingly
      if (state.iscreate = 0) then
        @text = "{text a0a0a0}Cannot Add Rewards After Creation"
        done
        endif

      ~get the color-highlighted "add" text
      @text = field[resAddItem].text
      ]]></additem>
    </table_dynamic>
  </portal> 

Just like we did for the hindrances table, we must now integrate the portal into the layout and position it properly. Adding it to the layout is achieved by adding a new "portalref" element that reference the table portal. Since rewards will be at the bottom, we'll assign a tab order after the others. This results in the new element shown below.

<portalref portal="edRewards" taborder="30"/>

The final step is positioning the table portal properly. Just to get things working quickly, we position the rewards table beneath the table of hindrances by adding the following lines of code to the Position script in the layout.

portal[edRewards].width = width
portal[edRewards].top = portal[edHinders].bottom + 10 

Intelligent Positioning

We now have all three tables in place, but their positioning logic is incredibly crude. If enough edges are added, both the hindrances and rewards table could completely disappear beyond the bottom of the tab. So we need to change to logic that is more intelligent.

We start by establishing suitable minimum heights for the tables of hindrances and rewards, then calculating the vertical space remaining. Next, we allow the edges table to use as much vertical space as remains when those minimums are factored in. If the edge table doesn't need all the space, then the hindrances table is first allowed to expand as much as necessary. Lastly, if there is still unused space remaining, the rewards table is given an opportunity to expand. This logic ensures that we optimize our use of the vertical space, giving preference to edges and then hindrances, while we also ensure that the maximum amount of the edges table is kept visible at all times. The net result is the Position script shown below.

~freeze our tables in advancement mode to disable adding new choices
~Note: All freezing must be done *before* any positioning is performed.
if (state.iscreate = 0) then
  portal[edEdges].freeze = 1
  portal[edHinders].freeze = 1
  portal[edRewards].freeze = 1
  endif 

~determine the vertical gap we want to use between tables
var gap as number
gap = 15 

~size all tables to span the full layout width
portal[edEdges].width = width
portal[edHinders].width = width
portal[edRewards].width = width 

~set the height of the small tables to be a maximum number of rows for now
portal[edHinders].maxrows = 3
portal[edRewards].maxrows = 1 

~position the rewards table at the bottom
portal[edRewards].top = height - portal[edRewards].height 

~position the hindrances table above the rewards
portal[edHinders].top = portal[edRewards].top - gap - portal[edHinders].height 

~assign the remaining space to the edges table
portal[edEdges].height = portal[edHinders].top - gap - portal[edEdges].top 

~position the hindrances table beneath the edges table and let it expand to
~fill whatever vertical space is available between the edges and rewards
portal[edHinders].top = portal[edEdges].bottom + gap
portal[edHinders].height = portal[edRewards].top - gap - portal[edHinders].top 

~position the rewards table beneath hindrance and let it expand to fill space
portal[edRewards].top = portal[edHinders].bottom + gap
portal[edRewards].height = height - portal[edRewards].top 

Reporting Errors

Earlier in the evolution process of our data files, we established panel linkages to the "basics" panel for edges, rewards, and hindrances. Consequently, if we add one of those three items to the character and the item is invalid in some way, the "Basics" panel will turn red to highlight the error to the user. Now that we have an appropriate panel in place for those three objects, we need to highlight the proper panel when errors are encountered. This is simply a matter of opening the file "traits.str" and changing the "panellink" attribute of the "Edge", "Hindrance", and "Reward" components. Change the attribute to associate the new "edges" panel with the component and everything will be hooked up properly.