Commit 786ef25f authored by Vury Leo's avatar Vury Leo

Add ガーディアン・キマイラ

parent 81a1b411
--ガーディアン・キマイラ --ガーディアン・キマイラ
function c11321089.initial_effect(c) local s,id,o=GetID()
function s.initial_effect(c)
aux.AddCodeList(c,24094653) aux.AddCodeList(c,24094653)
c:EnableReviveLimit() c:EnableReviveLimit()
aux.AddFusionProcFunRep(c,c11321089.ffilter,3,false) Fusion.AddFusionProcedure(c,{
slots={
Fusion.Slot.Group({
min=3,
max=3,
unique_by=function(mc) return { mc:GetCode(),mc:GetFusionCode() } end,
})
},
mat_filter=s.mat_filter,
fgoalcheck=s.fgoalcheck,
})
--material limit --material limit
local e0=Effect.CreateEffect(c) local e0=Effect.CreateEffect(c)
e0:SetType(EFFECT_TYPE_SINGLE) e0:SetType(EFFECT_TYPE_SINGLE)
e0:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE) e0:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
e0:SetCode(EFFECT_MATERIAL_LIMIT) e0:SetCode(EFFECT_MATERIAL_LIMIT)
e0:SetValue(c11321089.matlimit) e0:SetValue(s.matlimit)
c:RegisterEffect(e0) c:RegisterEffect(e0)
--spsummon condition --spsummon condition
local e1=Effect.CreateEffect(c) local e1=Effect.CreateEffect(c)
e1:SetType(EFFECT_TYPE_SINGLE) e1:SetType(EFFECT_TYPE_SINGLE)
e1:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE) e1:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
e1:SetCode(EFFECT_SPSUMMON_CONDITION) e1:SetCode(EFFECT_SPSUMMON_CONDITION)
e1:SetValue(c11321089.splimit) e1:SetValue(s.splimit)
c:RegisterEffect(e1) c:RegisterEffect(e1)
--draw --draw
local e2=Effect.CreateEffect(c) local e2=Effect.CreateEffect(c)
e2:SetDescription(aux.Stringid(11321089,0)) e2:SetDescription(aux.Stringid(id,0))
e2:SetCategory(CATEGORY_DRAW+CATEGORY_DESTROY) e2:SetCategory(CATEGORY_DRAW+CATEGORY_DESTROY)
e2:SetType(EFFECT_TYPE_SINGLE+EFFECT_TYPE_TRIGGER_O) e2:SetType(EFFECT_TYPE_SINGLE+EFFECT_TYPE_TRIGGER_O)
e2:SetCode(EVENT_SPSUMMON_SUCCESS) e2:SetCode(EVENT_SPSUMMON_SUCCESS)
e2:SetProperty(EFFECT_FLAG_DELAY) e2:SetProperty(EFFECT_FLAG_DELAY)
e2:SetCountLimit(1,11321089) e2:SetCountLimit(1,id)
e2:SetCondition(c11321089.drcon) e2:SetCondition(s.drcon)
e2:SetTarget(c11321089.drtg) e2:SetTarget(s.drtg)
e2:SetOperation(c11321089.drop) e2:SetOperation(s.drop)
c:RegisterEffect(e2) c:RegisterEffect(e2)
local e3=Effect.CreateEffect(c) local e3=Effect.CreateEffect(c)
e3:SetType(EFFECT_TYPE_SINGLE) e3:SetType(EFFECT_TYPE_SINGLE)
e3:SetCode(EFFECT_MATERIAL_CHECK) e3:SetCode(EFFECT_MATERIAL_CHECK)
e3:SetValue(c11321089.valcheck) e3:SetValue(s.valcheck)
e3:SetLabelObject(e2) e3:SetLabelObject(e2)
c:RegisterEffect(e3) c:RegisterEffect(e3)
--cannot target --cannot target
...@@ -41,30 +52,48 @@ function c11321089.initial_effect(c) ...@@ -41,30 +52,48 @@ function c11321089.initial_effect(c)
e4:SetProperty(EFFECT_FLAG_SINGLE_RANGE) e4:SetProperty(EFFECT_FLAG_SINGLE_RANGE)
e4:SetCode(EFFECT_CANNOT_BE_EFFECT_TARGET) e4:SetCode(EFFECT_CANNOT_BE_EFFECT_TARGET)
e4:SetRange(LOCATION_MZONE) e4:SetRange(LOCATION_MZONE)
e4:SetCondition(c11321089.indcon) e4:SetCondition(s.indcon)
e4:SetValue(aux.tgoval) e4:SetValue(aux.tgoval)
c:RegisterEffect(e4) c:RegisterEffect(e4)
end end
function c11321089.ffilter(c,fc,sub,mg,sg) function s.ffilter(c,fc,sub,mg,sg)
if not sg then return true end if not sg then return true end
local chkloc=LOCATION_HAND local chkloc=LOCATION_HAND
if c:IsOnField() then chkloc=LOCATION_ONFIELD end if c:IsOnField() then chkloc=LOCATION_ONFIELD end
return not sg:IsExists(Card.IsFusionCode,1,c,c:GetFusionCode()) return not sg:IsExists(Card.IsFusionCode,1,c,c:GetFusionCode())
and (not c:IsLocation(LOCATION_HAND+LOCATION_ONFIELD) or #sg<2 or sg:IsExists(aux.NOT(Card.IsLocation),1,c,chkloc)) and (not c:IsLocation(LOCATION_HAND+LOCATION_ONFIELD) or #sg<2 or sg:IsExists(aux.NOT(Card.IsLocation),1,c,chkloc))
end end
function c11321089.matlimit(e,c,fc,st)
function s.fgoalcheck(mg)
-- must include ≥1 from hand and ≥1 from field
local hand,field=0,0
for c in aux.Next(mg) do
if c:IsLocation(LOCATION_HAND) then
hand=hand+1
else
field=field+1
end
end
return hand>=1 and field>=1
end
function s.mat_filter(mc,tc)
return mc:IsLocation(LOCATION_HAND) or mc:IsControler(tc:GetControler()) and mc:IsOnField()
end
function s.matlimit(e,c,fc,st)
if st~=SUMMON_TYPE_FUSION then return true end if st~=SUMMON_TYPE_FUSION then return true end
return c:IsLocation(LOCATION_HAND) or c:IsControler(fc:GetControler()) and c:IsOnField() return c:IsLocation(LOCATION_HAND) or c:IsControler(fc:GetControler()) and c:IsOnField()
end end
function c11321089.splimit(e,se,sp,st) function s.splimit(e,se,sp,st)
return not e:GetHandler():IsLocation(LOCATION_EXTRA) return not e:GetHandler():IsLocation(LOCATION_EXTRA)
or st&SUMMON_TYPE_FUSION==SUMMON_TYPE_FUSION or st&SUMMON_TYPE_FUSION==SUMMON_TYPE_FUSION
end end
function c11321089.drcon(e,tp,eg,ep,ev,re,r,rp) function s.drcon(e,tp,eg,ep,ev,re,r,rp)
local c=e:GetHandler() local c=e:GetHandler()
return re and re:IsActiveType(TYPE_SPELL) and c:IsSummonType(SUMMON_TYPE_FUSION) return re and re:IsActiveType(TYPE_SPELL) and c:IsSummonType(SUMMON_TYPE_FUSION)
end end
function c11321089.drtg(e,tp,eg,ep,ev,re,r,rp,chk) function s.drtg(e,tp,eg,ep,ev,re,r,rp,chk)
local dr,des=e:GetLabel() local dr,des=e:GetLabel()
if chk==0 then return dr and des and Duel.IsPlayerCanDraw(tp,dr) if chk==0 then return dr and des and Duel.IsPlayerCanDraw(tp,dr)
and Duel.GetFieldGroupCount(tp,0,LOCATION_ONFIELD)>=des end and Duel.GetFieldGroupCount(tp,0,LOCATION_ONFIELD)>=des end
...@@ -74,7 +103,7 @@ function c11321089.drtg(e,tp,eg,ep,ev,re,r,rp,chk) ...@@ -74,7 +103,7 @@ function c11321089.drtg(e,tp,eg,ep,ev,re,r,rp,chk)
local g=Duel.GetMatchingGroup(aux.TRUE,tp,0,LOCATION_ONFIELD,nil) local g=Duel.GetMatchingGroup(aux.TRUE,tp,0,LOCATION_ONFIELD,nil)
Duel.SetOperationInfo(0,CATEGORY_DESTROY,g,1,0,0) Duel.SetOperationInfo(0,CATEGORY_DESTROY,g,1,0,0)
end end
function c11321089.drop(e,tp,eg,ep,ev,re,r,rp) function s.drop(e,tp,eg,ep,ev,re,r,rp)
local dr,des=e:GetLabel() local dr,des=e:GetLabel()
if Duel.Draw(tp,dr,REASON_EFFECT)>0 then if Duel.Draw(tp,dr,REASON_EFFECT)>0 then
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_DESTROY) Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_DESTROY)
...@@ -85,12 +114,12 @@ function c11321089.drop(e,tp,eg,ep,ev,re,r,rp) ...@@ -85,12 +114,12 @@ function c11321089.drop(e,tp,eg,ep,ev,re,r,rp)
end end
end end
end end
function c11321089.valcheck(e,c) function s.valcheck(e,c)
local mg=c:GetMaterial() local mg=c:GetMaterial()
local mg1=mg:Filter(Card.IsLocation,nil,LOCATION_HAND) local mg1=mg:Filter(Card.IsLocation,nil,LOCATION_HAND)
local mg2=mg:Filter(Card.IsLocation,nil,LOCATION_ONFIELD) local mg2=mg:Filter(Card.IsLocation,nil,LOCATION_ONFIELD)
e:GetLabelObject():SetLabel(#mg1,#mg2) e:GetLabelObject():SetLabel(#mg1,#mg2)
end end
function c11321089.indcon(e) function s.indcon(e)
return Duel.IsExistingMatchingCard(Card.IsCode,e:GetHandlerPlayer(),LOCATION_GRAVE,0,1,nil,24094653) return Duel.IsExistingMatchingCard(Card.IsCode,e:GetHandlerPlayer(),LOCATION_GRAVE,0,1,nil,24094653)
end end
...@@ -3375,28 +3375,46 @@ end ...@@ -3375,28 +3375,46 @@ end
Fusion={} Fusion={}
function Fusion.AddFusionProcedure(fcard,opts) function Fusion.AddFusionProcedure(tc,opts)
local slots=opts.slots local slots=opts.slots
local mat_filter=opts.mat_filter or nil
local fgoalcheck=opts.fgoalcheck or aux.TRUE
-- Register effect -- Register effect
local e=Effect.CreateEffect(fcard) local e=Effect.CreateEffect(tc)
e:SetType(EFFECT_TYPE_SINGLE) e:SetType(EFFECT_TYPE_SINGLE)
e:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE) e:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
e:SetCode(EFFECT_FUSION_MATERIAL) e:SetCode(EFFECT_FUSION_MATERIAL)
e:SetCondition(Fusion.FusionCondition(slots,true)) e:SetCondition(Fusion.FusionCondition(tc,slots,mat_filter,fgoalcheck,true))
e:SetOperation(Fusion.FusionOperation(slots)) e:SetOperation(Fusion.FusionOperation(tc,slots,mat_filter,fgoalcheck))
e:SetDescription(1379) --- 启用扩展卡包调试模式 e:SetDescription(1379) --- 启用扩展卡包调试模式
fcard:RegisterEffect(e) tc:RegisterEffect(e)
end end
---@param allow_extras boolean whether to allow extra materials for checking propose ---@param allow_extras boolean whether to allow extra materials for checking propose
function Fusion.FusionCondition(slots,allow_extras) function Fusion.FusionCondition(tc,slots,mat_filter,fgoalcheck,allow_extras,selected)
--g:Material group(nil for Instant Fusion) --g:Material group(nil for Instant Fusion)
--gc:Material already used --gc:Material already used
--chkf: check field, default:PLAYER_NONE --chkf: check field, default:PLAYER_NONE
--chkf&0x100: Not fusion summon, can use substitute (Hex-Sealed Fusion) --chkf&0x100: Not fusion summon, can use substitute (Hex-Sealed Fusion)
--chkf&0x200: Not fusion summon, can't use substitute ("Contact Fusion", Neos Fusion) --chkf&0x200: Not fusion summon, can't use substitute ("Contact Fusion", Neos Fusion)
return function(e,g,gc,chkf) return function(e,g,gc,chkf)
if not g or g:GetCount()<#slots then return false end if not g then return false end
-- array
local cards={}
for mc in aux.Next(g) do
table.insert(cards,mc)
end
-- apply the global mat_filter if present
if mat_filter~=nil then
local tg={}
for _,mc in ipairs(cards) do
if mat_filter(mc,tc) then
table.insert(tg,mc)
end
end
cards=tg
end
if #cards<#slots then return false end
-- split slots -- split slots
local single_slots, group_slots = {}, {} local single_slots, group_slots = {}, {}
for _, slot in ipairs(slots) do for _, slot in ipairs(slots) do
...@@ -3415,11 +3433,6 @@ function Fusion.FusionCondition(slots,allow_extras) ...@@ -3415,11 +3433,6 @@ function Fusion.FusionCondition(slots,allow_extras)
return false return false
end end
local cards={}
for tc in aux.Next(g) do
table.insert(cards,tc)
end
local used={} local used={}
local sub_count=0 local sub_count=0
-- DFS assign slots -- DFS assign slots
...@@ -3427,17 +3440,17 @@ function Fusion.FusionCondition(slots,allow_extras) ...@@ -3427,17 +3440,17 @@ function Fusion.FusionCondition(slots,allow_extras)
if i>#single_slots then if i>#single_slots then
-- check group slots on leftovers -- check group slots on leftovers
local leftovers={} local leftovers={}
for idx,tc in ipairs(cards) do for idx,mc in ipairs(cards) do
if not used[idx] then if not used[idx] then
table.insert(leftovers,tc) table.insert(leftovers,mc)
end end
end end
-- if strict (no extra), ensure leftover only match group slots -- if strict (no extra), ensure leftover only match group slots
if not allow_extras then if not allow_extras then
for _,tc in ipairs(leftovers) do for _,mc in ipairs(leftovers) do
local ok=false local ok=false
for _,grp in ipairs(group_slots) do for _,grp in ipairs(group_slots) do
if (not grp.filter or grp.filter(tc)) then if (not grp.filter or grp.filter(mc)) then
ok=true ok=true
break break
end end
...@@ -3451,9 +3464,9 @@ function Fusion.FusionCondition(slots,allow_extras) ...@@ -3451,9 +3464,9 @@ function Fusion.FusionCondition(slots,allow_extras)
for _,grp in ipairs(group_slots) do for _,grp in ipairs(group_slots) do
-- collect exactly the cards from leftovers that match this grp -- collect exactly the cards from leftovers that match this grp
local matched={} local matched={}
for _,tc in ipairs(leftovers) do for _,mc in ipairs(leftovers) do
if (not grp.filter or grp.filter(tc)) then if (not grp.filter or grp.filter(mc)) then
table.insert(matched,tc) table.insert(matched,mc)
end end
end end
-- cardinality check -- cardinality check
...@@ -3579,6 +3592,16 @@ function Fusion.FusionCondition(slots,allow_extras) ...@@ -3579,6 +3592,16 @@ function Fusion.FusionCondition(slots,allow_extras)
end end
end end
end end
if fgoalcheck then
--- merge selected card if provided
local mg=g:Clone()
if selected then
mg:Merge(selected)
end
if not fgoalcheck(mg) then
return false
end
end
return true return true
end end
...@@ -3594,9 +3617,9 @@ function Fusion.FusionCondition(slots,allow_extras) ...@@ -3594,9 +3617,9 @@ function Fusion.FusionCondition(slots,allow_extras)
end end
-- try each card -- try each card
local slot=single_slots[i] local slot=single_slots[i]
for idx,tc in ipairs(cards) do for idx,mc in ipairs(cards) do
if not used[idx] then if not used[idx] then
local match,is_sub=Fusion.MatchSlot(tc,slot,e:GetHandler()) local match,is_sub=Fusion.MatchSlot(mc,slot,tc)
if match==true then if match==true then
used[idx]=true used[idx]=true
local prev_sub=sub_count local prev_sub=sub_count
...@@ -3647,10 +3670,20 @@ end ...@@ -3647,10 +3670,20 @@ end
--- Generator: operation from named slots --- Generator: operation from named slots
---@param slots table[] ---@param slots table[]
function Fusion.FusionOperation(slots) function Fusion.FusionOperation(tc,slots,mat_filter,fgoalcheck)
return function(e,tp,eg,ep,ev,re,rp,gc,chkf) return function(e,tp,eg,ep,ev,re,rp,gc,chkf)
if mat_filter then
local pool=eg
pool=Group.CreateGroup()
for mc in aux.Next(eg) do
if mat_filter(mc,e:GetHandler()) then
pool:AddCard(mc)
end
end
eg=pool
end
-- strict final check (no extras) -- strict final check (no extras)
local strict_cond=Fusion.FusionCondition(slots,false) local strict_cond=Fusion.FusionCondition(tc,slots,mat_filter,fgoalcheck,false)
-- precompute minimum materials required -- precompute minimum materials required
local min_req=0 local min_req=0
local max_req=0 local max_req=0
...@@ -3677,18 +3710,18 @@ function Fusion.FusionOperation(slots) ...@@ -3677,18 +3710,18 @@ function Fusion.FusionOperation(slots)
local addable=Group.CreateGroup() local addable=Group.CreateGroup()
local candidates={} local candidates={}
for tc in aux.Next(eg) do for mc in aux.Next(eg) do
if not sg:IsContains(tc) then if not sg:IsContains(mc) then
table.insert(candidates,tc) table.insert(candidates,mc)
end end
end end
for _,tc in ipairs(candidates) do for _,mc in ipairs(candidates) do
sg:AddCard(tc) sg:AddCard(mc)
if Fusion.CanCompleteFromMappings(e,sg,eg,slots,e:GetHandler(),gc,chkf) then if Fusion.CanCompleteFromMappings(e,sg,eg,slots,mat_filter,fgoalcheck,tc,gc,chkf) then
addable:AddCard(tc) addable:AddCard(mc)
end end
sg:RemoveCard(tc) sg:RemoveCard(mc)
end end
if addable:GetCount()==0 then if addable:GetCount()==0 then
...@@ -3905,9 +3938,9 @@ end ...@@ -3905,9 +3938,9 @@ end
--- @param sel Group currently picked materials --- @param sel Group currently picked materials
--- @param eg Group the full pool (e.g. your material group) --- @param eg Group the full pool (e.g. your material group)
--- @param slots table[] your slot definitions --- @param slots table[] your slot definitions
--- @param handler Card the Fusion monster (for substitutes) --- @param tc Card the Fusion monster (for substitutes)
--- @return boolean true if ∃ a mapping + completion path --- @return boolean true if ∃ a mapping + completion path
function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf) function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,gc,chkf)
-- arrayify sel so we can refer by index -- arrayify sel so we can refer by index
local cards_sel={} local cards_sel={}
for c in aux.Next(sel) do for c in aux.Next(sel) do
...@@ -3915,7 +3948,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf) ...@@ -3915,7 +3948,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf)
end end
-- get every possible assignment of sel→slots -- get every possible assignment of sel→slots
local mappings=Fusion.FindAllMappings(cards_sel,slots,handler) local mappings=Fusion.FindAllMappings(cards_sel,slots,tc)
if #mappings==0 then if #mappings==0 then
return false return false
end end
...@@ -3980,7 +4013,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf) ...@@ -3980,7 +4013,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf)
-- fold each selected card’s fn(...) into either bitmask or keytbl -- fold each selected card’s fn(...) into either bitmask or keytbl
for idx,mapped_i in pairs(mapping) do for idx,mapped_i in pairs(mapping) do
if mapped_i==i then if mapped_i==i then
local v=fn(cards_sel[idx],handler) local v=fn(cards_sel[idx],tc)
if type(v)=="number" then if type(v)=="number" then
bitmask=bitmask and (bitmask&v) or v bitmask=bitmask and (bitmask&v) or v
elseif type(v)=="table" then elseif type(v)=="table" then
...@@ -4006,7 +4039,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf) ...@@ -4006,7 +4039,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf)
end end
-- for each fn in has_same, check against the precomputed overlap -- for each fn in has_same, check against the precomputed overlap
for fn,overlap in pairs(used_overlap) do for fn,overlap in pairs(used_overlap) do
local v=fn(mc,handler) local v=fn(mc,tc)
if type(overlap)=="number" then if type(overlap)=="number" then
-- bitmask path -- bitmask path
if (overlap&v)==0 then if (overlap&v)==0 then
...@@ -4030,7 +4063,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf) ...@@ -4030,7 +4063,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf)
end end
end end
end end
if need>0 then if slot.group.max-slot.group.min+need>0 then
-- preserve the full group slot -- preserve the full group slot
table.insert(rem_slots,{ table.insert(rem_slots,{
group={ group={
...@@ -4050,13 +4083,17 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf) ...@@ -4050,13 +4083,17 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,handler,gc,chkf)
end end
end end
-- if nothing remains, we already succeed -- if nothing remains, we already succeed, check fgoal
if #rem_slots==0 then if #rem_slots==0 then
return true if fgoalcheck==nil or fgoalcheck(sel)==true then
return true
else
return false
end
end end
-- delegate to FusionCondition (allow_extras = true) -- delegate to FusionCondition (allow_extras = true)
local search_cond=Fusion.FusionCondition(rem_slots,true) local search_cond=Fusion.FusionCondition(tc,rem_slots,mat_filter,fgoalcheck,true,sel)
if search_cond(e,rem_pool,gc,chkf) then if search_cond(e,rem_pool,gc,chkf) then
return true return true
end 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