A Tab for Skills (Savage): Difference between revisions

From HLKitWiki
Jump to navigationJump to search
New page: {{context|Authoring Examples|Savage Worlds Walk-Through}} ===Overview=== In Savage Worlds, skills are a bit more complex that within the Skeleton files. For example, skills like "Knowled...
 
 
(4 intermediate revisions by the same user not shown)
Line 17: Line 17:
Beneath the table portal is the template that needs to have its unique id changed to "skPick". The component set must be changed to "Skill" and the name should be changed to something appropriate. All other facets of the template can remain unchanged for now, as they are generic and will work fine for skills.
Beneath the table portal is the template that needs to have its unique id changed to "skPick". The component set must be changed to "Skill" and the name should be changed to something appropriate. All other facets of the template can remain unchanged for now, as they are generic and will work fine for skills.


If we were to re-compile the data files at this point, we would have an error that still needs to be resolved, so we'll address it now. Open the "tags.1st" file and locate the "HideTab" tag group. The "abilities" tag needs to be changed to "skills", since that's what we now key on within the Live tag expression of the panel. Once the change has been made, you should end up with something that looks like the following:
Once all these changes have been made, you should end up with something that looks like the following:


<pre>
<pre>
Line 28: Line 28:
     choosetemplate="SimpleItem"
     choosetemplate="SimpleItem"
     fixedlast="yes"
     fixedlast="yes"
     addthing="resSkill"
     addpick="resSkill">
    addspace="2">
     <candidate>!Hide.Skill</candidate>
     <candidate>!Hide.Skill</candidate>
     <titlebar><![CDATA[
     <titlebar><![CDATA[
       @text = "Add a Special Skill - " & hero.child[resSkill].field[resSummary].text
       @text = "Add a Special Skill - " & hero.child[resSkill].field[resSummary].text
       ]]></titlebar>
       ]]></titlebar>
    <description><![CDATA[
      var descript as string
      call Descript
      @text = descript
      ]]></description>
     <headertitle><![CDATA[
     <headertitle><![CDATA[
       @text = "Skills: " & hero.child[resSkill].field[resSummary].text
       @text = "Skills: " & hero.child[resSkill].field[resSummary].text
Line 48: Line 42:
         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 76: Line 71:
       action="info">
       action="info">
       </action>
       </action>
     <mouseinfo mousepos="middle+above"><![CDATA[
     <mouseinfo mousepos="middle+above"/>
      var mouseinfo as string
      call MouseInfo
      @text = mouseinfo
      ]]></mouseinfo>
     </portal>
     </portal>


Line 95: Line 86:
     ~set up our height based on our tallest portal
     ~set up our height based on our tallest portal
     height = portal[info].height
     height = portal[info].height
     ~if this is a "sizing" calculation, we're done
     ~if this is a "sizing" calculation, we're done
     if (issizing <> 0) then
     if (issizing <> 0) then
       done
       done
       endif
       endif
     ~position our tallest portal at the top
     ~position our tallest portal at the top
     portal[info].top = 0
     portal[info].top = 0
     ~center the other portals vertically
     ~center the other portals vertically
     perform portal[name].centervert
     perform portal[name].centervert
     perform portal[delete].centervert
     perform portal[delete].centervert
     ~position the delete portal on the far right
     ~position the delete portal on the far right
     perform portal[delete].alignedge[right,0]
     perform portal[delete].alignedge[right,0]
     ~position the info portal to the left of the delete button
     ~position the info portal to the left of the delete button
     perform portal[info].alignrel[rtol,delete,-8]
     perform portal[info].alignrel[rtol,delete,-8]
     ~position the name on the left and let it use all available space
     ~position the name on the left and let it use all available space
     portal[name].left = 0
     portal[name].left = 0
     portal[name].width = minimum(portal[name].width,portal[info].left - 5)
     portal[name].width = minimum(portal[name].width,portal[info].left - 5)
     ~if the ability is auto-added, change its font to indicate that fact
     ~if the ability is auto-added, change its font to indicate that fact
     if (candelete = 0) then
     if (candelete = 0) then
Line 127: Line 125:
       portal[skSkills].freeze = 1
       portal[skSkills].freeze = 1
       endif
       endif
     ~size the table to span the full layout width
 
    portal[skSkills].width = width
     ~position and size the table to span the full layout; it will only use the
    ~set the height of the table to the full height of the layout; the table
     ~vertical space that it actually needs
     ~will actually only use the vertical space it needs if it's smaller
     perform portal[abAbility].autoplace
     portal[skSkills].height = height - portal[skSkills].top
     ]]></position>
     ]]></position>
   </layout>
   </layout>
Line 147: Line 144:
   </panel>
   </panel>
