• Please note: In an effort to ensure that all of our users feel welcome on our forums, we’ve updated our forum rules. You can review the updated rules here: http://forums.wolflair.com/showthread.php?t=5528.

    If a fellow Community member is not following the forum rules, please report the post by clicking the Report button (the red yield sign on the left) located on every post. This will notify the moderators directly. If you have any questions about these new rules, please contact support@wolflair.com.

    - The Lone Wolf Development Team

Detecting bootstraps associated with a choice.

Daphne Pfister

Well-known member
Detecting bootstraps associated with a choice / Polymorph Spells

I'm attempting to implement adjustments for the various shape change spells and have size modifiers and size adjustments working correctly based on the chosen race. But I don't see how I can detect what bootstraps a choice provides so that I can add the relevant details.

Currently what I have is for example a: "Alter Self" adjustment which bootstraps an "Alter Self" feat since I couldn't find a way from within Alter Self to get a menu of races.

From the "Alter Self" feat I have usrCandid1 set to:
Code:
thingid.iidNone | ( HasType.tpHumanoid & ( RaceSize.Small11 | RaceSize.Medium0 ) )

And I have a script:
Code:
doneif (field[usrChosen1].ischosen = 0)

if (field[usrChosen1].chosen.tagis[RaceSize.Medium0] <> 0) then
  herofield[tSize].value = 0
  hero.child[aSTR].field[Bonus].value += 2
endif

if (field[usrChosen1].chosen.tagis[RaceSize.Small11] <> 0) then
  herofield[tSize].value = -1
  hero.child[aDEX].field[Bonus].value += 2
endif

I'm trying to figure out how to add a test to see if field[usrChosen1].chosen has raDarkVis as one of it's bootstraps.

I'm intending to put together similar adjustment / fake feat combinations for the rest of the shape change adjustments to replace my collection of individual adjust based on each option. Dragons and Elementals should be the easiest since they specifically list the abilities given and I can just hard code those choices in. But alter-self, beast form, giant form, plant form will all need to make decisions based on the bootstraps on the chosen race.
 
Last edited:
Looks like I've found a way to find the bootstraps though not sure if it's the most efficient yet.

Code:
foreach bootstrap in field[usrChosen1].chosen where "thingid.raDarkVis"
  debug "id: " & eachthing.idstring
nexteach

Edit: Oh there is an isbootstrap[ thingid ] thing that works.

Code:
if ( field[usrChosen1].chosen.isbootstrap[raDarkVis] <> 0 ) then
  debug "has dark vision"
endif
 
Last edited:
I have not actually tried that yet to be able to confirm it will always work.

Just to let you know I know Mathias has a Thing he has plans to make to allow for this additional functionality. Its the reason I have not done allot of the Polymorph spells as was waiting until he had this new feature in HL. Just an FYI is all.
 
I have not actually tried that yet to be able to confirm it will always work.

I've done a quick spot check of at least the valid races for Alter Self and seems to mostly work so far. Though some powers might not be as easy to test for. And I'm not sure what would happen if the bootstrap for a race had a condition. Now I just have to figure out how to trigger it to add the bootstraps I need, since I doubt I can use that directly in a containerreq.

Just to let you know I know Mathias has a Thing he has plans to make to allow for this additional functionality. Its the reason I have not done allot of the Polymorph spells as was waiting until he had this new feature in HL. Just an FYI is all.

That will be awesome. Unfortunately I am juggling a lot of forms for my character at the moment and there are so many adjustments needed for each shapechange that I was ended up spending a lot of time just keeping track of all the effects, so decided to try anyways. I'd already had a bunch ( but not all ) of the shape change spells as individual adjustments, but that's a lot of work too keep the right adjustments on the characters, as well as exactly what races are allowed.

BTW I really appreciate all the adjustments you contributed. I was able to get rid of a bunch of my user files with the last upgrade.
 
One place it won't work is for races that gain Darkvision because they're a specific type, rather than because it's directly added by their race.
 
One place it won't work is for races that gain Darkvision because they're a specific type, rather than because it's directly added by their race.

I've added detection for Subtypes that seems to work. I use the custom poly tags to bootstrap Dark Vision and Low Light Vision.

Code:
doneif (field[usrChosen1].ischosen = 0)

if (field[usrChosen1].chosen.tagis[RaceSize.Medium0] <> 0) then
  herofield[tSize].value = 0
  hero.child[aSTR].field[Bonus].value += 2
endif

if (field[usrChosen1].chosen.tagis[RaceSize.Small11] <> 0) then
  herofield[tSize].value = -1
  hero.child[aDEX].field[Bonus].value += 2
endif

foreach bootstrap in field[usrChosen1].chosen from Subtype
  debug "id: " & eachthing.idstring
  if ( eachthing.isbootstrap[raDarkVis] <> 0 ) then
    debug "Subtype: Darkvision"
    perform hero.assign[Custom.PolyDrkVis]
  endif
  if ( eachthing.isbootstrap[raLowLight] <> 0 ) then
    debug "Subtype: Low Light Vision"
    perform hero.assign[Custom.PolyLowLt]
  endif
nexteach

if ( field[usrChosen1].chosen.isbootstrap[raDarkVis] <> 0 ) then
  debug "Race: Darkvision"
  perform hero.assign[Custom.PolyDrkVis]
endif

if ( field[usrChosen1].chosen.isbootstrap[raLowLight] <> 0 ) then
  debug "Race: Low Light Vision"
  perform hero.assign[Custom.PolyLowLt]
endif

Now I just need to figure out how to handle races with Darkvision but less than 60 feet, and scent and swim and I'll be finished with Alter Self, then I'll start in on Beast Shape.
 
I have the first pass of Beast Form I done except for the same limits that I have with abilities being under the maximum range of the polymorph spells. I'll figure out how to share user files when I'm finished. But off to my game now.
 
Alter Self

Spell: Alter Self

Here's the complete user file contents for what I have for Alter Self.

Limitations:
  • Does not handle race abilities that are less than the maximum provided by the spell.
  • Implemented by adding a feat because the infrastructure to add a race menu to a Spell Adjustment has not yet been implemented. Hopefully this will be easy to convert to the proper approach once that is added.
  • Does not yet have a way to restrict the race choices to races that provide a bootstrap which would be useful for users of the spell.
  • Does not update the hero race or type description to reflect the polymorph.
  • I was lazy and haven't yet added any guards to the feat to prevent them from being picked directly as a feat.
  • I probably should figure out if I can add macros or procedures to simplify the repeated cut-&-paste code.
  • Code is probably not as fast as it could be as I really should fold the bodies of the for loops together. But I keep each of the racial ability add checks as a separate script to make it easier for me to just cut and paste the entire eval blocks.

