Weird Science Gizmos (Savage)

From HLKitWiki
Revision as of 00:11, 24 January 2009 by Rob (talk | contribs)
Jump to navigationJump to search

Context: HL Kit … Authoring Examples … Savage Worlds Walk-Through 

Overview

We're going to dedicate a full section to this topic. The actual changes are not complex, but there are a variety of issues that need to be considered. This results in a series of steps that we'll address one at a time.

How Gizmos Differ

Gizmos are a special variety of arcane power. In addition to the power itself, gizmos need to be controlled. In general, the use of a gizmo entails use of the "Weird Science" skill. However, a "ray gun" gizmo might use the "Shooting" skill instead. We need to track the associated skill for each gizmo and allow the user to specify that skill.

Gizmos are devices, so they each have their own pool of power points. This pool needs to be tracked independently for each gizmo. That means we need to integrate the proper handling for trackers into gizmos and display them on the "In-Play" tab so that user can manage them.

The final wrinkle with gizmos is that they can be shared. This means that a character with no arcane background can possess a gizmo. We therefore have to allow all characters to possess gizmos, and gizmos from other characters must allow the player to specify the number of power points available to each gizmo. We even have to handle the case where a weird scientist has both his own gizmos and gizmos created by others.

Differentiating a Gizmo

The first thing we need to resolve is how we're going to differentiate a gizmo from a normal power. One option would be to handle gizmos and powers much like we do weapons. We could define a new "base" component that has all the common behaviors of the two, then have separate "Power" and "Gizmo" components with the distinct behaviors. This would entail adding a new component set for gizmos as well. While this approach would definitely work, it's a non-trivial amount of work, so we should only go that route if it's truly necessary.

