Difference between revisions of "Add an "Edges" Tab (Savage)"

From HLKitWiki
Jump to: navigation, search
(Something Simple to Start With)
 
Line 102: Line 102:
 
     portal[name].left = 0
 
     portal[name].left = 0
 
     portal[name].width = minimum(portal[name].width,portal[info].left - portal[name].left - 10)
 
     portal[name].width = minimum(portal[name].width,portal[info].left - portal[name].left - 10)
 +
 +
    ~if the ability is auto-added, change its font to indicate that fact
 +
    if (candelete = 0) then
 +
      perform portal[name].setstyle[lblAuto]
 +
      endif
 
     ]]></position>
 
     ]]></position>
 
   </template>
 
   </template>

Latest revision as of 04:13, 12 February 2009

Context: HL KitAuthoring Examples … Savage Worlds Walk-Through 

Overview

The next logical step in the evolution of the Savage Worlds data files is to add a tab for edges. Due to the close relationship between edges and hindrances, we'll also include hindrances on the same tab, as well as the rewards that will be selected to offset any chosen hindrances. However, we'll simply call the tab "Edges". The sections below outline the process of adding and tailoring this new tab.

Something Simple to Start With

We need to a create an entirely new tab, so one option would be to start from scratch. A faster approach is to find an existing tab that is extremely simple and adapt it for use as our starting point. The "Skills" tab is perfect for this purpose, so we'll use it.

We first copy the file "tab_skills.dat" to "tab_edges.dat". If we try to re-compile the data files now, we'll get lots of errors about duplicate unique ids and such. So we need to rename the contents of the new file, and we'll tailor everything to use "edge" instead of "skill". This entails renaming all unique ids and names, changing all references to components and component sets, modifying all uses of "addpick" and actual references to resources, etc. 

We also need to add a new "HideTab" tag for the new "edges" tab and adjust the Live tag expression to use it. Lastly, the template for skills includes handling for domains and an incrementer for adjusting the die types, neither of which we need. So we must strip those portals out of the template and adjust the Position script accordingly. We could potentially switch to using the "SimpleItem" template, except that we plan to add special support later on for edges like "Scholar" and "Professional", so we need a separate template that we can customize.

When the conversion is done, we'll have a single portal, template, layout, and panel. All of them will be tailored for the display of edges, and our new tab will look just like the "Skills" tab, except that it will manage the selection of edges. The four pieces will look like those shown below.

