Injuries (Savage): Difference between revisions
No edit summary |
|||
(One intermediate revision by the same user not shown) | |||
Line 51: | Line 51: | ||
The next step is the creation of the various injury things. In order to keep them all together, we'll create a new data file exclusively for injuries. We'll name the file "thing_injuries.dat" and we can start with any of the current data files, then we can strip out everything but the outer framework so that we have an initial file that we can put to use. | The next step is the creation of the various injury things. In order to keep them all together, we'll create a new data file exclusively for injuries. We'll name the file "thing_injuries.dat" and we can start with any of the current data files, then we can strip out everything but the outer framework so that we have an initial file that we can put to use. | ||
An example of an injury that applies an attribute adjustment is the "Guts | An example of an injury that applies an attribute adjustment is the "Broken Guts" injury, which degrades the character's Agility by one die type. When we apply adjustments to attributes and other traits, we'll modify the "trtBonus" field on the trait. This will keep injury adjustments distinct from normal in-play adjustments. The sample thing below reflects a suitable definition for the "Broken Guts" injury. | ||
<pre> | <pre> | ||
<thing | <thing | ||
id=" | id="injBroken" | ||
name="Guts | name="Broken Guts" | ||
compset="Injury" | compset="Injury" | ||
description="Description goes here"> | description="Description goes here"> | ||
<eval phase=" | <eval index="1" phase="PreTraits" priority="5000"> | ||
<before name="Calc trtFinal"/><![CDATA[ | <before name="Calc trtFinal"/><![CDATA[ | ||
#traitbonus[attrAgi] -= 1 | #traitbonus[attrAgi] -= 1 | ||
Line 66: | Line 66: | ||
</pre> | </pre> | ||
The other interesting type of injury is one that bootstraps an appropriate hindrance. For example, the " | The other interesting type of injury is one that bootstraps an appropriate hindrance. For example, the "Hideous Scar" injury confers the "Ugly" hindrance to the character. When we bootstrap the hindrance, it is critical that we also ensure that the "Helper.Displace" tag is assigned to the hindrance. Doing so guarantees that the hindrance will be properly displaced onto the character (from the advancement gizmo), which allows it to be clearly visible to the user (e.g. shown on the "Edges" tab). This yields a thing that should look like the following. | ||
<pre> | <pre> | ||
<thing | <thing | ||
id=" | id="injScar" | ||
name=" | name="Hideous Scar" | ||
compset="Injury" | compset="Injury" | ||
isunique="yes" | isunique="yes" | ||
Line 81: | Line 81: | ||
</pre> | </pre> | ||
Note that one of the above examples is designated as "unique" and the other is not. Appropriate injuries must be designated as unique to avoid duplicate selection by the user. There are some that have an effect which makes it pointless to select the injury more than once (e.g. "Unmentionables"). These injuries should be marked as unique so that they are not able to be selected multiple times. Other injuries that can occur multiple times can omit this designation. You can now either define the remaining injuries yourself or pull them from the completed Savage Worlds data files. | Note that one of the above examples is designated as "unique" and the other is not. Appropriate injuries must be designated as unique to avoid duplicate selection by the user. There are some that have an effect which makes it pointless to select the injury more than once (e.g. "Unmentionables"). These injuries should be marked as unique so that they are not able to be selected multiple times. Other injuries that can occur multiple times can omit this designation. You can now either define the remaining injuries yourself or pull them from the completed Savage Worlds data files. | ||
===Injury Advancement=== | ===Injury Advancement=== | ||
Line 107: | Line 107: | ||
The one big drawback with this mechanism is that injuries are added just like new skills. This results in the interface presenting injuries for selection as if the user is selecting a new skill. The mechanism looks extremely odd. The solution is to introduce a new type of advancement and adapt the mechanism to work well for injuries as well. For the new advancement type, we'll define a new "Advance.Injury" tag within the file "advancements.core". This way, that we can readily distinguish injury advancements from other advancements. | The one big drawback with this mechanism is that injuries are added just like new skills. This results in the interface presenting injuries for selection as if the user is selecting a new skill. The mechanism looks extremely odd. The solution is to introduce a new type of advancement and adapt the mechanism to work well for injuries as well. For the new advancement type, we'll define a new "Advance.Injury" tag within the file "advancements.core". This way, that we can readily distinguish injury advancements from other advancements. | ||
We can now open the file " | We can now open the file "form_advance.dat" and look into adapting the current advancement mechanism for better use with injuries. Ideally, we could adapt the "advNew" chooser portal for use with injury selection. Unfortunately, the chooser lacks sufficient contextual details to be able to adapt the current portal. This means that we need to duplicate the chooser portal, rename it, and then look to adapt the copy. For simplicity, we'll start by duplicating the "advNew" chooser portal. After revising the chooser for suitability to injuries, we should have a new portal that looks very similar to the following. | ||
<pre> | <pre> | ||
Line 134: | Line 134: | ||
@text = "Choose the New Injury to Add" | @text = "Choose the New Injury to Add" | ||
]]></titlebar> | ]]></titlebar> | ||
<description | <description/> | ||
</chooser_table> | </chooser_table> | ||
</portal> | </portal> | ||
Line 158: | Line 154: | ||
~setup a width that is generally reasonable | ~setup a width that is generally reasonable | ||
width = 475 | width = 475 | ||
~set the fixed dimensions and render the title template | ~set the fixed dimensions and render the title template | ||
template[advTitle].width = width | template[advTitle].width = width | ||
perform template[advTitle].render | perform template[advTitle].render | ||
~position the chooser to add a new advancement | ~position the chooser to add a new advancement | ||
portal[advNew].left = 20 | portal[advNew].left = 20 | ||
portal[advNew].top = template[advTitle].bottom + 30 | portal[advNew].top = template[advTitle].bottom + 30 | ||
portal[advNew].width = 310 | portal[advNew].width = 310 | ||
~position the chooser for injuries in the same place | ~position the chooser for injuries in the same place | ||
portal[advInjury].left = portal[advNew].left | portal[advInjury].left = portal[advNew].left | ||
Line 174: | Line 173: | ||
portal[advBoost].top = portal[advNew].top | portal[advBoost].top = portal[advNew].top | ||
portal[advBoost].width = portal[advNew].width | portal[advBoost].width = portal[advNew].width | ||
~position the static template in the same place (for non-editable items) | ~position the static template in the same place (for non-editable items) | ||
template[advStatic].left = portal[advNew].left | template[advStatic].left = portal[advNew].left | ||
template[advStatic].top = portal[advNew].top | template[advStatic].top = portal[advNew].top | ||
template[advStatic].width = portal[advNew].width | template[advStatic].width = portal[advNew].width | ||
~hide all of the different portals/templates - we'll show one below | ~hide all of the different portals/templates - we'll show one below | ||
template[advStatic].visible = 0 | template[advStatic].visible = 0 | ||
Line 183: | Line 184: | ||
portal[advInjury].visible = 0 | portal[advInjury].visible = 0 | ||
portal[advBoost].visible = 0 | portal[advBoost].visible = 0 | ||
~if this is NOT the newest advancement, show the static template so the user | ~if this is NOT the newest advancement, show the static template so the user | ||
~can't change anything; otherwise, determine which chooser should be shown | ~can't change anything; otherwise, determine which chooser should be shown | ||
Line 194: | Line 196: | ||
portal[advBoost].visible = 1 | portal[advBoost].visible = 1 | ||
endif | endif | ||
~position the domain template | ~position the domain template | ||
template[advDomain].left = portal[advNew].left + 15 | template[advDomain].left = portal[advNew].left + 15 | ||
template[advDomain].top = portal[advNew].bottom + 8 | template[advDomain].top = portal[advNew].bottom + 8 | ||
~position the notes template | ~position the notes template | ||
template[advNotes].left = portal[advNew].left | template[advNotes].left = portal[advNew].left | ||
setup fixed dimensions of our templates | ~setup fixed dimensions of our templates | ||
template[advDomain].width = portal[advNew].width - template[advDomain].left | template[advDomain].width = portal[advNew].width - template[advDomain].left | ||
template[advNotes].width = width - template[advNotes].left * 2 | template[advNotes].width = width - template[advNotes].left * 2 | ||
~render all remaining templates to finalize their dimensions | ~render all remaining templates to finalize their dimensions | ||
perform template[advDomain].render | perform template[advDomain].render | ||
perform template[advNotes].render | perform template[advNotes].render | ||
~determine whether the domain template should be shown | ~determine whether the domain template should be shown | ||
~Note: The final test below ensures that we only let the user change the domain | ~Note: The final test below ensures that we only let the user change the domain | ||
Line 217: | Line 223: | ||
endif | endif | ||
endif | endif | ||
template[advDomain].visible = isdomain | |||
~position the notes at the bottom | ~position the notes at the bottom | ||
template[advNotes].top = template[advDomain].bottom + 20 | if (isdomain <> 0) then | ||
template[advNotes].top = template[advDomain].bottom + 20 | |||
else | |||
template[advNotes].top = portal[advNew].bottom + 20 | |||
endif | |||
~determine our overall height | ~determine our overall height | ||
height = template[advNotes].bottom | height = template[advNotes].bottom | ||
]]></position> | ]]></position> | ||
</layout> | </layout> | ||
</pre> | </pre> |
Latest revision as of 11:19, 11 February 2009
Context: HL Kit … Authoring Examples … Savage Worlds Walk-Through
Overview
Savage Worlds includes the notion of injuries that can be attributed to characters, with corresponding penalties being applied.
Permanent Versus Temporary
There are both temporary and permanent injuries to worry about within Savage Worlds. When a temporary injury is incurred, it can simply be managed on an interim basis by applying a temporary adjustment to the character on the In-Play tab. However, a permanent injury is an entirely different situation, as it has subsequent implications on character advancement. This is because some injuries will confer penalties to attributes, which impacts advancements to skills that are linked to those attributes (i.e. skills may transition from being less than the linked attribute to equal).
The upshot of this is that permanent injuries need to be treated as advancements. That way, any attribute adjustments due to the injuries will properly impact subsequent advancements to skills. There are a number of steps that need to be taken in order to manage permanent injuries via advancements. The following paragraphs will outline each of them.
Injury Component
The first step is to create a new component and component set for handling injuries. We'll call both of them "Injury". In order to incorporate the appropriate handling for advancements, the component set needs to include the "CanAdvance" component. We don't need any special fields or behaviors for injuries, since all of the mechanisms we need are provided by the "CanAdvance" component. However, we define a new component just to be safe, since this will make it easy for us to add new behaviors in the future, if necessary. This yields the following definitions for both the component and component set.
<component id="Injury" name="Injury" autocompset="no"> </component> <compset id="Injury"> <compref component="Injury"/> <compref component="CanAdvance"/> </compset>
Bootstrapping Hindrances
We can now assess exactly what the behaviors should be for each of the different injuries. A couple of the injuries will consist of nothing more than description text. A number of others need to apply adjustments to attributes and/or other traits (e.g. Pace). And the final ones will automatically confer a hindrance upon the character.
Due to the need to confer hindrances via injuries, we must be sure to modify the "Hindrance" component set to also inherit the "CanAdvance" component. This will ensure that hindrances can be bootstrapped by injuries and properly displaced up to the hero. This results in the revised "Hindrance" component set below.
<compset id="Hindrance" forceunique="yes"> <compref component="Hindrance"/> <compref component="Ability"/> <compref component="Domain"/> <compref component="SpecialTab"/> <compref component="CanAdvance"/> </compset>
Add Injuries
The next step is the creation of the various injury things. In order to keep them all together, we'll create a new data file exclusively for injuries. We'll name the file "thing_injuries.dat" and we can start with any of the current data files, then we can strip out everything but the outer framework so that we have an initial file that we can put to use.
An example of an injury that applies an attribute adjustment is the "Broken Guts" injury, which degrades the character's Agility by one die type. When we apply adjustments to attributes and other traits, we'll modify the "trtBonus" field on the trait. This will keep injury adjustments distinct from normal in-play adjustments. The sample thing below reflects a suitable definition for the "Broken Guts" injury.
<thing id="injBroken" name="Broken Guts" compset="Injury" description="Description goes here"> <eval index="1" phase="PreTraits" priority="5000"> <before name="Calc trtFinal"/><![CDATA[ #traitbonus[attrAgi] -= 1 ]]></eval> </thing>
The other interesting type of injury is one that bootstraps an appropriate hindrance. For example, the "Hideous Scar" injury confers the "Ugly" hindrance to the character. When we bootstrap the hindrance, it is critical that we also ensure that the "Helper.Displace" tag is assigned to the hindrance. Doing so guarantees that the hindrance will be properly displaced onto the character (from the advancement gizmo), which allows it to be clearly visible to the user (e.g. shown on the "Edges" tab). This yields a thing that should look like the following.
<thing id="injScar" name="Hideous Scar" compset="Injury" isunique="yes" description="Description goes here"> <bootstrap thing="hinUgly"> <autotag group="Helper" tag="Displace"/> </bootstrap> </thing>
Note that one of the above examples is designated as "unique" and the other is not. Appropriate injuries must be designated as unique to avoid duplicate selection by the user. There are some that have an effect which makes it pointless to select the injury more than once (e.g. "Unmentionables"). These injuries should be marked as unique so that they are not able to be selected multiple times. Other injuries that can occur multiple times can omit this designation. You can now either define the remaining injuries yourself or pull them from the completed Savage Worlds data files.
Injury Advancement
Once the injuries are in place, we can setup the handling for the new advancement thing that will be used to add and select permanent injuries. Our advancement can now be configured to force the user to select a new injury. We set the "cost" of the advancement to zero so that adding a permanent injury does not consume a normal advancement slot. The net result is a thing that looks very similar to the following.
<thing id="advInjury" name="Permanent Injury" compset="Advance" description="Select this advance to apply a permanent injury to the character. The effects of temporary injuries should be applied via temporary adjustments on the In-Play tab."> <fieldval field="advAction" value="Permanent Injury"/> <fieldval field="advDynamic" value="component.Injury"/> <fieldval field="advCost" value="0"/> <tag group="Advance" tag="AddNew"/> <child entity="Advance"> <tag group="Advance" tag="MustChoose"/> </child> </thing>
Revise Interface
The one big drawback with this mechanism is that injuries are added just like new skills. This results in the interface presenting injuries for selection as if the user is selecting a new skill. The mechanism looks extremely odd. The solution is to introduce a new type of advancement and adapt the mechanism to work well for injuries as well. For the new advancement type, we'll define a new "Advance.Injury" tag within the file "advancements.core". This way, that we can readily distinguish injury advancements from other advancements.
We can now open the file "form_advance.dat" and look into adapting the current advancement mechanism for better use with injuries. Ideally, we could adapt the "advNew" chooser portal for use with injury selection. Unfortunately, the chooser lacks sufficient contextual details to be able to adapt the current portal. This means that we need to duplicate the chooser portal, rename it, and then look to adapt the copy. For simplicity, we'll start by duplicating the "advNew" chooser portal. After revising the chooser for suitability to injuries, we should have a new portal that looks very similar to the following.
<portal id="advInjury" style="chsNormal" width="275"> <chooser_table component="none" template="advNew" prereqtarget="hero" candidatepick="advDetails" candidatefield="advTagexpr" descwidth="350"> <denytag usehero="yes" container="IsAdvance" thing="IsAdvance"/> <autotag group="Helper" tag="Displace"/> <autotag group="Advance" tag="Gizmo"/> <chosen><![CDATA[ if (@ispick = 0) then @text = "{text ff0000}Select New Injury" else @text = "New Injury: " & field[name].text endif ]]></chosen> <titlebar><![CDATA[ @text = "Choose the New Injury to Add" ]]></titlebar> <description/> </chooser_table> </portal>
The final thing we need to do is add the new portal to the layout. Once added, we can properly position it within the layout and control its visibility. This can be seen in the revised layout shown below.
<layout id="advance"> <portalref portal="advNew" taborder="20"/> <portalref portal="advInjury" taborder="20"/> <portalref portal="advBoost" taborder="20"/> <templateref template="advTitle" thing="advDetails" taborder="10"/> <templateref template="advStatic" thing="advDetails" taborder="20"/> <templateref template="advDomain" thing="advDetails" taborder="30"/> <templateref template="advNotes" thing="advDetails" taborder="40"/> <position><![CDATA[ ~setup a width that is generally reasonable width = 475 ~set the fixed dimensions and render the title template template[advTitle].width = width perform template[advTitle].render ~position the chooser to add a new advancement portal[advNew].left = 20 portal[advNew].top = template[advTitle].bottom + 30 portal[advNew].width = 310 ~position the chooser for injuries in the same place portal[advInjury].left = portal[advNew].left portal[advInjury].top = portal[advNew].top portal[advInjury].width = portal[advNew].width ~position the chooser for boosting in the same place portal[advBoost].left = portal[advNew].left portal[advBoost].top = portal[advNew].top portal[advBoost].width = portal[advNew].width ~position the static template in the same place (for non-editable items) template[advStatic].left = portal[advNew].left template[advStatic].top = portal[advNew].top template[advStatic].width = portal[advNew].width ~hide all of the different portals/templates - we'll show one below template[advStatic].visible = 0 portal[advNew].visible = 0 portal[advInjury].visible = 0 portal[advBoost].visible = 0 ~if this is NOT the newest advancement, show the static template so the user ~can't change anything; otherwise, determine which chooser should be shown if (container.parent.tagis[Advance.Newest] = 0) then template[advStatic].visible = 1 elseif (container.parent.tagis[Advance.AddNew] <> 0) then portal[advNew].visible = 1 elseif (container.parent.tagis[Advance.Injury] <> 0) then portal[advInjury].visible = 1 else portal[advBoost].visible = 1 endif ~position the domain template template[advDomain].left = portal[advNew].left + 15 template[advDomain].top = portal[advNew].bottom + 8 ~position the notes template template[advNotes].left = portal[advNew].left ~setup fixed dimensions of our templates template[advDomain].width = portal[advNew].width - template[advDomain].left template[advNotes].width = width - template[advNotes].left * 2 ~render all remaining templates to finalize their dimensions perform template[advDomain].render perform template[advNotes].render ~determine whether the domain template should be shown ~Note: The final test below ensures that we only let the user change the domain ~ when editing the newest advancement and not an old one. var isdomain as number isdomain = container.parent.tagis[Advance.AddNew] if (isdomain <> 0) then isdomain = container.firstchild["Advance.Gizmo"].tagis[User.NeedDomain] if (isdomain <> 0) then isdomain = container.parent.tagis[Advance.Newest] endif endif template[advDomain].visible = isdomain ~position the notes at the bottom if (isdomain <> 0) then template[advNotes].top = template[advDomain].bottom + 20 else template[advNotes].top = portal[advNew].bottom + 20 endif ~determine our overall height height = template[advNotes].bottom ]]></position> </layout>