Commit 0844c2fe authored by Vury Leo's avatar Vury Leo

Add 花札衛

parent e31bc28c
......@@ -3,7 +3,7 @@ local s,id,o=GetID()
function s.initial_effect(c)
c:EnableReviveLimit()
--material
aux.AddSynchroProcedure(c,nil,aux.NonTuner(nil),1)
Synchro.AddSynchroProcedure(c)
--chain attack
local e1=Effect.CreateEffect(c)
e1:SetDescription(aux.Stringid(id,0))
......
......@@ -3488,7 +3488,7 @@ end
--- @param tuner_max integer|table -- Maximum number of tuner materials allowed.
--- @param non_tuner_min integer -- Minimum number of non-tuner materials required.
--- @param non_tuner_max integer|table -- Maximum number of non-tuner materials allowed.
--- @param levelMapper fun(card:Card,tc:Card):integer[]
--- @param base_mapper fun(card:Card,tc:Card):integer[]
--- -- Function returning possible levels for a card.
--- @param selected? Card[] -- Currently selected material cards.
--- @param index? integer -- Current index in candidates for DFS (default 1).
......@@ -3498,15 +3498,18 @@ end
--- -- non_tuner_count (integer): current non-tuner count.
--- @return boolean -- True if a valid selection exists, false otherwise.
function Synchro.CanCompleteSelection(candidates,target_level,tuner_filter,non_tuner_filter,tc,
tuner_min,tuner_max,non_tuner_min,non_tuner_max,levelMapper,selected,index,state)
tuner_min,tuner_max,non_tuner_min,non_tuner_max,base_mapper,selected,index,state)
index=index or 1
selected=selected or {}
state=state or {
possible_sums={[0]=true},
tuner_count=0,
non_tuner_count=0,
level_mapper=base_mapper or Synchro.LevelMapper,
}
local mapper = state.level_mapper
if Synchro.ExceedsMax(state.tuner_count,tuner_max) then return false end
if Synchro.ExceedsMax(state.non_tuner_count,non_tuner_max) then return false end
......@@ -3521,30 +3524,51 @@ function Synchro.CanCompleteSelection(candidates,target_level,tuner_filter,non_t
end
local mc=candidates[index]
local lvls=levelMapper(mc,tc)
local tuner_inc=tuner_filter(mc,tc) and 1 or 0
local non_tuner_inc=non_tuner_filter(mc,tc) and 1 or 0
local newpossible_sums=Synchro.Updatepossible_sums(state.possible_sums,lvls,target_level)
if next(newpossible_sums) then
-- include branch
local variants={}
-- 1) Normal include branch
local lvls=mapper(mc,tc)
local sums_norm=Synchro.UpdatepossibleSums(state.possible_sums,lvls,target_level)
if next(sums_norm)then
table.insert(variants,{sums=sums_norm,mapper=mapper})
end
-- 2) override if Peony
if mc:IsCode(57261568,33541430,89818984) then
local cnt=#selected+1
local sums_ovr={[2*cnt]=true}
table.insert(variants,{sums=sums_ovr,mapper=function() return{2} end})
end
for _,var in ipairs(variants) do
local new_state={
possible_sums=newpossible_sums,
possible_sums=var.sums,
tuner_count=state.tuner_count+tuner_inc,
non_tuner_count=state.non_tuner_count+non_tuner_inc,
level_mapper=var.mapper,
}
table.insert(selected,mc)
if Synchro.CanCompleteSelection(candidates,target_level,tuner_filter,non_tuner_filter,tc,
tuner_min,tuner_max,non_tuner_min,non_tuner_max,levelMapper,selected,index+1,new_state) then
if Synchro.CanCompleteSelection(
candidates,target_level,
tuner_filter,non_tuner_filter,tc,
tuner_min,tuner_max,non_tuner_min,non_tuner_max,
base_mapper,selected,index+1,new_state
)
then
table.remove(selected)
return true
end
table.remove(selected)
end
-- Option: exclude this card
-- exclude branch
if Synchro.CanCompleteSelection(candidates,target_level,tuner_filter,non_tuner_filter,tc,
tuner_min,tuner_max,non_tuner_min,non_tuner_max,levelMapper,selected,index+1,state) then
tuner_min,tuner_max,non_tuner_min,non_tuner_max,base_mapper,selected,index+1,state) then
return true
end
......@@ -3568,7 +3592,7 @@ function Synchro.SynCondition(tuner_filter,non_tuner_filter,tuner_min,tuner_max,
end
end
function Synchro.SynTarget(tuner_filter,non_tuner_filter,tuner_min,tuner_max,non_tuner_min,non_tuner_max)
function Synchro.SynTarget(tuner_filter,non_tuner_filter,tuner_min,tuner_max,non_tuner_min,non_tuner_max,base_mapper)
return function(e,tp,eg,ep,ev,re,r,rp,chk,tc,smat,mg,min,max)
mg=mg or Duel.GetMatchingGroup(function(mc) return mc:IsCanBeSynchroMaterial(mc,tc) end,tc:GetOwner(),LOCATION_MZONE+LOCATION_HAND,0,nil)
local sg=Group.CreateGroup()
......@@ -3598,22 +3622,24 @@ function Synchro.SynTarget(tuner_filter,non_tuner_filter,tuner_min,tuner_max,non
end
end
if Synchro.CanCompleteSelection(
rest_candidates,
target_level,
tuner_filter,
non_tuner_filter,
tc,
tuner_min,
tuner_max,
non_tuner_min,
non_tuner_max,
Synchro.LevelMapper,
local base_states=Synchro.BuildStatesFromSelection(
test_selection,
1,
Synchro.BuildStateFromSelection(test_selection,tuner_filter,non_tuner_filter,Synchro.LevelMapper,tc,target_level)
) then
tuner_filter,non_tuner_filter,
base_mapper or Synchro.LevelMapper,
tc,target_level
)
for _,init_state in ipairs(base_states)do
if Synchro.CanCompleteSelection(
rest_candidates,target_level,
tuner_filter,non_tuner_filter,tc,
tuner_min,tuner_max,non_tuner_min,non_tuner_max,
nil,test_selection,1,init_state
)
then
addable:AddCard(candidate)
break
end
end
end
......@@ -3648,7 +3674,6 @@ function Synchro.SynTarget(tuner_filter,non_tuner_filter,tuner_min,tuner_max,non
end
end
--- Synchro operation function that applies selected materials
function Synchro.SynOperation()
return function(e,tp,eg,ep,ev,re,r,rp,c)
......@@ -3672,120 +3697,123 @@ function Synchro.GetDisplayMax(tuner_max,non_tuner_max)
end
function Synchro.IsSelectionValid(selection,target_level,tuner_filter,non_tuner_filter,tc,tuner_min,tuner_max,non_tuner_min,non_tuner_max)
local state=Synchro.BuildStateFromSelection(selection,tuner_filter,non_tuner_filter,Synchro.LevelMapper,tc,target_level)
-- check if target_level achievable exactly
if Synchro.ExceedsMax(state.tuner_count,tuner_max) then return false end
if Synchro.ExceedsMax(state.non_tuner_count,non_tuner_max) then return false end
if state.possible_sums[target_level] and
state.tuner_count>=tuner_min and
state.non_tuner_count>=non_tuner_min then
local states=Synchro.BuildStatesFromSelection(
selection,
tuner_filter,non_tuner_filter,
Synchro.LevelMapper,
tc,target_level
)
for _,state in ipairs(states)do
if not Synchro.ExceedsMax(state.tuner_count,tuner_max) then
if not Synchro.ExceedsMax(state.non_tuner_count,non_tuner_max) then
if state.possible_sums[target_level]
and state.tuner_count>=tuner_min
and state.non_tuner_count>=non_tuner_min
then
return true
end
end
end
end
return false
end
--- Returns a list of possible levels this card can be treated as when used as Synchro material.
--- @param card Card -- The candidate material card.
--- @param tc Card -- The Synchro monster being summoned.
--- @return integer[] -- Array of possible level integers (e.g., {1} or {1,2}).
function Synchro.LevelMapper(card,tc)
Debug.Message(string.format("lvel mapper for %d",card:GetCode()))
local levelDict={}
local level_dict={}
local effs={card:IsHasEffect(EFFECT_SYNCHRO_LEVEL)}
Debug.Message(string.format("lvel mapper for %d, effs %d",card:GetCode(),#effs))
if #effs>0 then
local val=effs[1]:GetValue()(effs[1],tc)
Debug.Message(string.format("lvel mapper for %d, effs %d",card:GetCode(),#effs))
if type(val)=="table" then
for _, v in ipairs(val) do
levelDict[v]=true
level_dict[v]=true
end
elseif type(val)=="number" then
if val>=(1<<16) then -- compatibility
val=val>>16
end
Debug.Message(string.format("add additional level %d",val))
levelDict[val]=true
level_dict[val]=true
end
end
-- Always include original level
levelDict[card:GetLevel()]=true
level_dict[card:GetLevel()]=true
-- Convert dictionary keys back to array
local levels={}
for lvl,_ in pairs(levelDict) do
for lvl,_ in pairs(level_dict) do
table.insert(levels,lvl)
end
Debug.Message(string.format("lvel mapper result for %d, %d",card:GetCode(),#levels))
return levels
end
function Synchro.Updatepossible_sums(possible_sums, cardLevels, target_level)
local newSums={}
function Synchro.UpdatepossibleSums(possible_sums, card_levels, target_level)
local new_sums={}
for sum, _ in pairs(possible_sums) do
for _, lvl in ipairs(cardLevels) do
for _, lvl in ipairs(card_levels) do
local newSum=sum+lvl
if newSum<=target_level then
newSums[newSum] = true
new_sums[newSum] = true
end
end
end
return newSums
return new_sums
end
function Synchro.BuildStateFromSelection(sg_arr, tuner_filter, non_tuner_filter, levelMapper, tc, target_level)
local possible_sums={[0]=true}
local tuner_count=0
local non_tuner_count=0
function Synchro.BuildStatesFromSelection(selection,tuner_filter,non_tuner_filter,base_mapper,tc,target_level)
local states={
{
possible_sums={[0]=true},
tuner_count=0,
non_tuner_count=0,
level_mapper=base_mapper
}
}
for _,card in ipairs(sg_arr) do
local levels=levelMapper(card,tc)
possible_sums=Synchro.Updatepossible_sums(possible_sums,levels,target_level)
if next(possible_sums)==nil then
-- no possible sums from current selection, invalid state
assert(false)
return {}
for idx,card in ipairs(selection)do
local next_states={}
for _,st in ipairs(states) do
local tuner_inc=tuner_filter(card,tc) and 1 or 0
local non_tuner_inc=non_tuner_filter(card,tc) and 1 or 0
local mapper=st.level_mapper
-- normal branch
local lvls=mapper(card,tc)
local sums_norm=Synchro.UpdatepossibleSums(st.possible_sums,lvls,target_level)
if next(sums_norm) then
table.insert(next_states,{
possible_sums=sums_norm,
tuner_count=st.tuner_count+tuner_inc,
non_tuner_count=st.non_tuner_count+non_tuner_inc,
level_mapper=mapper,
})
end
if tuner_filter(card,tc) then
tuner_count=tuner_count+1
elseif non_tuner_filter(card,tc) then
non_tuner_count=non_tuner_count+1
else
assert(false)
return {} -- invalid material type
-- override level mapper branch if Flower Cardian
if card:IsCode(57261568,33541430,89818984) then
local sums_ovr={[2*idx]=true}
table.insert(next_states,{
possible_sums=sums_ovr,
tuner_count=st.tuner_count+tuner_inc,
non_tuner_count=st.non_tuner_count+non_tuner_inc,
level_mapper=function() return {2} end,
})
end
end
return {
possible_sums=possible_sums,
tuner_count=tuner_count,
non_tuner_count=non_tuner_count,
}
end
function Synchro.DeepcopyState(base_state)
local new_state={}
-- Copy primitive flags and counters
new_state.tuner_count=base_state and base_state.tuner_count or 0
new_state.non_tuner_count=base_state and base_state.non_tuner_count or 0
-- Copy or create possible sums table
if base_state and base_state.possible_sums then
new_state.possible_sums={}
for k,v in pairs(base_state.possible_sums) do
new_state.possible_sums[k]=v
states=next_states
if #states==0 then
break
end
else
new_state.possible_sums={[0]=true}
end
-- Copy other as needed
return new_state
return states
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