forked from ProjectIgnis/CardScripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
proc_ritual.lua
349 lines (340 loc) · 14.2 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
if not aux.RitualProcedure then
aux.RitualProcedure = {}
Ritual = aux.RitualProcedure
end
if not Ritual then
Ritual = aux.RitualProcedure
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 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,extratg)
--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,extratg))
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","extratg")
Ritual.AddProc = aux.FunctionWithNamedArgs(
function(c,_type,filter,lv,desc,extrafil,extraop,matfilter,stage2,location,forcedselection,customoperation,specificmatfilter,requirementfunc,sumpos,extratg)
local e1=Ritual.CreateProc(c,_type,filter,lv,desc,extrafil,extraop,matfilter,stage2,location,forcedselection,customoperation,specificmatfilter,requirementfunc,sumpos,extratg)
c:RegisterEffect(e1)
return e1
end,"handler","lvtype","filter","lv","desc","extrafil","extraop","matfilter","stage2","location","forcedselection","customoperation","specificmatfilter","requirementfunc","sumpos","extratg")
local function WrapTableReturn(func)
if func then
return function(...)
return {func(...)}
end
end
end
local function MergeForcedSelection(f1,f2)
if f1==nil or f2==nil then
return f1 or f2
end
return function(...)
local ret1,ret2=f1(...)
local repl1,repl2=f2(...)
return ret1 and repl1,ret2 or repl2
end
end
function Ritual.Filter(c,filter,_type,e,tp,m,m2,forcedselection,specificmatfilter,lv,requirementfunc,sumpos)
if not (c:IsOriginalType(TYPE_RITUAL) and c:IsOriginalType(TYPE_MONSTER)) 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
forcedselection=MergeForcedSelection(c.ritual_custom_check,forcedselection)
local res=aux.SelectUnselectGroup(mg,e,tp,1,lv,Ritual.Check(c,lv,WrapTableReturn(forcedselection),_type,requirementfunc),0)
Ritual.SummoningLevel=nil
return res
end
local function ExtraReleaseFilter(c,tp)
return c:IsControler(1-tp) and c:IsHasEffect(EFFECT_EXTRA_RELEASE)
end
local function ForceExtraRelease(mg)
return function(e,tp,g,c)
return g:Includes(mg)
end
end
Ritual.Target = aux.FunctionWithNamedArgs(
function(filter,_type,lv,extrafil,extraop,matfilter,stage2,location,forcedselection,specificmatfilter,requirementfunc,sumpos,extratg)
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)
local func=forcedselection
--if a card controlled by the opponent has EFFECT_EXTRA_RELEASE, then it MUST be
--used as material
local extra_mat_g=mg:Filter(ExtraReleaseFilter,nil,tp)
if #extra_mat_g>0 then
func=MergeForcedSelection(ForceExtraRelease(extra_mat_g),func)
end
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]
func=MergeForcedSelection(func,repl_function[1])
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,func,specificmatfilter,lv,requirementfunc,sumpos)
end
if extratg then extratg(e,tp,eg,ep,ev,re,r,rp,chk) 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","extratg")
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,forcedselection,requirementfunc,_type)
return function(sg,e,tp,mg)
if forcedselection then
local ret=forcedselection(e,tp,sg,sc)
if not ret[1] then return false end
end
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 func=forcedselection
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]
func=MergeForcedSelection(func,repl_function[1])
end
end
end
end
--if a card controlled by the opponent has EFFECT_EXTRA_RELEASE, then it MUST be
--used as material
local extra_mat_g=mg:Filter(ExtraReleaseFilter,nil,tp)
if #extra_mat_g>0 then
func=MergeForcedSelection(ForceExtraRelease(extra_mat_g),func)
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,func,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,func,_type)
mat=tc:GetMaterial()
else
func=MergeForcedSelection(tc.ritual_custom_check,func)
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,WrapTableReturn(func),_type,requirementfunc),1,tp,HINTMSG_RELEASE,Ritual.Finishcon(tc,lv,WrapTableReturn(func),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 tc:IsFacedown() then Duel.ConfirmCards(1-tp,tc) end
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,extratg)
return Ritual.AddProc(c,RITPROC_GREATER,filter,lv,desc,extrafil,extraop,matfilter,stage2,location,forcedselection,customoperation,specificmatfilter,requirementfunc,sumpos,extratg)
end,"handler","filter","lv","desc","extrafil","extraop","matfilter","stage2","location","forcedselection","customoperation","specificmatfilter","requirementfunc","sumpos","extratg")
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,extratg)
return Ritual.AddProc(c,RITPROC_EQUAL,filter,lv,desc,extrafil,extraop,matfilter,stage2,location,forcedselection,customoperation,specificmatfilter,requirementfunc,sumpos,extratg)
end,"handler","filter","lv","desc","extrafil","extraop","matfilter","stage2","location","forcedselection","customoperation","specificmatfilter","requirementfunc","sumpos","extratg")
function Ritual.AddProcEqualCode(c,lv,desc,...)
return Ritual.AddProcCode(c,RITPROC_EQUAL,lv,desc,...)
end