</pre>
</pre>
===Getting Everything to Work===
If we were to re-compile the data files at this point, we would have an error that still needs to be resolved, so we'll address it now. Open the "tags.1st" file and locate the "HideTab" tag group. The "abilities" tag needs to be changed to "skills", since that's what we now key on within the Live tag expression of the panel.


There are also a few panel linkages on components that are currently tied to the "abilities" tab as a placeholder. These linkages are for edges and the like that have no relationship to the "Skills" tab, but we need to change them to something so the compiler can resolve everything. We can change the linkages to "skills", "basics", or any other tab, as long as the tab exists. We'll change it to "basics" as something safe for the time being. We'll fix it once we have a suitable tab in place to hook these components up to.  
There are also a few panel linkages on components that are currently tied to the "abilities" tab as a placeholder. These linkages are for edges and the like that have no relationship to the "Skills" tab, but we need to change them to something so the compiler can resolve everything. We can change the linkages to "skills", "basics", or any other tab, as long as the tab exists. We'll change it to "basics" as something safe for the time being. We'll fix it once we have a suitable tab in place to hook these components up to.  
We should now be able to re-load our data files and see our new "Skills" tab appear. It isn't working correctly yet, but we'll take care of that in the following sections.


===Internal Mechanics Changes===
===Internal Mechanics Changes===
Line 157: Line 160:


If errors are identified with any skills, it would be helpful to the user for the "Skills" tab to appear in red, drawing attention to the problem for easy correction. To simplify this, we need to associate all skills with the new tab. This can be accomplished by linking the "Skill" component to the new "skills" panel via a "panellink" attribute.
If errors are identified with any skills, it would be helpful to the user for the "Skills" tab to appear in red, drawing attention to the problem for easy correction. To simplify this, we need to associate all skills with the new tab. This can be accomplished by linking the "Skill" component to the new "skills" panel via a "panellink" attribute.
<pre>
<component
  id="Skill"
  name="Skill"
  autocompset="no"
  panellink="skills">
  ...
  </component>
</pre>


The final detail is to eliminate the special validation thing that is defined for abilities. You'll find this thing in the file "thing_validate.dat" and it will have the unique id "valAbility". Since skills are governed by points, we don't need anything equivalent for Savage Worlds and can simply delete the thing.  
The final detail is to eliminate the special validation thing that is defined for abilities. You'll find this thing in the file "thing_validate.dat" and it will have the unique id "valAbility". Since skills are governed by points, we don't need anything equivalent for Savage Worlds and can simply delete the thing.  
Line 203: Line 216:
</pre>
</pre>


Now that the portals have been added to the template, we need to properly position everything. We want to put the incrementer on the far left, with the name of the skill just to the right of the incrementer. If the skill requires a domain, we'll place it just to the right of the skill name, but we need to hide the portals associated with the domain if the skill does not require a domain. By default, all of the portals are always present for every skill, so we control the visibility of each portal to ensure the contents being displayed reflect the correct behaviors for each skill. We can determine whether a skill needs a domain based on the presence of the "User.NeedDomain" tag. We also need to position the domain label such that it shares a common baseline (i.e. bottom edge) with the edit portal, since it's a smaller font and will look odd if it is vertically centered. Putting it all together yields the following new Position script.
Now that the portals have been added to the template, we need to properly position everything. We want to put the incrementer on the far left, with the name of the skill just to the right of the incrementer. If the skill requires a domain, we'll place it just to the right of the skill name, but we need to hide the portals associated with the domain if the skill does not require a domain. By default, all of the portals are always shown for every skill, so we control the visibility of each portal to ensure the contents being displayed reflect the correct behaviors for each skill. We can determine whether a skill needs a domain based on the presence of the "User.NeedDomain" tag. Putting it all together yields the following new Position script.


<pre>
<pre>
Line 220: Line 233:
perform portal[name].centervert
perform portal[name].centervert
perform portal[domain].centervert
perform portal[domain].centervert
perform portal[lbldomain].alignrel[btob,domain,0]
perform portal[lbldomain].centervert
perform portal[value].centervert
perform portal[value].centervert
perform portal[delete].centervert
perform portal[delete].centervert
Line 248: Line 261:
   portal[domain].width = 150
   portal[domain].width = 150
   endif  
   endif  
~if the ability is auto-added, change its font to indicate that fact
if (candelete = 0) then
  perform portal[name].setstyle[lblAuto]
  endif
</pre>
</pre>
===Problem with Domains===
Unfortunately, there is a problem with the way we're handling domains. The "Domain" component automatically integrates the domain into the name of the pick. This means that entering a domain of "foo" for a "Knowledge" skill will change the name shown for the pick to "Knowledge: foo". Since we are also showing an edit portal for the domain, this behavior will appear wrong to the user.
We need to show a name for the pick that excludes the domain. For that, we'll need to utilize the basic name for the pick. That name is accessible via the "thingname" field, so we need to change the "name" portal to reference the "thingname" field instead of the full name. Once we do this, everything works nicely.


