Finishing Off Weapons (Savage): Difference between revisions

From HLKitWiki
Jump to navigationJump to search
New page: {{context|Authoring Examples|Savage Worlds Walk-Through}} ===Overview=== Now that hand weapons are in place, we'll continue with ranged weapons. ===Ranged Weapons=== Ranged weapons in ...
 
No edit summary
 
(2 intermediate revisions by the same user not shown)
Line 3: Line 3:
===Overview===
===Overview===


Now that hand weapons are in place, we'll continue with ranged weapons.
We now need to reconcile the remaining facets of weapons, such as the proper calculation of attack values and the handling of ammunition.
 
===Ranged Weapons===
 
Ranged weapons in Savage Worlds introduce four new variable ratings that need to be tracked, as well as a handful of special attributes that are either present or not. The variable ratings corresponding to the following characteristics: rate of fire, number of shots, number of actions to reload, and ammunition type. They can be managed via new fields that we'll add to the "WeapRange" component, which is defined in the file "equipment.str". They should look similar to the field definitions provided below.
 
<pre>
<field
  id="wpReload"
  name="Actions to Reload"
  type="static">
  </field>
 
<field
  id="wpFireRate"
  name="Rate of Fire"
  type="static"
  defvalue="1"
  maxlength="10">
  </field>
 
<field
  id="wpShots"
  name="Number of Shots"
  type="static">
  </field>
 
<field
  id="wpAmmo"
  name="Ammunition"
  type="static"
  maxlength="10">
  </field>
</pre>
 
The special attributes represent facets of weapons that are optionally present, such as snap fire, double tap, three-round burst, etc. All of these are either present or not, so they can be best represented as individual tags. The Skeleton files provide a tag group intended just for this purpose, with the id "Weapon". So we can add each of the tags we need to this tag group in the file "tags.1st". Whichever tags apply to a given weapon can simply be assigned to the thing. The revised tag group should look similar to the example shown below.
 
<pre>
<group
  id="Weapon">
  <value id="SpecRange" name="Range is special"/>
  <value id="SnapFire" name="Snap Fire"/>
  <value id="DoubleTap" name="Double Tap"/>
  <value id="HvyWeapon" name="Heavy Weapon"/>
  <value id="HighExplos" name="High Explosive"/>
  <value id="ThreeRound" name="Three-Round Burst"/>
  <value id="NoMove" name="May Not Move"/>
  <value id="Revolver"/>
  <value id="SemiAuto" name="Semi-Auto"/>
  <value id="FullAuto" name="Full-Auto"/>
  <value id="Shotgun"/>
  </group>
</pre>
 
Just like we did for hand weapons, the new fields and attributes need to be included within the weapon description details. The description for ranged weapons is handled by the "InfoRange" procedure within the file "procedures.dat". We only add the new information when it applies. This yields code that should look similar to the following.
 
<pre>
<procedure id="InfoRange" context="info"><![CDATA[
  ~declare variables that are used to communicate with our caller
  var iteminfo as string
 
  ~start with generic details for all weapons
  call InfoWeapon
 
  ~add the range details for the weapon
  iteminfo &= "Range: " & field[wpRange].text & "\n"
 
  ~report the fire rate of the weapon (if any)
  iteminfo &= "Rate of Fire: " & field[wpFireRate].text & "\n"
 
  ~report the number of shots for the weapon (if any)
  if (field[wpShots].value > 0) then
    iteminfo &= "# Shots: " & field[wpShots].value & "\n"
    endif
 
  ~report the number of actions to reload the weapon (if any)
  if (field[wpReload].value > 0) then
    iteminfo &= "Actions to Reload: " & field[wpReload].value & "\n"
    endif
 
  ~report the ammunition for the weapon (if any)
  if (field[wpAmmo].isempty = 0) then
    iteminfo &= "Ammunition: " & field[wpAmmo].text & "\n"
    endif
  ]]></procedure>
</pre>
 
