Yep - even if they're unique, you'll need to use useronce uniqueness to make this work - then, yeah, shadow them to the hero, and then you need to set up scripts that can make one copy the main copy, and add together each one's bonuses to get a final value that's from all your lifepaths.
Here are the relevant scripts in SR5, although you'll have to wade through a lot of code relating to skill groups and skillsofts that are shadowrun-specific, and probably not something you have to worry about. So you'll want to pull all that out. I'm afraid I don't remember right now what caused us to have to split "Shadowed skills find their normal versions" into two scripts, and whether you'll need to retain that.
Code:
<eval index="3" phase="Initialize" priority="29999" name="Determine FirstCopy"><![CDATA[
~if we're not user once unique, then every copy is the FirstCopy
if (tagis[User.Unique] = 0) then
perform assign[Helper.FirstCopy]
done
endif
if (quickadd <> 0) then
perform assign[Helper.FirstCopy]
endif
]]></eval>
<eval index="4" phase="Initialize" priority="30000" name="Not FirstCopy"><![CDATA[
if (tagis[Helper.FirstCopy] = 0) then
perform quickfind.redirect
perform assign[Hide.Skill]
endif
]]></eval>
Code:
<eval index="8" phase="Traits" priority="8500" name="Shadowed skills find their normal versions">
<before name="Calc trtFinal Final"/>
<after name="Calc grRating #3"/><![CDATA[
~this only applies to shadowed skills
~those will be the ones added as skillsofts
doneif (shadowed + tagexpr[SkillHelp.Autosoft | SkillHelp.Personafix] = 0)
~exclude new skill advancements
doneif (tagis[Advance.Gizmo] <> 0)
~if we have a root pick, and our root pick is an advancement, stop now
if (isroot <> 0) then
doneif (root.tagis[Advance.Gizmo] <> 0)
~if that root pick has a root, and that's an advancement, stop now
~(this happens when Drake is added as an advancement - the Elemental
~Attack skill is two bootstraps down from the actual pick)
if (root.isroot <> 0) then
doneif (root.root.tagis[Advance.Gizmo] <> 0)
endif
endif
~handling for if we're added by a life module
if (parent.tagis[component.LifeModule] <> 0) then
~no special handling needed in this case
~if we weren't added by a life module, and we're a skill group, stop now
elseif (tagis[component.SkillGroup] <> 0) then
done
~if we're a skillsoft/autosoft, our rating is our parent's rating
elseif (parent.tagis[component.Gear] <> 0) then
~our replacement value is the rating of the program that added us
field[trtReplace].value = parent.field[grRating].value
~if we're attached to the targeting autosoft, we'll need to grab some
~tags in order for the weapons to find us
perform parent.pulltags[AutosoType.Targeting]
perform parent.pulltags[ExoticProf.?]
~if we're not in a device, or not running, hide ourselves and don't
~proceed to looking for existing copies of the skill to replace
if (hero.tagexpr[Hero.MatrixOnly | Hero.Vehicle] <> 0) then
if (parent.field[grIsEquip].value = 0) then
perform assign[Hide.Skill]
perform assign[Helper.Disable]
done
endif
elseif (tagis[SkillHelp.Personafix] <> 0) then
~nothing we need to do in this case
elseif (tagis[SkillHelp.Autosoft] <> 0) then
if (hero.tagis[Hero.Vehicle] = 0) then
perform assign[Hide.Skill]
perform assign[Helper.Disable]
done
endif
elseif (parent.tagis[Equipment.KnowInfus] <> 0) then
perform field[trtBase].modify[+,1,"Knowledge Infusion"]
perform assign[SkillHelp.KnowInfus]
elseif (parent.tagis[Equipment.GearSkill] <> 0) then
if (parent.field[grIsEquip].value = 0) then
perform assign[Hide.Skill]
perform assign[Helper.Disable]
done
endif
elseif (parent.container.ishero = 0) then
if (container.parent.field[grIsEquip].value = 0) then
perform assign[Hide.Skill]
perform assign[Helper.Disable]
done
endif
else
perform assign[Hide.Skill]
perform assign[Helper.Disable]
done
endif
~if the thing we're bootstrapped by requires activation, but it's not
~active, then we're hidden
if (parent.tagis[User.Activation] <> 0) then
if (parent.field[abilActive].value = 0) then
perform assign[Hide.Skill]
perform assign[Helper.Disable]
done
endif
endif
~if we're a skill that came from a possessing spirit, there are some
~changes that need to be applied
elseif (parent.tagis[component.Adjustment] <> 0) then
if (hero.tagis[Hero.Channeling] <> 0) then
perform assign[Hide.Skill]
done
endif
perform assign[SkillHelp.FixSkill]
perform assign[SkillHelp.NoSpecial]
perform assign[SkillHelp.SpiritSkl]
~if our parent isn't activated, we're hidden. We also don't want to run
~the rest of this script, since that's when our value is added to the
~regular version of our skill
if (parent.activated = 0) then
perform assign[Hide.Skill]
done
endif
~normally, this is an overriding value
perform field[trtOver].modify[=,container.child[attrFor].field[trtFinal].value,"Possessing Spirit's Force"]
endif
var ismatch as number
var cantest as number
~now, check to see if a non-skillsoft copy of this skill is present on the hero
foreach pick in hero from Skill where "!Hide.Skill & " & tagids[thingid.?]
ismatch = 0
cantest = 0
~if the skill we found is shadowed, then we can only make use of it if
~we're a skill from a life module, and it's also from a life module
if (eachpick.shadowed <> 0) then
~if it's shadowed because it was originally added as an advancement,
~then that's OK - we can use that copy
if (eachpick.tagis[Advance.Gizmo] <> 0) then
cantest = 1
elseif (tagis[SkillHelp.LifeSkill] <> 0) then
if (eachpick.tagexpr[SkillHelp.LifeSkill & !SkillHelp.LaterLMSkl] <> 0) then
cantest = 1
endif
endif
else
cantest = 1
endif
~if the skill we found is ourself, discard it as an option
if (eachpick.uniqindex = uniqindex) then
cantest = 0
endif
if (cantest <> 0) then
~if we need a menu selection, make sure that the target's menu
~menu selection is the same as ours
if (field[usrCandid1].isempty = 0) then
if (field[usrChosen1].ischosen <> 0) then
if (eachpick.field[usrChosen1].ischosen <> 0) then
if (compare(eachpick.field[usrChosen1].chosen.idstring, field[usrChosen1].chosen.idstring) = 0) then
ismatch = 1
endif
endif
endif
elseif (tagis[User.NeedDomain] <> 0) then
if (eachpick.field[domDomain].isempty = 0) then
if (field[domDomain].isempty = 0) then
if (compare(eachpick.field[domDomain].text,field[domDomain].text) = 0) then
ismatch = 1
endif
endif
endif
else
ismatch = 1
endif
~for a knowledge skill, make sure that the knowledge skill categories
~are the same. For example, the Academic Knowledge: Buildings skill
~from a university architecture module would not stack with the
~Professional Knowledge: Buildings from a Trade school architecture
~life module
if (tagis[component.SkillKnow] <> 0) then
if (eachpick.field[sklKnowCat].value <> field[sklKnowCat].value) then
ismatch = 0
endif
endif
endif
if (ismatch <> 0) then
if (field[trtOver].value >= 0) then
eachpick.field[trtOver].value = maximum(eachpick.field[trtOver].value,field[trtOver].value)
perform eachpick.assign[SkillHelp.DisableSpc]
endif
eachpick.field[trtReplace].value = maximum(eachpick.field[trtReplace].value,field[trtReplace].value)
perform assign[Hide.Skill]
perform assign[SkillHelp.LaterLMSkl]
endif
nexteach
]]></eval>
<eval index="9" phase="Traits" priority="950" name="Shadowed skills find their normal versions - early changes">
<before name="Bound trtUser"/><![CDATA[
~this only applies to shadowed skills
~those will be the ones added as skillsofts
doneif (shadowed + tagexpr[SkillHelp.Autosoft | SkillHelp.Personafix] = 0)
~exclude new skill advancements
doneif (tagis[Advance.Gizmo] <> 0)
~if we have a root pick, and our root pick is an advancement, stop now
if (isroot <> 0) then
doneif (root.tagis[Advance.Gizmo] <> 0)
~if that root pick has a root, and that's an advancement, stop now
~(this happens when Drake is added as an advancement - the Elemental
~Attack skill is two bootstraps down from the actual pick)
if (root.isroot <> 0) then
doneif (root.root.tagis[Advance.Gizmo] <> 0)
endif
endif
~this script is specific to those added as life modules
doneif (parent.tagis[component.LifeModule] = 0)
perform assign[SkillHelp.LifeSkill]
var ismatch as number
var cantest as number
~now, check to see if a non-skillsoft copy of this skill is present on the hero
foreach pick in hero from Skill where tagids[thingid.?]
ismatch = 0
cantest = 0
~if the skill we found is shadowed, then we can only make use of it if
~we're a skill from a life module, and it's
if (eachpick.shadowed <> 0) then
if (tagis[SkillHelp.LifeSkill] <> 0) then
if (eachpick.tagis[SkillHelp.LifeSkill] <> 0) then
cantest = 1
endif
endif
else
cantest = 1
endif
~if the skill we found is ourself, discard it as an option
if (eachpick.uniqindex = uniqindex) then
cantest = 0
endif
if (cantest <> 0) then
~if we need a menu selection, make sure that the target's menu
~menu selection is the same as ours
if (field[usrCandid1].isempty = 0) then
if (field[usrChosen1].ischosen <> 0) then
if (eachpick.field[usrChosen1].ischosen <> 0) then
if (compare(eachpick.field[usrChosen1].chosen.idstring, field[usrChosen1].chosen.idstring) = 0) then
ismatch = 1
endif
endif
endif
elseif (tagis[User.NeedDomain] <> 0) then
if (eachpick.field[domDomain].isempty = 0) then
if (field[domDomain].isempty = 0) then
if (compare(eachpick.field[domDomain].text,field[domDomain].text) = 0) then
ismatch = 1
endif
endif
endif
else
ismatch = 1
endif
~for a knowledge skill, make sure that the knowledge skill categories
~are the same. For example, the Academic Knowledge: Buildings skill
~from a university architecture module would not stack with the
~Professional Knowledge: Buildings from a Trade school architecture
~life module
if (tagis[component.SkillKnow] <> 0) then
if (eachpick.field[sklKnowCat].value <> field[sklKnowCat].value) then
ismatch = 0
endif
endif
endif
if (ismatch <> 0) then
~what we're going to do here is make sure that both copies - ourselves
~and the copy we found - have identical trtInitial fields - both the
~value and the history should be the same. So, we start by recording
~the history that's currently in eachpick's field, then add our value
~to the copy we found, and then set our own value = to the new total,
~but we only add the history we recorded to our own history, meaning
~that at the end, from either copy, you'll see each thing that
~contributed to the history recorded here.
if (field[trtLifMod].value <> 0) then
perform eachpick.field[trtInitial].modify[+,field[trtLifMod].value,"Life Module: " & parent.field[name].text]
endif
if (eachpick.field[trtLifMod].value <> 0) then
perform field[trtInitial].modify[+,eachpick.field[trtLifMod].value,"Life Module: " & eachpick.parent.field[name].text]
endif
endif
nexteach
]]></eval>