forked from ProjectIgnis/CardScripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathproc_ritual.lua
372 lines (362 loc) · 14.8 KB
/
proc_ritual.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
if not aux.RitualProcedure then
aux.RitualProcedure = {}
Ritual = aux.RitualProcedure
end
if not Ritual then
Ritual = aux.RitualProcedure
end
--overwrite Duel.GetRitualMaterial to return Extra Deck monsters
--that have an EFFECT_EXTRA_RITUAL_MATERIAL effect on them
Duel.GetRitualMaterial=(function()
local oldfunc=Duel.GetRitualMaterial
return function(tp,check)
local res=oldfunc(tp,check)
local g=Duel.GetMatchingGroup(Card.IsHasEffect,tp,LOCATION_EXTRA,0,nil,EFFECT_EXTRA_RITUAL_MATERIAL)
if #g>0 then
res:Merge(g)
end
return res
end
end)()
--overwrite Duel.ReleaseRitualMaterial to support sending Extra Deck
--"mats" to the GY by default
Duel.ReleaseRitualMaterial=(function()
local oldfunc=Duel.ReleaseRitualMaterial
return function(g)
local extra_g=g:Filter(Card.IsLocation,nil,LOCATION_EXTRA)
if #extra_g>0 then
Duel.SendtoGrave(extra_g,REASON_RITUAL+REASON_EFFECT+REASON_MATERIAL)
g:Sub(extra_g)
end
return oldfunc(g)
end
end)()
function Ritual.GetMatchingFilterFunction(c)
local mt=c.__index
if not mt.ritual_matching_function or not mt.ritual_matching_function[c] then
return aux.TRUE
end
return mt.ritual_matching_function[c]
end
function Ritual.CheckMatFilter(matfilter,e,tp,mg,mg2)
if matfilter then
if type(matfilter)=="function" then
mg:Sub(mg:Filter(aux.NOT(matfilter),nil,e,tp))
mg2:Sub(mg2:Filter(aux.NOT(matfilter),nil,e,tp))
else
local f=function(c)
return not matfilter:IsContains(c)
end
mg:Sub(mg:Filter(f,nil))
mg2:Sub(mg2:Filter(f,nil))
end
end
end
--The current total level to match for the monster being summoned, to be used with monsters that can be used as whole tribute
Ritual.SummoningLevel=nil
function Ritual.AddWholeLevelTribute(c,condition)
local e=Effect.CreateEffect(c)
e:SetType(EFFECT_TYPE_SINGLE)
e:SetCode(EFFECT_RITUAL_LEVEL)
e:SetValue(Ritual.WholeLevelTributeValue(condition))
c:RegisterEffect(e)
return e
end
function Ritual.WholeLevelTributeValue(cond)
return function(e,c)
local lv=e:GetHandler():GetLevel()
if cond(c,e) then
local clv=Ritual.SummoningLevel and Ritual.SummoningLevel or c:GetLevel()
return (lv<<16)|clv
else return lv end
end
end
--Ritual Summon
Ritual.CreateProc = aux.FunctionWithNamedArgs(
function(c,_type,filter,lv,desc,extrafil,extraop,matfilter,stage2,location,forcedselection,customoperation,specificmatfilter,requirementfunc,sumpos)
--lv can be a function (like GetLevel/GetOriginalLevel), fixed level, if nil it defaults to GetLevel
if filter and type(filter)=="function" then
local mt=c.__index
if not mt.ritual_matching_function then
mt.ritual_matching_function={}
end
mt.ritual_matching_function[c]=filter
end
local e1=Effect.CreateEffect(c)
if desc then
e1:SetDescription(desc)
else
e1:SetDescription(1171)
end
e1:SetCategory(CATEGORY_SPECIAL_SUMMON)
e1:SetType(EFFECT_TYPE_ACTIVATE)
e1:SetCode(EVENT_FREE_CHAIN)
e1:SetTarget(Ritual.Target(filter,_type,lv,extrafil,extraop,matfilter,stage2,location,forcedselection,specificmatfilter,requirementfunc,sumpos))
e1:SetOperation(Ritual.Operation(filter,_type,lv,extrafil,extraop,matfilter,stage2,location,forcedselection,customoperation,specificmatfilter,requirementfunc,sumpos))
return e1
end,"handler","lvtype","filter","lv","desc","extrafil","extraop","matfilter","stage2","location","forcedselection","customoperation","specificmatfilter","requirementfunc","sumpos")
Ritual.AddProc = aux.FunctionWithNamedArgs(
function(c,_type,filter,lv,desc,extrafil,extraop,matfilter,stage2,location,forcedselection,customoperation,specificmatfilter,requirementfunc,sumpos)
local e1=Ritual.CreateProc(c,_type,filter,lv,desc,extrafil,extraop,matfilter,stage2,location,forcedselection,customoperation,specificmatfilter,requirementfunc,sumpos)
c:RegisterEffect(e1)
return e1
end,"handler","lvtype","filter","lv","desc","extrafil","extraop","matfilter","stage2","location","forcedselection","customoperation","specificmatfilter","requirementfunc","sumpos")
local function WrapTableReturn(func)
return function(...)
return {func(...)}
end
end
function Ritual.Filter(c,filter,_type,e,tp,m,m2,forcedselection,specificmatfilter,lv,requirementfunc,sumpos)
if not c:IsRitualMonster() or (filter and not filter(c)) or not c:IsCanBeSpecialSummoned(e,SUMMON_TYPE_RITUAL,tp,false,true,sumpos) then return false end
local lv=(lv and (type(lv)=="function" and lv(c)) or lv) or c:GetLevel()
lv=math.max(1,lv)
Ritual.SummoningLevel=lv
local mg=m:Filter(Card.IsCanBeRitualMaterial,c,c)
mg:Merge(m2-c)
if c.ritual_custom_condition then
return c:ritual_custom_condition(mg,forcedselection,_type)
end
if c.mat_filter then
mg:Match(c.mat_filter,c,tp)
end
if specificmatfilter then
mg:Match(specificmatfilter,nil,c,mg,tp)
end
local func=forcedselection and WrapTableReturn(forcedselection) or nil
if c.ritual_custom_check then
if forcedselection then
func=aux.tableAND(WrapTableReturn(c.ritual_custom_check),forcedselection)
else
func=WrapTableReturn(c.ritual_custom_check)
end
end
local res=aux.SelectUnselectGroup(mg,e,tp,1,lv,Ritual.Check(c,lv,func,_type,requirementfunc),0)
Ritual.SummoningLevel=nil
return res
end
Ritual.Target = aux.FunctionWithNamedArgs(
function(filter,_type,lv,extrafil,extraop,matfilter,stage2,location,forcedselection,specificmatfilter,requirementfunc,sumpos)
location = location or LOCATION_HAND
sumpos = sumpos or POS_FACEUP
return function(e,tp,eg,ep,ev,re,r,rp,chk)
if chk==0 then
local mg=Duel.GetRitualMaterial(tp,not requirementfunc)
local mg2=extrafil and extrafil(e,tp,eg,ep,ev,re,r,rp,chk) or Group.CreateGroup()
--if an EFFECT_EXTRA_RITUAL_MATERIAL effect has a forcedselection of its own
--add that forcedselection to the one of the Ritual Spell, if any
local extra_eff_g=mg:Filter(Card.IsHasEffect,nil,EFFECT_EXTRA_RITUAL_MATERIAL)
if #extra_eff_g>0 then
local prev_repl_function=nil
for tmp_c in extra_eff_g:Iter() do
local effs={tmp_c:IsHasEffect(EFFECT_EXTRA_RITUAL_MATERIAL)}
for _,eff in ipairs(effs) do
local repl_function=eff:GetLabelObject()
if repl_function and prev_repl_function~=repl_function[1] then
prev_repl_function=repl_function[1]
if not forcedselection then
forcedselection=repl_function[1]
elseif forcedselection~=repl_function[1] then
forcedselection=(function()
local oldfunc=forcedselection
return function(e,tp,sg,sc)
local ret1,ret2=oldfunc(e,tp,sg,sc)
local repl1,repl2=repl_function[1](e,tp,sg,sc)
return ret1 and repl1,ret2 or repl2
end
end)()
end
end
end
end
end
Ritual.CheckMatFilter(matfilter,e,tp,mg,mg2)
return Duel.IsExistingMatchingCard(Ritual.Filter,tp,location,0,1,e:GetHandler(),filter,_type,e,tp,mg,mg2,forcedselection,specificmatfilter,lv,requirementfunc,sumpos)
end
Duel.SetOperationInfo(0,CATEGORY_SPECIAL_SUMMON,nil,1,tp,location)
end
end,"filter","lvtype","lv","extrafil","extraop","matfilter","stage2","location","forcedselection","specificmatfilter","requirementfunc","sumpos")
function Auxiliary.RitualCheckAdditionalLevel(c,rc)
local raw_level=c:GetRitualLevel(rc)
local lv1=raw_level&0xffff
local lv2=raw_level>>16
if lv2>0 then
return math.min(lv1,lv2)
else
return lv1
end
end
function Ritual.Check(sc,lv,forcedselection,_type,requirementfunc)
local chk
if _type==RITPROC_EQUAL then
chk=function(g) return g:GetSum(requirementfunc or Auxiliary.RitualCheckAdditionalLevel,sc)<=lv end
else
chk=function(g,c) return g:GetSum(requirementfunc or Auxiliary.RitualCheckAdditionalLevel,sc) - (requirementfunc or Auxiliary.RitualCheckAdditionalLevel)(c,sc)<=lv end
end
return function(sg,e,tp,mg,c)
local res=chk(sg,c)
if not res then return false,true end
local stop=false
if forcedselection then
local ret=forcedselection(e,tp,sg,sc)
res=ret[1]
stop=ret[2] or stop
end
if res and not stop then
if _type==RITPROC_EQUAL then
res=sg:CheckWithSumEqual(requirementfunc or Card.GetRitualLevel,lv,#sg,#sg,sc)
else
Duel.SetSelectedCard(sg)
res=sg:CheckWithSumGreater(requirementfunc or Card.GetRitualLevel,lv,sc)
end
local stop=false
res=res and Duel.GetMZoneCount(tp,sg,tp)>0
end
return res,stop
end
end
function Ritual.Finishcon(sc,lv,requirementfunc,_type)
return function(sg,e,tp,mg)
if _type==RITPROC_EQUAL then
return sg:CheckWithSumEqual(requirementfunc or Card.GetRitualLevel,lv,#sg,#sg,sc)
else
Duel.SetSelectedCard(sg)
return sg:CheckWithSumGreater(requirementfunc or Card.GetRitualLevel,lv,sc)
end
end
end
Ritual.Operation = aux.FunctionWithNamedArgs(
function(filter,_type,lv,extrafil,extraop,matfilter,stage2,location,forcedselection,customoperation,specificmatfilter,requirementfunc,sumpos)
location = location or LOCATION_HAND
sumpos = sumpos or POS_FACEUP
return function(e,tp,eg,ep,ev,re,r,rp)
local mg=Duel.GetRitualMaterial(tp,not requirementfunc)
local mg2=extrafil and extrafil(e,tp,eg,ep,ev,re,r,rp) or Group.CreateGroup()
--if an EFFECT_EXTRA_RITUAL_MATERIAL effect has a forcedselection of its own
--add that forcedselection to the one of the Ritual Spell, if any
local extra_eff_g=mg:Filter(Card.IsHasEffect,nil,EFFECT_EXTRA_RITUAL_MATERIAL)
if #extra_eff_g>0 then
local prev_repl_function=nil
for tmp_c in extra_eff_g:Iter() do
local effs={tmp_c:IsHasEffect(EFFECT_EXTRA_RITUAL_MATERIAL)}
for _,eff in ipairs(effs) do
local repl_function=eff:GetLabelObject()
if repl_function and prev_repl_function~=repl_function[1] then
prev_repl_function=repl_function[1]
if not forcedselection then
forcedselection=repl_function[1]
elseif forcedselection~=repl_function[1] then
forcedselection=(function()
local oldfunc=forcedselection
return function(e,tp,sg,sc)
local ret1,ret2=oldfunc(e,tp,sg,sc)
local repl1,repl2=repl_function[1](e,tp,sg,sc)
return ret1 and repl1,ret2 or repl2
end
end)()
end
end
end
end
end
Ritual.CheckMatFilter(matfilter,e,tp,mg,mg2)
local ft=Duel.GetLocationCount(tp,LOCATION_MZONE)
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SPSUMMON)
local tg=Duel.SelectMatchingCard(tp,aux.NecroValleyFilter(Ritual.Filter),tp,location,0,1,1,e:GetHandler(),filter,_type,e,tp,mg,mg2,forcedselection,specificmatfilter,lv,requirementfunc,sumpos)
if #tg>0 then
local tc=tg:GetFirst()
local lv=(lv and (type(lv)=="function" and lv(tc)) or lv) or tc:GetLevel()
lv=math.max(1,lv)
Ritual.SummoningLevel=lv
local mat=nil
mg:Match(Card.IsCanBeRitualMaterial,tc,tc)
mg:Merge(mg2-tc)
if specificmatfilter then
mg:Match(specificmatfilter,nil,tc,mg,tp)
end
if tc.ritual_custom_operation then
tc:ritual_custom_operation(mg,forcedselection,_type)
mat=tc:GetMaterial()
else
local func=forcedselection and WrapTableReturn(forcedselection) or nil
if tc.ritual_custom_check then
if forcedselection then
func=aux.tableAND(WrapTableReturn(tc.ritual_custom_check),forcedselection)
else
func=WrapTableReturn(tc.ritual_custom_check)
end
end
if tc.mat_filter then
mg:Match(tc.mat_filter,tc,tp)
end
if ft>0 and not func then
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_RELEASE)
if _type==RITPROC_EQUAL then
mat=mg:SelectWithSumEqual(tp,requirementfunc or Card.GetRitualLevel,lv,1,#mg,tc)
else
mat=mg:SelectWithSumGreater(tp,requirementfunc or Card.GetRitualLevel,lv,tc)
end
else
mat=aux.SelectUnselectGroup(mg,e,tp,1,lv,Ritual.Check(tc,lv,func,_type,requirementfunc),1,tp,HINTMSG_RELEASE,Ritual.Finishcon(tc,lv,requirementfunc,_type))
end
end
--check if a card from an "once per turn" EFFECT_EXTRA_RITUAL_MATERIAL effect was selected
local extra_eff_g=mat:Filter(Card.IsHasEffect,nil,EFFECT_EXTRA_RITUAL_MATERIAL)
for tmp_c in extra_eff_g:Iter() do
local effs={tmp_c:IsHasEffect(EFFECT_EXTRA_RITUAL_MATERIAL)}
for _,eff in ipairs(effs) do
--if eff is OPT and tmp_c is not returned
--by the Ritual Spell's exrafil
--then use the count limit and register
--the flag to turn the extra eff OFF
--requires the EFFECT_EXTRA_RITUAL_MATERIAL effect
--to check the flag in its condition
local _,max_count_limit=eff:GetCountLimit()
if max_count_limit>0 and not mg2:IsContains(tmp_c) then
eff:UseCountLimit(tp,1)
Duel.RegisterFlagEffect(tp,eff:GetHandler():GetCode(),RESET_PHASE+PHASE_END,0,1)
end
end
end
if not customoperation then
tc:SetMaterial(mat)
if extraop then
extraop(mat:Clone(),e,tp,eg,ep,ev,re,r,rp,tc)
else
Duel.ReleaseRitualMaterial(mat)
end
Duel.BreakEffect()
Duel.SpecialSummon(tc,SUMMON_TYPE_RITUAL,tp,tp,false,true,sumpos)
tc:CompleteProcedure()
if stage2 then
stage2(mat,e,tp,eg,ep,ev,re,r,rp,tc)
end
else
customoperation(mat:Clone(),e,tp,eg,ep,ev,re,r,rp,tc)
end
Ritual.SummoningLevel=nil
end
end
end,"filter","lvtype","lv","extrafil","extraop","matfilter","stage2","location","forcedselection","customoperation","specificmatfilter","requirementfunc","sumpos")
--Ritual Summon, geq fixed lv
Ritual.AddProcGreater = aux.FunctionWithNamedArgs(
function(c,filter,lv,desc,extrafil,extraop,matfilter,stage2,location,forcedselection,customoperation,specificmatfilter,requirementfunc,sumpos)
return Ritual.AddProc(c,RITPROC_GREATER,filter,lv,desc,extrafil,extraop,matfilter,stage2,location,forcedselection,customoperation,specificmatfilter,requirementfunc,sumpos)
end,"handler","filter","lv","desc","extrafil","extraop","matfilter","stage2","location","forcedselection","customoperation","specificmatfilter","requirementfunc","sumpos")
function Ritual.AddProcCode(c,_type,lv,desc,...)
if not c:IsStatus(STATUS_COPYING_EFFECT) and c.fit_monster==nil then
local mt=c:GetMetatable()
mt.fit_monster={...}
end
return Ritual.AddProc(c,_type,Auxiliary.FilterBoolFunction(Card.IsCode,...),lv,desc)
end
function Ritual.AddProcGreaterCode(c,lv,desc,...)
return Ritual.AddProcCode(c,RITPROC_GREATER,lv,desc,...)
end
--Ritual Summon, equal to
Ritual.AddProcEqual = aux.FunctionWithNamedArgs(
function(c,filter,lv,desc,extrafil,extraop,matfilter,stage2,location,forcedselection,customoperation,specificmatfilter,requirementfunc,sumpos)
return Ritual.AddProc(c,RITPROC_EQUAL,filter,lv,desc,extrafil,extraop,matfilter,stage2,location,forcedselection,customoperation,specificmatfilter,requirementfunc,sumpos)
end,"handler","filter","lv","desc","extrafil","extraop","matfilter","stage2","location","forcedselection","customoperation","specificmatfilter","requirementfunc","sumpos")
function Ritual.AddProcEqualCode(c,lv,desc,...)
return Ritual.AddProcCode(c,RITPROC_EQUAL,lv,desc,...)
end