Incidentally, I found a partial solution. Because every Specialty is tagged with the skill it applies to, I was able to instead bar individual skills when there were no possibilities (which is the case when the number of ranks in the skill are not greater than the number of specialties the character has in that skill). Since most characters have many skills they have no ranks in, this will work for now, but I feel like this is bound to break again at some point.
Code:
<!-- Add Specialty advance -->
<thing
id="advSpec"
name="Add Specialty"
compset="Advance"
description="Add a skill specialty">
<fieldval field="advAction" value="Add Specialty"/>
<fieldval field="advDynamic" value="component.Specialty & !Hide.Specialty"/>
<tag group="Advance" tag="AddNew"/>
<eval value="1" phase="Render" priority="1000">
<before name="Assign Dynamic Tagexpr"/><![CDATA[
~get the list of all unique specialties on the hero and assemble it as a list of precluded tags
debug "Assign Dynamic"
var tagexpr as string
foreach pick in hero where "component.Skill"
var skillID as string
var skillrank as number
var speccount as number
skillID = eachpick.idstring
skillrank = eachpick.field[trtFinal].value
speccount = eachpick.tagcount[User.HasSpec]
if (speccount < skillrank) then
foreach pick in eachpick.gizmo where "component.Specialty & !Hide.Specialty"
~ debug eachpick.idstring
if (each.isunique <> 0) then
tagexpr &= " & !Specialty." & each.idstring
endif
nexteach
else
tagexpr &= " & !Skill." & skillID
endif
nexteach
~ debug "Precluded: " & tagexpr
~if there are any tags to exclude, append them to the tagexpr appropriately
if (empty(tagexpr) = 0) then
field[advDynamic].text &= tagexpr
debug "advDynamic: " & field[advDynamic].text
endif
]]></eval>
<child entity="Advance">
<tag group="Advance" tag="MustChoose"/>
</child></thing>
Next step is to figure out if there's a nice way to define three independent skills for the "Advance 3 different skills by 1 point" Advance without having to define a custom portal for each.