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

From HLKitWiki
Jump to navigationJump to search
New page: ===Adding Hindrances=== Once we have a basic tab in place with the "Edges" table, we need to add tables for selection of hindrances and rewards. We'll handle hindrances next, since we sho...
 
No edit summary
Line 1: Line 1:
{{context|Authoring 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===
===Adding Hindrances===


Once we have a basic tab in place with the "Edges" table, we need to add tables for selection of hindrances and rewards. 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 be fixed after character creation.
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.
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.
Line 14: Line 20:
     component="Hindrance"
     component="Hindrance"
     showtemplate="SimpleItem"
     showtemplate="SimpleItem"
     choosetemplate="SimpleItem"
     choosetemplate="SimpleItem">  
    addspace="2">  
     <titlebar><![CDATA[
     <titlebar><![CDATA[
       @text = "Add a Hindrance"
       @text = "Add a Hindrance"
Line 52: Line 57:
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.
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.  
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.  
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.  
Line 76: Line 83:
</pre>
</pre>


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 simple 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 create 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 how we can clearly convey "major" versus "minor" to the user via bitmaps - not an easy proposition.  
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. We can designate either value as the default selection, but we'll choose "minor", since that's more likely what the user will be wanting to choose for a character.
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.
 
<pre>
<portal
  id="severity"
  style="menuNormal">
  <menu_literal
    field="hinMajor">
    <choice value="0" display="Minor"/>
    <choice value="1" display="Major"/>
    </menu_literal>
  </portal>
</pre>


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 to the right of the hindrance name. The additions made to the Position script should look similar to the code below.
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 to the right of the hindrance name. The additions made to the Position script should look similar to the code below.

Revision as of 03:25, 18 December 2008

Context: HL Kit &#133; Authoring Examples &#133; 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 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 

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"
    addthing="resHinder"
    addspace="2"
    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, 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.

~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 

~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 

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

~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.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.