Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Y
ygopro-scripts-888
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
3
Merge Requests
3
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
ygopro-scripts-888
Commits
6c193bc3
Commit
6c193bc3
authored
Jul 14, 2025
by
Vury Leo
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
tuning 白の枢機竜
parent
0d056a5a
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
725 additions
and
781 deletions
+725
-781
c11321089.lua
c11321089.lua
+20
-1
c93053159.lua
c93053159.lua
+19
-3
procedure.lua
procedure.lua
+686
-777
No files found.
c11321089.lua
View file @
6c193bc3
...
@@ -8,7 +8,26 @@ function s.initial_effect(c)
...
@@ -8,7 +8,26 @@ function s.initial_effect(c)
Fusion
.
Slot
.
Group
({
Fusion
.
Slot
.
Group
({
min
=
3
,
min
=
3
,
max
=
3
,
max
=
3
,
unique_by
=
function
(
mc
)
return
{
mc
:
GetCode
(),
mc
:
GetFusionCode
()
}
end
,
--- @param mc Card
unique_by
=
function
(
mc
)
local
function
dedup_represent
(
code
)
if
code
==
78734254
then
return
17955766
elseif
code
==
13857930
then
return
17732278
end
return
code
end
local
code
=
dedup_represent
(
mc
:
GetCode
())
local
res
=
{
code
}
--- Add Fusion Tag names
for
_
,
eff
in
ipairs
({
mc
:
IsHasEffect
(
EFFECT_ADD_FUSION_CODE
)})
do
local
fusion_tag_code
=
eff
:
GetValue
()
assert
(
type
(
fusion_tag_code
)
==
'number'
)
table.insert
(
res
,
dedup_represent
(
fusion_tag_code
))
end
return
res
end
,
})
})
},
},
mat_filter
=
s
.
mat_filter
,
mat_filter
=
s
.
mat_filter
,
...
...
c93053159.lua
View file @
6c193bc3
...
@@ -9,9 +9,25 @@ function s.initial_effect(c)
...
@@ -9,9 +9,25 @@ function s.initial_effect(c)
Fusion
.
Slot
.
Group
({
-- 6 monsters in your GY with different names
Fusion
.
Slot
.
Group
({
-- 6 monsters in your GY with different names
min
=
6
,
min
=
6
,
max
=
6
,
max
=
6
,
filter
=
function
(
mc
)
return
mc
:
IsLocation
(
LOCATION_GRAVE
)
end
,
filter
=
function
(
mc
,
tc
)
return
mc
:
IsLocation
(
LOCATION_GRAVE
)
end
,
unique_by
=
function
(
tc
)
unique_by
=
function
(
mc
)
return
{
tc
:
GetFusionCode
()}
local
function
dedup_represent
(
code
)
if
code
==
78734254
then
return
17955766
elseif
code
==
13857930
then
return
17732278
end
return
code
end
local
code
=
dedup_represent
(
mc
:
GetCode
())
local
res
=
{
code
}
--- Add Fusion Tag names
for
_
,
eff
in
ipairs
({
mc
:
IsHasEffect
(
EFFECT_ADD_FUSION_CODE
)})
do
local
fusion_tag_code
=
eff
:
GetValue
()
assert
(
type
(
fusion_tag_code
)
==
'number'
)
table.insert
(
res
,
dedup_represent
(
fusion_tag_code
))
end
return
res
end
,
end
,
})
})
}
}
...
...
procedure.lua
View file @
6c193bc3
...
@@ -3476,339 +3476,247 @@ end
...
@@ -3476,339 +3476,247 @@ 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
.
BasicCondition
(
tc
,
slots
,
mat_filter
,
fgoalcheck
,
allow_extras
,
selected
)
function
Fusion
.
BasicCondition
(
tc
,
slots
,
mat_filter
,
fgoalcheck
,
allow_extras
,
selected
)
--g:Material group(nil for Instant Fusion)
--gc:Material already used
--chkf: check field, default:PLAYER_NONE
--chkf&0x100: Not fusion summon, can use substitute (Hex-Sealed 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
then
return
false
end
if
not
g
then
return
false
end
-- array
-- Collect cards and apply global mat_filter
local
cards
=
{}
local
cards
=
{}
for
mc
in
aux
.
Next
(
g
)
do
for
c
in
aux
.
Next
(
g
)
do
table.insert
(
cards
,
mc
)
if
not
mat_filter
or
mat_filter
(
c
,
tc
)
then
table.insert
(
cards
,
c
)
end
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
end
cards
=
tg
-- Split slots into singles and (at most one) group
end
local
single_slots
=
{}
if
#
cards
<#
slots
then
return
false
end
local
grp
-- split slots
local
single_slots
,
group_slots
=
{},
{}
for
_
,
slot
in
ipairs
(
slots
)
do
for
_
,
slot
in
ipairs
(
slots
)
do
if
slot
.
group
then
if
slot
.
group
then
table.insert
(
group_slots
,
slot
.
group
)
assert
(
not
grp
,
"only one group slot supported"
)
grp
=
slot
.
group
else
else
table.insert
(
single_slots
,
slot
)
table.insert
(
single_slots
,
slot
)
end
end
end
end
-- minimal total count
-- Quick minimal‐count check
local
total_req
=#
single_slots
local
total_min
=#
single_slots
+
(
grp
and
grp
.
min
or
0
)
for
_
,
grp
in
ipairs
(
group_slots
)
do
if
#
cards
<
total_min
then
total_req
=
total_req
+
grp
.
min
end
if
g
:
GetCount
()
<
total_req
then
return
false
return
false
end
end
--
prepare per-slot lock flags (lock only first matching slot per code or code list)
--
Prepare locked flags for substitute materials
local
locked
_slots
=
{}
local
locked
=
{}
if
Fusion
.
LockedCodes
then
if
Fusion
.
LockedCodes
then
for
_
,
code
in
ipairs
(
Fusion
.
LockedCodes
)
do
for
_
,
code
in
ipairs
(
Fusion
.
LockedCodes
)
do
for
i
dx
,
slot
in
ipairs
(
single_slots
)
do
for
i
,
slot
in
ipairs
(
single_slots
)
do
--
lock slot if its match_code equals code
--
direct match_code?
if
slot
.
match_code
==
code
then
if
slot
.
match_code
==
code
then
locked
_slots
[
idx
]
=
true
locked
[
i
]
=
true
break
break
end
end
--
lock slot if it's a multi-code slot containing code
--
or match_codes list?
if
slot
.
match_codes
then
if
slot
.
match_codes
then
for
_
,
c
in
ipairs
(
slot
.
match_codes
)
do
for
_
,
c
2
in
ipairs
(
slot
.
match_codes
)
do
if
c
==
code
then
if
c
2
==
code
then
locked
_slots
[
idx
]
=
true
locked
[
i
]
=
true
break
break
end
end
end
end
if
locked_slots
[
idx
]
then
break
end
if
locked
[
i
]
then
break
end
end
end
end
end
end
end
end
end
-- 5) DFS assign single‐slots
local
used
=
{}
local
used
=
{}
local
sub_count
=
0
local
sub_count
=
0
-- DFS assign slots
local
function
dfs_singles
(
i
)
local
function
dfs
(
i
)
if
i
>#
single_slots
then
if
i
>#
single_slots
then
-- check group slots on leftovers
-- Build base material group (selected + assigned singles)
local
mg_base
=
selected
and
selected
:
Clone
()
or
Group
.
CreateGroup
()
for
idx
,
flag
in
pairs
(
used
)
do
if
flag
then
mg_base
:
AddCard
(
cards
[
idx
])
end
end
-- Build leftovers list
local
leftovers
=
{}
local
leftovers
=
{}
for
idx
,
m
c
in
ipairs
(
cards
)
do
for
idx
,
c
in
ipairs
(
cards
)
do
if
not
used
[
idx
]
then
if
not
used
[
idx
]
then
table.insert
(
leftovers
,
mc
)
table.insert
(
leftovers
,
c
)
end
end
-- if strict (no extra), ensure leftover only match group slots
if
not
allow_extras
then
for
_
,
mc
in
ipairs
(
leftovers
)
do
local
ok
=
false
for
_
,
grp
in
ipairs
(
group_slots
)
do
if
(
not
grp
.
filter
or
grp
.
filter
(
mc
))
then
ok
=
true
break
end
end
if
not
ok
then
return
false
end
end
end
end
end
-- check each group-slot’s min/max its unique_by
for
_
,
grp
in
ipairs
(
group_slots
)
do
-- No group slot? Just do final checks
-- collect exactly the cards from leftovers that match this grp
if
not
grp
then
local
matched
=
{}
return
Fusion
.
FinalCheck
(
e
,
mg_base
,
tc
,
fgoalcheck
,
chkf
)
for
_
,
mc
in
ipairs
(
leftovers
)
do
if
(
not
grp
.
filter
or
grp
.
filter
(
mc
))
then
table.insert
(
matched
,
mc
)
end
end
-- cardinality check
if
#
matched
<
grp
.
min
then
return
false
end
if
not
allow_extras
then
if
#
matched
>
grp
.
max
then
return
false
end
end
end
-- unique‐key check
if
grp
.
unique_by
then
-- Group slot exists: branch on allow_extras
if
allow_extras
then
if
allow_extras
then
-- in “search” mode we only require *some* subset of size grp.min
-- search mode: try to find some subset of size grp.min
local
matcher
=
Fusion
.
UniqueByMatching
(
grp
.
unique_by
,
grp
.
min
)
return
Fusion
.
SearchGroup
(
e
,
leftovers
,
mg_base
,
grp
,
tc
,
fgoalcheck
,
chkf
)
if
not
matcher
(
matched
)
then
return
false
end
else
else
-- strict: need to cover *all* matched cards
-- strict mode: leftovers must *all* satisfy grp
local
matcher
=
Fusion
.
UniqueByMatching
(
grp
.
unique_by
,
#
matched
)
return
Fusion
.
StrictGroup
(
e
,
leftovers
,
mg_base
,
grp
,
tc
,
fgoalcheck
,
chkf
)
if
not
matcher
(
matched
)
then
return
false
end
end
end
end
end
-- has_same: each fn must overlap
if
grp
.
has_same
then
if
allow_extras
then
-- search-mode: find SOME subset of size grp.min satisfying both unique_by & all has_same
local
n
,
k
=#
matched
,
grp
.
min
local
comb
,
found
=
{},
false
local
function
check_subset
()
-- Prune if not enough cards remain
local
S
=
{}
local
used_count
=
0
for
_
,
idx_sub
in
ipairs
(
comb
)
do
for
_
,
v
in
pairs
(
used
)
do
table.insert
(
S
,
matched
[
idx_sub
])
if
v
then
end
used_count
=
used_count
+
1
-- unique_by on S
if
grp
.
unique_by
then
local
m
=
Fusion
.
UniqueByMatching
(
grp
.
unique_by
,
k
)
if
not
m
(
S
)
then
return
false
end
end
-- all has_same on S
for
_
,
fn
in
ipairs
(
grp
.
has_same
)
do
local
v0
=
fn
(
S
[
1
],
e
:
GetHandler
())
if
type
(
v0
)
==
"number"
then
local
mask
=
v0
for
j
=
2
,
#
S
do
mask
=
mask
&
fn
(
S
[
j
],
e
:
GetHandler
())
if
mask
==
0
then
return
false
end
end
else
local
common
=
{}
for
_
,
key
in
ipairs
(
v0
)
do
common
[
key
]
=
true
end
for
j
=
2
,
#
S
do
local
next_common
=
{}
for
_
,
key
in
ipairs
(
fn
(
S
[
j
],
e
:
GetHandler
()))
do
if
common
[
key
]
then
next_common
[
key
]
=
true
end
end
common
=
next_common
if
next
(
common
)
==
nil
then
return
false
end
end
end
end
end
-- build mg
local
mg
=
Group
.
FromCards
(
table.unpack
(
S
))
-- merge selected
mg
:
Merge
(
selected
)
-- merge in the DFS‐used cards
for
idx
,
flag
in
pairs
(
used
)
do
if
flag
then
mg
:
AddCard
(
cards
[
idx
])
end
end
if
(
#
cards
-
used_count
)
<
(
#
single_slots
-
i
+
1
)
then
return
false
end
end
if
fgoalcheck
then
local
slot
=
single_slots
[
i
]
if
not
fgoalcheck
(
mg
)
then
for
idx
,
c
in
ipairs
(
cards
)
do
return
false
if
not
used
[
idx
]
then
local
ok
,
is_sub
=
Fusion
.
MatchSlot
(
c
,
slot
,
tc
)
if
ok
and
not
(
is_sub
and
locked
[
i
])
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_singles
(
i
+
1
)
then
return
true
end
end
used
[
idx
]
=
false
sub_count
=
prev_sub
end
end
if
aux
.
FCheckAdditional
then
if
not
aux
.
FCheckAdditional
(
tc
:
GetOwner
(),
mg
,
tc
)
then
return
false
end
end
end
end
if
aux
.
FGoalCheckAdditional
then
if
not
aux
.
FGoalCheckAdditional
(
tc
:
GetOwner
(),
mg
,
tc
)
then
return
false
return
false
end
end
return
dfs_singles
(
1
)
end
end
if
not
aux
.
TuneMagicianCheckAdditionalX
(
EFFECT_TUNE_MAGICIAN_F
)(
mg
)
then
end
return
false
end
-- Final, post‐fusion checks (common to both modes)
-- ensure there's at least one free Monster Zone if chkf requests a field-checked summon
function
Fusion
.
FinalCheck
(
e
,
mg
,
tc
,
fgoalcheck
,
chkf
)
if
chkf
&
0xf
~=
PLAYER_NONE
then
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
not
aux
.
TuneMagicianCheckAdditionalX
(
EFFECT_TUNE_MAGICIAN_F
)(
mg
)
then
return
false
end
if
(
chkf
&
0xf
)
~=
PLAYER_NONE
then
local
tp
=
chkf
&
0xf
local
tp
=
chkf
&
0xf
if
Duel
.
GetLocationCountFromEx
(
tp
,
tp
,
mg
,
tc
)
<=
0
then
if
Duel
.
GetLocationCountFromEx
(
tp
,
tp
,
mg
,
tc
)
<=
0
then
return
false
return
false
end
end
end
end
return
true
return
true
end
end
local
function
dfs_comb
(
start
)
if
found
then
return
end
if
#
comb
==
k
then
if
check_subset
()
then
found
=
true
end
return
end
for
idx
=
start
,
n
do
table.insert
(
comb
,
idx
)
dfs_comb
(
idx
+
1
)
table.remove
(
comb
)
if
found
then
return
end
end
end
dfs_comb
(
1
)
-- Strict mode: *all* leftovers must fit grp, then final check
if
not
found
then
return
false
end
function
Fusion
.
StrictGroup
(
e
,
leftovers
,
mg_base
,
grp
,
tc
,
fgoalcheck
,
chkf
)
-- filter leftovers by grp.filter
local
matched
=
{}
for
_
,
c
in
ipairs
(
leftovers
)
do
if
not
grp
.
filter
or
grp
.
filter
(
c
,
tc
)
then
table.insert
(
matched
,
c
)
else
else
for
_
,
fn
in
ipairs
(
grp
.
has_same
)
do
local
v0
=
fn
(
matched
[
1
],
e
:
GetHandler
())
if
type
(
v0
)
==
"number"
then
-- bitmask path
local
common_mask
=
v0
for
j
=
2
,
#
matched
do
common_mask
=
common_mask
&
fn
(
matched
[
j
],
e
:
GetHandler
())
if
common_mask
==
0
then
return
false
return
false
end
end
end
end
elseif
type
(
v0
)
==
"table"
then
-- cardinality
-- list-of-keys path
if
#
matched
<
grp
.
min
or
#
matched
>
grp
.
max
then
local
common
=
{}
for
_
,
k
in
ipairs
(
v0
)
do
common
[
k
]
=
true
end
for
j
=
2
,
#
matched
do
local
next_common
=
{}
for
_
,
k
in
ipairs
(
fn
(
matched
[
j
],
e
:
GetHandler
()))
do
if
common
[
k
]
then
next_common
[
k
]
=
true
end
end
common
=
next_common
if
next
(
common
)
==
nil
then
return
false
end
end
else
error
(
"unsupported return type of group.has_same"
)
return
false
return
false
end
end
end
-- has_same on full matched
end
if
grp
.
has_same
and
not
Fusion
.
CheckHasSame
(
grp
,
Group
.
FromCards
(
table.unpack
(
matched
)),
e
)
then
end
end
-- build mg
local
mg
=
selected
and
selected
:
Clone
()
or
Group
.
CreateGroup
()
-- merge in the DFS‐used cards
for
idx
,
flag
in
pairs
(
used
)
do
if
flag
then
mg
:
AddCard
(
cards
[
idx
])
end
end
if
fgoalcheck
then
if
not
fgoalcheck
(
mg
)
then
return
false
return
false
end
end
end
-- unique_by on full matched
if
aux
.
FCheckAdditional
then
if
grp
.
unique_by
then
if
not
aux
.
FCheckAdditional
(
tc
:
GetOwner
(),
mg
,
tc
)
then
local
matcher
=
Fusion
.
UniqueByMatching
(
grp
.
unique_by
,
#
matched
)
if
not
matcher
(
matched
)
then
return
false
return
false
end
end
end
end
if
aux
.
FGoalCheckAdditional
then
-- merge and final
if
not
aux
.
FGoalCheckAdditional
(
tc
:
GetOwner
(),
mg
,
tc
)
then
local
mg
=
mg_base
:
Clone
()
return
false
for
_
,
c
in
ipairs
(
matched
)
do
mg
:
AddCard
(
c
)
end
return
Fusion
.
FinalCheck
(
e
,
mg
,
tc
,
fgoalcheck
,
chkf
)
end
-- Search mode: find *some* size‐grp.min subset that passes
function
Fusion
.
SearchGroup
(
e
,
leftovers
,
mg_base
,
grp
,
tc
,
fgoalcheck
,
chkf
)
-- filter leftovers by grp.filter
local
matched
=
{}
for
_
,
c
in
ipairs
(
leftovers
)
do
if
not
grp
.
filter
or
grp
.
filter
(
c
,
tc
)
then
table.insert
(
matched
,
c
)
end
end
end
end
if
not
aux
.
TuneMagicianCheckAdditionalX
(
EFFECT_TUNE_MAGICIAN_F
)(
mg
)
then
if
#
matched
<
grp
.
min
then
return
false
end
local
comb
=
{}
local
function
dfs_comb
(
start
,
depth
)
if
depth
>
grp
.
min
then
-- subset built in comb[1..grp.min]
local
subG
=
Group
.
FromCards
(
table.unpack
(
comb
))
-- has_same
if
grp
.
has_same
and
not
Fusion
.
CheckHasSame
(
grp
,
subG
,
e
)
then
return
false
return
false
end
end
-- ensure there's at least one free Monster Zone if chkf requests a field-checked summon
-- unique_by
if
chkf
&
0xf
~=
PLAYER_NONE
then
if
grp
.
unique_by
then
local
tp
=
chkf
&
0xf
local
matcher
=
Fusion
.
UniqueByMatching
(
grp
.
unique_by
,
grp
.
min
)
if
Duel
.
GetLocationCountFromEx
(
tp
,
tp
,
mg
,
tc
)
<=
0
then
if
not
matcher
(
comb
)
then
return
false
return
false
end
end
end
end
return
true
-- merge & final
local
mg
=
mg_base
:
Clone
()
mg
:
Merge
(
subG
)
return
Fusion
.
FinalCheck
(
e
,
mg
,
tc
,
fgoalcheck
,
chkf
)
end
end
-- prune if not enough cards left
for
i
=
start
,
#
matched
-
(
grp
.
min
-
depth
)
+
1
do
local
used_count
=
0
comb
[
depth
]
=
matched
[
i
]
for
_
,
v
in
pairs
(
used
)
do
if
dfs_comb
(
i
+
1
,
depth
+
1
)
then
if
v
then
return
true
used_count
=
used_count
+
1
end
end
end
end
if
(
#
cards
-
used_count
)
<
(
#
single_slots
-
i
+
1
)
then
return
false
return
false
end
end
-- try each card
local
slot
=
single_slots
[
i
]
return
dfs_comb
(
1
,
1
)
for
idx
,
mc
in
ipairs
(
cards
)
do
end
if
not
used
[
idx
]
then
local
match
,
is_sub
=
Fusion
.
MatchSlot
(
mc
,
slot
,
tc
)
-- Shared has_same checker (bitmask or key‐list)
if
match
==
true
then
function
Fusion
.
CheckHasSame
(
grp
,
group_obj
,
e
)
-- skip sub material if slot is locked
local
cards
=
{}
if
not
(
is_sub
and
locked_slots
[
i
])
then
for
c
in
aux
.
Next
(
group_obj
)
do
table.insert
(
cards
,
c
)
end
-- commit material
for
_
,
fn
in
ipairs
(
grp
.
has_same
)
do
used
[
idx
]
=
true
local
v0
=
fn
(
cards
[
1
],
e
:
GetHandler
())
local
prev_sub
=
sub_count
if
type
(
v0
)
==
"number"
then
if
is_sub
then
sub_count
=
sub_count
+
1
end
local
mask
=
v0
if
sub_count
<=
1
and
dfs
(
i
+
1
)
then
for
j
=
2
,
#
cards
do
return
true
mask
=
mask
&
fn
(
cards
[
j
],
e
:
GetHandler
())
end
if
mask
==
0
then
return
false
end
-- backtrack
used
[
idx
]
=
false
sub_count
=
prev_sub
end
end
end
else
local
common
=
{}
for
_
,
k
in
ipairs
(
v0
)
do
common
[
k
]
=
true
end
for
j
=
2
,
#
cards
do
local
nextc
=
{}
for
_
,
k
in
ipairs
(
fn
(
cards
[
j
],
e
:
GetHandler
()))
do
if
common
[
k
]
then
nextc
[
k
]
=
true
end
end
end
common
=
nextc
if
not
next
(
common
)
then
return
false
end
end
end
return
false
end
end
return
dfs
(
1
)
end
end
return
true
end
end
--- Helper: check one card against a named slot
--- Helper: check one card against a named slot
...
@@ -3869,6 +3777,8 @@ end
...
@@ -3869,6 +3777,8 @@ end
---@param filter fun(mc:Card,tc:Card):boolean
---@param filter fun(mc:Card,tc:Card):boolean
---@return table
---@return table
function
Fusion
.
Slot
.
Filter
(
filter
)
function
Fusion
.
Slot
.
Filter
(
filter
)
local
base_filter
=
filter
filter
=
aux
.
AND
(
base_filter
,
function
(
mc
,
tc
)
return
not
mc
:
IsHasEffect
(
6205579
)
end
)
return
{
return
{
filter
=
filter
,
filter
=
filter
,
allow_sub
=
false
allow_sub
=
false
...
@@ -3881,25 +3791,27 @@ end
...
@@ -3881,25 +3791,27 @@ end
function
Fusion
.
Slot
.
Group
(
opts
)
function
Fusion
.
Slot
.
Group
(
opts
)
opts
.
min
=
opts
.
min
or
1
opts
.
min
=
opts
.
min
or
1
opts
.
max
=
opts
.
max
or
math.huge
opts
.
max
=
opts
.
max
or
math.huge
opts
.
filter
=
opts
.
filter
or
aux
.
TRUE
local
base_filter
=
opts
.
filter
or
aux
.
TRUE
opts
.
filter
=
aux
.
AND
(
base_filter
,
function
(
mc
,
tc
)
return
not
mc
:
IsHasEffect
(
6205579
)
end
)
return
{
return
{
group
=
opts
group
=
opts
}
}
end
end
--- FindAllMapping
--- FindAllMapping
s
--- @param cards_sel Card[] currently picked materials
--- @param cards_sel Card[] currently picked materials
--- @param slots table[] your original slots spec
--- @param slots table[] your original slots spec
--- @param tc 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)
--- @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
)
--- empty selection, just return
--- empty selection, just return
one “empty” mapping
if
#
cards_sel
==
0
then
if
#
cards_sel
==
0
then
return
{{}}
return
{{}}
end
end
-- Trackers
local
filled
=
{}
-- for single slots
-- Trackers: single‐slots vs group‐slots
local
group_assigned
=
{}
-- how many cards assigned so far to each group slot
local
filled
=
{}
-- filled[i] = true if single slot i is already taken
local
group_assigned
=
{}
-- group_assigned[i] = count assigned to slots[i].group
for
i
,
slot
in
ipairs
(
slots
)
do
for
i
,
slot
in
ipairs
(
slots
)
do
if
slot
.
group
then
if
slot
.
group
then
group_assigned
[
i
]
=
0
group_assigned
[
i
]
=
0
...
@@ -3908,16 +3820,19 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
...
@@ -3908,16 +3820,19 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
end
end
end
end
-- prepare locked_slots for this mapping
-- Prepare locked_slots for substitute‐material restrictions
local
locked_slots
=
{}
local
locked_slots
=
{}
if
Fusion
.
LockedCodes
then
if
Fusion
.
LockedCodes
then
for
_
,
code
in
ipairs
(
Fusion
.
LockedCodes
)
do
for
_
,
code
in
ipairs
(
Fusion
.
LockedCodes
)
do
for
idx
,
slot
in
ipairs
(
slots
)
do
for
idx
,
slot
in
ipairs
(
slots
)
do
local
matched
=
false
local
matched
=
false
if
slot
.
match_code
==
code
then
matched
=
true
-- direct code match?
if
slot
.
match_code
==
code
then
matched
=
true
-- or inside match_codes?
elseif
slot
.
match_codes
then
elseif
slot
.
match_codes
then
for
_
,
c
in
ipairs
(
slot
.
match_codes
)
do
for
_
,
c2
in
ipairs
(
slot
.
match_codes
)
do
if
c
==
code
then
if
c
2
==
code
then
matched
=
true
matched
=
true
break
break
end
end
...
@@ -3925,41 +3840,42 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
...
@@ -3925,41 +3840,42 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
end
end
if
matched
then
if
matched
then
locked_slots
[
idx
]
=
true
locked_slots
[
idx
]
=
true
break
break
-- stop scanning slots for this code
end
end
end
end
end
end
end
end
local
all_maps
=
{}
local
all_maps
=
{}
local
mapping
=
{}
-- mapping[idx_in_cards_sel] = slot_index
local
mapping
=
{}
-- mapping[j] = slot index assigned to cards_sel[j]
--- Depth‐first search over cards_sel
local
function
dfs
(
idx
,
sub_count
)
local
function
dfs
(
idx
,
sub_count
)
-- prune: no more than 1 substitute
-- never use more than 1 substitute material
if
sub_count
>
1
then
if
sub_count
>
1
then
return
return
end
end
-- all cards assigned: check per‐group unique_by, then record
if
idx
>#
cards_sel
then
if
idx
>#
cards_sel
then
-- Before recording, run unique_by on each group‐slot that has one
for
i
,
slot
in
ipairs
(
slots
)
do
for
i
,
slot
in
ipairs
(
slots
)
do
if
slot
.
group
and
slot
.
group
.
unique_by
then
local
assigned
=
group_assigned
[
i
]
-- collect the cards assigned to slot i
if
slot
.
group
and
slot
.
group
.
unique_by
and
assigned
>
0
then
-- collect the cards mapped to slot i
local
sel_group
=
{}
local
sel_group
=
{}
for
j
,
t
c
in
ipairs
(
cards_sel
)
do
for
j
,
m
c
in
ipairs
(
cards_sel
)
do
if
mapping
[
j
]
==
i
then
if
mapping
[
j
]
==
i
then
table.insert
(
sel_group
,
t
c
)
table.insert
(
sel_group
,
m
c
)
end
end
end
end
-- run the matcher: must cover all |sel_group| cards
-- run the uniqueness matcher on that set
local
matcher
=
Fusion
.
UniqueByMatching
(
slot
.
group
.
unique_by
,
#
sel_group
)
local
matcher
=
Fusion
.
UniqueByMatching
(
slot
.
group
.
unique_by
,
#
sel_group
)
if
not
matcher
(
sel_group
)
then
if
not
matcher
(
sel_group
)
then
-- this mapping fails uniqueness → prune it
return
-- fails unique_by → abandon this mapping
return
end
end
end
end
end
end
-- passed all unique_by checks → save it
-- passes all uniqueness checks → record it
local
copy
=
{}
local
copy
=
{}
for
k
,
v
in
pairs
(
mapping
)
do
for
k
,
v
in
pairs
(
mapping
)
do
copy
[
k
]
=
v
copy
[
k
]
=
v
...
@@ -3969,15 +3885,13 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
...
@@ -3969,15 +3885,13 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
end
end
local
mc
=
cards_sel
[
idx
]
local
mc
=
cards_sel
[
idx
]
local
any_match
=
false
-- track if we managed to assign tc
local
any_match
=
false
-- try single
slots
-- try single
‐
slots
for
i
,
slot
in
ipairs
(
slots
)
do
for
i
,
slot
in
ipairs
(
slots
)
do
if
not
slot
.
group
and
not
filled
[
i
]
then
if
not
slot
.
group
and
not
filled
[
i
]
then
local
match
,
is_sub
=
Fusion
.
MatchSlot
(
mc
,
slot
,
tc
)
local
ok
,
is_sub
=
Fusion
.
MatchSlot
(
mc
,
slot
,
tc
)
if
match
then
if
ok
and
not
(
is_sub
and
locked_slots
[
i
])
then
-- skip if substitute and this slot is locked
if
not
(
is_sub
and
locked_slots
[
i
])
then
local
new_sub
=
sub_count
+
(
is_sub
and
1
or
0
)
local
new_sub
=
sub_count
+
(
is_sub
and
1
or
0
)
if
new_sub
<=
1
then
if
new_sub
<=
1
then
any_match
=
true
any_match
=
true
...
@@ -3990,44 +3904,38 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
...
@@ -3990,44 +3904,38 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
end
end
end
end
end
end
end
-- try group slots
-- try the group‐slot, if any
for
i
,
slot
in
ipairs
(
slots
)
do
for
i
,
slot
in
ipairs
(
slots
)
do
if
slot
.
group
then
if
slot
.
group
then
local
assigned
=
group_assigned
[
i
]
local
assigned
=
group_assigned
[
i
]
if
assigned
<
slot
.
group
.
max
then
if
assigned
<
slot
.
group
.
max
then
-- base filter
-- filter check
if
not
slot
.
group
.
filter
or
slot
.
group
.
filter
(
mc
,
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
-- has_same check (if this isn’t the first in the group)
local
ok
=
true
local
ok
=
true
if
slot
.
group
.
has_same
and
assigned
>
0
then
if
slot
.
group
.
has_same
and
assigned
>
0
then
for
_
,
fn
in
ipairs
(
slot
.
group
.
has_same
)
do
for
_
,
fn
in
ipairs
(
slot
.
group
.
has_same
)
do
-- start intersection with this candidate
local
v0
=
fn
(
mc
,
tc
)
local
v0
=
fn
(
mc
,
tc
)
if
type
(
v0
)
==
"number"
then
if
type
(
v0
)
==
"number"
then
-- bitmask path
local
mask
=
v0
local
mask
=
v0
-- AND with each already‐assigned card
for
j
=
1
,
idx
-
1
do
for
j
=
1
,
idx
-
1
do
if
mapping
[
j
]
==
i
then
if
mapping
[
j
]
==
i
then
mask
=
mask
&
fn
(
cards_sel
[
j
],
tc
)
mask
=
mask
&
fn
(
cards_sel
[
j
],
tc
)
if
mask
==
0
then
break
end
if
mask
==
0
then
break
end
end
end
end
end
if
mask
==
0
then
ok
=
false
end
if
mask
==
0
then
ok
=
false
end
else
else
-- list-of-keys path
local
common
=
{}
local
common
=
{}
for
_
,
k
in
ipairs
(
v0
)
do
common
[
k
]
=
true
end
for
_
,
key
in
ipairs
(
v0
)
do
common
[
key
]
=
true
end
-- intersect with each already-assigned card
for
j
=
1
,
idx
-
1
do
for
j
=
1
,
idx
-
1
do
if
mapping
[
j
]
==
i
then
if
mapping
[
j
]
==
i
then
local
next_
c
=
{}
local
next
c
=
{}
for
_
,
k
in
ipairs
(
fn
(
cards_sel
[
j
],
tc
))
do
for
_
,
key
in
ipairs
(
fn
(
cards_sel
[
j
],
tc
))
do
if
common
[
k
]
then
next_c
[
k
]
=
true
end
if
common
[
key
]
then
nextc
[
key
]
=
true
end
end
end
common
=
next_
c
common
=
next
c
if
not
next
(
common
)
then
break
end
if
not
next
(
common
)
then
break
end
end
end
end
end
...
@@ -4039,7 +3947,7 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
...
@@ -4039,7 +3947,7 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
if
ok
then
if
ok
then
any_match
=
true
any_match
=
true
group_assigned
[
i
]
=
assigned
+
1
group_assigned
[
i
]
=
assigned
+
1
mapping
[
idx
]
=
i
mapping
[
idx
]
=
i
dfs
(
idx
+
1
,
sub_count
)
dfs
(
idx
+
1
,
sub_count
)
group_assigned
[
i
]
=
assigned
group_assigned
[
i
]
=
assigned
...
@@ -4050,7 +3958,7 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
...
@@ -4050,7 +3958,7 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
end
end
end
end
-- If we couldn’t assign tc to any slot, prune
this branch
-- if nothing matched, abandon
this branch
if
not
any_match
then
if
not
any_match
then
return
return
end
end
...
@@ -4060,6 +3968,7 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
...
@@ -4060,6 +3968,7 @@ function Fusion.FindAllMappings(cards_sel,slots,tc)
return
all_maps
return
all_maps
end
end
--- “Given all mappings of sel into slots, can any one of them be completed by drawing from eg?”
--- “Given all mappings of sel into slots, can any one of them be completed by drawing from eg?”
--- @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)
...
@@ -4145,7 +4054,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
...
@@ -4145,7 +4054,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
-- if this slot has a has_same, wrap its filter to include only sames
-- if this slot has a has_same, wrap its filter to include only sames
if
slot
.
group
.
has_same
then
if
slot
.
group
.
has_same
then
-- only if there is at least one already‐selected card for this slot…
-- only if there is at least one already‐selected card for this slot…
local
has_sel
=
false
local
has_sel
=
false
for
_
,
mapped_i
in
pairs
(
mapping
)
do
for
_
,
mapped_i
in
pairs
(
mapping
)
do
if
mapped_i
==
i
then
if
mapped_i
==
i
then
has_sel
=
true
has_sel
=
true
...
@@ -4181,12 +4090,12 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
...
@@ -4181,12 +4090,12 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
local
prev
=
new_filter
local
prev
=
new_filter
new_filter
=
function
(
mc
,
p_tc
)
new_filter
=
function
(
mc
,
p_tc
)
-- original criteria
-- original criteria
if
prev
and
not
prev
(
mc
,
tc
)
then
if
prev
and
not
prev
(
mc
,
p_
tc
)
then
return
false
return
false
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
,
tc
)
local
v
=
fn
(
mc
,
p_
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
...
@@ -4232,7 +4141,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
...
@@ -4232,7 +4141,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
-- if nothing remains, we exhausted slots, check fgoal
-- if nothing remains, we exhausted slots, check fgoal
if
#
rem_slots
==
0
then
if
#
rem_slots
==
0
then
if
(
fgoalcheck
==
nil
or
fgoalcheck
(
sel
)
==
true
)
and
(
aux
.
FGoalCheckAdditional
==
nil
or
aux
.
FGoalCheckAdditional
(
tc
:
GetOwner
(),
sel
,
tc
))
and
aux
.
TuneMagicianCheckAdditionalX
(
EFFECT_TUNE_MAGICIAN_F
)(
sel
)
then
if
Fusion
.
FinalCheck
(
e
,
sel
,
tc
,
fgoalcheck
,
chkf
)
then
Fusion
.
LockedCodes
=
old_locked
Fusion
.
LockedCodes
=
old_locked
return
true
return
true
else
else
...
@@ -4241,7 +4150,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
...
@@ -4241,7 +4150,7 @@ function Fusion.CanCompleteFromMappings(e,sel,eg,slots,mat_filter,fgoalcheck,tc,
end
end
end
end
-- delegate to FusionCondition (allow_extras =
true)
-- delegate to FusionCondition (allow_extras=
true)
local
search_cond
=
Fusion
.
BasicCondition
(
tc
,
rem_slots
,
mat_filter
,
fgoalcheck
,
true
,
sel
)
local
search_cond
=
Fusion
.
BasicCondition
(
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
Fusion
.
LockedCodes
=
old_locked
Fusion
.
LockedCodes
=
old_locked
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment