Commit bd9a5a7f authored by Vury Leo's avatar Vury Leo

init new fusion monsters

parent b0675727
--超魔導師-ブラック・マジシャンズ --超魔導師-ブラック・マジシャンズ--クリッチー
function c50237654.initial_effect(c) local s,id,o=GetID()
function s.initial_effect(c)
--fusion material --fusion material
c:EnableReviveLimit() c:EnableReviveLimit()
aux.AddFusionProcCodeFun(c,{46986414,38033121},aux.FilterBoolFunction(Card.IsRace,RACE_SPELLCASTER),1,true,true) -- aux.AddFusionProcCodeFun(c,{46986414,38033121},aux.FilterBoolFunction(Card.IsRace,RACE_SPELLCASTER),1,true,true)
Fusion.AddFusionProcedure(c,{
slots={
Fusion.Slot.Codes({46986414,38033121}),
Fusion.Slot.Filter(function(mc) return mc:IsRace(RACE_SPELLCASTER) end),
}
})
--draw --draw
local e1=Effect.CreateEffect(c) local e1=Effect.CreateEffect(c)
e1:SetDescription(aux.Stringid(50237654,1)) e1:SetDescription(aux.Stringid(id,1))
e1:SetCategory(CATEGORY_DRAW) e1:SetCategory(CATEGORY_DRAW)
e1:SetType(EFFECT_TYPE_FIELD+EFFECT_TYPE_TRIGGER_O) e1:SetType(EFFECT_TYPE_FIELD+EFFECT_TYPE_TRIGGER_O)
e1:SetCode(EVENT_CHAINING) e1:SetCode(EVENT_CHAINING)
e1:SetProperty(EFFECT_FLAG_DELAY) e1:SetProperty(EFFECT_FLAG_DELAY)
e1:SetRange(LOCATION_MZONE) e1:SetRange(LOCATION_MZONE)
e1:SetCountLimit(1) e1:SetCountLimit(1)
e1:SetCondition(c50237654.drcon) e1:SetCondition(s.drcon)
e1:SetTarget(c50237654.drtg) e1:SetTarget(s.drtg)
e1:SetOperation(c50237654.drop) e1:SetOperation(s.drop)
c:RegisterEffect(e1) c:RegisterEffect(e1)
--spsummon --spsummon
local e2=Effect.CreateEffect(c) local e2=Effect.CreateEffect(c)
...@@ -22,28 +29,28 @@ function c50237654.initial_effect(c) ...@@ -22,28 +29,28 @@ function c50237654.initial_effect(c)
e2:SetType(EFFECT_TYPE_SINGLE+EFFECT_TYPE_TRIGGER_O) e2:SetType(EFFECT_TYPE_SINGLE+EFFECT_TYPE_TRIGGER_O)
e2:SetCode(EVENT_DESTROYED) e2:SetCode(EVENT_DESTROYED)
e2:SetProperty(EFFECT_FLAG_DELAY) e2:SetProperty(EFFECT_FLAG_DELAY)
e2:SetTarget(c50237654.sptg) e2:SetTarget(s.sptg)
e2:SetOperation(c50237654.spop) e2:SetOperation(s.spop)
c:RegisterEffect(e2) c:RegisterEffect(e2)
end end
function c50237654.drcon(e,tp,eg,ep,ev,re,r,rp) function s.drcon(e,tp,eg,ep,ev,re,r,rp)
return re:IsActiveType(TYPE_SPELL+TYPE_TRAP) return re:IsActiveType(TYPE_SPELL+TYPE_TRAP)
end end
function c50237654.drtg(e,tp,eg,ep,ev,re,r,rp,chk) function s.drtg(e,tp,eg,ep,ev,re,r,rp,chk)
if chk==0 then return Duel.IsPlayerCanDraw(tp,1) end if chk==0 then return Duel.IsPlayerCanDraw(tp,1) end
Duel.SetOperationInfo(0,CATEGORY_DRAW,nil,0,tp,1) Duel.SetOperationInfo(0,CATEGORY_DRAW,nil,0,tp,1)
end end
function c50237654.drop(e,tp,eg,ep,ev,re,r,rp) function s.drop(e,tp,eg,ep,ev,re,r,rp)
local c=e:GetHandler() local c=e:GetHandler()
if Duel.Draw(tp,1,REASON_EFFECT)~=0 then if Duel.Draw(tp,1,REASON_EFFECT)~=0 then
local dc=Duel.GetOperatedGroup():GetFirst() local dc=Duel.GetOperatedGroup():GetFirst()
if dc:IsType(TYPE_SPELL+TYPE_TRAP) and dc:IsSSetable() if dc:IsType(TYPE_SPELL+TYPE_TRAP) and dc:IsSSetable()
and Duel.SelectYesNo(tp,aux.Stringid(50237654,0)) then and Duel.SelectYesNo(tp,aux.Stringid(id,0)) then
Duel.BreakEffect() Duel.BreakEffect()
if Duel.SSet(tp,dc,tp,false)==0 then return end if Duel.SSet(tp,dc,tp,false)==0 then return end
if dc:IsType(TYPE_QUICKPLAY) then if dc:IsType(TYPE_QUICKPLAY) then
local e1=Effect.CreateEffect(c) local e1=Effect.CreateEffect(c)
e1:SetDescription(aux.Stringid(50237654,2)) e1:SetDescription(aux.Stringid(id,2))
e1:SetType(EFFECT_TYPE_SINGLE) e1:SetType(EFFECT_TYPE_SINGLE)
e1:SetProperty(EFFECT_FLAG_SET_AVAILABLE) e1:SetProperty(EFFECT_FLAG_SET_AVAILABLE)
e1:SetCode(EFFECT_QP_ACT_IN_SET_TURN) e1:SetCode(EFFECT_QP_ACT_IN_SET_TURN)
...@@ -52,7 +59,7 @@ function c50237654.drop(e,tp,eg,ep,ev,re,r,rp) ...@@ -52,7 +59,7 @@ function c50237654.drop(e,tp,eg,ep,ev,re,r,rp)
end end
if dc:IsType(TYPE_TRAP) then if dc:IsType(TYPE_TRAP) then
local e1=Effect.CreateEffect(c) local e1=Effect.CreateEffect(c)
e1:SetDescription(aux.Stringid(50237654,2)) e1:SetDescription(aux.Stringid(id,2))
e1:SetType(EFFECT_TYPE_SINGLE) e1:SetType(EFFECT_TYPE_SINGLE)
e1:SetCode(EFFECT_TRAP_ACT_IN_SET_TURN) e1:SetCode(EFFECT_TRAP_ACT_IN_SET_TURN)
e1:SetProperty(EFFECT_FLAG_SET_AVAILABLE) e1:SetProperty(EFFECT_FLAG_SET_AVAILABLE)
...@@ -62,26 +69,26 @@ function c50237654.drop(e,tp,eg,ep,ev,re,r,rp) ...@@ -62,26 +69,26 @@ function c50237654.drop(e,tp,eg,ep,ev,re,r,rp)
end end
end end
end end
function c50237654.spfilter1(c,e,tp) function s.spfilter1(c,e,tp)
return c:IsCode(46986414) and c:IsCanBeSpecialSummoned(e,0,tp,false,false) return c:IsCode(46986414) and c:IsCanBeSpecialSummoned(e,0,tp,false,false)
and Duel.IsExistingMatchingCard(c50237654.spfilter2,tp,LOCATION_HAND+LOCATION_DECK+LOCATION_GRAVE,0,1,c,e,tp) and Duel.IsExistingMatchingCard(s.spfilter2,tp,LOCATION_HAND+LOCATION_DECK+LOCATION_GRAVE,0,1,c,e,tp)
end end
function c50237654.spfilter2(c,e,tp) function s.spfilter2(c,e,tp)
return c:IsCode(38033121) and c:IsCanBeSpecialSummoned(e,0,tp,false,false) return c:IsCode(38033121) and c:IsCanBeSpecialSummoned(e,0,tp,false,false)
end end
function c50237654.sptg(e,tp,eg,ep,ev,re,r,rp,chk) function s.sptg(e,tp,eg,ep,ev,re,r,rp,chk)
if chk==0 then return Duel.IsExistingMatchingCard(c50237654.spfilter1,tp,LOCATION_HAND+LOCATION_DECK+LOCATION_GRAVE,0,1,nil,e,tp) if chk==0 then return Duel.IsExistingMatchingCard(s.spfilter1,tp,LOCATION_HAND+LOCATION_DECK+LOCATION_GRAVE,0,1,nil,e,tp)
and Duel.GetLocationCount(tp,LOCATION_MZONE)>1 and Duel.GetLocationCount(tp,LOCATION_MZONE)>1
and not Duel.IsPlayerAffectedByEffect(tp,59822133) end and not Duel.IsPlayerAffectedByEffect(tp,59822133) end
Duel.SetOperationInfo(0,CATEGORY_SPECIAL_SUMMON,nil,2,tp,LOCATION_HAND+LOCATION_DECK+LOCATION_GRAVE) Duel.SetOperationInfo(0,CATEGORY_SPECIAL_SUMMON,nil,2,tp,LOCATION_HAND+LOCATION_DECK+LOCATION_GRAVE)
end end
function c50237654.spop(e,tp,eg,ep,ev,re,r,rp) function s.spop(e,tp,eg,ep,ev,re,r,rp)
if Duel.IsPlayerAffectedByEffect(tp,59822133) then return end if Duel.IsPlayerAffectedByEffect(tp,59822133) then return end
if Duel.GetLocationCount(tp,LOCATION_MZONE)<2 then return end if Duel.GetLocationCount(tp,LOCATION_MZONE)<2 then return end
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON) Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON)
local g1=Duel.SelectMatchingCard(tp,aux.NecroValleyFilter(c50237654.spfilter1),tp,LOCATION_HAND+LOCATION_DECK+LOCATION_GRAVE,0,1,1,nil,e,tp) local g1=Duel.SelectMatchingCard(tp,aux.NecroValleyFilter(s.spfilter1),tp,LOCATION_HAND+LOCATION_DECK+LOCATION_GRAVE,0,1,1,nil,e,tp)
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON) Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON)
local g2=Duel.SelectMatchingCard(tp,aux.NecroValleyFilter(c50237654.spfilter2),tp,LOCATION_HAND+LOCATION_DECK+LOCATION_GRAVE,0,1,1,g1:GetFirst(),e,tp) local g2=Duel.SelectMatchingCard(tp,aux.NecroValleyFilter(s.spfilter2),tp,LOCATION_HAND+LOCATION_DECK+LOCATION_GRAVE,0,1,1,g1:GetFirst(),e,tp)
g1:Merge(g2) g1:Merge(g2)
if g1:GetCount()==2 then if g1:GetCount()==2 then
Duel.SpecialSummon(g1,0,tp,tp,false,false,POS_FACEUP) Duel.SpecialSummon(g1,0,tp,tp,false,false,POS_FACEUP)
......
--クリッチー --クリッチー
function c53539634.initial_effect(c) local s,id,o=GetID()
function s.initial_effect(c)
--fusion material --fusion material
c:EnableReviveLimit() c:EnableReviveLimit()
aux.AddFusionProcCode2(c,78010363,26202165,true,true) -- aux.AddFusionProcCode2(c,78010363,26202165,true,true)
Fusion.AddFusionProcedure(c,{
slots={
Fusion.Slot.Code(78010363),
Fusion.Slot.Code(26202165),
}
})
end end
--キメラテック・オーバー・ドラゴン --キメラテック・オーバー・ドラゴン
function c64599569.initial_effect(c) local s,id,o=GetID()
function s.initial_effect(c)
c:EnableReviveLimit() c:EnableReviveLimit()
--fusion material --fusion material
aux.AddFusionProcCodeFunRep(c,70095154,aux.FilterBoolFunction(Card.IsRace,RACE_MACHINE),1,127,true,true) -- aux.AddFusionProcCodeFunRep(c,70095154,aux.FilterBoolFunction(Card.IsRace,RACE_MACHINE),1,127,true,true)
Fusion.AddFusionProcedure(c,{
slots={
Fusion.Slot.Code(70095154), -- Cyber Dragon
Fusion.Slot.Group({ -- 1+ Machine monsters
filter=function(mc) return mc:IsRace(RACE_MACHINE) end,
})
}
})
--spsummon condition --spsummon condition
local e2=Effect.CreateEffect(c) local e2=Effect.CreateEffect(c)
e2:SetType(EFFECT_TYPE_SINGLE) e2:SetType(EFFECT_TYPE_SINGLE)
...@@ -14,24 +23,24 @@ function c64599569.initial_effect(c) ...@@ -14,24 +23,24 @@ function c64599569.initial_effect(c)
local e3=Effect.CreateEffect(c) local e3=Effect.CreateEffect(c)
e3:SetType(EFFECT_TYPE_SINGLE+EFFECT_TYPE_CONTINUOUS) e3:SetType(EFFECT_TYPE_SINGLE+EFFECT_TYPE_CONTINUOUS)
e3:SetCode(EVENT_SPSUMMON_SUCCESS) e3:SetCode(EVENT_SPSUMMON_SUCCESS)
e3:SetCondition(c64599569.sumcon) e3:SetCondition(s.sumcon)
e3:SetOperation(c64599569.sucop) e3:SetOperation(s.sucop)
c:RegisterEffect(e3) c:RegisterEffect(e3)
local e4=Effect.CreateEffect(c) local e4=Effect.CreateEffect(c)
e4:SetType(EFFECT_TYPE_SINGLE+EFFECT_TYPE_TRIGGER_F) e4:SetType(EFFECT_TYPE_SINGLE+EFFECT_TYPE_TRIGGER_F)
e4:SetCode(EVENT_SPSUMMON_SUCCESS) e4:SetCode(EVENT_SPSUMMON_SUCCESS)
e4:SetCondition(c64599569.sumcon) e4:SetCondition(s.sumcon)
e4:SetOperation(c64599569.tgop) e4:SetOperation(s.tgop)
c:RegisterEffect(e4) c:RegisterEffect(e4)
end end
c64599569.material_setcode=0x1093 s.material_setcode=0x1093
function c64599569.cyber_fusion_check(tp,sg,fc) function s.cyber_fusion_check(tp,sg,fc)
return sg:IsExists(Card.IsFusionCode,1,nil,70095154) return sg:IsExists(Card.IsFusionCode,1,nil,70095154)
end end
function c64599569.sumcon(e,tp,eg,ep,ev,re,r,rp) function s.sumcon(e,tp,eg,ep,ev,re,r,rp)
return e:GetHandler():IsSummonType(SUMMON_TYPE_FUSION) return e:GetHandler():IsSummonType(SUMMON_TYPE_FUSION)
end end
function c64599569.sucop(e,tp,eg,ep,ev,re,r,rp) function s.sucop(e,tp,eg,ep,ev,re,r,rp)
local c=e:GetHandler() local c=e:GetHandler()
local e1=Effect.CreateEffect(c) local e1=Effect.CreateEffect(c)
e1:SetType(EFFECT_TYPE_SINGLE) e1:SetType(EFFECT_TYPE_SINGLE)
...@@ -48,7 +57,7 @@ function c64599569.sucop(e,tp,eg,ep,ev,re,r,rp) ...@@ -48,7 +57,7 @@ function c64599569.sucop(e,tp,eg,ep,ev,re,r,rp)
e3:SetReset(RESET_EVENT+RESETS_STANDARD) e3:SetReset(RESET_EVENT+RESETS_STANDARD)
c:RegisterEffect(e3) c:RegisterEffect(e3)
end end
function c64599569.tgop(e,tp,eg,ep,ev,re,r,rp) function s.tgop(e,tp,eg,ep,ev,re,r,rp)
local g=Duel.GetMatchingGroup(nil,tp,LOCATION_ONFIELD,0,aux.ExceptThisCard(e)) local g=Duel.GetMatchingGroup(nil,tp,LOCATION_ONFIELD,0,aux.ExceptThisCard(e))
Duel.SendtoGrave(g,REASON_EFFECT) Duel.SendtoGrave(g,REASON_EFFECT)
end end
...@@ -3367,3 +3367,439 @@ function FusionSpell.GetCheckFieldPlayer(tp,skip_location_count_check) ...@@ -3367,3 +3367,439 @@ function FusionSpell.GetCheckFieldPlayer(tp,skip_location_count_check)
end end
return tp return tp
end end
--- Fusion
Fusion={}
function Fusion.AddFusionProcedure(fcard,opts)
local slots=opts.slots
-- Register effect
local e=Effect.CreateEffect(fcard)
e:SetType(EFFECT_TYPE_SINGLE)
e:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
e:SetCode(EFFECT_FUSION_MATERIAL)
e:SetCondition(Fusion.FusionCondition(slots,true))
e:SetOperation(Fusion.FusionOperation(slots))
e:SetDescription(1379) --- 启用扩展卡包调试模式
fcard:RegisterEffect(e)
end
---@param allow_extras boolean whether to allow extra materials (default true) for checking propose
function Fusion.FusionCondition(slots,allow_extras)
--g:Material group(nil for Instant Fusion)
--gc:Material already used
--chkf: check field, default:PLAYER_NONE
--chkf&0x100: Not fusion summon, can use substitute (Hex-Sealed Fusion)
--chkf&0x200: Not fusion summon, can't use substitute ("Contact Fusion", Neos Fusion)
return function(e,g,gc,chkf)
if not g or g:GetCount()<#slots then return false end
-- split slots
local single_slots, group_slots = {}, {}
for _, slot in ipairs(slots) do
if slot.group then
table.insert(group_slots,slot.group)
else
table.insert(single_slots,slot)
end
end
-- minimal total count
local total_req=#single_slots
for _, grp in ipairs(group_slots) do
total_req=total_req+grp.min end
if g:GetCount()<total_req then
return false
end
local cards={}
for tc in aux.Next(g) do
table.insert(cards,tc)
end
local used={}
local sub_count=0
-- DFS assign slots
local function dfs(i)
if i>#single_slots then
-- check group slots on leftovers
local leftovers={}
for idx,tc in ipairs(cards) do
if not used[idx] then
table.insert(leftovers,tc)
end
end
-- if strict (no extra), ensure leftover only match group slots
if not allow_extras then
for _,tc in ipairs(leftovers) do
local ok=false
for _,grp in ipairs(group_slots) do
if (not grp.filter or grp.filter(tc)) then
ok=true
break
end
end
if not ok then
return false
end
end
end
-- check each group slot has enough
for _, grp in ipairs(group_slots) do
local cnt=0
for _, tc in ipairs(leftovers) do
if (not grp.filter or grp.filter(tc)) then
cnt=cnt+1
end
end
if cnt<grp.min then
return false
end
end
return true
end
-- prune if not enough cards left
local used_count=0
for _,v in pairs(used) do
if v then
used_count=used_count+1
end
end
if (#cards-used_count)<(#single_slots-i+1) then
return false
end
-- try each card
local slot=single_slots[i]
for idx,tc in ipairs(cards) do
if not used[idx] then
local match,is_sub=Fusion.MatchSlot(tc,slot,e:GetHandler())
if match==true then
used[idx]=true
local prev_sub=sub_count
if is_sub then
sub_count=sub_count+1
end
if sub_count<=1 and dfs(i+1) then
return true
end
used[idx]=false
sub_count=prev_sub
end
end
end
return false
end
return dfs(1)
end
end
--- Helper: check one card against a named slot
---@param tc Card
---@param slot table match_code|match_codes|allow_sub
---@param handler Card
---@return boolean match
---@return boolean is_sub
function Fusion.MatchSlot(tc,slot,handler)
-- exact code match
if slot.match_code and tc:IsFusionCode(slot.match_code) then
return true,false
end
-- any-of-codes
if slot.match_codes then
for _,code in ipairs(slot.match_codes) do
if tc:IsFusionCode(code) then
return true,false
end
end
end
-- filter
if slot.filter and slot.filter(tc) then return true,false end
-- generic substitute
if slot.allow_sub and tc:CheckFusionSubstitute(handler) then
return true,true
end
return false,false
end
--- Generator: operation from named slots
---@param slots table[]
function Fusion.FusionOperation(slots)
return function(e,tp,eg,ep,ev,re,rp,gc,chkf)
-- strict final check (no extras)
local strict_cond=Fusion.FusionCondition(slots,false)
-- precompute minimum materials required
local min_req=0
for _,slot in ipairs(slots) do
if slot.group then
min_req=min_req+slot.group.min
else
min_req=min_req+1
end
end
local max_req=eg:GetCount()
-- prompt player
Duel.Hint(HINT_SELECTMSG, tp, HINTMSG_FMATERIAL)
local sg=Group.CreateGroup()
while true do
-- can we finish right now?
local finishable=(sg:GetCount()>=min_req) and strict_cond(e,sg,gc,chkf)
-- build “addable” via exhaustive mapping + completion test
local addable=Group.CreateGroup()
local candidates={}
for tc in aux.Next(eg) do
if not sg:IsContains(tc) then
table.insert(candidates,tc)
end
end
for _,tc in ipairs(candidates) do
sg:AddCard(tc)
if Fusion.CanCompleteFromMappings(e,sg,eg,slots,e:GetHandler(),gc,chkf) then
addable:AddCard(tc)
end
sg:RemoveCard(tc)
end
if addable:GetCount()==0 then
assert(finishable==true)
Duel.SetFusionMaterial(sg)
return
end
-- UI: let the player pick or finalize
local picked=Group.SelectUnselect(addable,sg,tp,finishable,true,min_req,max_req)
if not picked then
if finishable then
Duel.SetFusionMaterial(sg)
return -- user clicked “OK”
else
Duel.SetFusionMaterial(Group.CreateGroup())
return -- user clicked “Cancel” on invalid selection
end
end
assert(picked~=nil)
-- toggle selection
if sg:IsContains(picked) then
sg:RemoveCard(picked)
else
sg:AddCard(picked)
end
end
end
end
-- Slot constructors
Fusion.Slot = {}
--- Create a slot for a single code (default allow_sub = true)
---@param code number
---@param opts table? {allow_sub?:boolean, allow_parasite?:boolean}
---@return table
function Fusion.Slot.Code(code,opts)
opts=opts or {}
return {
match_code=code,
allow_sub=opts.allow_sub~=false,
}
end
--- Create a slot for multiple codes (default allow_sub = true)
---@param codes number[]
---@param opts table? {allow_sub?:boolean, allow_parasite?:boolean}
---@return table
function Fusion.Slot.Codes(codes,opts)
opts=opts or {}
return {
match_codes=codes,
allow_sub=opts.allow_sub~=false,
}
end
--- Create a slot for generic filter (no substitutes)
---@param filter fun(mc:Card):boolean
---@return table
function Fusion.Slot.Filter(filter)
return {
filter=filter,
allow_sub=false
}
end
--- Group slot (multi-card)
---@param opts {min:number,max?:number,filter?:fun(mc:Card):boolean }
---@return table
function Fusion.Slot.Group(opts)
opts.min=opts.min or 1
opts.max=opts.max or math.huge
return {
group=opts
}
end
--- FindAllMapping
--- @param cards_sel Card[] currently picked materials
--- @param slots table[] your original slots spec
--- @param handler Card the fusion monster (for substitutes)
--- @return table[] an array of mapping tables (or empty if none)
function Fusion.FindAllMappings(cards_sel,slots,handler)
-- Prepare trackers
local filled={} -- for single slots: filled[i] = true once used
local group_assigned={} -- for group slots: need[i] = how many left to fill
for i,slot in ipairs(slots) do
if slot.group then
group_assigned[i]=slot.group.min
else
filled[i]=false
end
end
-- Collector for all mappings
local all_maps={}
local mapping={} -- current partial mapping: mapping[idx] = slot_idx
-- DFS that tries every assignment for cards[idx]
local function dfs(idx)
if idx>#cards_sel then
-- Found one complete mapping: copy it
local copy={}
for k,v in pairs(mapping) do
copy[k]=v
end
table.insert(all_maps,copy)
return
end
local tc=cards_sel[idx]
-- Try each unused single slot
for i,slot in ipairs(slots) do
if not slot.group
and not filled[i]
and Fusion.MatchSlot(tc,slot,handler)
then
filled[i]=true
mapping[idx]=i
dfs(idx+1)
filled[i]=false
mapping[idx]=nil
end
end
-- Try each group slot that still needs cards
for i,slot in ipairs(slots) do
if slot.group then
local assigned=group_assigned[i] or 0
-- check filter *and* max‐constraint (nil max means unlimited)
if (slot.group.filter==nil or slot.group.filter(tc)) and (assigned<slot.group.max)
then
-- assign one more to this group‐slot
group_assigned[i]=assigned + 1
mapping[idx]=i
dfs(idx+1)
-- backtrack
group_assigned[i]=assigned
mapping[idx]=nil
end
end
end
end
dfs(1)
return all_maps
end
--- “Given all mappings of sel into slots, can any one of them be completed by drawing from eg?”
--- @param sel Group currently picked materials
--- @param eg Group the full pool (e.g. your material group)
--- @param slots table[] your slot definitions
--- @param handler Card the Fusion monster (for substitutes)
--- @return boolean true if ∃ a mapping + completion path
function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf)
-- arrayify sel so we can refer by index
local cards_sel={}
for c in aux.Next(sel) do
table.insert(cards_sel,c)
end
-- get every possible assignment of sel→slots
local mappings=Fusion.FindAllMappings(cards_sel,slots,handler)
if #mappings==0 then
return false
end
-- 2) build rem_pool = eg minus sel
local rem_pool=Group.CreateGroup()
for c in aux.Next(eg) do
if not sel:IsContains(c) then
rem_pool:AddCard(c)
end
end
-- for each mapping, build what’s still needed and test dfs_fill
for _,mapping in ipairs(mappings) do
-- track what’s been filled
local filled_single={}
local group_need={}
for i,slot in ipairs(slots) do
if slot.group then
group_need[i]=slot.group.min
else
filled_single[i]=false
end
end
-- consume sel into those trackers
for sel_idx,slot_idx in pairs(mapping) do
local slot=slots[slot_idx]
if slot.group then
group_need[slot_idx]=group_need[slot_idx]-1
else
filled_single[slot_idx]=true
end
end
-- build the “leftover” slots list
local rem_slots={}
for i,slot in ipairs(slots) do
if slot.group then
local need=group_need[i] or 0
if need>0 then
-- preserve the full group slot
table.insert(rem_slots,{
group={
min=need,
max=slot.group.max,
filter=slot.group.filter,
}
})
end
else
if not filled_single[i] then
-- single‐slot still unfilled
table.insert(rem_slots,slot)
end
end
end
-- if nothing remains, we already succeed
if #rem_slots==0 then
return true
end
-- 5) delegate to FusionCondition (allow_extras = true)
local search_cond=Fusion.FusionCondition(rem_slots,true)
if search_cond(e,rem_pool,gc,chkf) then
return true
end
end
return false
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment