Okay, looks like the quickadd mechanism that we use isn't in any of the documentation, so here's the relevant scripts in Pathfinder;
On the hero:
Code:
<eval value="31" phase="PostLevel" priority="149" name="Prepare First Copy"><![CDATA[
~This eval script is meant to foreach through all the class specials
~and mark each as a FirstCopy or not. We do this with a foreach rather
~than a component script so that we can proceed from the lower level
~copies to the higher level copies, ensuring that Helper.FirstCopy ends
~up on the lowest level copy that is not disabled or replaced.
foreach pick in hero from BaseClSpec where "!Helper.SpcDisable & !Helper.SpcReplace" sortas ClassSpec
~For things which are multiple copies, each independant, all of them are "first" copies.
if (eachpick.tagis[Helper.MultiCopy] <> 0) then
perform eachpick.assign[Helper.FirstCopy]
else
~add the first active thing we found to our quick list - if quickadd
~returns nonzero, we were the first version, so add the "first copy" tag
~to ourselves.
~NOTE: at this point, we'll assume that the first copy is the only copy -
~the OnlyCopy tag is deleted in the "Determine First Copy" script if
~there's more than one.
if (eachpick.quickadd <> 0) then
perform eachpick.assign[Helper.FirstCopy]
perform eachpick.assign[Helper.OnlyCopy]
perform eachpick.quickadd
endif
endif
nexteach
~The next step is going to take place in the BaseClSpec component script.
]]></eval>
On a component that's added to everything that needs FirstCopy mechanics:
Code:
<!-- Note that the first part of this, "Prepare First Copy" has been moved
to a script on the actor, and now uses a foreach instead of a component
script on this component. This is because a foreach can use a SortAs to
proceed up the copies of class specials, assigning Helper.FirstCopy to the
lowest level copy of a class special which isn't disabled or replaced. The
previous implementation would assign Helper.FirstCopy to the first copy
of a multi-bootstrapped class special to run the component script (which
was random since they all had the same priority).
That would lead to a bug where crossblooded sorcerers could not target a
class special to be re-enabled even though they were high enough level to
do so (because Helper.FirstCopy had been assigned to the 2nd or 3rd copy
of the class ability).
The gap between the actor script foreach and this step has also been
widened slightly, so that certain targetted scripts (like those of the
crossblooded sorcerer) can occur between them.
-->
<eval index="3" phase="PostLevel" priority="155" name="Determine First Copy"><![CDATA[
doneif (tagis[Helper.FirstCopy] <> 0)
~if we're not the first copy of a special ability, we need to set up a
~redirection to the actual first copy. That means whenever another pick
~does a "hero.child[x]" to find pick x, they always arrive at the first
~copy. This allows the first copy to be determined at every evaluation,
~and the first copy is then the one used to display the totals for the
~ability, even if it's added in multiple places (e.g. sneak attack, which
~can be added by multiple classes). The first copy is the one in the
~quickfind list, so retrieve it.
perform quickfind.setfocus
~if we found a copy to set our focus to, we're a secondary copy of this
~ability, delete the Helper.OnlyCopy tag from the first (primary) copy.
~That means the Helper.OnlyCopy tag will only be left on those picks that
~are the only copy of their things.
if (state.isfocus <> 0) then
perform focus.redirect
perform assign[Helper.SpecUp]
perform focus.delete[Helper.OnlyCopy]
endif
]]></eval>
<eval index="4" phase="PostLevel" priority="200" name="Calc xAllLev and xMaxLev"><![CDATA[
~we only need to run this if we're not the only copy
~if we aren't the only copy, we need to search the rest of our copies and get information
if (tagis[Helper.OnlyCopy] = 0) then
~only run these for the first copy
if (tagis[Helper.FirstCopy] <> 0) then
var searchexpr as string
searchexpr = "thingid." & this.idstring
var index as number
index = 1
var runonce as number
foreach pick in hero from BaseClSpec where searchexpr sortas ClSpecSrch
~generate an index value
~if our SpecSource tags are different from the last thing we checked, reset the counter
if (eachpick.intersect[SpecSource,TempSource,all] = 0) then
perform delete[TempSource.?]
perform eachpick.pulltags[SpecSource.?,TempSource]
index = 1
~once for each class, we want to set our xalllev value, so if we
~find that we're on a new class, we reset that test, so that we'll
~get the new value for the new class
runonce = 0
endif
~we only calculate the xAllLev of the FirstCopy one time, based on
~the first non-disabled copy we find.
if (runonce = 0) then
~some things should only be done for active copies
if (eachpick.tagis[Helper.SpcDisable] = 0) then
~we found a copy, so we won't be calculating this again.
runonce = 1
~we use the copy we found to calculate our xAllLev and xMaxLev
~values.
if (eachpick.tagis[Helper.FirstCopy] <> 0) then
field[xAllLev].value += eachpick.field[xTotalLev].value
field[xMaxLev].value = maximum(field[xMaxLev].value, eachpick.field[xTotalLev].value)
else
field[xAllLev].value += eachpick.field[xTotalLev].value + eachpick.field[xEffectLev].value
field[xMaxLev].value = maximum(field[xMaxLev].value, eachpick.field[xTotalLev].value + eachpick.field[xEffectLev].value)
endif
endif
endif
~assign this thing the current index value, then increment the index for the next thing
eachpick.field[xIndex].value = index
index += 1
nexteach
else
field[xCount].value += 1
endif
else
~if we are the only copy, our xAllLev and xMaxLev fields are simply our own xTotalLev
~and xIndex and xCount = 1
field[xAllLev].value = field[xTotalLev].value
field[xMaxLev].value = field[xTotalLev].value
field[xIndex].value = 1
field[xCount].value = 1
endif
~The new UseTotLev tag means we should use our total character level
if (tagis[Helper.UseTotLev] <> 0) then
field[xAllLev].value = maximum(field[xAllLev].value,#totallevelcount[])
field[xMaxLev].value = maximum(field[xMaxLev].value,#totallevelcount[])
endif
perform delete[TempSource.?]
]]></eval>
<eval index="5" phase="PostLevel" priority="250" name="Calc xCount, copy xAllLev and xMaxLev"><![CDATA[
~we only need to run this if we're not the only copy
~if we aren't the only copy, we need to search the rest of our copies and get information
doneif (tagis[Helper.OnlyCopy] <> 0)
var index as number
var source as string
~only run these if we're the first copy
if (tagis[Helper.FirstCopy] <> 0) then
var searchexpr as string
searchexpr = "thingid." & this.idstring
foreach pick in hero from BaseClSpec where searchexpr sortas ClSpecSrch
~set the xAllLev and xMaxLev fields of anything we come across (other than ourself)
if (eachpick.tagis[Helper.FirstCopy] = 0) then
eachpick.field[xAllLev].value = field[xAllLev].value
eachpick.field[xMaxLev].value = field[xMaxLev].value
endif
~some things should only be done for active copies
if (eachpick.tagis[Helper.SpcDisable] = 0) then
~if the special has reached the appropriate level, add it to our count
if (eachpick.tagis[Helper.UseOwnLev] <> 0) then
if (eachpick.tagvalue[ClSpecWhen.?] <= eachpick.field[xTotalLev].value) then
field[xCount].value += 1
~any AddReq tags that have been applied to an active copy apply to the FirstCopy, too
perform eachpick.pulltags[AddReq.?]
endif
else
~generate an index value
~if our SpecSource tags are different from the last thing we checked, reset the counter
if (eachpick.intersect[SpecSource,TempSource,all] = 0) then
perform delete[TempSource.?]
perform eachpick.pulltags[SpecSource.?,TempSource]
index = 1
endif
if (eachpick.tagvalue[ClSpecWhen.?] <= eachpick.field[xAllLev].value) then
field[xCount].value = maximum(field[xCount].value, index)
index += 1
~any AddReq tags that have been applied to an active copy apply to the FirstCopy, too
perform eachpick.pulltags[AddReq.?]
endif
endif
endif
nexteach
endif
perform delete[TempSource.?]
]]></eval>