Gizmos are a proper superset of powers (i.e. they add behaviors but don't change any behaviors). In addition, there are only two pieces of new information that need to be tracked for powers. This means that the various new components we're considering would each be relatively small. An easier solution might be to just add the gizmo behaviors to the "Power" component and then use a tag to indicate whether a power is actually a gizmo. Since the changes we need to make aren't very complicated, using a tag ought to be more than adequate, so we'll give this approach a try.

We're actually going to have two different types of gizmos when we're finished. We need to identify gizmos in general, which can be handled via one tag. We also need to differentiate between gizmos created by the character and gizmos borrowed from another character. We'll refer to borrowed gizmos as "foreign" gizmos, and we can handle this distinction via a second tag. For simplicity, we'll just define these tags within the "Helper" tag group, and the new tags should look like below.

<value id="Foreign"/>
<value id="Gizmo"/>

We'll worry about how and when to assign these tags in the next section.

Managing Shared Gizmos

Gizmos that are shared need to be managed appropriately by the user. We currently only show the "Arcane" tab when a character has an arcane background, but we could always change that behavior. If we always showed the "Arcane" tab, then shared gizmos could be handled on it. The problem with this approach is that shared gizmos are more generally perceived as "gear" - instead of arcane powers by - by characters that are using them. As such, it would probably be better if we added shared gizmos to the "Gear" tab.

Our first task is to decide how we're going to handle shared gizmos on the separate tab. We can easily share the same template for displaying shared gizmos and powers. The question is whether we can also share the same table portal. Unfortunately, we can't. The two tables need to show different collections of powers/gizmos, so we need to use a different List tag expression on each. The existing table portal on the "Arcane" tab needs to show powers that do not possess the "Helper.Foreign" tag, which the table on the "Gear" tab only shows powers that do possess the tag. We also want to change the various text displayed for the header, adding an item, etc.

We can modify the "apPowers" table portal on the "Arcane" tab to have a suitable List tag expression, yielding the portal shown below.

<portal
  id="apPowers"
  style="tblNormal">
  <table_dynamic
    component="Power"
    showtemplate="apPower"
    choosetemplate="SimpleItem"
    addpick="resPowers"
    descwidth="350">
    <list>!Helper.Foreign</list>
    <titlebar><![CDATA[
      @text = "Add an Arcane Power - " & hero.child[resPowers].field[resSummary].text
      ]]></titlebar>
    <description/>
    <headertitle><![CDATA[
      @text = "Arcane Powers -  " & hero.child[resPowers].field[resSummary].text
      ]]></headertitle>
    <additem><![CDATA[
      ~get the color-highlighted "add" text
      @text = field[resAddItem].text
      ]]></additem>
    </table_dynamic>
  </portal>

For our new table portal on the "Gear" tab, we can start by copying the "apPowers" portal. We can then give it a new id, change the List tag expression to only include powers that possess the tag, and revise the various text shown via the scripts. However, there is one important question we haven't resolved yet. How do we get the "Helper.Foreign" tag to be assigned to items added via our new table?

The answer to this is the "autotag" element. Table portals can assign tags to each pick that they add to the hero. The assigned tags behave as if they are part of the defined nature of the pick. Consequently, by specifying an "autotag" element that assigns the "Helper.Foreign" tag, all picks added by the new table possess the tag, while all picks added by the original table on the "Arcane" tab do not.

Putting all this together results in the following new table portal being defined.


<portal

 id="grGizmos"
 style="tblNormal">
 <table_dynamic
   component="Power"
   showtemplate="apPower"
   choosetemplate="SimpleItem"
   descwidth="350">
   <list>Helper.Foreign</list>
   <autotag group="Helper" tag="Foreign"/>
   <titlebar><![CDATA[
     @text = "Add a Borrowed Weird Science Gizmo"
     ]]></titlebar>
   <description/>
   <headertitle><![CDATA[
     @text = "Borrowed Weird Science Gizmos"
     ]]></headertitle>
   <additem><![CDATA[
     @text = "Add a Borrowed Weird Science Gizmo"
     ]]></additem>
   </table_dynamic>
 </portal>

The final thing we need to do is integrate our new table portal into the layout. The layout for gear currently contains all the gear and any vehicles. We'll insert the shared gizmos between the two tables. We can use the same approach as is already used for the vehicles, reserving space for a single item in the table. This way, we can easily integrate the new portal and dedicate the majority of space on the table to normal gear. If there is space left over, we'll allocate it first to additional shared gizmos and lastly to additional vehicles. The revised layout should look like the one below.

<layout
  id="gear">
  <portalref portal="grGear" taborder="10"/>
  <portalref portal="grGizmos" taborder="20"/>
  <portalref portal="grVehicle" taborder="30"/>

  <!-- This script sizes and positions the layout and its child visual elements. -->
  <position><![CDATA[
    ~set all tables to span the full width of the layout
    portal[grGear].width = width
    portal[grGizmos].width = width
    portal[grVehicle].width = width

    ~position the vehicles table at the bottom with a minimum height of 2 items
    portal[grVehicle].maxrows = 2
    portal[grVehicle].top = height - portal[grVehicle].height

    ~position the gizmos table above the vehicles table with a minimum of 1 item
    portal[grGizmos].maxrows = 1
    portal[grGizmos].top = portal[grVehicle].top - portal[grGizmos].height

    ~position and size the gear table to fill all remaining space
    portal[grGear].top = 0
    portal[grGear].height = portal[grGizmos].top - 10

    ~position and size the gizmos and vehicle tables to use the remaining space
    ~at the bottom
    portal[grGizmos].top = portal[grGear].bottom + 10
    portal[grGizmos].height = portal[grVehicle].top - portal[grGizmos].top
    portal[grVehicle].top = portal[grGizmos].bottom + 10
    portal[grVehicle].height = height - portal[grVehicle].top
    ]]></position>

  </layout>

If we reload the data files and give our new table a try, we discover that we have a problem. No matter what we do, HL tells us that there are no powers to choose from. But we know that there are powers available, because we can readily add those powers on the "Arcane" tab. The problem is due to our List tag expression, which only includes powers that possess the "Helper.Foreign" tag. By default, the Kit assumes that the restrictions set forth by the List tag expression should also apply when identifying items for selection. However, the "Helper.Foreign" tag is only added when things are added via the table, so none exist with the tag pre-assigned, hence there is nothing to select.

The solution is to add our own Candidate tag expression, which tells the Kit to ignore the List tag expression by default. The Candidate tag expression doesn't actually have to contain anything, since we don't need to perform any special candidate tests - it must only exist. So all we need to do to fix the problem is add an empty Candidate tag expression to our table portal, which consists of the XML element below.

<candidate/>

If we reload the data files and try again, we now have no problems selecting powers from our new table. More importantly, powers added via our new table only appear within that table, and powers added on the "Arcane" tab only appear within that table. This means that a character with an arcane background can also borrow gizmos from other characters, with the two groups being fully distinguished.

Adding the Fields

We can now begin adding the logic for gizmos to powers. There are two separate pieces of information that we need to maintain for gizmos. The first is the linked skill and the second is the power points for the gizmo. We'll need one new field for each of these bits of information.

The linked skill will need to be selected by the user from a list of all the various skills. As such, we'll need to utilize a menu for the skill. Menu selections require special handling for the fields in which the selection will be saved. We must properly designate the field as being used for saving a menu selection by assigning it the correct "style". The resulting field definition is shown below.

<field
  id="powSkill"
  name="Linked Skill"
  type="user"
  style="menu">
  </field>

The stored power points for a gizmo are simpler. It's a value-based field that can be modified by the user. This yields the following field definition.

<field
  id="powStorage"
  name="Stored Points"
  type="user">
  </field>

Now that we've added the fields, we should also determine when to use them.

While we're modifying the "Power" component, we might as well also handle the assignment of the "Helper.Gizmo" tag. We haven't done this yet, and we're going to be putting it to use shortly. There are two situations where we'll


Revising the Template

Tracking Power Points

Validation

-add fields for linked skill and power points -add Tracker component to Power compset -add portals to template for specifying skill and power points -determine whether menu and edit portals are visible - impacts height of template -position menu and edit portals -add tag to reset trackers to maximum -add script to setup power points -hide non-gizmos from list of trackers on in-play tab -verify gizmos have linked skill assigned -verify foreign gizmos have non-zero power points assigned -highlight menu in red if no selection is chosen