===Delete Old Skills Table===
===Delete Old Skills Table===

Latest revision as of 06:58, 31 January 2009

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

Overview

In Savage Worlds, skills are a bit more complex that within the Skeleton files. For example, skills like "Knowledge" require that the user be able to specify a suitable domain. This requires more horizontal space than the half-width provided on the "Basics" panel. So we need to move skills to their own tab. This section walks you through the process.

Re-Purpose Existing Tab

The Skeleton files provide an "Abilities" tab that we don't need for Savage Worlds, so we'll re-purpose that tab as the new "Skills" tab. We start by renaming the file "tab_abilities.dat" to "tab_skills.dat". Then we need to open the file "tab_skills.dat" and convert the contents over to behave as a "Skills" tab.

At the bottom of the file, the "abilities" panel is defined. Change the id to "skills" and the name to "Skills". The Live tag expression must be changed to key on a "skills" tag (that we'll define in just a moment). And the layout referenced should be "skills" instead of "abilities".

Just above the panel definition is the layout definition. Change the id from "abilities" to "skills". The portal referenced should be changed to "skSkills". This entails that uses of the portal id within the Position script must also be changed to "skSkills" (there are three of them).

Moving to the top of the file, there is the table portal that needs to have its unique id changed to "skSkills". Within this portal, a variety of other facets must also be changed. The component must be "Skill" to show skills. The "showtemplate" should be changed to "skPick", and the "addthing" should be changed to "resSkill". Within the various scripts for the portal, change references from "Abilities" to "Skills" and uses of the "resAbility" resource to "resSkill".

Beneath the table portal is the template that needs to have its unique id changed to "skPick". The component set must be changed to "Skill" and the name should be changed to something appropriate. All other facets of the template can remain unchanged for now, as they are generic and will work fine for skills.

Once all these changes have been made, you should end up with something that looks like the following:

<portal
  id="skSkills"
  style="tblNormal">
  <table_dynamic
    component="Skill"
    showtemplate="skPick"
    choosetemplate="SimpleItem"
    fixedlast="yes"
    addpick="resSkill">
    <candidate>!Hide.Skill</candidate>
    <titlebar><![CDATA[
      @text = "Add a Special Skill - " & hero.child[resSkill].field[resSummary].text
      ]]></titlebar>
    <headertitle><![CDATA[
      @text = "Skills: " & hero.child[resSkill].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/Increase Skills Via Advances Tab"
        done
        endif

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

<template
  id="skPick"
  name="Skill Pick"
  compset="Skill"
  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

    ~center 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 let it use all available space
    portal[name].left = 0
    portal[name].width = minimum(portal[name].width,portal[info].left - 5)

    ~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="skills">
  <portalref portal="skSkills" taborder="10"/>
  <position><![CDATA[
    ~freeze our table 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[skSkills].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[abAbility].autoplace
    ]]></position>
  </layout>

<panel
  id="skills"
  name="Skills"
  marginhorz="5"
  marginvert="5"
  order="120">
  <live>!HideTab.skills</live>
  <layoutref layout="skills"/>
  <position><![CDATA[
    ]]></position>
  </panel>

Getting Everything to Work

If we were to re-compile the data files at this point, we would have an error that still needs to be resolved, so we'll address it now. Open the "tags.1st" file and locate the "HideTab" tag group. The "abilities" tag needs to be changed to "skills", since that's what we now key on within the Live tag expression of the panel.

There are also a few panel linkages on components that are currently tied to the "abilities" tab as a placeholder. These linkages are for edges and the like that have no relationship to the "Skills" tab, but we need to change them to something so the compiler can resolve everything. We can change the linkages to "skills", "basics", or any other tab, as long as the tab exists. We'll change it to "basics" as something safe for the time being. We'll fix it once we have a suitable tab in place to hook these components up to.

We should now be able to re-load our data files and see our new "Skills" tab appear. It isn't working correctly yet, but we'll take care of that in the following sections.

Internal Mechanics Changes

We now need to make some internal changes to mechanics in order to get skills behaving properly. The first thing to address is the fact that all skills are being automatically added to every character. In Savage Worlds, skills are purchased, so each character should start out with zero skills. Open the file "bootstrap.1st" and look for the various "enmasse" entries. Each of these entries automatically adds all things that satisfy a particular tag expression. One entry specifies all things with the "component.Skill" tag, which will add all skills. Delete this "enmasse" entry.

The next detail we need to address is that there may be some skills that the user is not allowed to purchase directly and that are automatically added (e.g. via edges, powers, etc.). This means that we need a method for designating some skills as hidden from the user for selection. A general mechanism for hiding things/picks is already defined via the "Hide" tag group, and we already have a tag for hiding skills in the "Hide.Skill" tag. We can assign this tag to any things that should be hidden from the user. The Candidate tag expression of the table portal will preclude such things from being shown for selection.

If errors are identified with any skills, it would be helpful to the user for the "Skills" tab to appear in red, drawing attention to the problem for easy correction. To simplify this, we need to associate all skills with the new tab. This can be accomplished by linking the "Skill" component to the new "skills" panel via a "panellink" attribute.

<component
  id="Skill"
  name="Skill"
  autocompset="no"
  panellink="skills">
  ...
  </component>

The final detail is to eliminate the special validation thing that is defined for abilities. You'll find this thing in the file "thing_validate.dat" and it will have the unique id "valAbility". Since skills are governed by points, we don't need anything equivalent for Savage Worlds and can simply delete the thing.

Enhancing the Skill Template

The current "skPick" template within the file "tab_skills.dat" contains only generic mechanisms. We now need to enhance the template to include the important facets of skills that are currently missing. The first thing we need to add is an incrementer that will allow the user to adjust the die type for a given skill. We'll use the same incrementer style that is already being used for attributes. So we add the portal shown below.

<portal
  id="value"
  style="incrSimple">
  <incrementer
    field="trtUser">
    </incrementer>
  <mouseinfo mousepos="middle+above"><![CDATA[
    if (hero.tagis[mode.creation] = 0) then
      @text = "Skills must be modified via the Advances tab once the character is locked for play."
    elseif (autonomous = 0) then
      @text = "This trait has been improved via the Advances tab and cannot be modified further from here."
    else
      @text = "Allocate points to this skill by clicking on the arrows to increase/decrease the number of points assigned."
      endif
    ]]></mouseinfo>
  </portal>

We also need to allow the user to specify a suitable domain for skills that require one, such as the "Knowledge" skill. We need an edit portal in order to let the user enter the name of the domain, plus we need a label portal to identify the empty edit portal as being for the domain. We want the label portal to be in a smaller font and softer color than the name of the skill itself, so we choose a suitable style that reflects that behavior. The result is that we add the two portals shown below.

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

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

Now that the portals have been added to the template, we need to properly position everything. We want to put the incrementer on the far left, with the name of the skill just to the right of the incrementer. If the skill requires a domain, we'll place it just to the right of the skill name, but we need to hide the portals associated with the domain if the skill does not require a domain. By default, all of the portals are always shown for every skill, so we control the visibility of each portal to ensure the contents being displayed reflect the correct behaviors for each skill. We can determine whether a skill needs a domain based on the presence of the "User.NeedDomain" tag. Putting it all together yields the following new Position script.

~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[domain].centervert
perform portal[lbldomain].centervert
perform portal[value].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 incrementer on the left
portal[value].left = 0

~position the name next to the incrementer
perform portal[name].alignrel[ltor,value,10]

~if we don't need a domain, hide it and let the name use all available space
if (tagis[User.NeedDomain] = 0) then
  portal[lbldomain].visible = 0
  portal[domain].visible = 0
  portal[name].width = minimum(portal[name].width,portal[info].left - portal[name].left - 10)

~otherwise, position the domain portals next to the name
else
  perform portal[lbldomain].alignrel[ltor,name,20]
  perform portal[domain].alignrel[ltor,lbldomain,5]
  portal[domain].width = 150
  endif 

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

Problem with Domains

Unfortunately, there is a problem with the way we're handling domains. The "Domain" component automatically integrates the domain into the name of the pick. This means that entering a domain of "foo" for a "Knowledge" skill will change the name shown for the pick to "Knowledge: foo". Since we are also showing an edit portal for the domain, this behavior will appear wrong to the user.

We need to show a name for the pick that excludes the domain. For that, we'll need to utilize the basic name for the pick. That name is accessible via the "thingname" field, so we need to change the "name" portal to reference the "thingname" field instead of the full name. Once we do this, everything works nicely.

Delete Old Skills Table

The final task we need to complete is to delete the old "Skills" table from the "Basics" tab. Open the file "tab_basics.dat" and locate the "baSkill" table portal. This table of skills is no longer applicable, so delete it. Now scroll further down to the "baSklPick" template. This template is only used by the table portal we just deleted, so it can also be deleted. Finally, we need to delete the table from the "basics" layout. This amounts to deleting the appropriate "portalref" element and deleting the positioning details for the portal from the Position script.

NOTE! Remember that you can always comment out sections instead of deleting them until you're certain what can be safely deleted.