We also need to add the new fields and attributes to the special notes shown for weapons on the Armory tab. This can be done via the Eval script within the "WeapRange" component that performs this function. The exception is the ammunition type, which doesn't belong here and can be accessed via the description text if the user wants to reference that info. The code parallels what we've already done for hand weapons, which results in a revised script that looks like the following.
 
<pre>
<eval index="2" phase="Render" priority="2000"><![CDATA[
  var special as string
  ~report the rate of fire for the weapon
  if (empty(special) = 0) then
    special &= ", "
    endif
  special &= "RoF " & field[wpFireRate].text
 
  ~report the number of shots for the weapon (if any)
  if (field[wpShots].value <> 0) then
    if (empty(special) = 0) then
      special &= ", "
      endif
    special &= "Shots " & field[wpShots].value
    endif
 
  ~report the reload actions of the weapon (if any)
  if (field[wpReload].value <> 0) then
    if (empty(special) = 0) then
      special &= ", "
      endif
    special &= "Reload " & field[wpReload].value & " action(s)"
    endif
 
  ~prepend any existing special details with the notes for this weapon
  if (empty(special) = 0) then
    if (field[wpNotes].isempty = 0) then
      special &= ", "
      endif
    field[wpNotes].text = special & field[wpNotes].text
    endif
  ]]></eval>
</pre>
 
===Add Ranged Weapons===
 
We can now begin adding all of the various ranged weapons to the data files. As with hand weapons, they should be added to the file "thing_armory.dat". A few examples are provided below. You can either add the rest or pull them out of the complete Savage Worlds data files that are provided.
 
<pre>
<thing
  id="wpCrossbow"
  name="Crossbow"
  compset="Ranged"
  description="Description goes here">
  <fieldval field="wpDamage" value="2d6"/>
  <fieldval field="wpShort" value="15"/>
  <fieldval field="wpMedium" value="30"/>
  <fieldval field="wpLong" value="60"/>
  <fieldval field="wpStrReq" value="3"/>
  <fieldval field="wpPiercing" value="2"/>
  <fieldval field="wpReload" value="1"/>
  <fieldval field="grCost" value="500"/>
  <fieldval field="grWeight" value="10"/>
  <usesource id="TimeMedi"/>
  <tag group="WeaponType" tag="MedRange"/>
  <tag group="Equipment" tag="TwoHand"/>
  </thing>
 
<thing
  id="wpColt1911"
  name="Colt 1911"
  compset="Ranged"
  description="Description goes here">
  <fieldval field="wpDamage" value="2d6+1"/>
  <fieldval field="wpShort" value="12"/>
  <fieldval field="wpMedium" value="24"/>
  <fieldval field="wpLong" value="48"/>
  <fieldval field="wpPiercing" value="1"/>
  <fieldval field="wpShots" value="7"/>
  <fieldval field="wpAmmo" value=".45"/>
  <fieldval field="grCost" value="200"/>
  <fieldval field="grWeight" value="4"/>
  <usesource id="TimeModern"/>
  <tag group="WeaponType" tag="ModPistol"/>
  <tag group="Weapon" tag="DoubleTap"/>
  <tag group="Weapon" tag="SemiAuto"/>
  </thing>
 
<thing
  id="wpBarrett"
  name="Barrett"
  compset="Ranged"
  description="Description goes here">
  <fieldval field="wpDamage" value="2d10"/>
  <fieldval field="wpShort" value="50"/>
  <fieldval field="wpMedium" value="100"/>
  <fieldval field="wpLong" value="200"/>
  <fieldval field="wpStrReq" value="4"/>
  <fieldval field="wpPiercing" value="4"/>
  <fieldval field="wpShots" value="11"/>
  <fieldval field="wpAmmo" value=".50"/>
  <fieldval field="grCost" value="750"/>
  <fieldval field="grWeight" value="35"/>
  <usesource id="TimeModern"/>
  <tag group="WeaponType" tag="ModRifle"/>
  <tag group="Weapon" tag="SnapFire"/>
  <tag group="Weapon" tag="HvyWeapon"/>
  <tag group="Equipment" tag="TwoHand"/>
  </thing>