<portal
  id="edEdges"
  style="tblNormal">
  <table_dynamic
    component="Edge"
    showtemplate="edEdge"
    choosetemplate="SimpleItem"
    addthing="resEdge">
    <titlebar><![CDATA[
      @text = "Add an Edge - " & hero.child[resEdge].field[resSummary].text
      ]]></titlebar>
    <headertitle><![CDATA[
      @text = "Edges - " & hero.child[resEdge].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}Add Edges Via Advances Tab"
        done
      endif

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

<template
  id="edEdge"
  name="Edge Pick"
  compset="Edge"
  marginhorz="3"
  marginvert="2">

  <portal
    id="name"
    style="lblNormal"
    showinvalid="yes">
    <label
      field="name">
      </label>
    </portal>

  <portal
    id="info"
    style="actInfo">
    <action
      action="info">
      </action>
    <mouseinfo mousepos="middle+above"/>
    </portal>

  <portal
    id="delete"
    style="actDelete"
    tiptext="Click to delete this item">
    <action
      action="delete">
      </action>
    </portal>

  <position><![CDATA[
    ~set up our height based on our tallest portal
    height = portal[info].height

    ~if this is a "sizing" calculation, we're done
    if (issizing <> 0) then
      done
      endif

    ~position our tallest portal at the top
    portal[info].top = 0

    ~position the other portals vertically
    perform portal[name].centervert
    perform portal[delete].centervert

    ~position the delete portal on the far right
    perform portal[delete].alignedge[right,0]

    ~position the info portal to the left of the delete button
    perform portal[info].alignrel[rtol,delete,-8]

    ~position the name on the left and use all availble space
    portal[name].left = 0
    portal[name].width = minimum(portal[name].width,portal[info].left - portal[name].left - 10)

    ~if the ability is auto-added, change its font to indicate that fact
    if (candelete = 0) then
      perform portal[name].setstyle[lblAuto]
      endif
    ]]></position>
  </template>

<layout
  id="edges">
  <portalref portal="edEdges" taborder="10"/>
  <position><![CDATA[
    ~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
      endif

    ~position and size the table to span the full layout; it will only use the
    ~vertical space that it actually needs
    perform portal[skSkills].autoplace
    ]]></position>
  </layout>

<panel
  id="edges"
  name="Edges"
  marginhorz="5"
  marginvert="5"
  order="130">
  <live>!HideTab.edges</live>
  <layoutref layout="edges"/>
  <position><![CDATA[
    ]]></position>
  </panel> 

Refining Edges

Our edges table is now in place, but it's still a little bit rough in how it works, so we need to refine its behavior. If you click within the "Edges" table to add a new edge, you'll see all of the edges listed properly. Our pre-requisites appear to be handled correctly, with any failed pre-requisites being listed in the description region and appropriate edges being greyed out when the pre-requisites aren't satisfied. However, some of the names of edges are being cut off due to the horizontal space being too narrow. This can be easily fixed by specifying a width of our own choosing for the "thing" template. Unfortunately, we're using the "SimpleItem" template as our "choose" template, so changing the width within that template will change it everywhere the template is used, and that's not what we want.

One solution would be to copy the "SimpleItem" template into the file "tab_edges.dat", rename it, and adapt it to our needs. That would work, but then we'd find ourselves copying the template whenever we wanted to make minor adjustments, and that will make the data files harder to maintain over time. Fortunately, the "SimpleItem" template has been designed so that it can be easily customized in situations like this. By assigning a "SimpleItem.widthXXX" tag to a thing, where "XXX" is the width value we want to use, the "SimpleItem" template will detect a custom width and use it. For example, a tag of "SimpleItem.width250" indicates a width of 250 pixels should be used. Since the tag needs to be assigned to all things to ensure that it will always be recognized by the template, we can assign the tag to the component and all things derived from that component will inherit the tag. This means that all we need to do to specify a custom width for the "SimpleItem" template when showing edges for selection is add the tag as shown below to the "Edge" component within the file "traits.str".

<tag group="SimpleItem" tag="width250"/> 

The next thing of note is that the edges are sorted alphabetically, but they are not grouped like they are within the rulebook. By default, all tables list their contents alphabetically unless we specify something else. This is accomplish via the use of a "sort set". Open the file "control.1st" and scroll towards the bottom, where you'll find a number of "sortset" elements. These elements define the various sort sets that are provided by the Skeleton files. We need to add a new one that will sort the edges first by their type and then by name within each type. Each sort key within a sort set can be either a field or a tag group, specified by its unique id, and the order of the sort keys dictates the ultimate ordering of the items. We want our edges to be sorted by the type and then the name, so we'll need two sort keys. Putting it all together yields a sort set that looks similar to the one shown below.

<sortset
  id="Edge"
  name="Edge By Type and Name">
  <sortkey isfield="no" id="Edge"/>
  <sortkey isfield="no" id="_Name_"/>
  </sortset>

Once the sort set is defined, we can reference it from the table portal so that all edges are shown to the user in the order dictated by the sort set. This is accomplished by adding the "choosesortset" attribute to the "table_dynamic" element of the table portal and specifying the id of our new sort set. The new attribute should look like below.

choosesortset="Edge" 

After making this change and experimenting with edges again, the behavior just doesn't seem very intuitive. While we've now listed the edges in the same organization as the rulebook, there is no clear structural association to the rulebook here. Coupled with the fact that there are some edge types with only a few edges and others with lengthy lists, this new ordering is likely to be more confusing than helpful to most users. Consequently, we're probably better off not using the new sort set and leaving the list in a purely alphabetical order.

This is the sort of trade-off that you'll need to make at times. Sometimes, it's better to emulate the rulebook's organization, while sometimes it's better to use a different approach that is better suited to the way users will be putting your data files to work.