diff --git a/c11020863.lua b/c11020863.lua index 1323a8a707..1ec2a4f202 100644 --- a/c11020863.lua +++ b/c11020863.lua @@ -45,7 +45,7 @@ function s.destg(e,tp,eg,ep,ev,re,r,rp,chk) if chk==0 then if not Duel.IsExistingMatchingCard(aux.TRUE,tp,0,LOCATION_ONFIELD,1,nil) then return false end local tg=Duel.GetMatchingGroup(s.tgfilter,tp,LOCATION_HAND+LOCATION_DECK,0,nil) - return tg:CheckSubGroup(aux.dlvcheck,5,5) + return tg:WithCheckSpec(aux.dlvcheck_spec):CheckSubGroup(nil,5,5) end local g=Duel.GetMatchingGroup(aux.TRUE,tp,0,LOCATION_ONFIELD,nil) Duel.SetOperationInfo(0,CATEGORY_TOGRAVE,nil,5,tp,LOCATION_HAND+LOCATION_DECK) @@ -54,7 +54,7 @@ end function s.desop(e,tp,eg,ep,ev,re,r,rp) local tg=Duel.GetMatchingGroup(s.tgfilter,tp,LOCATION_HAND+LOCATION_DECK,0,nil) Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_TOGRAVE) - local sg=tg:SelectSubGroup(tp,aux.dlvcheck,false,5,5) + local sg=tg:WithCheckSpec(aux.dlvcheck_spec):SelectSubGroup(tp,nil,false,5,5) if sg then Duel.SendtoGrave(sg,REASON_EFFECT) local g=Duel.GetMatchingGroup(aux.TRUE,tp,0,LOCATION_ONFIELD,nil) diff --git a/c12215894.lua b/c12215894.lua index 12c88c6df8..3cbad1a89f 100644 --- a/c12215894.lua +++ b/c12215894.lua @@ -70,9 +70,7 @@ function c12215894.cost2(e,tp,eg,ep,ev,re,r,rp,chk) local g=Duel.GetMatchingGroup(c12215894.cfilter,tp,LOCATION_GRAVE+LOCATION_ONFIELD,0,nil) if chk==0 then return g:GetClassCount(Card.GetCode)>=9 end Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_REMOVE) - aux.GCheckAdditional=aux.dncheck - local rg=g:SelectSubGroup(tp,aux.TRUE,false,9,9) - aux.GCheckAdditional=nil + local rg=g:WithCheckSpec(aux.dncheck_spec):SelectSubGroup(tp,aux.TRUE,false,9,9) Duel.Remove(rg,POS_FACEUP,REASON_COST) end function c12215894.target2(e,tp,eg,ep,ev,re,r,rp,chk) diff --git a/c12289247.lua b/c12289247.lua index 1095a990ea..e2ed9a0d85 100644 --- a/c12289247.lua +++ b/c12289247.lua @@ -45,6 +45,10 @@ function c12289247.initial_effect(c) end end c12289247.hnchecks=aux.CreateChecks(Card.IsSetCard,{0x10f2,0x2073,0x2017,0x1046}) +function c12289247.hnclassifier(c) + if c:IsLocation(LOCATION_MZONE) then return nil end + return aux.GetCheckMask(c,c12289247.hnchecks) +end function c12289247.spcfilter(c,tp) return c:IsReason(REASON_BATTLE+REASON_EFFECT) and c:IsPreviousControler(tp) and c:IsPreviousLocation(LOCATION_ONFIELD) @@ -127,11 +131,13 @@ end function c12289247.hncost(e,tp,eg,ep,ev,re,r,rp,chk) local c=e:GetHandler() local mg=Duel.GetMatchingGroup(c12289247.cfilter,tp,LOCATION_HAND+LOCATION_MZONE+LOCATION_GRAVE,0,nil) - if chk==0 then return c:IsAbleToRemoveAsCost() - and Duel.IsExistingMatchingCard(c12289247.hnfilter,tp,LOCATION_EXTRA,0,1,nil,e,tp) - and mg:CheckSubGroupEach(c12289247.hnchecks,c12289247.hngoal,e,tp,c) end + if chk==0 then + if not (c:IsAbleToRemoveAsCost() + and Duel.IsExistingMatchingCard(c12289247.hnfilter,tp,LOCATION_EXTRA,0,1,nil,e,tp)) then return false end + return mg:WithSubGroupContext(nil,c12289247.hnclassifier):CheckSubGroupEach(c12289247.hnchecks,c12289247.hngoal,e,tp,c) + end Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_REMOVE) - local sg=mg:SelectSubGroupEach(tp,c12289247.hnchecks,false,c12289247.hngoal,e,tp,c) + local sg=mg:WithSubGroupContext(nil,c12289247.hnclassifier):SelectSubGroupEach(tp,c12289247.hnchecks,false,c12289247.hngoal,e,tp,c) sg:AddCard(c) Duel.Remove(sg,POS_FACEUP,REASON_COST) end diff --git a/c14386013.lua b/c14386013.lua index 9e424e3d2f..911b001917 100644 --- a/c14386013.lua +++ b/c14386013.lua @@ -57,9 +57,7 @@ function c14386013.drop(e,tp,eg,ep,ev,re,r,rp) local p=Duel.GetChainInfo(0,CHAININFO_TARGET_PLAYER) local g=Duel.GetMatchingGroup(aux.NecroValleyFilter(c14386013.drfilter),p,LOCATION_HAND+LOCATION_GRAVE,0,nil) Duel.Hint(HINT_SELECTMSG,p,HINTMSG_TODECK) - aux.GCheckAdditional=aux.dncheck - local sg=g:SelectSubGroup(p,aux.TRUE,false,1,Duel.GetFieldGroupCount(p,LOCATION_DECK,0)) - aux.GCheckAdditional=nil + local sg=g:WithCheckSpec(aux.dncheck_spec):SelectSubGroup(p,aux.TRUE,false,1,Duel.GetFieldGroupCount(p,LOCATION_DECK,0)) if sg then Duel.ConfirmCards(1-p,sg) local ct=aux.PlaceCardsOnDeckBottom(p,sg) diff --git a/c15094540.lua b/c15094540.lua index ea38e205b9..b0154cb982 100644 --- a/c15094540.lua +++ b/c15094540.lua @@ -81,7 +81,7 @@ function s.sptg(e,tp,eg,ep,ev,re,r,rp,chk,chkc) if chk==0 then return ft>=5 and Duel.IsExistingTarget(s.spfilter,tp,LOCATION_REMOVED,0,5,nil,e,tp) and g:GetClassCount(Card.GetCode)>=5 and not Duel.IsPlayerAffectedByEffect(tp,59822133) end Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON) - local tg=g:SelectSubGroup(tp,aux.dncheck,false,5,5) + local tg=g:WithCheckSpec(aux.dncheck_spec):SelectSubGroup(tp,nil,false,5,5) Duel.SetTargetCard(tg) Duel.SetOperationInfo(0,CATEGORY_SPECIAL_SUMMON,tg,tg:GetCount(),0,0) end diff --git a/c16329071.lua b/c16329071.lua index 2f1289ca80..2446cd1fd6 100644 --- a/c16329071.lua +++ b/c16329071.lua @@ -25,9 +25,7 @@ function c16329071.activate(e,tp,eg,ep,ev,re,r,rp) local g=Duel.GetMatchingGroup(aux.NecroValleyFilter(c16329071.filter),tp,LOCATION_HAND+LOCATION_GRAVE+LOCATION_ONFIELD+LOCATION_REMOVED,0,nil) if g:GetClassCount(Card.GetCode)<5 then return end Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_TODECK) - aux.GCheckAdditional=aux.dncheck - local sg=g:SelectSubGroup(tp,aux.TRUE,false,5,5) - aux.GCheckAdditional=nil + local sg=g:WithCheckSpec(aux.dncheck_spec):SelectSubGroup(tp,aux.TRUE,false,5,5) local cg=sg:Filter(Card.IsLocation,nil,LOCATION_HAND) if cg:GetCount()>0 then Duel.ConfirmCards(1-tp,cg) diff --git a/c17197110.lua b/c17197110.lua index fc3e070b40..040655ff44 100644 --- a/c17197110.lua +++ b/c17197110.lua @@ -58,7 +58,7 @@ function c17197110.activate(e,tp,eg,ep,ev,re,r,rp) if ft0 then Duel.SendtoGrave(sg,REASON_EFFECT) end diff --git a/c61411502.lua b/c61411502.lua index 7bcadc58bf..c6cd126c67 100644 --- a/c61411502.lua +++ b/c61411502.lua @@ -12,14 +12,19 @@ function c61411502.initial_effect(c) c:RegisterEffect(e1) end c61411502.rchecks=aux.CreateChecks(Card.IsAttribute,{ATTRIBUTE_WIND,ATTRIBUTE_WATER,ATTRIBUTE_FIRE,ATTRIBUTE_EARTH}) +function c61411502.rclassifier(c) + return aux.GetCheckMask(c,c61411502.rchecks) +end function c61411502.rgoal(g,tp) return Duel.IsExistingMatchingCard(aux.TRUE,tp,0,LOCATION_ONFIELD,1,g) end function c61411502.cost(e,tp,eg,ep,ev,re,r,rp,chk) local g=Duel.GetReleaseGroup(tp) - if chk==0 then return g:CheckSubGroupEach(c61411502.rchecks,c61411502.rgoal,tp) end + if chk==0 then + return g:WithSubGroupContext(nil,c61411502.rclassifier):CheckSubGroupEach(c61411502.rchecks,c61411502.rgoal,tp) + end Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_RELEASE) - local rg=g:SelectSubGroupEach(tp,c61411502.rchecks,false,c61411502.rgoal,tp) + local rg=g:WithSubGroupContext(nil,c61411502.rclassifier):SelectSubGroupEach(tp,c61411502.rchecks,false,c61411502.rgoal,tp) aux.UseExtraReleaseCount(rg,tp) Duel.Release(rg,REASON_COST) end diff --git a/c6309986.lua b/c6309986.lua index 1c5a69373b..09aa34a9b3 100644 --- a/c6309986.lua +++ b/c6309986.lua @@ -13,6 +13,9 @@ function c6309986.initial_effect(c) c:RegisterEffect(e1) end c6309986.spchecks=aux.CreateChecks(Card.IsCode,{44632120,71036835,7021574,34419588,40640057}) +function c6309986.spclassifier(c) + return aux.GetCheckMask(c,c6309986.spchecks) +end function c6309986.cfilter(c,tp) return c:IsFaceup() and c:IsLevel(5) and c:IsReleasable() and Duel.GetMZoneCount(tp,c)>=5 end @@ -31,8 +34,8 @@ function c6309986.target(e,tp,eg,ep,ev,re,r,rp,chk) if chk==0 then e:SetLabel(0) local g=Duel.GetMatchingGroup(c6309986.spfilter,tp,LOCATION_HAND+LOCATION_DECK+LOCATION_GRAVE,0,nil,e,tp) - return res and not Duel.IsPlayerAffectedByEffect(tp,59822133) - and g:CheckSubGroupEach(c6309986.spchecks) + if not (res and not Duel.IsPlayerAffectedByEffect(tp,59822133)) then return false end + return g:WithSubGroupContext(nil,c6309986.spclassifier):CheckSubGroupEach(c6309986.spchecks) end Duel.SetOperationInfo(0,CATEGORY_SPECIAL_SUMMON,nil,5,tp,LOCATION_HAND+LOCATION_DECK+LOCATION_GRAVE) end @@ -40,7 +43,7 @@ function c6309986.activate(e,tp,eg,ep,ev,re,r,rp) if Duel.GetLocationCount(tp,LOCATION_MZONE)>=5 and not Duel.IsPlayerAffectedByEffect(tp,59822133) then local g=Duel.GetMatchingGroup(aux.NecroValleyFilter(c6309986.spfilter),tp,LOCATION_HAND+LOCATION_DECK+LOCATION_GRAVE,0,nil,e,tp) Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON) - local sg=g:SelectSubGroupEach(tp,c6309986.spchecks,false) + local sg=g:WithSubGroupContext(nil,c6309986.spclassifier):SelectSubGroupEach(tp,c6309986.spchecks,false) if sg then Duel.SpecialSummon(sg,0,tp,tp,false,false,POS_FACEUP) for tc in aux.Next(sg) do diff --git a/c70914287.lua b/c70914287.lua index 4287d53758..f789dd7275 100644 --- a/c70914287.lua +++ b/c70914287.lua @@ -40,6 +40,9 @@ function c70914287.initial_effect(c) c:RegisterEffect(e5) end c70914287.spchecks=aux.CreateChecks(Card.IsCode,{44632120,71036835,7021574,34419588,40640057}) +function c70914287.spclassifier(c) + return aux.GetCheckMask(c,c70914287.spchecks) +end function c70914287.spcon1(e,tp,eg,ep,ev,re,r,rp) return Duel.GetMatchingGroupCount(Card.IsType,tp,LOCATION_GRAVE,0,nil,TYPE_MONSTER)>Duel.GetMatchingGroupCount(Card.IsType,1-tp,LOCATION_GRAVE,0,nil,TYPE_MONSTER) end @@ -71,8 +74,10 @@ end function c70914287.sptg2(e,tp,eg,ep,ev,re,r,rp,chk) local c=e:GetHandler() local g=Duel.GetMatchingGroup(c70914287.spfilter,tp,LOCATION_HAND+LOCATION_GRAVE,0,nil,e,tp) - if chk==0 then return c:IsAbleToHand() and Duel.GetMZoneCount(tp,c)>=5 and not Duel.IsPlayerAffectedByEffect(tp,59822133) - and g:CheckSubGroupEach(c70914287.spchecks) end + if chk==0 then + if not (c:IsAbleToHand() and Duel.GetMZoneCount(tp,c)>=5 and not Duel.IsPlayerAffectedByEffect(tp,59822133)) then return false end + return g:WithSubGroupContext(nil,c70914287.spclassifier):CheckSubGroupEach(c70914287.spchecks) + end Duel.SetOperationInfo(0,CATEGORY_TOHAND,c,1,0,0) Duel.SetOperationInfo(0,CATEGORY_SPECIAL_SUMMON,nil,5,tp,LOCATION_HAND+LOCATION_GRAVE) end @@ -82,7 +87,7 @@ function c70914287.spop2(e,tp,eg,ep,ev,re,r,rp) and Duel.GetLocationCount(tp,LOCATION_MZONE)>=5 and not Duel.IsPlayerAffectedByEffect(tp,59822133) then local g=Duel.GetMatchingGroup(aux.NecroValleyFilter(c70914287.spfilter),tp,LOCATION_HAND+LOCATION_GRAVE,0,nil,e,tp) Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON) - local sg=g:SelectSubGroupEach(tp,c70914287.spchecks,false) + local sg=g:WithSubGroupContext(nil,c70914287.spclassifier):SelectSubGroupEach(tp,c70914287.spchecks,false) if sg then Duel.SpecialSummon(sg,0,tp,tp,false,false,POS_FACEUP_ATTACK) end diff --git a/c76794549.lua b/c76794549.lua index 5d58d32d6a..324fd4ad66 100644 --- a/c76794549.lua +++ b/c76794549.lua @@ -50,6 +50,10 @@ function c76794549.initial_effect(c) end end c76794549.hnchecks=aux.CreateChecks(Card.IsSetCard,{0x10f2,0x2073,0x2017,0x1046}) +function c76794549.hnclassifier(c) + if c:IsLocation(LOCATION_MZONE) then return nil end + return aux.GetCheckMask(c,c76794549.hnchecks) +end function c76794549.checkop(e,tp,eg,ep,ev,re,r,rp) local tc=eg:GetFirst() while tc do @@ -155,11 +159,13 @@ end function c76794549.hncost(e,tp,eg,ep,ev,re,r,rp,chk) local c=e:GetHandler() local mg=Duel.GetMatchingGroup(c76794549.cfilter,tp,LOCATION_HAND+LOCATION_MZONE+LOCATION_GRAVE,0,nil) - if chk==0 then return c:IsAbleToRemoveAsCost() - and Duel.IsExistingMatchingCard(c76794549.hnfilter,tp,LOCATION_EXTRA,0,1,nil,e,tp,nil) - and mg:CheckSubGroupEach(c76794549.hnchecks,c76794549.hngoal,e,tp,c) end + if chk==0 then + if not (c:IsAbleToRemoveAsCost() + and Duel.IsExistingMatchingCard(c76794549.hnfilter,tp,LOCATION_EXTRA,0,1,nil,e,tp,nil)) then return false end + return mg:WithSubGroupContext(nil,c76794549.hnclassifier):CheckSubGroupEach(c76794549.hnchecks,c76794549.hngoal,e,tp,c) + end Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_REMOVE) - local sg=mg:SelectSubGroupEach(tp,c76794549.hnchecks,false,c76794549.hngoal,e,tp,c) + local sg=mg:WithSubGroupContext(nil,c76794549.hnclassifier):SelectSubGroupEach(tp,c76794549.hnchecks,false,c76794549.hngoal,e,tp,c) sg:AddCard(c) Duel.Remove(sg,POS_FACEUP,REASON_COST) end diff --git a/c77075360.lua b/c77075360.lua index 8c9213428c..6d3e1a1fa2 100644 --- a/c77075360.lua +++ b/c77075360.lua @@ -65,9 +65,7 @@ function c77075360.spop(e,tp,eg,ep,ev,re,r,rp) if Duel.IsPlayerAffectedByEffect(tp,59822133) then ft=1 end local ct=math.min(g:GetClassCount(Card.GetLevel),ft) Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON) - aux.GCheckAdditional=aux.dlvcheck - local sg=g:SelectSubGroup(tp,aux.TRUE,false,ct,ct) - aux.GCheckAdditional=nil + local sg=g:WithCheckSpec(aux.dlvcheck_spec):SelectSubGroup(tp,aux.TRUE,false,ct,ct) Duel.SpecialSummon(sg,0,tp,tp,false,false,POS_FACEUP_DEFENSE) end function c77075360.regop(e,tp,eg,ep,ev,re,r,rp) diff --git a/c7986397.lua b/c7986397.lua index a2e8e2db6c..3bf1d546d1 100644 --- a/c7986397.lua +++ b/c7986397.lua @@ -19,7 +19,7 @@ end function c7986397.rcheck(tp,g,c) return g:FilterCount(Card.IsLocation,nil,LOCATION_DECK)<=1 end -function c7986397.rgcheck(g,ec) +function c7986397.rgcheck(g) return g:FilterCount(Card.IsLocation,nil,LOCATION_DECK)<=1 end function c7986397.target(e,tp,eg,ep,ev,re,r,rp,chk) diff --git a/c80033124.lua b/c80033124.lua index 192524852d..6168326f84 100644 --- a/c80033124.lua +++ b/c80033124.lua @@ -11,6 +11,10 @@ function c80033124.initial_effect(c) c:RegisterEffect(e1) end c80033124.fchecks=aux.CreateChecks(Card.IsFusionCode,{41230939,77625948,3019642}) +function c80033124.fclassifier(c) + if c:IsLocation(LOCATION_MZONE) then return nil end + return aux.GetCheckMask(c,c80033124.fchecks) +end function c80033124.ffilter0(c) return c:IsFusionCode(41230939,77625948,3019642) and c:IsCanBeFusionMaterial() and c:IsAbleToDeck() end @@ -30,7 +34,7 @@ function c80033124.target(e,tp,eg,ep,ev,re,r,rp,chk) if not aux.MustMaterialCheck(nil,tp,EFFECT_MUST_BE_FMATERIAL) then return false end if not Duel.IsExistingMatchingCard(c80033124.spfilter,tp,LOCATION_EXTRA,0,1,nil,e,tp,nil) then return false end local mg=Duel.GetMatchingGroup(c80033124.ffilter0,tp,LOCATION_HAND+LOCATION_ONFIELD+LOCATION_GRAVE,0,nil) - return mg:CheckSubGroupEach(c80033124.fchecks,c80033124.fgoal,e,tp) + return mg:WithSubGroupContext(nil,c80033124.fclassifier):CheckSubGroupEach(c80033124.fchecks,c80033124.fgoal,e,tp) end Duel.SetOperationInfo(0,CATEGORY_SPECIAL_SUMMON,nil,1,tp,LOCATION_EXTRA) end @@ -44,7 +48,7 @@ function c80033124.activate(e,tp,eg,ep,ev,re,r,rp) if not aux.MustMaterialCheck(nil,tp,EFFECT_MUST_BE_FMATERIAL) then return end local mg=Duel.GetMatchingGroup(aux.NecroValleyFilter(c80033124.ffilter),tp,LOCATION_HAND+LOCATION_ONFIELD+LOCATION_GRAVE,0,nil,e) Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_TODECK) - local sg=mg:SelectSubGroupEach(tp,c80033124.fchecks,false,c80033124.fgoal,e,tp) + local sg=mg:WithSubGroupContext(nil,c80033124.fclassifier):SelectSubGroupEach(tp,c80033124.fchecks,false,c80033124.fgoal,e,tp) if not sg then return end local cg=sg:Filter(c80033124.cfilter,nil) if cg:GetCount()>0 then diff --git a/c81560239.lua b/c81560239.lua index e53c13021b..4d80ec6b55 100644 --- a/c81560239.lua +++ b/c81560239.lua @@ -17,20 +17,15 @@ end function s.mfilter(c) return c:GetLevel()>0 and c:IsRace(RACE_REPTILE) and c:IsReleasable(REASON_EFFECT|REASON_MATERIAL|REASON_RITUAL) end -function s.rcheck(tp,g,c) - return g:GetCount()<3 -end -function s.rgcheck(g,ec) +function s.rgcheck(g) return g:GetCount()<3 end function s.target(e,tp,eg,ep,ev,re,r,rp,chk) local mg1=Duel.GetRitualMaterial(tp):Filter(Card.IsRace,nil,RACE_REPTILE) local mg2=Duel.GetMatchingGroup(s.mfilter,tp,LOCATION_DECK,0,nil) local s1=Duel.IsExistingMatchingCard(aux.RitualUltimateFilter,tp,LOCATION_DECK,0,1,nil,s.filter,e,tp,mg1,nil,Card.GetLevel,"Equal") - aux.RCheckAdditional=s.rcheck aux.RGCheckAdditional=s.rgcheck local s2=Duel.IsExistingMatchingCard(aux.RitualUltimateFilter,tp,LOCATION_HAND,0,1,nil,s.filter,e,tp,mg1,mg2,Card.GetLevel,"Equal") - aux.RCheckAdditional=nil aux.RGCheckAdditional=nil local b1=s1 and (Duel.GetFlagEffect(tp,id)==0 or not e:IsCostChecked()) local b2=s2 and (Duel.GetFlagEffect(tp,id+o)==0 or not e:IsCostChecked()) diff --git a/c82428674.lua b/c82428674.lua index db15499995..0711a09fd4 100644 --- a/c82428674.lua +++ b/c82428674.lua @@ -37,9 +37,7 @@ function c82428674.activate(e,tp,eg,ep,ev,re,r,rp) local g=Duel.GetMatchingGroup(c82428674.rmfilter,tp,LOCATION_HAND+LOCATION_GRAVE+LOCATION_MZONE,0,nil) if ct==0 or g:GetCount()==0 then return end Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_REMOVE) - aux.GCheckAdditional=aux.dlvcheck - local rg=g:SelectSubGroup(tp,aux.TRUE,false,1,ct) - aux.GCheckAdditional=nil + local rg=g:WithCheckSpec(aux.dlvcheck_spec):SelectSubGroup(tp,aux.TRUE,false,1,ct) local rc=Duel.Remove(rg,POS_FACEUP,REASON_EFFECT) if rc>0 then Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_DESTROY) diff --git a/c87985506.lua b/c87985506.lua index 6a18f82b3a..6a3f27dec8 100644 --- a/c87985506.lua +++ b/c87985506.lua @@ -39,7 +39,7 @@ function s.activate(e,tp,eg,ep,ev,re,r,rp) if ft>0 and #g>0 then if Duel.IsPlayerAffectedByEffect(tp,59822133) then ft=1 end Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON) - local sg=g:SelectSubGroup(tp,aux.dncheck,false,1,math.min(3,ft)) + local sg=g:WithCheckSpec(aux.dncheck_spec):SelectSubGroup(tp,nil,false,1,math.min(3,ft)) if sg then Duel.SpecialSummon(sg,0,tp,tp,false,false,POS_FACEUP) end diff --git a/c91323605.lua b/c91323605.lua index f307b62919..beb2d9ec89 100644 --- a/c91323605.lua +++ b/c91323605.lua @@ -49,7 +49,7 @@ function s.activate(e,tp,eg,ep,ev,re,r,rp) Duel.MoveToField(tc,tp,tp,LOCATION_FZONE,POS_FACEUP,true) local g=Duel.GetMatchingGroup(s.sfilter,tp,LOCATION_DECK,0,nil,e,tp) Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON) - local mg=g:SelectSubGroup(tp,aux.dncheck,false,5,5) + local mg=g:WithCheckSpec(aux.dncheck_spec):SelectSubGroup(tp,nil,false,5,5) if mg then Duel.BreakEffect() Duel.ConfirmCards(1-tp,mg) diff --git a/c93053159.lua b/c93053159.lua index b9ac6b9b0f..81a13f9bd4 100644 --- a/c93053159.lua +++ b/c93053159.lua @@ -42,16 +42,20 @@ function s.initial_effect(c) e4:SetOperation(s.tgop) c:RegisterEffect(e4) end +-- check/spec for materials with different Fusion Codes +s.dfccheck,s.dfccheck_spec=aux.MakeDistinctCheckSpec(Card.GetFusionCode) function s.splimit(e,se,sp,st) return bit.band(st,SUMMON_TYPE_FUSION)==SUMMON_TYPE_FUSION end -function s.Alba_System_Drugmata_Fusion_Filter(c,mg,fc,tp,chkf,gc) - if not c:IsFusionCode(68468459) and not c:IsHasEffect(EFFECT_FUSION_SUBSTITUTE) then return false end +-- The custom fusion procedure picks this required Alba/substitute material first, +-- then checks whether the remaining pool can complete the 6-material fusion. +function s.IsAlbaSystemDrugmataLeadMaterial(c) + return c:IsFusionCode(68468459) or c:IsHasEffect(EFFECT_FUSION_SUBSTITUTE) +end +function s.CanCompleteAlbaSystemDrugmataFusion(c,mg,fc,tp,chkf,gc) + if not s.IsAlbaSystemDrugmataLeadMaterial(c) then return false end local g=mg:Filter(s.matfilter,c,tp) - aux.GCheckAdditional=aux.dncheck - local res=g:CheckSubGroup(s.Alba_System_Drugmata_Fusion_Gcheck,6,6,fc,tp,c,chkf,gc) - aux.GCheckAdditional=nil - return res + return g:WithSubGroupContext(s.dfccheck_spec.additional,s.dfccheck_spec.classifier):CheckSubGroup(s.Alba_System_Drugmata_Fusion_Gcheck,6,6,fc,tp,c,chkf,gc) end function s.matfilter(c,tp) return c:IsLocation(LOCATION_GRAVE) and c:IsControler(tp) and not c:IsHasEffect(6205579) @@ -73,9 +77,9 @@ function s.Alba_System_Drugmata_Fusion_Condition() local tp=e:GetHandlerPlayer() if gc then if not g:IsContains(gc) then return false end - return g:IsExists(s.Alba_System_Drugmata_Fusion_Filter,1,nil,g,fc,tp,chkf,gc) + return g:IsExists(s.CanCompleteAlbaSystemDrugmataFusion,1,nil,g,fc,tp,chkf,gc) end - return g:IsExists(s.Alba_System_Drugmata_Fusion_Filter,1,nil,g,fc,tp,chkf,nil) + return g:IsExists(s.CanCompleteAlbaSystemDrugmataFusion,1,nil,g,fc,tp,chkf,nil) end end function s.Alba_System_Drugmata_Fusion_Operation() @@ -90,7 +94,7 @@ function s.Alba_System_Drugmata_Fusion_Operation() fg:AddCard(g:GetFirst()) end if gc then - if s.Alba_System_Drugmata_Fusion_Filter(gc,fg,fc,tp,chkf) then + if s.CanCompleteAlbaSystemDrugmataFusion(gc,fg,fc,tp,chkf) then g=Group.FromCards(gc) fg:RemoveCard(gc) local mg=fg:Filter(s.matfilter,fc,tp) @@ -98,7 +102,7 @@ function s.Alba_System_Drugmata_Fusion_Operation() sg=mg:SelectSubGroup(tp,s.Alba_System_Drugmata_Fusion_Gcheck,false,6,6,fc,tp,g:GetFirst(),chkf,gc) else Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_FMATERIAL) - g=fg:FilterSelect(tp,s.Alba_System_Drugmata_Fusion_Filter,1,1,nil,fg,fc,tp,chkf,gc) + g=fg:FilterSelect(tp,s.CanCompleteAlbaSystemDrugmataFusion,1,1,nil,fg,fc,tp,chkf,gc) fg:Sub(g) local mg=fg:Filter(s.matfilter,fc,tp) Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_FMATERIAL) @@ -106,13 +110,11 @@ function s.Alba_System_Drugmata_Fusion_Operation() end else Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_FMATERIAL) - g=fg:FilterSelect(tp,s.Alba_System_Drugmata_Fusion_Filter,1,1,nil,fg,fc,tp,chkf,nil) + g=fg:FilterSelect(tp,s.CanCompleteAlbaSystemDrugmataFusion,1,1,nil,fg,fc,tp,chkf,nil) fg:Sub(g) local mg=fg:Filter(s.matfilter,fc,tp) - aux.GCheckAdditional=aux.dncheck Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_FMATERIAL) - sg=mg:SelectSubGroup(tp,s.Alba_System_Drugmata_Fusion_Gcheck,true,6,6,fc,tp,g:GetFirst(),chkf) - aux.GCheckAdditional=nil + sg=mg:WithSubGroupContext(s.dfccheck_spec.additional,s.dfccheck_spec.classifier):SelectSubGroup(tp,s.Alba_System_Drugmata_Fusion_Gcheck,true,6,6,fc,tp,g:GetFirst(),chkf) end end g:Merge(sg) diff --git a/c99162753.lua b/c99162753.lua index b751dd4a0d..de5b2d6643 100644 --- a/c99162753.lua +++ b/c99162753.lua @@ -11,6 +11,13 @@ function c99162753.initial_effect(c) c:RegisterEffect(e1) end c99162753.spchecks=aux.CreateChecks(Card.IsType,{TYPE_RITUAL,TYPE_FUSION,TYPE_SYNCHRO,TYPE_XYZ,TYPE_PENDULUM,TYPE_LINK}) +function c99162753.fadditional(sg) + return sg:GetClassCount(Card.GetOriginalRace)<=1 +end +function c99162753.fclassifier(c) + if c:IsLocation(LOCATION_MZONE) then return nil end + return c:GetOriginalRace().."|"..aux.GetCheckMask(c,c99162753.spchecks) +end function c99162753.rmfilter(c) return (not c:IsLocation(LOCATION_MZONE) or c:IsFaceup()) and c:IsType(TYPE_RITUAL+TYPE_FUSION+TYPE_SYNCHRO+TYPE_XYZ+TYPE_PENDULUM+TYPE_LINK) and c:IsAbleToRemove() end @@ -25,14 +32,16 @@ function c99162753.spfilter(c,e,tp,g) end function c99162753.target(e,tp,eg,ep,ev,re,r,rp,chk) local g=Duel.GetMatchingGroup(c99162753.rmfilter,tp,LOCATION_HAND+LOCATION_MZONE+LOCATION_GRAVE,0,nil) - if chk==0 then return g:CheckSubGroupEach(c99162753.spchecks,c99162753.fgoal,e,tp) end + if chk==0 then + return g:WithSubGroupContext(c99162753.fadditional,c99162753.fclassifier):CheckSubGroupEach(c99162753.spchecks,c99162753.fgoal,e,tp) + end Duel.SetOperationInfo(0,CATEGORY_REMOVE,nil,6,tp,LOCATION_HAND+LOCATION_MZONE+LOCATION_GRAVE) Duel.SetOperationInfo(0,CATEGORY_SPECIAL_SUMMON,nil,1,tp,LOCATION_DECK+LOCATION_EXTRA) end function c99162753.activate(e,tp,eg,ep,ev,re,r,rp) local g=Duel.GetMatchingGroup(aux.NecroValleyFilter(c99162753.rmfilter),tp,LOCATION_HAND+LOCATION_MZONE+LOCATION_GRAVE,0,nil) Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_REMOVE) - local rg=g:SelectSubGroupEach(tp,c99162753.spchecks,false,c99162753.fgoal,e,tp) + local rg=g:WithSubGroupContext(c99162753.fadditional,c99162753.fclassifier):SelectSubGroupEach(tp,c99162753.spchecks,false,c99162753.fgoal,e,tp) if rg and rg:GetCount()==6 and Duel.Remove(rg,POS_FACEUP,REASON_EFFECT)~=0 then Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON) local tg=Duel.SelectMatchingCard(tp,c99162753.spfilter,tp,LOCATION_DECK+LOCATION_EXTRA,0,1,1,nil,e,tp,rg) diff --git a/c99426088.lua b/c99426088.lua index 815eef4983..bea32ea715 100644 --- a/c99426088.lua +++ b/c99426088.lua @@ -31,10 +31,7 @@ end function c99426088.rexfilter(c) return c:IsType(TYPE_NORMAL) and c:IsLevelAbove(1) and c:IsAbleToGrave() end -function c99426088.frcheck(tp,sg,fc) - return sg:FilterCount(Card.IsLocation,nil,LOCATION_DECK)<=1 -end -function c99426088.gcheck(sg,ec) +function c99426088.gcheck(sg) return sg:FilterCount(Card.IsLocation,nil,LOCATION_DECK)<=1 end function c99426088.target(e,tp,eg,ep,ev,re,r,rp,chk) @@ -45,12 +42,10 @@ function c99426088.target(e,tp,eg,ep,ev,re,r,rp,chk) local fmg2=Duel.GetMatchingGroup(c99426088.fexfilter,tp,LOCATION_DECK,0,nil) if fmg2:GetCount()>0 then fmg1:Merge(fmg2) - aux.FCheckAdditional=c99426088.frcheck aux.GCheckAdditional=c99426088.gcheck end end local res=Duel.IsExistingMatchingCard(c99426088.ffilter2,tp,LOCATION_EXTRA,0,1,nil,e,tp,fmg1,nil,chkf) - aux.FCheckAdditional=nil aux.GCheckAdditional=nil if not res then local ce=Duel.GetChainMaterial(tp) @@ -67,10 +62,8 @@ function c99426088.target(e,tp,eg,ep,ev,re,r,rp,chk) if c99426088.excon(tp) then rmg2=Duel.GetMatchingGroup(c99426088.rexfilter,tp,LOCATION_DECK,0,nil) end - aux.RCheckAdditional=c99426088.frcheck aux.RGCheckAdditional=c99426088.gcheck res=Duel.IsExistingMatchingCard(aux.RitualUltimateFilter,tp,LOCATION_HAND,0,1,nil,c99426088.rfilter,e,tp,rmg1,rmg2,Card.GetLevel,"Greater") - aux.RCheckAdditional=nil aux.RGCheckAdditional=nil end return res @@ -89,11 +82,9 @@ function c99426088.activate(e,tp,eg,ep,ev,re,r,rp) end end if exmat then - aux.FCheckAdditional=c99426088.frcheck aux.GCheckAdditional=c99426088.gcheck end local fsg1=Duel.GetMatchingGroup(c99426088.ffilter2,tp,LOCATION_EXTRA,0,nil,e,tp,fmg1,nil,chkf) - aux.FCheckAdditional=nil aux.GCheckAdditional=nil local fmg3=nil local fsg2=nil @@ -109,10 +100,8 @@ function c99426088.activate(e,tp,eg,ep,ev,re,r,rp) if c99426088.excon(tp) then rmg2=Duel.GetMatchingGroup(c99426088.rexfilter,tp,LOCATION_DECK,0,nil) end - aux.RCheckAdditional=c99426088.frcheck aux.RGCheckAdditional=c99426088.gcheck local rsg=Duel.GetMatchingGroup(aux.RitualUltimateFilter,tp,LOCATION_HAND,0,nil,c99426088.rfilter,e,tp,rmg1,rmg2,Card.GetLevel,"Greater") - aux.RCheckAdditional=nil aux.RGCheckAdditional=nil local off=1 local ops={} @@ -137,11 +126,9 @@ function c99426088.activate(e,tp,eg,ep,ev,re,r,rp) fmg1:RemoveCard(tc) if fsg1:IsContains(tc) and (fsg2==nil or not fsg2:IsContains(tc) or not Duel.SelectYesNo(tp,ce:GetDescription())) then if exmat then - aux.FCheckAdditional=c99426088.frcheck aux.GCheckAdditional=c99426088.gcheck end local mat1=Duel.SelectFusionMaterial(tp,tc,fmg1,nil,chkf) - aux.FCheckAdditional=nil aux.GCheckAdditional=nil tc:SetMaterial(mat1) Duel.SendtoGrave(mat1,REASON_EFFECT+REASON_MATERIAL+REASON_FUSION) @@ -157,7 +144,6 @@ function c99426088.activate(e,tp,eg,ep,ev,re,r,rp) ::rcancel:: Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON) local tc=rsg:Select(tp,1,1,nil):GetFirst() - aux.RCheckAdditional=c99426088.frcheck aux.RGCheckAdditional=c99426088.gcheck local rmg=rmg1:Filter(Card.IsCanBeRitualMaterial,tc,tc) if rmg2 then rmg:Merge(rmg2) end @@ -171,7 +157,6 @@ function c99426088.activate(e,tp,eg,ep,ev,re,r,rp) local mat=rmg:SelectSubGroup(tp,aux.RitualCheck,true,1,tc:GetLevel(),tp,tc,tc:GetLevel(),"Greater") aux.GCheckAdditional=nil if not mat then - aux.RCheckAdditional=nil aux.RGCheckAdditional=nil goto rcancel end @@ -185,7 +170,6 @@ function c99426088.activate(e,tp,eg,ep,ev,re,r,rp) Duel.BreakEffect() Duel.SpecialSummon(tc,SUMMON_TYPE_RITUAL,tp,tp,false,true,POS_FACEUP) tc:CompleteProcedure() - aux.RCheckAdditional=nil aux.RGCheckAdditional=nil end end diff --git a/procedure.lua b/procedure.lua index ae8d650ae3..b2b27c9554 100644 --- a/procedure.lua +++ b/procedure.lua @@ -1809,15 +1809,23 @@ function Auxiliary.RitualCheckAdditional(c,lv,greater_or_equal) return (not Auxiliary.RGCheckAdditional or Auxiliary.RGCheckAdditional(g)) and g:GetSum(Auxiliary.RitualCheckAdditionalLevel,c)<=lv end else - return function(g,ec) - if ec then - return (not Auxiliary.RGCheckAdditional or Auxiliary.RGCheckAdditional(g,ec)) and g:GetSum(Auxiliary.RitualCheckAdditionalLevel,c)-Auxiliary.RitualCheckAdditionalLevel(ec,c)<=lv - else - return not Auxiliary.RGCheckAdditional or Auxiliary.RGCheckAdditional(g) - end + return function(g) + local sum=g:GetSum(Auxiliary.RitualCheckAdditionalLevel,c) + if Auxiliary.RGCheckAdditional and not Auxiliary.RGCheckAdditional(g) then return false end + local _,minv=g:GetMinGroup(Auxiliary.RitualCheckAdditionalLevel,c) + return sum-minv classifier(card). +Auxiliary.GCheckClassifierCache=nil +function Auxiliary.WithSubGroupContext(additional,classifier,f) + Auxiliary.GCheckAdditional=additional + Auxiliary.GCheckClassifier=classifier + Auxiliary.GCheckClassifierCache=nil + local ok,res=pcall(f) + Auxiliary.GCheckClassifier=nil + Auxiliary.GCheckClassifierCache=nil + Auxiliary.GCheckAdditional=nil + if not ok then error(res,0) end + return res +end --the table of xyz number Auxiliary.xyz_number={} @@ -1122,30 +1137,80 @@ function Auxiliary.bfgcost(e,tp,eg,ep,ev,re,r,rp,chk) if chk==0 then return e:GetHandler():IsAbleToRemoveAsCost() end Duel.Remove(e:GetHandler(),POS_FACEUP,REASON_COST) end ---check for cards with different names -function Auxiliary.dncheck(g) - return g:GetClassCount(Card.GetCode)==#g +function Auxiliary.MakeDistinctCheck(getter) + local group_check=function(g) + return g:GetClassCount(getter)==#g + end + local additional_check=function(sg,c) + return group_check(sg) + end + local classifier=function(c) + return getter(c) + end + return group_check,additional_check,classifier end ---check for cards with different levels -function Auxiliary.dlvcheck(g) - return g:GetClassCount(Card.GetLevel)==#g +function Auxiliary.MakeDistinctCheckSpec(getter) + local check,additional,classifier=Auxiliary.MakeDistinctCheck(getter) + return check,{check=check,additional=additional,classifier=classifier} end ---check for cards with different ranks -function Auxiliary.drkcheck(g) - return g:GetClassCount(Card.GetRank)==#g +local SubGroupContextProxy={} +function SubGroupContextProxy.CheckSubGroup(self,f,min,max,...) + local ext_params={...} + return Auxiliary.WithSubGroupContext(self.additional,self.classifier,function() + return self.group:CheckSubGroup(f,min,max,table.unpack(ext_params)) + end) end ---check for cards with different links -function Auxiliary.dlkcheck(g) - return g:GetClassCount(Card.GetLink)==#g +function SubGroupContextProxy.SelectSubGroup(self,tp,f,cancelable,min,max,...) + local ext_params={...} + return Auxiliary.WithSubGroupContext(self.additional,self.classifier,function() + return self.group:SelectSubGroup(tp,f,cancelable,min,max,table.unpack(ext_params)) + end) end ---check for cards with different attributes -function Auxiliary.dabcheck(g) - return g:GetClassCount(Card.GetAttribute)==#g +function SubGroupContextProxy.CheckSubGroupEach(self,checks,f,...) + local ext_params={...} + return Auxiliary.WithSubGroupContext(self.additional,self.classifier,function() + return self.group:CheckSubGroupEach(checks,f,table.unpack(ext_params)) + end) end ---check for cards with different races -function Auxiliary.drccheck(g) - return g:GetClassCount(Card.GetRace)==#g +function SubGroupContextProxy.SelectSubGroupEach(self,tp,checks,cancelable,f,...) + local ext_params={...} + return Auxiliary.WithSubGroupContext(self.additional,self.classifier,function() + return self.group:SelectSubGroupEach(tp,checks,cancelable,f,table.unpack(ext_params)) + end) +end +-- Syntax sugar for subgroup context chaining, e.g. +-- g:WithSubGroupContext(additional,classifier):CheckSubGroup(...) +-- g:WithCheckSpec(spec):SelectSubGroup(...) +function Group.WithSubGroupContext(g,additional,classifier) + return setmetatable({group=g,additional=additional,classifier=classifier},{__index=SubGroupContextProxy}) +end +function Group.WithCheckSpec(g,spec) + return g:WithSubGroupContext(spec.additional,spec.classifier) +end +function Auxiliary.CheckSubGroupByCheckSpec(g,spec,f,min,max,...) + local ext_params={...} + return Auxiliary.WithSubGroupContext(spec.additional,spec.classifier,function() + return g:CheckSubGroup(f or spec.check,min,max,table.unpack(ext_params)) + end) +end +function Auxiliary.SelectSubGroupByCheckSpec(g,tp,spec,f,cancelable,min,max,...) + local ext_params={...} + return Auxiliary.WithSubGroupContext(spec.additional,spec.classifier,function() + return g:SelectSubGroup(tp,f or spec.check,cancelable,min,max,table.unpack(ext_params)) + end) end +--check for cards with different names +Auxiliary.dncheck,Auxiliary.dncheck_spec=Auxiliary.MakeDistinctCheckSpec(Card.GetCode) +--check for cards with different levels +Auxiliary.dlvcheck,Auxiliary.dlvcheck_spec=Auxiliary.MakeDistinctCheckSpec(Card.GetLevel) +--check for cards with different ranks +Auxiliary.drkcheck,Auxiliary.drkcheck_spec=Auxiliary.MakeDistinctCheckSpec(Card.GetRank) +--check for cards with different links +Auxiliary.dlkcheck,Auxiliary.dlkcheck_spec=Auxiliary.MakeDistinctCheckSpec(Card.GetLink) +--check for cards with different attributes +Auxiliary.dabcheck,Auxiliary.dabcheck_spec=Auxiliary.MakeDistinctCheckSpec(Card.GetAttribute) +--check for cards with different races +Auxiliary.drccheck,Auxiliary.drccheck_spec=Auxiliary.MakeDistinctCheckSpec(Card.GetRace) --check for group with 2 cards, each card match f with a1/a2 as argument function Auxiliary.gfcheck(g,f,a1,a2) if #g~=2 then return false end @@ -1192,35 +1257,65 @@ function Auxiliary.GetMultiLinkedZone(tp) end return multi_linked_zone end -Auxiliary.SubGroupCaptured=nil -function Auxiliary.CheckGroupRecursive(c,sg,g,f,min,max,ext_params) - sg:AddCard(c) - if Auxiliary.GCheckAdditional and not Auxiliary.GCheckAdditional(sg,c,g) then - sg:RemoveCard(c) - return false +function Auxiliary.BuildGroupClassifierCache(g) + if not Auxiliary.GCheckClassifier then return nil end + local cache={} + for c in Auxiliary.Next(g) do + cache[c]=Auxiliary.GCheckClassifier(c) end - local res=(#sg>=min and #sg<=max and f(sg,table.unpack(ext_params))) - or (#sg=min and #sg<=max and f(sg,table.unpack(ext_params)) - if res then - Auxiliary.SubGroupCaptured:Clear() - Auxiliary.SubGroupCaptured:Merge(sg) - else - res=#sg=min and #sg<=max and f(sg,table.unpack(ext_params))) + if res or #sg>=max then + return res + end + -- Iterate a stable snapshot while `rg` is remove/add-mutated for each child branch. + local ig=rg:Clone() + local classified={} + for tc in Auxiliary.Next(ig) do + local cls=Auxiliary.GetGroupClassifier(tc) + local entry + if cls then + entry=classified[cls] + end + if entry~=nil then + res=entry + else + sg:AddCard(tc) + rg:RemoveCard(tc) + if Auxiliary.GCheckAdditional and not Auxiliary.GCheckAdditional(sg) then + res=false + else + res=Auxiliary.CheckGroupRecursive(sg,rg,f,min,max,ext_params) + end + rg:AddCard(tc) + sg:RemoveCard(tc) + if cls then + classified[cls]=res + end + end + if res then return true end end - sg:RemoveCard(c) - return res + return false end ---- ---@param g Group ---@param f function ---@param min? integer @@ -1232,16 +1327,12 @@ function Group.CheckSubGroup(g,f,min,max,...) max=max or #g if min>max then return false end local ext_params={...} + Auxiliary.BuildGroupClassifierCache(g) local sg=Duel.GrabSelectedCard() if #sg>max or #(g+sg)=min and #sg<=max and f(sg,...) and (not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg,nil,g)) then return true end - local eg=g:Clone() - for c in Auxiliary.Next(g-sg) do - if Auxiliary.CheckGroupRecursive(c,sg,eg,f,min,max,ext_params) then return true end - eg:RemoveCard(c) - end - return false + if #sg==max and (not f(sg,...) or Auxiliary.GCheckAdditional and not Auxiliary.GCheckAdditional(sg)) then return false end + if #sg>=min and #sg<=max and f(sg,...) and (not Auxiliary.GCheckAdditional or Auxiliary.GCheckAdditional(sg)) then return true end + return Auxiliary.CheckGroupRecursive(sg,g-sg,f,min,max,ext_params) end --- ---@param g Group @@ -1253,10 +1344,10 @@ end ---@param ... any ---@return Group function Group.SelectSubGroup(g,tp,f,cancelable,min,max,...) - Auxiliary.SubGroupCaptured=Group.CreateGroup() min=min or 1 max=max or #g local ext_params={...} + Auxiliary.BuildGroupClassifierCache(g) local sg=Group.CreateGroup() local fg=Duel.GrabSelectedCard() if #fg>max or min>max or #(g+fg)=min and #sg<=max and f(sg,...)) + if finish and Auxiliary.GCheckAdditional and not Auxiliary.GCheckAdditional(sg) then + finish=false + end while #sg=min and #sg<=max and f(sg,...)) + if finish and Auxiliary.GCheckAdditional and not Auxiliary.GCheckAdditional(sg) then + finish=false + end if #cg==0 then break end local cancel=not finish and cancelable local tc=cg:SelectUnselect(sg,tp,finish,cancel,min,max) @@ -1311,23 +1432,65 @@ function Auxiliary.CreateChecks(f,list) end return checks end -function Auxiliary.CheckGroupRecursiveEach(c,sg,g,f,checks,ext_params) - if not checks[1+#sg](c) then - return false - end - sg:AddCard(c) - if Auxiliary.GCheckAdditional and not Auxiliary.GCheckAdditional(sg,c,g) then - sg:RemoveCard(c) - return false +function Auxiliary.GetCheckMask(c,checks,...) + local mask=0 + for i=1,#checks do + if checks[i](c,...) then + mask=mask|(1<<(#checks-i)) + end end - local res + return mask +end +---Recursive ordered subgroup walker over the current branch state. +---Entry usage: call with the current selected subgroup and its remaining pool, +---normally `Auxiliary.CheckGroupRecursiveEach(sg,g-sg,f,checks,ext_params)`. +---Current root callers may pass `g` directly only because they always start +---from an empty `sg`, where `g-sg` is equivalent to `g`. +---@param sg Group Current subgroup already chosen on this branch. +---@param rg Group Remaining candidate pool for deeper choices on this branch. +---@param f function +---@param checks table +---@param ext_params table +---@return boolean +function Auxiliary.CheckGroupRecursiveEach(sg,rg,f,checks,ext_params) + -- Ordered subgroup checks consume exactly one predicate per depth, so once all + -- predicates are matched we can evaluate the completed subgroup and stop here. if #sg==#checks then - res=f(sg,table.unpack(ext_params)) - else - res=g:IsExists(Auxiliary.CheckGroupRecursiveEach,1,sg,sg,g,f,checks,ext_params) + return f(sg,table.unpack(ext_params)) + end + -- Iterate a stable snapshot while `rg` is remove/add-mutated for each child branch. + local ig=rg:Clone() + local classified={} + for tc in Auxiliary.Next(ig) do + if checks[1+#sg](tc) then + local cls=Auxiliary.GetGroupClassifier(tc) + local entry + local res + if cls then + entry=classified[cls] + end + if entry~=nil then + res=entry + else + sg:AddCard(tc) + rg:RemoveCard(tc) + if Auxiliary.GCheckAdditional and not Auxiliary.GCheckAdditional(sg) then + res=false + else + res=Auxiliary.CheckGroupRecursiveEach(sg,rg,f,checks,ext_params) + end + rg:AddCard(tc) + sg:RemoveCard(tc) + if cls then + classified[cls]=res + end + end + if res then + return true + end + end end - sg:RemoveCard(c) - return res + return false end --- ---@param g Group @@ -1339,8 +1502,9 @@ function Group.CheckSubGroupEach(g,checks,f,...) if f==nil then f=Auxiliary.TRUE end if #g<#checks then return false end local ext_params={...} + Auxiliary.BuildGroupClassifierCache(g) local sg=Group.CreateGroup() - return g:IsExists(Auxiliary.CheckGroupRecursiveEach,1,sg,sg,g,f,checks,ext_params) + return Auxiliary.CheckGroupRecursiveEach(sg,g,f,checks,ext_params) end --- ---@param g Group @@ -1355,10 +1519,43 @@ function Group.SelectSubGroupEach(g,tp,checks,cancelable,f,...) if f==nil then f=Auxiliary.TRUE end local ct=#checks local ext_params={...} + Auxiliary.BuildGroupClassifierCache(g) local sg=Group.CreateGroup() local finish=false while #sg