Commit 2afce688 authored by Vury Leo's avatar Vury Leo

Add LockedCodes

parent 9150d818
--ブルーアイズ・タイラント・ドラゴン
function c11443677.initial_effect(c)
local s,id,o=GetID()
function s.initial_effect(c)
--fusion material
c:EnableReviveLimit()
aux.AddFusionProcCodeFun(c,89631139,aux.FilterBoolFunction(Card.IsRace,RACE_DRAGON),1,true,true)
-- aux.AddFusionProcCodeFun(c,89631139,aux.FilterBoolFunction(Card.IsRace,RACE_DRAGON),1,true,true)
Fusion.AddFusionProcedure(c,{
slots={
Fusion.Slot.Code(89631139),
Fusion.Slot.Filter(function(mc,tc) return mc:IsRace(RACE_DRAGON) end),
}
})
--special summon condition
local e1=Effect.CreateEffect(c)
e1:SetType(EFFECT_TYPE_SINGLE)
......@@ -17,9 +24,9 @@ function c11443677.initial_effect(c)
e2:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
e2:SetCode(EFFECT_SPSUMMON_PROC)
e2:SetRange(LOCATION_EXTRA)
e2:SetCondition(c11443677.sprcon)
e2:SetTarget(c11443677.sprtg)
e2:SetOperation(c11443677.sprop)
e2:SetCondition(s.sprcon)
e2:SetTarget(s.sprtg)
e2:SetOperation(s.sprop)
c:RegisterEffect(e2)
--immune
local e3=Effect.CreateEffect(c)
......@@ -27,7 +34,7 @@ function c11443677.initial_effect(c)
e3:SetCode(EFFECT_IMMUNE_EFFECT)
e3:SetProperty(EFFECT_FLAG_SINGLE_RANGE)
e3:SetRange(LOCATION_MZONE)
e3:SetValue(c11443677.efilter)
e3:SetValue(s.efilter)
c:RegisterEffect(e3)
--attack all
local e4=Effect.CreateEffect(c)
......@@ -37,32 +44,32 @@ function c11443677.initial_effect(c)
c:RegisterEffect(e4)
--set trap
local e5=Effect.CreateEffect(c)
e5:SetDescription(aux.Stringid(11443677,0))
e5:SetDescription(aux.Stringid(id,0))
e5:SetType(EFFECT_TYPE_SINGLE+EFFECT_TYPE_TRIGGER_O)
e5:SetCode(EVENT_DAMAGE_STEP_END)
e5:SetProperty(EFFECT_FLAG_CARD_TARGET)
e5:SetCondition(c11443677.setcon)
e5:SetTarget(c11443677.settg)
e5:SetOperation(c11443677.setop)
e5:SetCondition(s.setcon)
e5:SetTarget(s.settg)
e5:SetOperation(s.setop)
c:RegisterEffect(e5)
end
function c11443677.ultimate_fusion_check(tp,sg,fc)
function s.ultimate_fusion_check(tp,sg,fc)
return aux.gffcheck(sg,Card.IsFusionCode,89631139,Card.IsRace,RACE_DRAGON)
end
function c11443677.cfilter(c)
function s.cfilter(c)
return c:IsFaceup() and c:GetOriginalType()&TYPE_FUSION~=0
end
function c11443677.sprfilter(c,tp,sc)
local eqc=c:GetEquipGroup():FilterCount(c11443677.cfilter,nil)
function s.sprfilter(c,tp,sc)
local eqc=c:GetEquipGroup():FilterCount(s.cfilter,nil)
return c:IsFusionCode(89631139) and eqc>0 and Duel.GetLocationCountFromEx(tp,tp,c,sc)>0 and c:IsCanBeFusionMaterial(sc,SUMMON_TYPE_SPECIAL)
end
function c11443677.sprcon(e,c)
function s.sprcon(e,c)
if c==nil then return true end
local tp=c:GetControler()
return Duel.CheckReleaseGroupEx(tp,c11443677.sprfilter,1,REASON_SPSUMMON,false,nil,tp,c)
return Duel.CheckReleaseGroupEx(tp,s.sprfilter,1,REASON_SPSUMMON,false,nil,tp,c)
end
function c11443677.sprtg(e,tp,eg,ep,ev,re,r,rp,chk,c)
local g=Duel.GetReleaseGroup(tp,false,REASON_SPSUMMON):Filter(c11443677.sprfilter,nil,tp,c)
function s.sprtg(e,tp,eg,ep,ev,re,r,rp,chk,c)
local g=Duel.GetReleaseGroup(tp,false,REASON_SPSUMMON):Filter(s.sprfilter,nil,tp,c)
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_RELEASE)
local tc=g:SelectUnselect(nil,tp,false,true,1,1)
if tc then
......@@ -70,31 +77,31 @@ function c11443677.sprtg(e,tp,eg,ep,ev,re,r,rp,chk,c)
return true
else return false end
end
function c11443677.sprop(e,tp,eg,ep,ev,re,r,rp,c)
function s.sprop(e,tp,eg,ep,ev,re,r,rp,c)
local tc=e:GetLabelObject()
c:SetMaterial(Group.FromCards(tc))
Duel.Release(tc,REASON_SPSUMMON)
end
function c11443677.efilter(e,te)
function s.efilter(e,te)
return te:IsActiveType(TYPE_TRAP)
end
function c11443677.setcon(e,tp,eg,ep,ev,re,r,rp)
return e:GetHandler():GetFlagEffect(11443677)==0 and aux.dsercon(e,tp,eg,ep,ev,re,r,rp)
function s.setcon(e,tp,eg,ep,ev,re,r,rp)
return e:GetHandler():GetFlagEffect(id)==0 and aux.dsercon(e,tp,eg,ep,ev,re,r,rp)
end
function c11443677.setfilter(c)
function s.setfilter(c)
return c:IsType(TYPE_TRAP) and c:IsSSetable()
end
function c11443677.settg(e,tp,eg,ep,ev,re,r,rp,chk,chkc)
if chkc then return chkc:IsLocation(LOCATION_GRAVE) and chkc:IsControler(tp) and c11443677.setfilter(chkc) end
if chk==0 then return Duel.IsExistingTarget(c11443677.setfilter,tp,LOCATION_GRAVE,0,1,nil) end
function s.settg(e,tp,eg,ep,ev,re,r,rp,chk,chkc)
if chkc then return chkc:IsLocation(LOCATION_GRAVE) and chkc:IsControler(tp) and s.setfilter(chkc) end
if chk==0 then return Duel.IsExistingTarget(s.setfilter,tp,LOCATION_GRAVE,0,1,nil) end
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SET)
local g=Duel.SelectTarget(tp,c11443677.setfilter,tp,LOCATION_GRAVE,0,1,1,nil)
local g=Duel.SelectTarget(tp,s.setfilter,tp,LOCATION_GRAVE,0,1,1,nil)
Duel.SetOperationInfo(0,CATEGORY_LEAVE_GRAVE,g,1,0,0)
if e:IsCostChecked() then
e:GetHandler():RegisterFlagEffect(11443677,RESET_EVENT|RESET_TOFIELD|RESET_TURN_SET|RESET_PHASE|PHASE_END,0,0,1)
e:GetHandler():RegisterFlagEffect(id,RESET_EVENT|RESET_TOFIELD|RESET_TURN_SET|RESET_PHASE|PHASE_END,0,0,1)
end
end
function c11443677.setop(e,tp,eg,ep,ev,re,r,rp)
function s.setop(e,tp,eg,ep,ev,re,r,rp)
local tc=Duel.GetFirstTarget()
if tc:IsRelateToEffect(e) then
Duel.SSet(tp,tc)
......
--青眼の双爆裂龍
function c2129638.initial_effect(c)
local s,id,o=GetID()
function s.initial_effect(c)
--fusion material
c:EnableReviveLimit()
aux.AddFusionProcCodeRep(c,89631139,2,true,true)
-- aux.AddFusionProcCodeRep(c,89631139,2,true,true)
Fusion.AddFusionProcedure(c,{
slots={
Fusion.Slot.Code(89631139),
Fusion.Slot.Code(89631139),
}
})
aux.AddContactFusionProcedure(c,Card.IsAbleToGraveAsCost,LOCATION_MZONE,0,Duel.SendtoGrave,REASON_COST)
--spsummon condition
local e1=Effect.CreateEffect(c)
e1:SetType(EFFECT_TYPE_SINGLE)
e1:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
e1:SetCode(EFFECT_SPSUMMON_CONDITION)
e1:SetValue(c2129638.splimit)
e1:SetValue(s.splimit)
c:RegisterEffect(e1)
--indes
local e3=Effect.CreateEffect(c)
......@@ -29,30 +36,30 @@ function c2129638.initial_effect(c)
c:RegisterEffect(e4)
--remove
local e7=Effect.CreateEffect(c)
e7:SetDescription(aux.Stringid(2129638,0))
e7:SetDescription(aux.Stringid(id,0))
e7:SetCategory(CATEGORY_REMOVE)
e7:SetType(EFFECT_TYPE_SINGLE+EFFECT_TYPE_TRIGGER_O)
e7:SetCode(EVENT_DAMAGE_STEP_END)
e7:SetCondition(c2129638.rmcon)
e7:SetTarget(c2129638.rmtg)
e7:SetOperation(c2129638.rmop)
e7:SetCondition(s.rmcon)
e7:SetTarget(s.rmtg)
e7:SetOperation(s.rmop)
c:RegisterEffect(e7)
end
function c2129638.splimit(e,se,sp,st)
function s.splimit(e,se,sp,st)
return bit.band(st,SUMMON_TYPE_FUSION)==SUMMON_TYPE_FUSION
end
function c2129638.rmcon(e,tp,eg,ep,ev,re,r,rp)
function s.rmcon(e,tp,eg,ep,ev,re,r,rp)
local c=e:GetHandler()
local bc=c:GetBattleTarget()
e:SetLabelObject(bc)
return c==Duel.GetAttacker() and aux.dsercon(e,tp,eg,ep,ev,re,r,rp)
and bc and c:IsStatus(STATUS_OPPO_BATTLE) and bc:IsOnField() and bc:IsRelateToBattle()
end
function c2129638.rmtg(e,tp,eg,ep,ev,re,r,rp,chk)
function s.rmtg(e,tp,eg,ep,ev,re,r,rp,chk)
if chk==0 then return e:GetLabelObject():IsAbleToRemove() end
Duel.SetOperationInfo(0,CATEGORY_REMOVE,e:GetLabelObject(),1,0,0)
end
function c2129638.rmop(e,tp,eg,ep,ev,re,r,rp)
function s.rmop(e,tp,eg,ep,ev,re,r,rp)
local bc=e:GetLabelObject()
if bc:IsRelateToBattle() then
Duel.Remove(bc,POS_FACEUP,REASON_EFFECT)
......
......@@ -6,7 +6,8 @@ function s.initial_effect(c)
local e1=FusionSpell.CreateSummonEffect(c,{
fusfilter=s.fusfilter,
pre_select_mat_location=LOCATION_HAND|LOCATION_DECK|LOCATION_MZONE,
additional_fcheck=s.fcheck
additional_fcheck=s.fcheck,
locked_codes={68468459},
})
e1:SetCategory(CATEGORY_SPECIAL_SUMMON+CATEGORY_FUSION_SUMMON+CATEGORY_DECKDES)
e1:SetCountLimit(1,id+EFFECT_COUNT_CODE_OATH)
......@@ -44,14 +45,14 @@ function s.fcheck(tp,mg,fc,mg_all)
if #mg_all>2 then
return false
end
if fc.branded_fusion_check~=nil then
if fc.branded_fusion_check(tp,mg_all,fc)==false then
return false
end
else
if not mg_all:IsExists(function(c) return c:IsFusionCode(68468459) end,1,nil) then
return false
end
end
-- if fc.branded_fusion_check~=nil then
-- if fc.branded_fusion_check(tp,mg_all,fc)==false then
-- return false
-- end
-- else
-- if not mg_all:IsExists(function(c) return c:IsFusionCode(68468459) end,1,nil) then
-- return false
-- end
-- end
return true
end
......@@ -3,7 +3,13 @@ local s,id,o=GetID()
function s.initial_effect(c)
--fusion material
c:EnableReviveLimit()
aux.AddFusionProcCodeFun(c,68468459,aux.FilterBoolFunction(Card.IsFusionAttribute,ATTRIBUTE_DARK),1,true,true)
-- aux.AddFusionProcCodeFun(c,68468459,aux.FilterBoolFunction(Card.IsFusionAttribute,ATTRIBUTE_DARK),1,true,true)
Fusion.AddFusionProcedure(c,{
slots={
Fusion.Slot.Code(68468459),
Fusion.Slot.Filter(function(mc,tc) return mc:IsFusionAttribute(ATTRIBUTE_DARK,tc:GetOwner()) end),
}
})
--spsummon
local e1=FusionSpell.CreateSummonEffect(c,{
fusfilter=s.fusfilter,
......
......@@ -10,7 +10,8 @@ function s.initial_effect(c)
{ [LOCATION_DECK]=FusionSpell.FUSION_OPERATION_GRAVE },
{ [0xff]=FusionSpell.FUSION_OPERATION_SHUFFLE }
},
stage_x_operation=s.stage_x_operation
stage_x_operation=s.stage_x_operation,
locked_codes={89631139,23995346}
})
e1:SetCategory(CATEGORY_SPECIAL_SUMMON+CATEGORY_FUSION_SUMMON+CATEGORY_GRAVE_ACTION)
e1:SetHintTiming(0,TIMINGS_CHECK_MONSTER+TIMING_MAIN_END)
......@@ -34,9 +35,9 @@ function s.fcheck(tp,mg,fc,mg_all)
if fc.ultimate_fusion_check(tp,mg_all,fc)==false then
return false
end
elseif not (mg_all:IsExists(function(c) return c:IsFusionCode(89631139) end,1,nil) and aux.IsMaterialListCode(fc,89631139)==true
or mg_all:IsExists(function(c) return c:IsFusionCode(23995346) end,1,nil) and aux.IsMaterialListCode(fc,23995346)==true) then
return false
-- elseif not (mg_all:IsExists(function(c) return c:IsFusionCode(89631139) end,1,nil) and aux.IsMaterialListCode(fc,89631139)==true
-- or mg_all:IsExists(function(c) return c:IsFusionCode(23995346) end,1,nil) and aux.IsMaterialListCode(fc,23995346)==true) then
-- return false
end
return true
end
......
......@@ -2254,6 +2254,8 @@ FusionSpell = {}
--- @field skip_summon_check? boolean
--- Whether skip the location count check, default false, used for 叛逆の堕天使, only works for target function
--- @field skip_location_count_check? boolean
--- Locked code, material code that can not use substitutes
--- @field locked_codes? integer[]
--- Add LOCATION_EXTRA and opponent mzone to EFFECT_EXTRA_FUSION_MATERIAL list, remove once core updated
......@@ -2334,6 +2336,7 @@ function FusionSpell.CreateSummonEffect(c,opts)
local fusion_spell_matfilter=opts.fusion_spell_matfilter or aux.TRUE
local skip_summon_check=opts.skip_summon_check or false
local skip_location_count_check=opts.skip_location_count_check or false
local locked_codes=opts.locked_codes or {}
-- Ensure material operation fallbacks are present
table.insert(mat_operation_code_map,{ [LOCATION_GRAVE] = FusionSpell.FUSION_OPERATION_BANISH })
......@@ -2361,7 +2364,8 @@ function FusionSpell.CreateSummonEffect(c,opts)
gc,
fusion_spell_matfilter,
skip_summon_check,
skip_location_count_check
skip_location_count_check,
locked_codes
))
e1:SetOperation(FusionSpell.GetSummonOperation(
fusfilter,
......@@ -2379,7 +2383,8 @@ function FusionSpell.CreateSummonEffect(c,opts)
post_select_mat_opponent_location,
gc,
fusion_spell_matfilter,
skip_summon_check
skip_summon_check,
locked_codes
))
e1:SetDescription(1169) --- 融合召喚
return e1
......@@ -2402,6 +2407,7 @@ end
---@param fusion_spell_matfilter FUSION_SPELL_MATFILTER_FUNCTION a material must pass this to be legal as material come from fusion spell
---@param skip_summon_check boolean whether skip the IsCanBeSpecialSummoned check, for クロック・リザード
---@param skip_location_count_check boolean Whether skip the location count check, default false, used for 叛逆の堕天使
---@param locked_codes integer[] Locked code, material code that can not use substitutes, used for 烙印融合
function FusionSpell.GetSummonTarget(
fusfilter,
matfilter,
......@@ -2419,7 +2425,8 @@ function FusionSpell.GetSummonTarget(
gc,
fusion_spell_matfilter,
skip_summon_check,
skip_location_count_check
skip_location_count_check,
locked_codes
)
return function(e,tp,eg,ep,ev,re,r,rp,chk)
if chk==0 then
......@@ -2444,7 +2451,8 @@ function FusionSpell.GetSummonTarget(
gc,
fusion_spell_matfilter,
skip_summon_check,
skip_location_count_check)
skip_location_count_check,
locked_codes)
end,
tp,fuslocation,0,1,nil)
if sg==true then
......@@ -2480,6 +2488,7 @@ end
---@param gc fun(e:Effect):Card|nil Function that returns a card that must be included in the fusion materials
---@param fusion_spell_matfilter FUSION_SPELL_MATFILTER_FUNCTION a material must pass this to be legal as material come from fusion spell
---@param skip_summon_check boolean whether skip the IsCanBeSpecialSummoned check, for クロック・リザード
---@param locked_codes integer[] Locked code, material code that can not use substitutes, used for 烙印融合
function FusionSpell.GetSummonOperation(
fusfilter,
matfilter,
......@@ -2496,7 +2505,8 @@ function FusionSpell.GetSummonOperation(
post_select_mat_opponent_location,
gc,
fusion_spell_matfilter,
skip_summon_check
skip_summon_check,
locked_codes
)
return function(e,tp,eg,ep,ev,re,r,rp)
local tc=nil
......@@ -2521,14 +2531,15 @@ function FusionSpell.GetSummonOperation(
gc,
fusion_spell_matfilter,
skip_summon_check,
false --[[skip_location_count_check]])
false --[[skip_location_count_check]],
locked_codes)
end,
tp,fuslocation,0,nil)
fusion_targets:Merge(sg)
--- check for chain material targets
local ce_sgs={}
if sumtype&SUMMON_TYPE_FUSION~=0 then
ce_sgs=FusionSpell.ListChainMaterialSummonTargets(e,tp,fusfilter,aux.NecroValleyFilter(matfilter),additional_fcheck,additional_fgoalcheck,fuslocation,sumtype,sumpos,gc,skip_summon_check,false--[[skip_location_count_check]])
ce_sgs=FusionSpell.ListChainMaterialSummonTargets(e,tp,fusfilter,aux.NecroValleyFilter(matfilter),additional_fcheck,additional_fgoalcheck,fuslocation,sumtype,sumpos,gc,skip_summon_check,false--[[skip_location_count_check]],locked_codes)
--- add chain material targets
for _,ce_sg in pairs(ce_sgs) do
fusion_targets:Merge(ce_sg)
......@@ -2586,9 +2597,11 @@ function FusionSpell.GetSummonOperation(
e,
mat_operation_code_map)
aux.FGoalCheckAdditional=FusionSpell.GetFusionSpellFGoalCheckAdditionalFunction(additional_fgoalcheck,tp,tc,pre_select_mat_location,e)
Fusion.LockedCodes=locked_codes
materials=Duel.SelectFusionMaterial(tp,tc,mg,gc(e),tp)
aux.FCheckAdditional=nil
aux.FGoalCheckAdditional=nil
Fusion.LockedCodes=nil
else
--- use chain material effect
---@type function
......@@ -2597,9 +2610,11 @@ function FusionSpell.GetSummonOperation(
assert(#chain_mg>0, "we are trying to apply a chain material, but it has no possible material")
aux.FCheckAdditional=FusionSpell.GetFusionSpellFCheckAdditionalFunctionForChainMaterial(additional_fcheck,e)
aux.FGoalCheckAdditional=FusionSpell.GetFusionSpellFGoalCheckAdditionalFunctionForChainMaterial(additional_fgoalcheck,e)
Fusion.LockedCodes=locked_codes
materials=Duel.SelectFusionMaterial(tp,tc,chain_mg,gc(e),tp)
aux.FCheckAdditional=nil
aux.FGoalCheckAdditional=nil
Fusion.LockedCodes=nil
end
end
......@@ -2864,6 +2879,7 @@ end
---@param fusion_spell_matfilter fun(c:Card):boolean a material must pass this to be legal as material come from fusion spell
---@param skip_summon_check boolean whether skip the IsCanBeSpecialSummoned check, for クロック・リザード
---@param skip_location_count_check boolean Whether skip the location count check, default false, used for 叛逆の堕天使
---@param locked_codes integer[] Locked code, material code that can not use substitutes, used for 烙印融合
function FusionSpell.SummonTargetFilter(
c,
fusfilter,
......@@ -2882,7 +2898,8 @@ function FusionSpell.SummonTargetFilter(
gc,
fusion_spell_matfilter,
skip_summon_check,
skip_location_count_check)
skip_location_count_check,
locked_codes)
if not c:IsType(TYPE_FUSION) or fusfilter(c,e,tp)==false then
return false
end
......@@ -2915,10 +2932,12 @@ function FusionSpell.SummonTargetFilter(
e,
mat_operation_code_map)
aux.FGoalCheckAdditional=FusionSpell.GetFusionSpellFGoalCheckAdditionalFunction(additional_fgoalcheck,tp,c,pre_select_mat_location,e)
Fusion.LockedCodes=locked_codes
local chkf=FusionSpell.GetCheckFieldPlayer(tp,skip_location_count_check)
local res=c:CheckFusionMaterial(mg,gc(e),chkf)
aux.FCheckAdditional=nil
aux.FGoalCheckAdditional=nil
Fusion.LockedCodes=nil
return res
end
......@@ -2927,7 +2946,7 @@ end
---@param skip_summon_check boolean whether skip the IsCanBeSpecialSummoned check, for クロック・リザード
---@param skip_location_count_check boolean Whether skip the location count check, default false, used for 叛逆の堕天使
---@return {[Effect]:Group} effect_targets_map Return a map of different chain material to potiential fusion targets
function FusionSpell.ListChainMaterialSummonTargets(e,tp,fusfilter,matfilter,additional_fcheck,additional_fgoalcheck,fuslocation,sumtype,sumpos,gc,skip_summon_check,skip_location_count_check)
function FusionSpell.ListChainMaterialSummonTargets(e,tp,fusfilter,matfilter,additional_fcheck,additional_fgoalcheck,fuslocation,sumtype,sumpos,gc,skip_summon_check,skip_location_count_check,locked_codes)
local chain_material_effects={Duel.IsPlayerAffectedByEffect(tp,EFFECT_CHAIN_MATERIAL)}
---@type {[Effect]:Group}
local chain_material_targets={}
......@@ -2939,7 +2958,7 @@ function FusionSpell.ListChainMaterialSummonTargets(e,tp,fusfilter,matfilter,add
if #chain_mg>0 then
local ce_fusfilter=ce:GetValue()
local ce_sg=Duel.GetMatchingGroup(function(c)
return FusionSpell.ChainMaterialSummonTargetFilter(c,aux.AND(ce_fusfilter,fusfilter),e,tp,chain_mg,additional_fcheck,additional_fgoalcheck,sumtype,sumpos,gc,skip_summon_check,skip_location_count_check)
return FusionSpell.ChainMaterialSummonTargetFilter(c,aux.AND(ce_fusfilter,fusfilter),e,tp,chain_mg,additional_fcheck,additional_fgoalcheck,sumtype,sumpos,gc,skip_summon_check,skip_location_count_check,locked_codes)
end,tp,fuslocation,0,nil)
if #ce_sg>0 then
chain_material_targets[ce]=ce_sg
......@@ -2982,7 +3001,7 @@ end
---@param skip_summon_check boolean whether skip the IsCanBeSpecialSummoned check, for クロック・リザード
---@param skip_location_count_check boolean Whether skip the location count check, default false, used for 叛逆の堕天使
---@return boolean result Whether c could be fusion summoned by this chain material effect
function FusionSpell.ChainMaterialSummonTargetFilter(c,fusfilter,e,tp,mg,additional_fcheck,additional_fgoalcheck,sumtype,sumpos,gc,skip_summon_check,skip_location_count_check)
function FusionSpell.ChainMaterialSummonTargetFilter(c,fusfilter,e,tp,mg,additional_fcheck,additional_fgoalcheck,sumtype,sumpos,gc,skip_summon_check,skip_location_count_check,locked_codes)
if not c:IsType(TYPE_FUSION) or fusfilter(c,e,tp)==false then
return false
end
......@@ -2993,10 +3012,12 @@ function FusionSpell.ChainMaterialSummonTargetFilter(c,fusfilter,e,tp,mg,additio
end
aux.FCheckAdditional=FusionSpell.GetFusionSpellFCheckAdditionalFunctionForChainMaterial(additional_fcheck,e)
aux.FGoalCheckAdditional=FusionSpell.GetFusionSpellFGoalCheckAdditionalFunctionForChainMaterial(additional_fgoalcheck,e)
Fusion.LockedCodes=locked_codes
local chkf=FusionSpell.GetCheckFieldPlayer(tp,skip_location_count_check)
local res=c:CheckFusionMaterial(mg,gc(e),chkf)
aux.FCheckAdditional=nil
aux.FGoalCheckAdditional=nil
Fusion.LockedCodes=nil
return res
end
......@@ -3375,19 +3396,61 @@ end
Fusion={}
function Fusion.AddFusionProcedure(tc,opts)
--- locked codes
Fusion.LockedCodes=nil
function Fusion.AddFusionProcedure(c,opts)
local slots=opts.slots
local mat_filter=opts.mat_filter or nil
local fgoalcheck=opts.fgoalcheck or aux.TRUE
-- Register metadata
if c:IsStatus(STATUS_COPYING_EFFECT) then return end
local mat={}
local min_req=0
local max_req=0
for _,slot in ipairs(slots) do
if slot.match_code then
mat[slot.match_code]=true
min_req=min_req+1
max_req=max_req+1
elseif slot.match_codes then
for _,code in ipairs(slot.match_codes) do
mat[code]=true
end
min_req=min_req+1
max_req=max_req+1
elseif slot.filter then
local prev=slot.filter
slot.filter=function(mc,p_tc) return prev(mc,p_tc) and not mc:IsHasEffect(6205579) end
min_req=min_req+1
max_req=max_req+1
elseif slot.group then
local prev=slot.group.filter
slot.group.filter=function(mc,p_tc) return prev(mc,p_tc) and not mc:IsHasEffect(6205579) end
min_req=min_req+slot.group.min
max_req=max_req+slot.group.max
end
end
local mt=getmetatable(c)
if mt.material==nil then
mt.material=mat
end
if mt.material_count==nil then
mt.material_count={min_req,max_req}
end
for index,_ in pairs(mat) do
Auxiliary.AddCodeList(c,index)
end
-- Register effect
local e=Effect.CreateEffect(tc)
local e=Effect.CreateEffect(c)
e:SetType(EFFECT_TYPE_SINGLE)
e:SetProperty(EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE)
e:SetCode(EFFECT_FUSION_MATERIAL)
e:SetCondition(Fusion.FusionCondition(tc,slots,mat_filter,fgoalcheck,true))
e:SetOperation(Fusion.FusionOperation(tc,slots,mat_filter,fgoalcheck))
e:SetCondition(Fusion.FusionCondition(c,slots,mat_filter,fgoalcheck,true))
e:SetOperation(Fusion.FusionOperation(c,slots,mat_filter,fgoalcheck))
e:SetDescription(1379) --- 启用扩展卡包调试模式
tc:RegisterEffect(e)
c:RegisterEffect(e)
end
---@param allow_extras boolean whether to allow extra materials for checking propose
......@@ -3433,6 +3496,31 @@ function Fusion.FusionCondition(tc,slots,mat_filter,fgoalcheck,allow_extras,sele
return false
end
-- prepare per-slot lock flags (lock only first matching slot per code or code list)
local locked_slots={}
if Fusion.LockedCodes then
for _,code in ipairs(Fusion.LockedCodes) do
for idx,slot in ipairs(single_slots) do
-- lock slot if its match_code equals code
if slot.match_code==code then
Debug.Message(string.format("locked %d, slot %d",code,idx))
locked_slots[idx]=true
break
end
-- lock slot if it's a multi-code slot containing code
if slot.match_codes then
for _,c in ipairs(slot.match_codes) do
if c==code then
locked_slots[idx]=true
break
end
end
if locked_slots[idx] then break end
end
end
end
end
local used={}
local sub_count=0
-- DFS assign slots
......@@ -3635,16 +3723,19 @@ function Fusion.FusionCondition(tc,slots,mat_filter,fgoalcheck,allow_extras,sele
if not used[idx] then
local match,is_sub=Fusion.MatchSlot(mc,slot,tc)
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
-- skip sub material if slot is locked
if not (is_sub and locked_slots[i]) then
-- commit material
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
-- backtrack
used[idx]=false
sub_count=prev_sub
end
end
end
end
......@@ -3655,28 +3746,28 @@ function Fusion.FusionCondition(tc,slots,mat_filter,fgoalcheck,allow_extras,sele
end
--- Helper: check one card against a named slot
---@param tc Card
---@param mc Card
---@param slot table match_code|match_codes|allow_sub
---@param handler Card
---@param tc Card
---@return boolean match
---@return boolean is_sub
function Fusion.MatchSlot(tc,slot,handler)
function Fusion.MatchSlot(mc,slot,tc)
-- exact code match
if slot.match_code and tc:IsFusionCode(slot.match_code) then
if slot.match_code and mc: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
if mc:IsFusionCode(code) then
return true,false
end
end
end
-- filter
if slot.filter and slot.filter(tc) then return true,false end
if slot.filter and slot.filter(mc,tc) then return true,false end
-- generic substitute
if slot.allow_sub and tc:CheckFusionSubstitute(handler) then
if slot.allow_sub and mc:CheckFusionSubstitute(tc) then
return true,true
end
return false,false
......@@ -3795,7 +3886,7 @@ function Fusion.Slot.Codes(codes,opts)
end
--- Create a slot for generic filter (no substitutes)
---@param filter fun(mc:Card):boolean
---@param filter fun(mc:Card,tc:Card):boolean
---@return table
function Fusion.Slot.Filter(filter)
return {
......@@ -3805,11 +3896,12 @@ function Fusion.Slot.Filter(filter)
end
--- Group slot (multi-card)
---@param opts {min?:number,max?:number,filter?:fun(mc:Card):boolean}
---@param opts {min?:number,max?:number,filter?:fun(mc:Card,tc:Card):boolean}
---@return table
function Fusion.Slot.Group(opts)
opts.min=opts.min or 1
opts.max=opts.max or math.huge
opts.filter=opts.filter or aux.TRUE
return {
group=opts
}
......@@ -3818,9 +3910,9 @@ end
--- FindAllMapping
--- @param cards_sel Card[] currently picked materials
--- @param slots table[] your original slots spec
--- @param handler Card the fusion monster (for substitutes)
--- @param tc Card the fusion monster (for substitutes)
--- @return table[] an array of mapping tables (or empty if none)
function Fusion.FindAllMappings(cards_sel,slots,handler)
function Fusion.FindAllMappings(cards_sel,slots,tc)
-- Trackers
local filled={} -- for single slots
local group_assigned={} -- how many cards assigned so far to each group slot
......@@ -3832,6 +3924,29 @@ function Fusion.FindAllMappings(cards_sel,slots,handler)
end
end
-- prepare locked_slots for this mapping
local locked_slots={}
if Fusion.LockedCodes then
for _,code in ipairs(Fusion.LockedCodes) do
for idx,slot in ipairs(slots) do
local matched=false
if slot.match_code==code then matched=true
elseif slot.match_codes then
for _,c in ipairs(slot.match_codes) do
if c==code then
matched=true
break
end
end
end
if matched then
locked_slots[idx]=true
break
end
end
end
end
local all_maps={}
local mapping={} -- mapping[idx_in_cards_sel] = slot_index
......@@ -3865,18 +3980,24 @@ function Fusion.FindAllMappings(cards_sel,slots,handler)
return
end
local tc=cards_sel[idx]
local mc=cards_sel[idx]
local any_match=false -- track if we managed to assign tc
-- try single slots
for i,slot in ipairs(slots) do
if not slot.group and not filled[i] and Fusion.MatchSlot(tc,slot,handler) then
any_match=true
filled[i]=true
mapping[idx]=i
dfs(idx+1)
filled[i]=false
mapping[idx]=nil
if not slot.group and not filled[i] then
local match,is_sub=Fusion.MatchSlot(mc,slot,tc)
if match then
-- skip substitute if slot is locked
if not (is_sub and locked_slots[i]) then
any_match=true
filled[i]=true
mapping[idx]=i
dfs(idx+1)
filled[i]=false
mapping[idx]=nil
end
end
end
end
......@@ -3886,20 +4007,20 @@ function Fusion.FindAllMappings(cards_sel,slots,handler)
local assigned=group_assigned[i]
if assigned<slot.group.max then
-- base filter
if not slot.group.filter or slot.group.filter(tc) then
if not slot.group.filter or slot.group.filter(mc,tc) then
-- has_same check: only if there's already ≥1 in this slot
local ok=true
if slot.group.has_same and assigned>0 then
for _,fn in ipairs(slot.group.has_same) do
-- start intersection with this candidate
local v0=fn(tc,handler)
local v0=fn(mc,tc)
if type(v0)=="number" then
-- bitmask path
local mask=v0
-- AND with each already‐assigned card
for j=1,idx-1 do
if mapping[j]==i then
mask=mask&fn(cards_sel[j],handler)
mask=mask&fn(cards_sel[j],tc)
if mask==0 then break end
end
end
......@@ -3912,7 +4033,7 @@ function Fusion.FindAllMappings(cards_sel,slots,handler)
for j=1,idx-1 do
if mapping[j]==i then
local next_c={}
for _,k in ipairs(fn(cards_sel[j],handler)) do
for _,k in ipairs(fn(cards_sel[j],tc)) do
if common[k] then next_c[k]=true end
end
common=next_c
......@@ -4000,6 +4121,27 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
-- build the “leftover” slots list
local rem_slots={}
-- rebuild dynamic locks per mapping
local old_locked=Fusion.LockedCodes
local new_locked={}
if old_locked then
for _,code in ipairs(old_locked) do
-- find slot index for this code
for j,slot in ipairs(slots) do
local matches=(slot.match_code==code or (slot.match_codes and (function()
for _,c in ipairs(slot.match_codes) do if c==code then return true end end; return false
end)()))
if matches then
-- if that slot was not filled, keep lock
if not filled_single[j] then table.insert(new_locked,code) end
break
end
end
end
end
Fusion.LockedCodes=new_locked
for i,slot in ipairs(slots) do
if slot.group then
local need=group_need[i] or 0
......@@ -4046,14 +4188,14 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
end
-- wrap the existing filter so it also enforces all has_same overlaps
local prev=new_filter
new_filter=function(mc)
new_filter=function(mc,p_tc)
-- original criteria
if prev and not prev(mc) then
if prev and not prev(mc,p_tc) then
return false
end
-- for each fn in has_same, check against the precomputed overlap
for fn,overlap in pairs(used_overlap) do
local v=fn(mc,tc)
local v=fn(mc,p_tc)
if type(overlap)=="number" then
-- bitmask path
if (overlap&v)==0 then
......@@ -4097,11 +4239,13 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
end
end
-- if nothing remains, we already succeed, check fgoal
-- if nothing remains, we exhausted slots, check fgoal
if #rem_slots==0 then
if (fgoalcheck==nil or fgoalcheck(sel)==true) and (aux.FGoalCheckAdditional==nil or aux.FGoalCheckAdditional(tc:GetOwner(),sel,tc)) then
Fusion.LockedCodes=old_locked
return true
else
Fusion.LockedCodes=old_locked
return false
end
end
......@@ -4109,8 +4253,10 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
-- delegate to FusionCondition (allow_extras = true)
local search_cond=Fusion.FusionCondition(tc,rem_slots,mat_filter,fgoalcheck,true,sel)
if search_cond(e,rem_pool,gc,chkf) then
Fusion.LockedCodes=old_locked
return true
end
Fusion.LockedCodes=old_locked
end
return false
......@@ -4201,18 +4347,18 @@ end
--- Builds a new filter that enforces both the original filter *and*
--- “none of this card’s keys are in used_keys.”
--- @param orig_filter fun(Card):boolean? (may be nil)
--- @param orig_filter fun(mc:Card,tc:Card):boolean? (may be nil)
--- @param key_func fun(Card):any[]
--- @param used_keys table as returned above
--- @return fun(Card):boolean
--- @return fun(mc:Card,tc:Card):boolean
function Fusion.MakeExcludeFilter(orig_filter,key_func,used_keys)
return function(tc)
return function(mc,tc)
-- first, pass the original criteria
if orig_filter and not orig_filter(tc) then
if orig_filter and not orig_filter(mc,tc) then
return false
end
-- then ensure no key overlaps
for _,k in ipairs(key_func(tc)) do
for _,k in ipairs(key_func(mc)) do
if used_keys[k] then
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