</pre>
 
===Revise Table for Ranged Weapons===
 
With all of the ranged weapons in place, we can now revise how they are managed visually within the table. The table portal for ranged weapons is named "arRange" within the file "tab_armory.dat". After a quick review, there are only two things that we need to change, and those are the same changes we already made to the "arMelee" table portal above. We first need to increase the width of the area for showing weapon descriptions, so we add the "descwidth" attribute to the "table_dynamic" element with a value of either 275 or 300. Then we add the "choosesortset" attribute to the same "table_dynamic" element and assign it the unique id of our custom sort set, which is "Weapon".  


===Weapon Attack Calculations===
===Weapon Attack Calculations===
Line 211: Line 18:
</pre>
</pre>


Once we change the field's nature, we are going to get a variety of compiler errors, since there are a handful of places where the field is accessed as a value-based field. Try compiling the file and use the list of errors to locate the handful of locations where the field usage needs to be adjusted. All you should need to do is change references to "field[wpNetAtk].value" over to "field[wpNetAtk].text".
===One Field to Harness Three===


While we're mucking with fields, we might as well address another need. In order to independently synthesize an appropriately adjusted trait roll for the weapon attacks, those scripts will need to access the net bonus/penalty for the particular trait. Currently, that information is tracked across three separate fields, so we need to introduce a new field that calculates the net adjustment and can be readily accessed. We'll call our new field "trtNetRoll", and it must be generated after any penalties are applied due to the load limit, so we'll base our timing on the script we defined earlier that performs that role. In the end, our new field should look a lot like the definition below.
While we're mucking with fields, we might as well address another need. In order to independently synthesize an appropriately adjusted trait roll for the weapon attacks, those scripts will need to access the net bonus/penalty for the particular trait. Currently, that information is tracked across three separate fields, so we need to introduce a new field that calculates the net adjustment and can be readily accessed. We'll call our new field "trtNetRoll", and it must be generated after any penalties are applied due to the load limit, so we'll base our timing on the script we defined earlier that performs that role. In the end, our new field should look a lot like the definition below.
Line 219: Line 26:
   id="trtNetRoll"
   id="trtNetRoll"
   name="Net Roll Bonus"
   name="Net Roll Bonus"
   type="derived"
   type="derived">
   calcphase="Traits"
   <calculate name="Calc trtNetRoll" phase="Traits" priority="9000">
  calcprior="9000">
  <calculate name="Calc trtNetRoll">
     <after name="Apply LoadLimit"/><![CDATA[
     <after name="Apply LoadLimit"/><![CDATA[
     @value = field[trtRoll].value + field[trtProf].value + herofield[acNetPenal].value
     @value = field[trtRoll].value + field[trtProf].value + herofield[acNetPenal].value
Line 228: Line 33:
   </field>
   </field>
</pre>
</pre>
===Re-Usable Procedure for Display===


The logic we'll want to use when synthesizing the net attack for display will be very similar to the logic used to generate the final trait rolls for display within the "trtDisplay" field. Consequently, our next task should be to carve out that logic for re-use by putting it into a procedure. Once it's in a procedure, it can be used from both the current script that synthesizes "trtDisplay" and any other script that synthesizes "wpNetAtk".  
The logic we'll want to use when synthesizing the net attack for display will be very similar to the logic used to generate the final trait rolls for display within the "trtDisplay" field. Consequently, our next task should be to carve out that logic for re-use by putting it into a procedure. Once it's in a procedure, it can be used from both the current script that synthesizes "trtDisplay" and any other script that synthesizes "wpNetAtk".  


Looking closely at the logic, there are two distinct values that must be passed into the procedure, with a since string being returned for use by the caller. The two inbound values are the die type for the trait and any bonus/penalty to the roll. Based on these two inputs, our procedure can interpret the values correctly and synthesize the appropriate string for display to the user. The only thing special we need to do is ensure that the die type is properly bounded, just like is already done within the logic that synthesizes "trtDisplay". In the end, we should end up with a procedure that looks very similar to the one provided below.
Looking closely at the logic, there are two distinct values that must be passed into the procedure, with a string being returned for use by the caller. The two inbound values are the die type for the trait and any bonus/penalty to the roll. Based on these two inputs, our procedure can interpret the values correctly and synthesize the appropriate string for display to the user. The only thing special we need to do is ensure that the die type is properly bounded, just like is already done within the logic that synthesizes "trtDisplay". In the end, we should end up with a procedure that looks very similar to the one provided below.


<pre>
<pre>
Line 239: Line 46:
   var finalbonus as number
   var finalbonus as number
   var finaltext as string
   var finaltext as string
   ~bound our final die type appropriately
   ~bound our final die type appropriately
   var final as number
   var final as number
Line 247: Line 55:
     final = 6
     final = 6
     endif
     endif
   ~convert the final value for the trait to the proper die type for display
   ~convert the final value for the trait to the proper die type for display
   var dietype as number
   var dietype as number
   dietype = final * 2
   dietype = final * 2
   finaltext = "d" & dietype
   finaltext = "d" & dietype
   ~if there are any bonuses or penalties on the roll, append those the final result
   ~if there are any bonuses or penalties on the roll, append those the final result
   if (finalbonus <> 0) then
   if (finalbonus <> 0) then
Line 261: Line 71:


<pre>
<pre>
<eval value="4" phase="Render" priority="5000" name="Calc trtDisplay">
<eval index="4" phase="Render" priority="5000" name="Calc trtDisplay">
   <after name="Calc trtNetRoll"/>
   <after name="Calc trtNetRoll"/>
   <after name="Calc trtFinal"/><![CDATA[
   <after name="Calc trtFinal"/><![CDATA[
Line 269: Line 79:
     done
     done
     endif
     endif
   ~calculate the net bonuses and penalties for the roll
   ~calculate the net bonuses and penalties for the roll
   var finalbonus as number
   var finalbonus as number
   finalbonus = field[trtNetRoll].value
   finalbonus = field[trtNetRoll].value
   ~generate the appropriate results for display
   ~generate the appropriate results for display
   var finaldie as number
   var finaldie as number
Line 277: Line 89:
   finaldie = field[trtFinal].value
   finaldie = field[trtFinal].value
   call FinalRoll
   call FinalRoll
   ~put the final result into the proper field
   ~put the final result into the proper field
   field[trtDisplay].text = finaltext
   field[trtDisplay].text = finaltext
Line 282: Line 95:
</pre>
</pre>


We've now got all of the pieces in place to be able to properly synthesize the "wpNetAtk" field for display to the user. There are two separate scripts in the file "equipment.pri" that synthesize the "wpNetAtk" field - one for ranged weapons and another for hand weapons. We need two separate scripts because one is based on the "Shooting" skill, while the other is based on the "Fighting" skill. We'll start by modifying the Eval script within the "WeapRange" component. The timing does not need to be touched, but we otherwise need to replace the script with revised logic that is similar to the synthesis of "trtDisplay" above and uses the "Shooting" skill. The key differences are two-fold. First, the bonus needs to incorporate both any bonus/penalty from the trait and any separate bonus/penalty from the weapon itself. Second, we need to handle the case where the character does not possess the needed skill. If not, then the die type will be zero due to the use of the "childfound." transition, which the procedure will bound as if it's a "d4". We must also apply the appropriate "-2" adjustment to the roll for being unskilled. The net result should yield a script that looks similar to the one below.
===Calculating the Net Attack===
 
We've now got all of the pieces in place to be able to properly synthesize the "wpNetAtk" field for display to the user. There are two separate scripts in the file "equipment.str" that synthesize the "wpNetAtk" field - one for ranged weapons and another for hand weapons. We need two separate scripts because one is based on the "Shooting" skill, while the other is based on the "Fighting" skill.  
 
We'll start by modifying the Eval script within the "WeapRange" component. The timing does not need to be touched, but we otherwise need to replace the script with revised logic that is similar to the synthesis of "trtDisplay" above and uses the "Shooting" skill. The key differences are two-fold. First, the bonus needs to incorporate both any bonus/penalty from the trait and any separate bonus/penalty from the weapon itself. Second, we need to handle the case where the character does not possess the needed skill. If not, then the die type will be zero due to the use of the "childfound." transition, which the procedure will bound as if it's a "d4". We must also apply the appropriate "-2" adjustment to the roll for being unskilled. The net result should yield a script that looks similar to the one below.


<pre>
<pre>
<eval value="1" phase="Final" priority="7000" name="Calc wpNetAtk">
<eval index="1" phase="Final" priority="7000" name="Calc wpNetAtk">
   <after name="Calc trtNetRoll"/>
   <after name="Calc trtNetRoll"/>
   <after name="Calc trtFinal"/><![CDATA[
   <after name="Calc trtFinal"/><![CDATA[
Line 291: Line 108:
   var finalbonus as number
   var finalbonus as number
   finalbonus = field[wpBonus].value + field[wpPenalty].value
   finalbonus = field[wpBonus].value + field[wpPenalty].value
   ~apply the appropriate adjustment for the associated skill
   ~apply the appropriate adjustment for the associated skill
   if (hero.childexists[skShooting] = 0) then
   if (hero.childexists[skShooting] = 0) then
Line 297: Line 115:
     finalbonus += hero.child[skShooting].field[trtNetRoll].value
     finalbonus += hero.child[skShooting].field[trtNetRoll].value
     endif
     endif
   ~get the proper die type for the associated skill
   ~get the proper die type for the associated skill
   var finaldie as number
   var finaldie as number
   finaldie = hero.childfound[skShooting].field[trtFinal].value
   finaldie = hero.childfound[skShooting].field[trtFinal].value
   ~generate the appropriate results for display
   ~generate the appropriate results for display
   var finaltext as string
   var finaltext as string
   call FinalRoll
   call FinalRoll
   ~put the final result into the proper field
   ~put the final result into the proper field
   field[wpNetAtk].text = finaltext
   field[wpNetAtk].text = finaltext
Line 317: Line 138:
   var finalbonus as number
   var finalbonus as number
   finalbonus = field[wpBonus].value + field[wpPenalty].value
   finalbonus = field[wpBonus].value + field[wpPenalty].value
   ~apply the appropriate adjustment for the associated skill
   ~apply the appropriate adjustment for the associated skill
   if (hero.childexists[skFighting] = 0) then
   if (hero.childexists[skFighting] = 0) then
Line 323: Line 145:
     finalbonus += hero.child[skFighting].field[trtNetRoll].value
     finalbonus += hero.child[skFighting].field[trtNetRoll].value
     endif
     endif
   ~get the proper die type for the associated skill
   ~get the proper die type for the associated skill
   var finaldie as number
   var finaldie as number
   finaldie = hero.childfound[skFighting].field[trtFinal].value
   finaldie = hero.childfound[skFighting].field[trtFinal].value
   ~generate the appropriate results for display
   ~generate the appropriate results for display
   var finaltext as string
   var finaltext as string
   call FinalRoll
   call FinalRoll
   ~put the final result into the proper field
   ~put the final result into the proper field
   field[wpNetAtk].text = finaltext
   field[wpNetAtk].text = finaltext
Line 363: Line 188:
   <tag group="GearType" tag="Ammo"/>
   <tag group="GearType" tag="Ammo"/>
   </thing>  
   </thing>  
</pre>
===Thrown Weapons===
After doing a bit of testing of our changes, there is something we've overlooked. Savage Worlds has separate skills for "Shooting" and "Throwing". However, we neglected to distinguish that detail when calculating the net attack for ranged weapons.
The first thing we need to do is differentiate between thrown weapons and fired weapons. We can accomplish that by defining a new tag in the "Weapon" tag group in the file "tags.1st". This new tag will identify a weapon that uses the "Throwing" skill, with any weapon lacking the tag using the "Shooting" skill. The new tag definition is as simple as below.
<pre>
<value id="Thrown"/>
</pre>
With the tag in place, we can assign it to the appropriate weapons, such as a throwing knife. We can then modify the Eval script that calculates the "wpNetAtk" field within the "WeapRange" component. The overall logic remains the same, but we need to use the different skill when a weapon is thrown. The revised Eval script is shown below.
<pre>
~start with the bonuses and penalties associated with the weapon
var finalbonus as number
finalbonus = field[wpBonus].value + field[wpPenalty].value
~apply the appropriate adjustment for the associated skill
if (tagis[Weapon.Thrown] <> 0) then
  if (hero.childexists[skThrowing] = 0) then
    finalbonus -= 2
  else
    finalbonus += hero.child[skThrowing].field[trtNetRoll].value
    endif
else
  if (hero.childexists[skShooting] = 0) then
    finalbonus -= 2
  else
    finalbonus += hero.child[skShooting].field[trtNetRoll].value
    endif
  endif
~get the proper die type for the associated skill
var finaldie as number
if (tagis[Weapon.Thrown] <> 0) then
  finaldie = hero.childfound[skThrowing].field[trtFinal].value
else
  finaldie = hero.childfound[skShooting].field[trtFinal].value
  endif
~generate the appropriate results for display
var finaltext as string
call FinalRoll
~put the final result into the proper field
field[wpNetAtk].text = finaltext
</pre>
</pre>

Latest revision as of 02:24, 12 February 2009

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

Overview

We now need to reconcile the remaining facets of weapons, such as the proper calculation of attack values and the handling of ammunition.

Weapon Attack Calculations

Early in the overall development process for these data files, we determined that Savage Worlds calculated the attack for weapons very differently from the default logic provided by the Skeleton files, so we disabled it. Now that we have all the various weapons in place, it's a perfect time to re-visit that and get it working correctly. The "wpNetAtk" field within the "BaseWeapon" component is provided for exactly this purpose. However, that field is value-based and it needs to be text-based so that it can display something like "d8+2". This means our first task is to change the "wpNetAtk" field to be text-based, which we can do by assigning it a "maxlength" attribute of "50". The revised field should look similar to the following.

<field
  id="wpNetAtk"
  name="Net Attack"
  type="derived"
  maxlength="50">
  </field>

One Field to Harness Three

While we're mucking with fields, we might as well address another need. In order to independently synthesize an appropriately adjusted trait roll for the weapon attacks, those scripts will need to access the net bonus/penalty for the particular trait. Currently, that information is tracked across three separate fields, so we need to introduce a new field that calculates the net adjustment and can be readily accessed. We'll call our new field "trtNetRoll", and it must be generated after any penalties are applied due to the load limit, so we'll base our timing on the script we defined earlier that performs that role. In the end, our new field should look a lot like the definition below.

<field
  id="trtNetRoll"
  name="Net Roll Bonus"
  type="derived">
  <calculate name="Calc trtNetRoll" phase="Traits" priority="9000">
    <after name="Apply LoadLimit"/><![CDATA[
    @value = field[trtRoll].value + field[trtProf].value + herofield[acNetPenal].value
    ]]></calculate>
  </field>

Re-Usable Procedure for Display

The logic we'll want to use when synthesizing the net attack for display will be very similar to the logic used to generate the final trait rolls for display within the "trtDisplay" field. Consequently, our next task should be to carve out that logic for re-use by putting it into a procedure. Once it's in a procedure, it can be used from both the current script that synthesizes "trtDisplay" and any other script that synthesizes "wpNetAtk".

Looking closely at the logic, there are two distinct values that must be passed into the procedure, with a string being returned for use by the caller. The two inbound values are the die type for the trait and any bonus/penalty to the roll. Based on these two inputs, our procedure can interpret the values correctly and synthesize the appropriate string for display to the user. The only thing special we need to do is ensure that the die type is properly bounded, just like is already done within the logic that synthesizes "trtDisplay". In the end, we should end up with a procedure that looks very similar to the one provided below.

<procedure id="FinalRoll" scripttype="none"><![CDATA[
  ~declare variables that are used to communicate with our caller
  var finaldie as number
  var finalbonus as number
  var finaltext as string

  ~bound our final die type appropriately
  var final as number
  final = finaldie
  if (final < 2) then
    final = 2
  elseif (final > 6) then
    final = 6
    endif

  ~convert the final value for the trait to the proper die type for display
  var dietype as number
  dietype = final * 2
  finaltext = "d" & dietype

  ~if there are any bonuses or penalties on the roll, append those the final result
  if (finalbonus <> 0) then
    finaltext &= signed(finalbonus)
    endif
  ]]></procedure>

Once the procedure is in place, we need to revise the Eval script that synthesizes the "trtDisplay" field so that it uses the new procedure. The net result should closely parallel the revised script below.

<eval index="4" phase="Render" priority="5000" name="Calc trtDisplay">
  <after name="Calc trtNetRoll"/>
  <after name="Calc trtFinal"/><![CDATA[
  ~if this is a derived trait, our display text is the final value
  if (tagis[component.Derived] <> 0) then
    field[trtDisplay].text = field[trtFinal].value
    done
    endif

  ~calculate the net bonuses and penalties for the roll
  var finalbonus as number
  finalbonus = field[trtNetRoll].value

  ~generate the appropriate results for display
  var finaldie as number
  var finaltext as string
  finaldie = field[trtFinal].value
  call FinalRoll

  ~put the final result into the proper field
  field[trtDisplay].text = finaltext
  ]]></eval>

Calculating the Net Attack

We've now got all of the pieces in place to be able to properly synthesize the "wpNetAtk" field for display to the user. There are two separate scripts in the file "equipment.str" that synthesize the "wpNetAtk" field - one for ranged weapons and another for hand weapons. We need two separate scripts because one is based on the "Shooting" skill, while the other is based on the "Fighting" skill.

We'll start by modifying the Eval script within the "WeapRange" component. The timing does not need to be touched, but we otherwise need to replace the script with revised logic that is similar to the synthesis of "trtDisplay" above and uses the "Shooting" skill. The key differences are two-fold. First, the bonus needs to incorporate both any bonus/penalty from the trait and any separate bonus/penalty from the weapon itself. Second, we need to handle the case where the character does not possess the needed skill. If not, then the die type will be zero due to the use of the "childfound." transition, which the procedure will bound as if it's a "d4". We must also apply the appropriate "-2" adjustment to the roll for being unskilled. The net result should yield a script that looks similar to the one below.

<eval index="1" phase="Final" priority="7000" name="Calc wpNetAtk">
  <after name="Calc trtNetRoll"/>
  <after name="Calc trtFinal"/><![CDATA[
  ~start with the bonuses and penalties associated with the weapon
  var finalbonus as number
  finalbonus = field[wpBonus].value + field[wpPenalty].value

  ~apply the appropriate adjustment for the associated skill
  if (hero.childexists[skShooting] = 0) then
    finalbonus -= 2
  else
    finalbonus += hero.child[skShooting].field[trtNetRoll].value
    endif

  ~get the proper die type for the associated skill
  var finaldie as number
  finaldie = hero.childfound[skShooting].field[trtFinal].value

  ~generate the appropriate results for display
  var finaltext as string
  call FinalRoll

  ~put the final result into the proper field
  field[wpNetAtk].text = finaltext
  ]]></eval>

We can now define a very similar Eval script for the "WeapMelee" component that synthesizes the net attack based on the "Fighting" skill. The existing script can have the comments removed from around it and can then have its contents replaced with the revised logic shown below.

<eval value="2" phase="Final" priority="7000" name="Calc wpNetAtk">
  <after name="Calc trtNetRoll"/>
  <after name="Calc trtFinal"/><![CDATA[
  ~start with the bonuses and penalties associated with the weapon
  var finalbonus as number
  finalbonus = field[wpBonus].value + field[wpPenalty].value

  ~apply the appropriate adjustment for the associated skill
  if (hero.childexists[skFighting] = 0) then
    finalbonus -= 2
  else
    finalbonus += hero.child[skFighting].field[trtNetRoll].value
    endif

  ~get the proper die type for the associated skill
  var finaldie as number
  finaldie = hero.childfound[skFighting].field[trtFinal].value

  ~generate the appropriate results for display
  var finaltext as string
  call FinalRoll

  ~put the final result into the proper field
  field[wpNetAtk].text = finaltext
  ]]></eval> 

Ammunition

The final aspect of weapons that we need to address is ammunition. All ammunition is actually purchased and managed as gear via the Gear tab, but we'll address it as part of the weapons. There really isn't anything to deal with for ammunition, except that we need to add a new tag for the new type of gear. Once that's done, it's just a matter of adding all of the appropriate entries for each type of ammunition. A couple of examples are provided below. You can either add the rest or pull them out of the complete Savage Worlds data files that are provided.

<thing
  id="eqBulletSm"
  name="Bullets (Small)"
  compset="Ammunition"
  lotsize="50"
  stacking="merge"
  description="Includes .22 to .32 caliber weapons">
  <fieldval field="grCost" value=".2"/>
  <fieldval field="grWeight" value=".06"/>
  <tag group="GearType" tag="Ammo"/>
  </thing> 

<thing
  id="eqLsrBatt"
  name="Laser Battery"
  compset="Ammunition"
  lotsize="1"
  stacking="merge"
  description="Provides one full load of shots for the laser pistol, rifle, or MG">
  <fieldval field="grCost" value="25"/>
  <fieldval field="grWeight" value="1"/>
  <usesource id="TimeFuture"/>
  <tag group="GearType" tag="Ammo"/>
  </thing> 

Thrown Weapons

After doing a bit of testing of our changes, there is something we've overlooked. Savage Worlds has separate skills for "Shooting" and "Throwing". However, we neglected to distinguish that detail when calculating the net attack for ranged weapons.

The first thing we need to do is differentiate between thrown weapons and fired weapons. We can accomplish that by defining a new tag in the "Weapon" tag group in the file "tags.1st". This new tag will identify a weapon that uses the "Throwing" skill, with any weapon lacking the tag using the "Shooting" skill. The new tag definition is as simple as below.

<value id="Thrown"/>

With the tag in place, we can assign it to the appropriate weapons, such as a throwing knife. We can then modify the Eval script that calculates the "wpNetAtk" field within the "WeapRange" component. The overall logic remains the same, but we need to use the different skill when a weapon is thrown. The revised Eval script is shown below.

~start with the bonuses and penalties associated with the weapon
var finalbonus as number
finalbonus = field[wpBonus].value + field[wpPenalty].value

~apply the appropriate adjustment for the associated skill
if (tagis[Weapon.Thrown] <> 0) then
  if (hero.childexists[skThrowing] = 0) then
    finalbonus -= 2
  else
    finalbonus += hero.child[skThrowing].field[trtNetRoll].value
    endif
else
  if (hero.childexists[skShooting] = 0) then
    finalbonus -= 2
  else
    finalbonus += hero.child[skShooting].field[trtNetRoll].value
    endif
  endif

~get the proper die type for the associated skill
var finaldie as number
if (tagis[Weapon.Thrown] <> 0) then
  finaldie = hero.childfound[skThrowing].field[trtFinal].value
else
  finaldie = hero.childfound[skShooting].field[trtFinal].value
  endif

~generate the appropriate results for display
var finaltext as string
call FinalRoll

~put the final result into the proper field
field[wpNetAtk].text = finaltext