Commit a5578101 authored by Vury Leo's avatar Vury Leo

remove core from fusion

parent 27ffa9d1
......@@ -28,7 +28,8 @@ function s.initial_effect(c)
local e4=FusionSpell.CreateSummonEffect(c,{
fusfilter=s.fusfilter,
pre_select_mat_location=s.pre_select_mat_location,
additional_fcheck=s.fcheck
additional_fcheck=s.fcheck,
fcheck_signature=s.fcheck_signature,
})
e4:SetCategory(CATEGORY_SPECIAL_SUMMON+CATEGORY_FUSION_SUMMON+CATEGORY_DECKDES)
e4:SetType(EFFECT_TYPE_IGNITION)
......@@ -72,3 +73,8 @@ function s.fcheck(tp,mg,fc,mg_all)
end
return true
end
--- Helper function to speed up select material, for this fusion, only location of the material matters for fcheck
function s.fcheck_signature(mc)
return mc:IsLocation(LOCATION_DECK)
end
......@@ -2256,6 +2256,8 @@ FusionSpell = {}
--- @field skip_location_count_check? boolean
--- Locked code, material code that can not use substitutes
--- @field locked_codes? (integer[]|fun(tc:Card):integer[])
--- A helper function to speed to material check. if 2 cards that would contribute same effect to fcheck, the signature should return same thingy (that could be a key of table), used for 煉獄の虚夢
--- @field fcheck_signature? fun(mc:Card):any
--- Add LOCATION_EXTRA and opponent mzone to EFFECT_EXTRA_FUSION_MATERIAL list, remove once core updated
......@@ -2337,6 +2339,7 @@ function FusionSpell.CreateSummonEffect(c,opts)
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 {}
local fcheck_signature=opts.fcheck_signature or nil
-- Ensure material operation fallbacks are present
table.insert(mat_operation_code_map,{ [LOCATION_GRAVE] = FusionSpell.FUSION_OPERATION_BANISH })
......@@ -2365,7 +2368,8 @@ function FusionSpell.CreateSummonEffect(c,opts)
fusion_spell_matfilter,
skip_summon_check,
skip_location_count_check,
locked_codes
locked_codes,
fcheck_signature
))
e1:SetOperation(FusionSpell.GetSummonOperation(
fusfilter,
......@@ -2384,7 +2388,8 @@ function FusionSpell.CreateSummonEffect(c,opts)
gc,
fusion_spell_matfilter,
skip_summon_check,
locked_codes
locked_codes,
fcheck_signature
))
e1:SetDescription(1169) --- 融合召喚
return e1
......@@ -2408,6 +2413,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 叛逆の堕天使
---@param locked_codes (integer[]|fun(tc:Card):integer[]) Locked code, material code that can not use substitutes, used for 烙印融合
---@param fcheck_signature (fun(mc:Card):any)|nil A helper function to speed to material check. if 2 cards that would contribute same effect to fcheck, the signature should return same thingy (that could be a key of table), used for 煉獄の虚夢
function FusionSpell.GetSummonTarget(
fusfilter,
matfilter,
......@@ -2426,7 +2432,8 @@ function FusionSpell.GetSummonTarget(
fusion_spell_matfilter,
skip_summon_check,
skip_location_count_check,
locked_codes
locked_codes,
fcheck_signature
)
return function(e,tp,eg,ep,ev,re,r,rp,chk)
if chk==0 then
......@@ -2452,7 +2459,8 @@ function FusionSpell.GetSummonTarget(
fusion_spell_matfilter,
skip_summon_check,
skip_location_count_check,
locked_codes)
locked_codes,
fcheck_signature)
end,
tp,fuslocation,0,1,nil)
if sg==true then
......@@ -2460,7 +2468,7 @@ function FusionSpell.GetSummonTarget(
end
-- --- check for chain material targets
if sumtype&SUMMON_TYPE_FUSION~=0 then
local ce_sg=FusionSpell.IsExistsChainMaterialSummonTargets(e,tp,fusfilter,matfilter,additional_fcheck,additional_fgoalcheck,fuslocation,sumtype,sumpos,gc,skip_summon_check,skip_location_count_check,locked_codes)
local ce_sg=FusionSpell.IsExistsChainMaterialSummonTargets(e,tp,fusfilter,matfilter,additional_fcheck,additional_fgoalcheck,fuslocation,sumtype,sumpos,gc,skip_summon_check,skip_location_count_check,locked_codes,fcheck_signature)
if ce_sg==true then
return true
end
......@@ -2489,6 +2497,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 locked_codes (integer[]|fun(tc:Card):integer[]) Locked code, material code that can not use substitutes, used for 烙印融合
---@param fcheck_signature (fun(mc:Card):any)|nil A helper function to speed to material check. if 2 cards that would contribute same effect to fcheck, the signature should return same thingy (that could be a key of table), used for 煉獄の虚夢
function FusionSpell.GetSummonOperation(
fusfilter,
matfilter,
......@@ -2506,7 +2515,8 @@ function FusionSpell.GetSummonOperation(
gc,
fusion_spell_matfilter,
skip_summon_check,
locked_codes
locked_codes,
fcheck_signature
)
return function(e,tp,eg,ep,ev,re,r,rp)
local tc=nil
......@@ -2585,7 +2595,7 @@ function FusionSpell.GetSummonOperation(
pre_select_mat_opponent_location,
post_select_mat_opponent_location,
fusion_spell_matfilter)
aux.FCheckAdditional=FusionSpell.GetFusionSpellFCheckAdditionalFunction(
local patched_additional_fcheck=FusionSpell.GetFusionSpellFCheckAdditionalFunction(
additional_fcheck,
tp,
tc,
......@@ -2596,33 +2606,35 @@ function FusionSpell.GetSummonOperation(
fusion_spell_matfilter,
e,
mat_operation_code_map)
aux.FGoalCheckAdditional=FusionSpell.GetFusionSpellFGoalCheckAdditionalFunction(additional_fgoalcheck,tp,tc,pre_select_mat_location,e)
local patched_additional_fgoalcheck=FusionSpell.GetFusionSpellFGoalCheckAdditionalFunction(additional_fgoalcheck,tp,tc,pre_select_mat_location,e)
local calculated_locked_codes=locked_codes
if type(locked_codes)=='function' then
Fusion.LockedCodes=locked_codes(tc)
else
Fusion.LockedCodes=locked_codes
calculated_locked_codes=locked_codes(tc)
end
materials=Duel.SelectFusionMaterial(tp,tc,mg,gc(e),tp)
aux.FCheckAdditional=nil
aux.FGoalCheckAdditional=nil
Fusion.LockedCodes=nil
materials=Fusion.SelectFusionMaterial(tp,tc,mg,gc(e),tp,{
additional_fcheck=patched_additional_fcheck,
additional_fgoalcheck=patched_additional_fgoalcheck,
locked_codes=calculated_locked_codes,
fcheck_signature=fcheck_signature,
})
else
--- use chain material effect
---@type function
local chain_material_filter=fusion_effect:GetTarget()
local chain_mg=chain_material_filter(fusion_effect,e,tp):Filter(aux.NecroValleyFilter(function(c) return matfilter(c,e,tp) end),nil)
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)
local patched_additional_fcheck=FusionSpell.GetFusionSpellFCheckAdditionalFunctionForChainMaterial(additional_fcheck,e)
local patched_additional_fgoalcheck=FusionSpell.GetFusionSpellFGoalCheckAdditionalFunctionForChainMaterial(additional_fgoalcheck,e)
local calculated_locked_codes=locked_codes
if type(locked_codes)=='function' then
Fusion.LockedCodes=locked_codes(tc)
else
Fusion.LockedCodes=locked_codes
calculated_locked_codes=locked_codes(tc)
end
materials=Duel.SelectFusionMaterial(tp,tc,chain_mg,gc(e),tp)
aux.FCheckAdditional=nil
aux.FGoalCheckAdditional=nil
Fusion.LockedCodes=nil
materials=Fusion.SelectFusionMaterial(tp,tc,chain_mg,gc(e),tp,{
additional_fcheck=patched_additional_fcheck,
additional_fgoalcheck=patched_additional_fgoalcheck,
locked_codes=calculated_locked_codes,
fcheck_signature=fcheck_signature,
})
end
end
......@@ -2888,6 +2900,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 叛逆の堕天使
---@param locked_codes (integer[]|fun(tc:Card):integer[]) Locked code, material code that can not use substitutes, used for 烙印融合
---@param fcheck_signature (fun(mc:Card):any)|nil A helper function to speed to material check. if 2 cards that would contribute same effect to fcheck, the signature should return same thingy (that could be a key of table), used for 煉獄の虚夢
function FusionSpell.SummonTargetFilter(
c,
fusfilter,
......@@ -2907,7 +2920,8 @@ function FusionSpell.SummonTargetFilter(
fusion_spell_matfilter,
skip_summon_check,
skip_location_count_check,
locked_codes)
locked_codes,
fcheck_signature)
if not c:IsType(TYPE_FUSION) or fusfilter(c,e,tp)==false then
return false
end
......@@ -2928,7 +2942,7 @@ function FusionSpell.SummonTargetFilter(
pre_select_mat_opponent_location,
post_select_mat_opponent_location,
fusion_spell_matfilter)
aux.FCheckAdditional=FusionSpell.GetFusionSpellFCheckAdditionalFunction(
local patched_additional_fcheck=FusionSpell.GetFusionSpellFCheckAdditionalFunction(
additional_fcheck,
tp,
c,
......@@ -2939,17 +2953,18 @@ function FusionSpell.SummonTargetFilter(
fusion_spell_matfilter,
e,
mat_operation_code_map)
aux.FGoalCheckAdditional=FusionSpell.GetFusionSpellFGoalCheckAdditionalFunction(additional_fgoalcheck,tp,c,pre_select_mat_location,e)
local patched_additional_fgoalcheck=FusionSpell.GetFusionSpellFGoalCheckAdditionalFunction(additional_fgoalcheck,tp,c,pre_select_mat_location,e)
local calculated_locked_codes=locked_codes
if type(locked_codes)=='function' then
Fusion.LockedCodes=locked_codes(c)
else
Fusion.LockedCodes=locked_codes
calculated_locked_codes=locked_codes(c)
end
local chkf=FusionSpell.GetCheckFieldPlayer(tp,skip_location_count_check)
local res=Fusion.CheckFusionMaterial(c,mg,gc(e),chkf)
aux.FCheckAdditional=nil
aux.FGoalCheckAdditional=nil
Fusion.LockedCodes=nil
local res=Fusion.CheckFusionMaterial(c,mg,gc(e),chkf,{
additional_fcheck=patched_additional_fcheck,
additional_fgoalcheck=patched_additional_fgoalcheck,
locked_codes=calculated_locked_codes,
fcheck_signature=fcheck_signature,
})
return res
end
......@@ -2986,8 +3001,9 @@ 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 叛逆の堕天使
---@param locked_codes (integer[]|fun(tc:Card):integer[]) Locked code, material code that can not use substitutes, used for 烙印融合
---@param fcheck_signature (fun(mc:Card):any)|nil A helper function to speed to material check. if 2 cards that would contribute same effect to fcheck, the signature should return same thingy (that could be a key of table), used for 煉獄の虚夢
---@return boolean res return whether there is a valid target for any chain material effect
function FusionSpell.IsExistsChainMaterialSummonTargets(e,tp,fusfilter,matfilter,additional_fcheck,additional_fgoalcheck,fuslocation,sumtype,sumpos,gc,skip_summon_check,skip_location_count_check,locked_codes)
function FusionSpell.IsExistsChainMaterialSummonTargets(e,tp,fusfilter,matfilter,additional_fcheck,additional_fgoalcheck,fuslocation,sumtype,sumpos,gc,skip_summon_check,skip_location_count_check,locked_codes,fcheck_signature)
local chain_material_effects={Duel.IsPlayerAffectedByEffect(tp,EFFECT_CHAIN_MATERIAL)}
---@type {[Effect]:Group}
for _,ce in ipairs(chain_material_effects) do
......@@ -2997,7 +3013,7 @@ function FusionSpell.IsExistsChainMaterialSummonTargets(e,tp,fusfilter,matfilter
if #chain_mg>0 then
local ce_fusfilter=ce:GetValue()
local res=Duel.IsExistingMatchingCard(function(c)
return FusionSpell.ChainMaterialSummonTargetFilter(c,aux.AND(ce_fusfilter,fusfilter or aux.TRUE),e,tp,chain_mg,additional_fcheck,additional_fgoalcheck,sumtype,sumpos,gc,skip_summon_check,skip_location_count_check,locked_codes)
return FusionSpell.ChainMaterialSummonTargetFilter(c,aux.AND(ce_fusfilter,fusfilter or aux.TRUE),e,tp,chain_mg,additional_fcheck,additional_fgoalcheck,sumtype,sumpos,gc,skip_summon_check,skip_location_count_check,locked_codes,fcheck_signature)
end,
tp,fuslocation,0,1,nil)
if res==true then
......@@ -3014,8 +3030,9 @@ 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 叛逆の堕天使
---@param locked_codes (integer[]|fun(tc:Card):integer[]) Locked code, material code that can not use substitutes, used for 烙印融合
---@param fcheck_signature (fun(mc:Card):any)|nil A helper function to speed to material check. if 2 cards that would contribute same effect to fcheck, the signature should return same thingy (that could be a key of table), 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,locked_codes)
function FusionSpell.ChainMaterialSummonTargetFilter(c,fusfilter,e,tp,mg,additional_fcheck,additional_fgoalcheck,sumtype,sumpos,gc,skip_summon_check,skip_location_count_check,locked_codes,fcheck_signature)
if not c:IsType(TYPE_FUSION) or fusfilter(c,e,tp)==false then
return false
end
......@@ -3024,18 +3041,19 @@ function FusionSpell.ChainMaterialSummonTargetFilter(c,fusfilter,e,tp,mg,additio
return false
end
end
aux.FCheckAdditional=FusionSpell.GetFusionSpellFCheckAdditionalFunctionForChainMaterial(additional_fcheck,e)
aux.FGoalCheckAdditional=FusionSpell.GetFusionSpellFGoalCheckAdditionalFunctionForChainMaterial(additional_fgoalcheck,e)
local patched_additional_fcheck=FusionSpell.GetFusionSpellFCheckAdditionalFunctionForChainMaterial(additional_fcheck,e)
local patched_additional_fgoalcheck=FusionSpell.GetFusionSpellFGoalCheckAdditionalFunctionForChainMaterial(additional_fgoalcheck,e)
local calculated_locked_codes=locked_codes
if type(locked_codes)=='function' then
Fusion.LockedCodes=locked_codes(c)
else
Fusion.LockedCodes=locked_codes
calculated_locked_codes=locked_codes(c)
end
local chkf=FusionSpell.GetCheckFieldPlayer(tp,skip_location_count_check)
local res=Fusion.CheckFusionMaterial(c,mg,gc(e),chkf)
aux.FCheckAdditional=nil
aux.FGoalCheckAdditional=nil
Fusion.LockedCodes=nil
local res=Fusion.CheckFusionMaterial(c,mg,gc(e),chkf,{
additional_fcheck=patched_additional_fcheck,
additional_fgoalcheck=patched_additional_fgoalcheck,
locked_codes=calculated_locked_codes,
fcheck_signature=fcheck_signature,
})
return res
end
......@@ -3414,10 +3432,6 @@ end
Fusion={}
--- locked codes
Fusion.LockedCodes=nil
-- Refactored Fusion.AddFusionProcedure using the above helpers
function Fusion.AddFusionProcedure(c, opts)
local patterns=Fusion.BuildPatterns(opts)
......@@ -3476,7 +3490,7 @@ function Fusion.AddFusionProcedure(c, opts)
end
function Fusion.BasicCondition(tc,slots,matfilter,fgoalcheck,selected)
return function(e,g,gc,chkf,allow_extras)
return function(e,g,gc,chkf,allow_extras,locked_codes,additional_fcheck,additional_fgoalcheck,fcheck_signature)
if not g then return false end
-- Collect cards and apply global matfilter
......@@ -3507,8 +3521,8 @@ function Fusion.BasicCondition(tc,slots,matfilter,fgoalcheck,selected)
-- Prepare locked flags for substitute materials
local locked={}
if Fusion.LockedCodes then
for _, code in ipairs(Fusion.LockedCodes) do
if locked_codes then
for _, code in ipairs(locked_codes) do
for i,slot in ipairs(single_slots) do
-- direct match_code?
if slot.match_code==code then
......@@ -3551,16 +3565,16 @@ function Fusion.BasicCondition(tc,slots,matfilter,fgoalcheck,selected)
-- No group slot? Just do final checks
if not grp then
return Fusion.FinalCheck(e,mg_base,tc,fgoalcheck,chkf)
return Fusion.FinalCheck(mg_base,tc,fgoalcheck,chkf,additional_fcheck,additional_fgoalcheck)
end
-- Group slot exists: branch on allow_extras
if allow_extras then
-- search mode: try to find some subset of size grp.min
return Fusion.SearchGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
return Fusion.SearchGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf,additional_fcheck,additional_fgoalcheck)
else
-- strict mode: leftovers must *all* satisfy grp
return Fusion.StrictGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
return Fusion.StrictGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf,additional_fcheck,additional_fgoalcheck)
end
end
......@@ -3600,10 +3614,10 @@ function Fusion.BasicCondition(tc,slots,matfilter,fgoalcheck,selected)
end
-- Final, post‐fusion checks (common to both modes)
function Fusion.FinalCheck(e,mg,tc,fgoalcheck,chkf)
function Fusion.FinalCheck(mg,tc,fgoalcheck,chkf,additional_fcheck,additional_fgoalcheck)
if fgoalcheck and not fgoalcheck(mg) then return false end
if aux.FCheckAdditional and not aux.FCheckAdditional(tc:GetOwner(),mg,tc) then return false end
if aux.FGoalCheckAdditional and not aux.FGoalCheckAdditional(tc:GetOwner(),mg,tc) then return false end
if additional_fcheck and not additional_fcheck(tc:GetOwner(),mg,tc) then return false end
if additional_fgoalcheck and not additional_fgoalcheck(tc:GetOwner(),mg,tc) then return false end
if not aux.TuneMagicianCheckAdditionalX(EFFECT_TUNE_MAGICIAN_F)(mg) then return false end
if (chkf&0xf)~=PLAYER_NONE then
local tp=chkf&0xf
......@@ -3615,7 +3629,7 @@ function Fusion.FinalCheck(e,mg,tc,fgoalcheck,chkf)
end
-- Strict mode: *all* leftovers must fit grp, then final check
function Fusion.StrictGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
function Fusion.StrictGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf,additional_fcheck,additional_fgoalcheck)
-- filter leftovers by grp.filter
local matched={}
for _,c in ipairs(leftovers) do
......@@ -3643,12 +3657,12 @@ function Fusion.StrictGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
-- merge and final
local mg=mg_base:Clone()
for _,c in ipairs(matched) do mg:AddCard(c) end
return Fusion.FinalCheck(e,mg,tc,fgoalcheck,chkf)
return Fusion.FinalCheck(mg,tc,fgoalcheck,chkf,additional_fcheck,additional_fgoalcheck)
end
--- @param mg_base Group
-- Search mode: find *some* subset of size [grp.min…grp.max] that passes
function Fusion.SearchGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
function Fusion.SearchGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf,additional_fcheck,additional_fgoalcheck)
-- pre‐filter by grp.filter
local matched={}
for _,c in ipairs(leftovers) do
......@@ -3726,7 +3740,7 @@ function Fusion.SearchGroup(e,leftovers,mg_base,grp,tc,fgoalcheck,chkf)
ok_unique=matcher(sub_g_arr)
end
-- final fusion checks
if ok_same and ok_unique and Fusion.FinalCheck(e,mg_tmp,tc,fgoalcheck,chkf) then
if ok_same and ok_unique and Fusion.FinalCheck(mg_tmp,tc,fgoalcheck,chkf,additional_fcheck,additional_fgoalcheck) then
return true
end
end
......@@ -3903,8 +3917,9 @@ end
--- @param cards_sel Card[] currently picked materials
--- @param slots table[] your original slots spec
--- @param tc Card the fusion monster (for substitutes)
--- @param locked_codes integer[]|nil the list of locked slot code
--- @return table[] an array of mapping tables (or empty if none)
function Fusion.FindAllMappings(cards_sel, slots, tc)
function Fusion.FindAllMappings(cards_sel,slots,tc,locked_codes)
--- empty selection, just return one “empty” mapping
if #cards_sel==0 then
return {{}}
......@@ -3923,8 +3938,8 @@ function Fusion.FindAllMappings(cards_sel, slots, tc)
-- Prepare locked_slots for substitute‐material restrictions
local locked_slots={}
if Fusion.LockedCodes then
for _, code in ipairs(Fusion.LockedCodes) do
if locked_codes then
for _, code in ipairs(locked_codes) do
for idx, slot in ipairs(slots) do
local matched=false
-- direct code match?
......@@ -4076,7 +4091,7 @@ end
--- @param slots table[] your slot definitions
--- @param tc Card the Fusion monster (for substitutes)
--- @return boolean true if ∃ a mapping + completion path
function Fusion.CanCompleteFromMappings(e,sel,eg,slots,matfilter,fgoalcheck,tc,gc,chkf)
function Fusion.CanCompleteFromMappings(e,sel,eg,slots,matfilter,fgoalcheck,tc,gc,chkf,locked_codes,additional_fcheck,additional_fgoalcheck,fcheck_signature)
-- arrayify sel so we can refer by index
local cards_sel={}
for c in aux.Next(sel) do
......@@ -4084,7 +4099,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,matfilter,fgoalcheck,tc,g
end
-- get every possible assignment of sel→slots
local mappings=Fusion.FindAllMappings(cards_sel,slots,tc)
local mappings=Fusion.FindAllMappings(cards_sel,slots,tc,locked_codes)
if #mappings==0 then
return false
end
......@@ -4124,10 +4139,9 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,matfilter,fgoalcheck,tc,g
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
if locked_codes then
for _,code in ipairs(locked_codes) 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()
......@@ -4141,7 +4155,6 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,matfilter,fgoalcheck,tc,g
end
end
end
Fusion.LockedCodes=new_locked
for i,slot in ipairs(slots) do
if slot.group then
......@@ -4242,22 +4255,18 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,matfilter,fgoalcheck,tc,g
-- if nothing remains, we exhausted slots, check fgoal
if #rem_slots==0 then
if Fusion.FinalCheck(e,sel,tc,fgoalcheck,chkf) then
Fusion.LockedCodes=old_locked
if Fusion.FinalCheck(sel,tc,fgoalcheck,chkf,additional_fcheck,additional_fgoalcheck) then
return true
else
Fusion.LockedCodes=old_locked
return false
end
end
-- delegate to BasicCondition (allow_extras=true)
local cond=Fusion.BasicCondition(tc,rem_slots,matfilter,fgoalcheck,sel)
if cond(e,rem_pool,gc,chkf,true--[[allow_extras]]) then
Fusion.LockedCodes=old_locked
if cond(e,rem_pool,gc,chkf,true--[[allow_extras]],new_locked,additional_fcheck,additional_fgoalcheck,fcheck_signature) then
return true
end
Fusion.LockedCodes=old_locked
end
return false
......@@ -4390,14 +4399,13 @@ end
-- Helper: combine multiple patterns into one condition function
function Fusion.MultiCondition(tc,patterns)
return function(e,g,gc,chkf,selected,allow_extras,slots_only)
return function(e,g,gc,chkf,selected,allow_extras,slots_only,locked_codes,additional_fcheck,additional_fgoalcheck,fcheck_signature)
if not g then return false end
local locked=Fusion.LockedCodes
for _,pat in ipairs(patterns) do
-- skip patterns that don't include all locked codes
local ok=true
if locked then
for _,code in ipairs(locked) do
if locked_codes then
for _,code in ipairs(locked_codes) do
if not Fusion.PatternIncludesCode(pat,code) then
ok=false
break
......@@ -4407,12 +4415,12 @@ function Fusion.MultiCondition(tc,patterns)
if ok then
if not slots_only then
local cond=Fusion.BasicCondition(tc,pat.slots,pat.matfilter,pat.fgoalcheck,selected)
if cond(e,g,gc,chkf,allow_extras) then
if cond(e,g,gc,chkf,allow_extras,locked_codes,additional_fcheck,additional_fgoalcheck,fcheck_signature) then
return true
end
else
local cond=Fusion.BasicCondition(tc,pat.slots,aux.TRUE,aux.TRUE,selected)
if cond(e,g,gc,chkf,allow_extras) then
if cond(e,g,gc,chkf,allow_extras,locked_codes,additional_fcheck,additional_fgoalcheck,fcheck_signature) then
return true
end
end
......@@ -4445,14 +4453,13 @@ end
-- Helper: combine patterns into one operation function
function Fusion.MultiOperation(tc,patterns)
return function(e,tp,eg,ep,ev,re,r,rp,gc,chkf,selected)
return function(e,tp,mg,gc,chkf,selected,locked_codes,additional_fcheck,additional_fgoalcheck,fcheck_signature)
-- filter patterns by any locked codes, once per operation
local locked=Fusion.LockedCodes
local active_patterns={}
if locked then
if locked_codes then
for _,pat in ipairs(patterns) do
local ok=true
for _, code in ipairs(locked) do
for _, code in ipairs(locked_codes) do
if not Fusion.PatternIncludesCode(pat,code) then
ok=false
break
......@@ -4467,7 +4474,7 @@ function Fusion.MultiOperation(tc,patterns)
-- compute min/max over active patterns
local min_req,max_req=Fusion.PatternsMinMax(active_patterns)
max_req=math.min(max_req,eg:GetCount())
max_req=math.min(max_req,mg:GetCount())
-- strict condition uses only active patterns
local cond=Fusion.MultiCondition(tc,active_patterns)
......@@ -4477,18 +4484,18 @@ function Fusion.MultiOperation(tc,patterns)
--- arraify eg
local eg_arr={}
for mc in aux.Next(eg) do
for mc in aux.Next(mg) do
table.insert(eg_arr,mc)
end
while true do
local finishable=sg:GetCount()>=min_req and cond(e,sg,gc,chkf,selected,false--[[allow_extras]])
local finishable=sg:GetCount()>=min_req and cond(e,sg,gc,chkf,selected,false--[[allow_extras]],false--[[slots_only]],locked_codes,additional_fcheck,additional_fgoalcheck,fcheck_signature)
local addable=Group.CreateGroup()
-- check fcheck on the *current* sg
local prev_ok=true
if aux.FCheckAdditional~=nil then
prev_ok=aux.FCheckAdditional(tc:GetOwner(),sg,tc)
if additional_fcheck~=nil then
prev_ok=additional_fcheck(tc:GetOwner(),sg,tc)
end
for _,mc in ipairs(eg_arr) do
......@@ -4497,15 +4504,15 @@ function Fusion.MultiOperation(tc,patterns)
-- early FCheckAdditional prune: if adding this card would cause fcheck to fail, we can not add it
-- check fcheck again
local new_ok=true
if aux.FCheckAdditional~=nil then
new_ok=aux.FCheckAdditional(tc:GetOwner(),sg,tc)
if additional_fcheck~=nil then
new_ok=additional_fcheck(tc:GetOwner(),sg,tc)
end
-- prune if it was OK before but fails now
if not (prev_ok and not new_ok) then
-- completion test against active patterns
for _,pat in ipairs(active_patterns) do
if Fusion.CanCompleteFromMappings(e,sg,eg,pat.slots,pat.matfilter,pat.fgoalcheck,tc,gc,chkf) then
if Fusion.CanCompleteFromMappings(e,sg,mg,pat.slots,pat.matfilter,pat.fgoalcheck,tc,gc,chkf,locked_codes,additional_fcheck,additional_fgoalcheck,fcheck_signature) then
addable:AddCard(mc)
break
end
......@@ -4517,20 +4524,19 @@ function Fusion.MultiOperation(tc,patterns)
if addable:GetCount()==0 then
assert(finishable)
Duel.SetFusionMaterial(sg)
return
return sg
end
local picked=Group.SelectUnselect(addable,sg,tp,finishable,true,min_req,max_req)
if not picked then
if finishable then
Duel.SetFusionMaterial(sg)
return sg
else
Duel.SetFusionMaterial(Group.CreateGroup())
return Group.CreateGroup()
end
return
end
assert(picked~=nil)
if sg:IsContains(picked) then
-- If EFFECT_MUST_BE_FMATERIAL is on your field, ensure it's in selected
local must_materials=Duel.GetMustMaterial(tp,EFFECT_MUST_BE_FMATERIAL)
......@@ -4564,7 +4570,7 @@ end
--- @param patterns table[]
function Fusion.FusionCondition(tc,patterns)
return function(e,g,gc,chkf,opts,not_core)
--- to bypass core check showing up in Card.IsHasEffect, we need this hack, used in Fusion.CheckFusionMaterial
--- to bypass core check showing up in Card.IsHasEffect, we need this hack, used in Fusion.CheckFusionMaterial/Fusion.SelectFusinMaterial
if not_core==nil then return true end
if not g then return false end
opts=opts or {}
......@@ -4573,6 +4579,11 @@ function Fusion.FusionCondition(tc,patterns)
allow_extras=false
end
local slots_only=opts.slots_only or false
local locked_codes=opts.locked_codes or nil
local additional_fcheck=opts.additional_fcheck or nil
local additional_fgoalcheck=opts.additional_fgoalcheck or nil
local fcheck_signature=opts.fcheck_signature or nil
-- build your seed group
local selected=Group.CreateGroup()
if gc then selected:AddCard(gc) end
......@@ -4583,12 +4594,11 @@ function Fusion.FusionCondition(tc,patterns)
if allow_extras then
-- attempt "search mode" on each pattern
local locked=Fusion.LockedCodes
for _,pat in ipairs(patterns) do
-- skip patterns that don't include all locked codes
local ok=true
if locked then
for _,code in ipairs(locked) do
if locked_codes then
for _,code in ipairs(locked_codes) do
if not Fusion.PatternIncludesCode(pat,code) then
ok=false
break
......@@ -4596,14 +4606,14 @@ function Fusion.FusionCondition(tc,patterns)
end
end
if ok then
if Fusion.CanCompleteFromMappings(e,selected,g,pat.slots,pat.matfilter,pat.fgoalcheck or aux.TRUE,tc,gc,chkf) then
if Fusion.CanCompleteFromMappings(e,selected,g,pat.slots,pat.matfilter,pat.fgoalcheck or aux.TRUE,tc,gc,chkf,locked_codes,additional_fcheck,additional_fgoalcheck,fcheck_signature) then
return true
end
end
end
else
-- attempt "strict mode"
if Fusion.MultiCondition(tc,patterns)(e,g,gc,chkf,selected,allow_extras,slots_only) then
if Fusion.MultiCondition(tc,patterns)(e,g,gc,chkf,selected,allow_extras,slots_only,locked_codes,additional_fcheck,additional_fgoalcheck,fcheck_signature) then
return true
end
end
......@@ -4612,7 +4622,11 @@ function Fusion.FusionCondition(tc,patterns)
end
function Fusion.FusionOperation(c,patterns)
return function(e,tp,eg,ep,ev,re,r,rp,gc,chkf)
return function(e,tp,mg,gc,chkf,opts)
local locked_codes=opts.locked_codes or nil
local additional_fcheck=opts.additional_fcheck or nil
local additional_fgoalcheck=opts.additional_fgoalcheck or nil
local fcheck_signature=opts.fcheck_signature or nil
-- build selected = {gc}
local selected = Group.CreateGroup()
if gc then selected:AddCard(gc) end
......@@ -4620,7 +4634,7 @@ function Fusion.FusionOperation(c,patterns)
local must_materials=Duel.GetMustMaterial(tp,EFFECT_MUST_BE_FMATERIAL)
selected:Merge(must_materials)
-- call the original op, swapping in selected for gc
return Fusion.MultiOperation(c,patterns)(e,tp,eg,ep,ev,re,r,rp,gc,chkf,selected)
return Fusion.MultiOperation(c,patterns)(e,tp,mg,gc,chkf,selected,locked_codes,additional_fcheck,additional_fgoalcheck,fcheck_signature)
end
end
......@@ -4635,3 +4649,12 @@ function Fusion.CheckFusionMaterial(tc,mg,gc,chkf,opts)
end
return false
end
--- shadowing Duel.SelectFusionMaterial as it core does not pass all param back to lua
function Fusion.SelectFusionMaterial(tp,tc,mg,gc,chkf,opts)
opts=opts or {}
local effs={tc:IsHasEffect(EFFECT_FUSION_MATERIAL,tp)}
local eff=effs[1]
local sg=eff:GetOperation()(eff,tp,mg,gc,chkf,opts)
return sg
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