Code:
<?xml version="1.0" encoding="ISO-8859-1"?>
<document signature="Hero Lab Data">
  <thing id="fAltSelf" name="Alter Self" description="Does not check if the target form&apos;s granted abilities are less than the maximum allowed by the spell. Does not set Race or RaceType." compset="Feat" uniqueness="useronce">
    <fieldval field="shortname" value="Alter Self"/>
    <arrayval field="usrArray" index="0" value="Any Size"/>
    <arrayval field="usrArray" index="1" value="Small"/>
    <arrayval field="usrArray" index="2" value="Medium"/>
    <tag group="Custom" tag="PolyDrkVis"/>
    <tag group="Custom" tag="PolyLowLt"/>
    <tag group="Custom" tag="PolyScent"/>
    <tag group="Custom" tag="PolySwim"/>
    <tag group="SpInfo" tag="spBeasSha3"/>
    <tag group="fCategory" tag="Special"/>
    <tag group="ChooseSrc1" tag="Thing"/>
    <tag group="Helper" tag="UserAdjust"/>
    <bootstrap thing="raDarkVis">
      <containerreq phase="First" priority="2000">hero#Custom.PolyDrkVis</containerreq>
      <autotag group="Value" tag="60"/>
      </bootstrap>
    <bootstrap thing="raLowLight">
      <containerreq phase="First" priority="2000">hero#Custom.PolyLowLt</containerreq>
      </bootstrap>
    <bootstrap thing="xScent">
      <containerreq phase="First" priority="2000">hero#Custom.PolyScent</containerreq>
      </bootstrap>
    <bootstrap thing="xSwim">
      <containerreq phase="First" priority="2000">hero#Custom.PolySwim</containerreq>
      <autotag group="Value" tag="30"/>
      </bootstrap>
    <eval phase="First" priority="1000"><![CDATA[var sizelim as string

if ( compare(field[usrSelect].text, "Small") = 0 ) then
  sizelim = "RaceSize.Small11"
elseif ( compare(field[usrSelect].text, "Medium") = 0 ) then
  sizelim = "RaceSize.Medium0"
else
  sizelim = "( RaceSize.Small11 | RaceSize.Medium0 )"
endif

field[usrCandid1].text = "thingid.iidNone | ( component.BaseRace & HasType.tpHumanoid & " & sizelim & " )"

~foreach thing in BaseRace where field[usrCandid1].text
~  debug eachthing.idstring
~nexteach]]></eval>
    <eval phase="First" priority="1100" index="2"><![CDATA[doneif (field[usrChosen1].ischosen = 0)

if (field[usrChosen1].chosen.tagis[RaceSize.Medium0] <> 0) then
  herofield[tSize].value = 0
  hero.child[aSTR].field[Bonus].value += 2
elseif (field[usrChosen1].chosen.tagis[RaceSize.Small11] <> 0) then
  herofield[tSize].value = -1
  hero.child[aDEX].field[Bonus].value += 2
endif]]></eval>
    <eval phase="First" priority="1100" index="3"><![CDATA[doneif (field[usrChosen1].ischosen = 0)

if ( field[usrChosen1].chosen.isbootstrap[raDarkVis] <> 0 ) then
  perform hero.assign[Custom.PolyDrkVis]
  done
endif

if ( field[usrChosen1].chosen.isbootstrap[raDarksens] <> 0 ) then
  perform hero.assign[Custom.PolyDrkVis]
  done
endif

if ( field[usrChosen1].chosen.isbootstrap[raSeeDark] <> 0 ) then
  perform hero.assign[Custom.PolyDrkVis]
  done
endif

if ( field[usrChosen1].chosen.isbootstrap[xPFSeeDark] <> 0 ) then
  perform hero.assign[Custom.PolyDrkVis]
  done
endif

foreach bootstrap in field[usrChosen1].chosen from Subtype
  if ( eachthing.isbootstrap[raDarkVis] <> 0 ) then
    perform hero.assign[Custom.PolyDrkVis]
    done
  endif

  if ( eachthing.isbootstrap[raDarksens] <> 0 ) then
    perform hero.assign[Custom.PolyDrkVis]
    done
  endif

  if ( eachthing.isbootstrap[raSeeDark] <> 0 ) then
    perform hero.assign[Custom.PolyDrkVis]
    done
  endif

  if ( eachthing.isbootstrap[xPFSeeDark] <> 0 ) then
    perform hero.assign[Custom.PolyDrkVis]
    done
  endif
nexteach]]></eval>
    <eval phase="First" priority="1100" index="4"><![CDATA[doneif (field[usrChosen1].ischosen = 0)

if ( field[usrChosen1].chosen.isbootstrap[raLowLight] <> 0 ) then
  perform hero.assign[Custom.PolyLowLt]
  done
endif

foreach bootstrap in field[usrChosen1].chosen from Subtype
  if ( eachthing.isbootstrap[raLowLight] <> 0 ) then
    perform hero.assign[Custom.PolyLowLt]
    done
  endif
nexteach]]></eval>
    <eval phase="First" priority="1100" index="5"><![CDATA[doneif (field[usrChosen1].ischosen = 0)

if ( field[usrChosen1].chosen.isbootstrap[xScent] <> 0 ) then
  perform hero.assign[Custom.PolyScent]
  done
endif

foreach bootstrap in field[usrChosen1].chosen from Subtype
  if ( eachthing.isbootstrap[xScent] <> 0 ) then
    perform hero.assign[Custom.PolyScent]
    done
  endif
nexteach]]></eval>
    <eval phase="First" priority="1100" index="6"><![CDATA[doneif (field[usrChosen1].ischosen = 0)

if ( field[usrChosen1].chosen.isbootstrap[xSwim] <> 0 ) then
  perform hero.assign[Custom.PolySwim]
  done
endif

foreach bootstrap in field[usrChosen1].chosen from Subtype
  if ( eachthing.isbootstrap[xSwim] <> 0 ) then
    perform hero.assign[Custom.PolySwim]
    done
  endif
nexteach]]></eval>
    </thing>
  <thing id="pAltSelf" name="Alter Self" description=""When you cast this spell, you can assume the form of any Small or Medium creature of the humanoid type. If the form you assume has any of the following abilities, you gain the listed ability: darkvision 60 feet, low-light vision, scent, and swim 30 feet.\n\n{b}Small creature{/b}: If the form you take is that of a Small humanoid, you gain a +2 size bonus to your Dexterity.\n\n{b}Medium creature{/b}: If the form you take is that of a Medium humanoid, you gain a +2 size bonus to your Strength." compset="InPlay">
    <fieldval field="pDuration" value="1 min. / level"/>
    <tag group="Helper" tag="AdjSpell"/>
    <tag group="Helper" tag="NoIncr"/>
    <bootstrap thing="fAltSelf">
      <containerreq phase="First" priority="1000"><![CDATA[fieldval:pIsOn <> 0]]></containerreq>
      </bootstrap>
    </thing>
  </document>
 
Beast Shape I

Spell: Beast Shape I

Same limitations as above. Note I also only use a quick scan for alternative ability names for equivalent abilities.

Code:
<?xml version="1.0" encoding="ISO-8859-1"?>
<document signature="Hero Lab Data">
  <thing id="fBstShape1" name="Beast Shape I" description="Does not check if the target form&apos;s granted abilities are less than the maximum allowed by the spell. Does not set Race or RaceType." compset="Feat" uniqueness="useronce">
    <fieldval field="shortname" value="Beast Shape I"/>
    <arrayval field="usrArray" index="0" value="Any Size"/>
    <arrayval field="usrArray" index="1" value="Small"/>
    <arrayval field="usrArray" index="2" value="Medium"/>
    <tag group="Custom" tag="PolyClimb"/>
    <tag group="Custom" tag="PolyDrkVis"/>
    <tag group="Custom" tag="PolyFly"/>
    <tag group="Custom" tag="PolyLowLt"/>
    <tag group="Custom" tag="PolyScent"/>
    <tag group="Custom" tag="PolySwim"/>
    <tag group="SpInfo" tag="spBeasSha3"/>
    <tag group="fCategory" tag="Special"/>
    <tag group="ChooseSrc1" tag="Thing"/>
    <tag group="Helper" tag="UserAdjust"/>
    <bootstrap thing="xClimb">
      <containerreq phase="First" priority="2000">hero#Custom.PolyClimb</containerreq>
      <autotag group="Value" tag="30"/>
      </bootstrap>
    <bootstrap thing="raDarkVis">
      <containerreq phase="First" priority="2000">hero#Custom.PolyDrkVis</containerreq>
      <autotag group="Value" tag="60"/>
      </bootstrap>
    <bootstrap thing="xFly">
      <containerreq phase="First" priority="2000">hero#Custom.PolyFly</containerreq>
      <autotag group="Value" tag="30"/>
      <autotag group="Maneuver" tag="Average"/>
      </bootstrap>
    <bootstrap thing="raLowLight">
      <containerreq phase="First" priority="2000">hero#Custom.PolyLowLt</containerreq>
      </bootstrap>
    <bootstrap thing="xScent">
      <containerreq phase="First" priority="2000">hero#Custom.PolyScent</containerreq>
      </bootstrap>
    <bootstrap thing="xSwim">
      <containerreq phase="First" priority="2000">hero#Custom.PolySwim</containerreq>
      <autotag group="Value" tag="30"/>
      </bootstrap>
    <eval phase="First" priority="1000"><![CDATA[var sizelim as string

if ( compare(field[usrSelect].text, "Small") = 0 ) then
  sizelim = "RaceSize.Small11"
elseif ( compare(field[usrSelect].text, "Medium") = 0 ) then
  sizelim = "RaceSize.Medium0"
else
  sizelim = "( RaceSize.Small11 | RaceSize.Medium0 )"
endif

field[usrCandid1].text = "thingid.iidNone | ( component.BaseRace & HasType.tpAnimal & " & sizelim & " )"

~foreach thing in BaseRace where field[usrCandid1].text
~  debug eachthing.idstring
~nexteach]]></eval>
    <eval phase="First" priority="1100" index="2"><![CDATA[doneif (field[usrChosen1].ischosen = 0)

if (field[usrChosen1].chosen.tagis[RaceSize.Medium0] <> 0) then
  herofield[tSize].value = 0
  hero.child[aSTR].field[Bonus].value += 2
  #enhancementbonus[hero.child[mNatural], 2]
elseif (field[usrChosen1].chosen.tagis[RaceSize.Small11] <> 0) then
  herofield[tSize].value = -1
  hero.child[aDEX].field[Bonus].value += 2
  #enhancementbonus[hero.child[mNatural], 1]
endif]]></eval>
    <eval phase="First" priority="1100" index="3"><![CDATA[doneif (field[usrChosen1].ischosen = 0)

if ( field[usrChosen1].chosen.isbootstrap[xClimb] <> 0 ) then
  perform hero.assign[Custom.PolyClimb]
  done
endif

foreach bootstrap in field[usrChosen1].chosen from Subtype
  if ( eachthing.isbootstrap[xClimb] <> 0 ) then
    perform hero.assign[Custom.PolyClimb]
    done
  endif
nexteach]]></eval>
    <eval phase="First" priority="1100" index="4"><![CDATA[doneif (field[usrChosen1].ischosen = 0)

if ( field[usrChosen1].chosen.isbootstrap[raDarkVis] <> 0 ) then
  perform hero.assign[Custom.PolyDrkVis]
  done
endif

if ( field[usrChosen1].chosen.isbootstrap[raDarksens] <> 0 ) then
  perform hero.assign[Custom.PolyDrkVis]
  done
endif

if ( field[usrChosen1].chosen.isbootstrap[raSeeDark] <> 0 ) then
  perform hero.assign[Custom.PolyDrkVis]
  done
endif

if ( field[usrChosen1].chosen.isbootstrap[xPFSeeDark] <> 0 ) then
  perform hero.assign[Custom.PolyDrkVis]
  done
endif

foreach bootstrap in field[usrChosen1].chosen from Subtype
  if ( eachthing.isbootstrap[raDarkVis] <> 0 ) then
    perform hero.assign[Custom.PolyDrkVis]
    done
  endif

  if ( eachthing.isbootstrap[raDarksens] <> 0 ) then
    perform hero.assign[Custom.PolyDrkVis]
    done
  endif

  if ( eachthing.isbootstrap[raSeeDark] <> 0 ) then
    perform hero.assign[Custom.PolyDrkVis]
    done
  endif

  if ( eachthing.isbootstrap[xPFSeeDark] <> 0 ) then
    perform hero.assign[Custom.PolyDrkVis]
    done
  endif
nexteach]]></eval>
    <eval phase="First" priority="1100" index="5"><![CDATA[doneif (field[usrChosen1].ischosen = 0)

if ( field[usrChosen1].chosen.isbootstrap[xFly] <> 0 ) then
  perform hero.assign[Custom.PolyFly]
  done
endif

foreach bootstrap in field[usrChosen1].chosen from Subtype
  if ( eachthing.isbootstrap[xFly] <> 0 ) then
    perform hero.assign[Custom.PolyFly]
    done
  endif
nexteach]]></eval>
    <eval phase="First" priority="1100" index="6"><![CDATA[doneif (field[usrChosen1].ischosen = 0)

if ( field[usrChosen1].chosen.isbootstrap[raLowLight] <> 0 ) then
  perform hero.assign[Custom.PolyLowLt]
  done
endif

foreach bootstrap in field[usrChosen1].chosen from Subtype
  if ( eachthing.isbootstrap[raLowLight] <> 0 ) then
    perform hero.assign[Custom.PolyLowLt]
    done
  endif
nexteach]]></eval>
    <eval phase="First" priority="1100" index="7"><![CDATA[doneif (field[usrChosen1].ischosen = 0)

if ( field[usrChosen1].chosen.isbootstrap[xScent] <> 0 ) then
  perform hero.assign[Custom.PolyScent]
  done
endif

foreach bootstrap in field[usrChosen1].chosen from Subtype
  if ( eachthing.isbootstrap[xScent] <> 0 ) then
    perform hero.assign[Custom.PolyScent]
    done
  endif
nexteach]]></eval>
    <eval phase="First" priority="1100" index="8"><![CDATA[doneif (field[usrChosen1].ischosen = 0)

if ( field[usrChosen1].chosen.isbootstrap[xSwim] <> 0 ) then
  perform hero.assign[Custom.PolySwim]
  done
endif

foreach bootstrap in field[usrChosen1].chosen from Subtype
  if ( eachthing.isbootstrap[xSwim] <> 0 ) then
    perform hero.assign[Custom.PolySwim]
    done
  endif
nexteach]]></eval>
    </thing>
  <thing id="pBstShape1" name="Beast Shape I" description="When you cast this spell, you can assume the form of any Small or Medium creature of the animal type. If the form you assume has any of the following abilities, you gain the listed ability: climb 30 feet, fly 30 feet (average maneuverability), swim 30 feet, darkvision 60 feet, low-light vision, and scent.\n\n{b}Small animal{/b}: If the form you take is that of a Small animal, you gain a +2 size bonus to your Dexterity and a +1 natural armor bonus.\n\n{b}Medium animal{/b}: If the form you take is that of a Medium animal, you gain a +2 size bonus to your Strength and a +2 natural armor bonus." compset="InPlay">
    <fieldval field="pDuration" value="1 min. / level"/>
    <tag group="Helper" tag="AdjSpell"/>
    <tag group="Helper" tag="NoIncr"/>
    <bootstrap thing="fBstShape1">
      <containerreq phase="First" priority="1000"><![CDATA[fieldval:pIsOn <> 0]]></containerreq>
      </bootstrap>
    </thing>
  </document>
 
detecting autotags

I'm switching over to a procedure to detect the racial abilities, but trying to figure out how to get the values of the auto tags assigned to the abilities for movement bootstraps.

My procedure is:
Code:
  <procedure id="hasRAMove" scripttype="eval"><![CDATA[
  var raceChoice as string
  var raceAbil as string
  var wasFound as number
  var subRace as string

  doneif ( wasFound <> 0 )
  doneif ( compare( raceChoice, "" ) = 0 )
  doneif ( compare( raceAbil, "" ) = 0 )

  debug "Call: "& raceChoice & "," & raceAbil
  foreach thing in BaseRace where "thingid." & raceChoice
    ~debug eachthing.idstring
    foreach bootstrap in eachthing where raceAbil
      debug "A " & " " & raceChoice & " " & eachthing.idstring & " " & eachthing.tagmax[Value.?] & " ft"
      wasFound += 1
      ~done
    nexteach

    foreach bootstrap in eachthing from Subtype
      subRace = eachthing.idstring
      ~debug subRace
      foreach bootstrap in eachthing where raceAbil
        debug "B " & subRace & " " & raceChoice & " " & eachthing.idstring & " " & eachthing.tagmax[Value.?] & " ft"
        wasFound += 1
        ~done
      nexteach
    nexteach
  nexteach]]></procedure>

Example of how it might be used:

Code:
...

var raceChoice as string
var raceAbil as string
var wasFound as number

raceChoice = "rMerfolk" ~ e.g. field[usrChosen1].chosen.idstring
raceAbil = "thingid.xSwim"
wasFound = 0
call hasRAMove
if ( wasFound <> 0 ) then
  perform hero.assign[Custom.PolySwim]
endif

...

My attempt at using eachthing.tagmax[Value.?] didn't work, nor did eachthing.field[abValue].
 
Back
Top