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

Add 花札衛

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