Commit b8ee1f64 authored by POLYMER's avatar POLYMER

fix

parent 8f0aa358
dofile("expansions/script/c20099997.lua") if fuef then return end --2025/7/16
if fuef then return end --2025/4/25 fuef = { }
fuef = {
DebugMode = false, -- 调试模式
StepReg = false -- 每次 Reload 皆印出 Reg
}
fuef.__index = fuef fuef.__index = fuef
---------------------------------------------------------------- Standard Register fuef.DebugMode = false -- 调试模式
-- no cod dofile("expansions/script/c20099997.lua")
function fuef.I(_owner, _handler, _ignore) ----------------------------------------------------------------
if _owner == false then _handler, _owner = false end -- _owner is _handler (use in FG --- 建立一个 IGNITION 的 fuef
return fuef:Creat("I", nil, _owner, _handler, _ignore) -- @param owner Card|Effect|nil 效果的持有者(若为 nil,仅建立效果表;需后续补设)
end -- @param target boolean|Card|Group|player 注册目标
function fuef.FG(_owner, _obj, _handler, _ignore) -- @param force boolean 是否强制注册
-- ex: cm.e3 = fuef.FG("e1+e2") -- @return fuef 新创建的效果表实例
if type(_owner) ~= "userdata" then _obj, _owner = _owner end function fuef.I(owner, target, force)
return fuef:Creat("F+G", nil, _owner, _handler, _ignore):OBJ(_obj) local log = fudf.StartLog(0, "fuef.I", owner, target, force)
end return fuef.New(log, "I", nil, owner, target, force)
-- need cod end
for i, typs in ipairs({"S,F,E,S+C,F+C,E+C,F+TO,F+TF,S+TO,S+TF,X", "A,QO,QF"}) do
for _, typ in typs:ForCut("typ_reg_1") do --- 建立一个 FIELD + GRANT 的 fuef
-- @param owner Card|Effect|nil 效果的持有者(若为 obj,仅建立效果表;需后续补设)
-- @param obj Effect|fuef|string 要赋予的效果(effect object)
-- @param target boolean|Card|Group|player 注册目标
-- @param force boolean 是否强制注册
-- @return fuef 新创建的效果表实例
function fuef.FG(owner, obj, target, force)
local log = fudf.StartLog(0, "fuef.FG", owner, obj, target, force)
local is_obj = pcall(fusf.CheckTypes, owner, "string/fuef/Effect")
if is_obj then
owner, obj, target, force = nil, owner, obj, target
end
return fuef.New(log, "F+G", nil, owner, target, force):OBJ(obj)
end
--- 建立剩余需要 cod 的 fuef
for i, typs in ipairs{"S,F,E,S+C,F+C,E+C,F+TO,F+TF,S+TO,S+TF,X", "A,QO,QF"} do
for _, typ in typs:ForCut() do
local name = typ:gsub("+", "") local name = typ:gsub("+", "")
fuef[name] = function(_owner, _cod, _handler, _ignore) fuef[name] = function(owner, cod, target, force)
if type(_owner) ~= "userdata" then _cod, _handler, _owner = _owner, _cod end -- _owner is cod (Noc local log = fudf.StartLog(0, "fuef."..name, owner, cod, target, force)
if i == 2 then _cod = _cod or "FC" end -- A,QO,QF
return fuef:Creat(typ, _cod, _owner, _handler, _ignore) local is_cod = pcall(fusf.CheckTypes, owner, "string/number")
if is_cod then
owner, cod, target, force = nil, owner, cod, target
end
if i == 2 then cod = cod or "FC" end -- A,QO,QF
return fuef.New(log, typ, cod, owner, target, force)
end end
end end
end end
---------------------------------------------------------------- procedure Register (just Noc ---------------------------------------------------------------- XYZ Proc
function fuef.Proc_XYZ(cf, gf, min, max, ex_loc) function fuef.ProcXyzLv(lv, cf, min, max)
min, max = min or 1, max or 99 fusf.CheckArgType("fuef.ProcXyzLv", 1, lv, "number")
return fuef.F(EFFECT_SPSUMMON_PROC):DES("XYZ"):PRO("OE"):RAN("E"):Func("XYZ,PX_con(%1,%2,%3,%4,%5),PX_tg(%1,%2,%3,%4,%5),XyzLevelFreeOperation()",cf,gf,min,max,ex_loc) fusf.CheckArgType("fuef.ProcXyzLv", 2, cf, "nil/function")
end local lvf = fucf.MakeCardFilter("IsLv", lv)
function fuef.PX_g_goal(g, tp, xyzc, gf) local _cf = function(c, xyzc)
return lvf(c) and (not cf or cf(c, xyzc))
end
return fuef.ProcXyz(_cf, nil, min, max)
end
function fuef.ProcXyzAlter(cf, gf, min, max, ex_op, ex_cf)
return fuef.ProcXyz(cf, gf, min, max, ex_op, ex_cf):Lab(1)
end
function fuef.ProcXyz(cf, gf, min, max, ex_op, ex_cf)
fusf.CheckArgType("fuef.ProcXyz", 1, cf, "nil/string/function")
fusf.CheckArgType("fuef.ProcXyz", 2, gf, "nil/string/function")
local _, min = fusf.CheckArgType("fuef.ProcXyz", 3, min or 2, "number")
local _, max = fusf.CheckArgType("fuef.ProcXyz", 4, max or min, "number")
fusf.CheckArgType("fuef.ProcXyz", 5, ex_op, "nil/string/function")
fusf.CheckArgType("fuef.ProcXyz", 6, ex_cf, "nil/string/function")
local e = fuef.F(EFFECT_SPSUMMON_PROC):Des(1165):Pro("OE"):Ran("E"):Val("XYZ")
e:Con("PX_con", cf, gf, min, max, ex_op, ex_cf)
e:Tg("PX_tg", cf, gf, min, max, ex_op, ex_cf)
return e:Op(aux.XyzLevelFreeOperation())
end
function fuef.PX_goal(g, tp, xyzc, gf)
return (not gf or gf(g, tp, xyzc)) and Duel.GetLocationCountFromEx(tp, tp, g, xyzc) > 0 return (not gf or gf(g, tp, xyzc)) and Duel.GetLocationCountFromEx(tp, tp, g, xyzc) > 0
end end
function fuef.PX_con(cf, gf, minc, maxc, ex_loc) function fuef.PX_con(cf, gf, minc, maxc, ex_op, ex_cf)
return function(e, c, og, min, max) return function(e, c, og, min, max)
if c == nil then return true end if c == nil then return true end
if c:IsType(TYPE_PENDULUM) and c:IsFaceup() then return false end if c:IsType(TYPE_PENDULUM) and c:IsFaceup() then return false end
local tp, minc, maxc = c:GetControler(), math.max(minc, min or minc), math.min(maxc, max or maxc) local minc, maxc = math.max(minc, min or minc), math.min(maxc, max or maxc)
if maxc < minc then return false end if maxc < minc then return false end
local catch = fusf.MakeFuncCatch(e)
local tp = c:GetControler()
if ex_op then
if type(ex_op) == "string" then ex_op = fusf.FindFuncCatch(catch, "ex_op", ex_op) end
if not ex_op(e, c, tp, 0) then return false end
end
if cf and type(cf) == "string" then cf = fusf.FindFuncCatch(catch, "cf", cf) end
local mg = fugf.Filter(og or fugf.Get(tp, "M"), "XyzLevelFreeFilter", {c, cf}) local mg = fugf.Filter(og or fugf.Get(tp, "M"), "XyzLevelFreeFilter", {c, cf})
if ex_loc then mg = mg + fugf.GetFilter(tp, ex_loc, "XyzLevelFreeFilter", {c, cf}) end
local sg = Duel.GetMustMaterial(tp,EFFECT_MUST_BE_XMATERIAL) if ex_cf then
local mg2 = fugf.GetFilter(tp, "A", "IsTyp/IsCanBeXyzMaterial", "S/T,%1", nil, c) - mg
if type(ex_cf) == "string" then ex_cf = fusf.FindFuncCatch(catch, "ex_cf", ex_cf) end
mg = mg + fugf.Filter(mg2, ex_cf, c)
end
local sg = Duel.GetMustMaterial(tp, EFFECT_MUST_BE_XMATERIAL)
if #mg > #(mg + sg) then return false end if #mg > #(mg + sg) then return false end
Duel.SetSelectedCard(sg) Duel.SetSelectedCard(sg)
Auxiliary.GCheckAdditional = Auxiliary.TuneMagicianCheckAdditionalX(EFFECT_TUNE_MAGICIAN_X) Auxiliary.GCheckAdditional = Auxiliary.TuneMagicianCheckAdditionalX(EFFECT_TUNE_MAGICIAN_X)
local res = mg:CheckSubGroup(fuef.PX_g_goal, minc, maxc, tp, c, gf) if gf and type(gf) == "string" then gf = fusf.FindFuncCatch(catch, "gf", gf) end
local res = mg:CheckSubGroup(fuef.PX_goal, minc, maxc, tp, c, gf)
Auxiliary.GCheckAdditional = nil Auxiliary.GCheckAdditional = nil
return res return res
end end
end end
function fuef.PX_tg(cf, gf, minc, maxc, ex_loc) function fuef.PX_tg(cf, gf, minc, maxc, ex_op, ex_cf)
return function(e, tp, eg, ep, ev, re, r, rp, chk, c, og, min, max) return function(e, tp, eg, ep, ev, re, r, rp, chk, c, og, min, max)
if og and not min then return true end if og and not min then return true end
minc, maxc = math.max(minc, min or minc), math.min(maxc, max or maxc) minc, maxc = math.max(minc, min or minc), math.min(maxc, max or maxc)
local catch = fusf.MakeFuncCatch(e)
if cf and type(cf) == "string" then cf = fusf.FindFuncCatch(catch, "cf", cf) end
local mg = fugf.Filter(og or fugf.Get(tp,"M"), "XyzLevelFreeFilter", {c, cf}) local mg = fugf.Filter(og or fugf.Get(tp,"M"), "XyzLevelFreeFilter", {c, cf})
if ex_loc then mg = mg + fugf.GetFilter(tp, ex_loc, "XyzLevelFreeFilter", {c, cf}) end
if ex_cf then
local mg2 = fugf.GetFilter(tp, "A", "IsTyp/IsCanBeXyzMaterial", "S/T,%1", nil, c) - mg
if type(ex_cf) == "string" then ex_cf = fusf.FindFuncCatch(catch, "ex_cf", ex_cf) end
mg = mg + fugf.Filter(mg2, ex_cf, c)
end
Duel.SetSelectedCard(Duel.GetMustMaterial(tp,EFFECT_MUST_BE_XMATERIAL)) Duel.SetSelectedCard(Duel.GetMustMaterial(tp,EFFECT_MUST_BE_XMATERIAL))
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_XMATERIAL) Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_XMATERIAL)
Auxiliary.GCheckAdditional = Auxiliary.TuneMagicianCheckAdditionalX(EFFECT_TUNE_MAGICIAN_X) Auxiliary.GCheckAdditional = Auxiliary.TuneMagicianCheckAdditionalX(EFFECT_TUNE_MAGICIAN_X)
mg = mg:SelectSubGroup(tp, fuef.PX_g_goal, Duel.IsSummonCancelable(), minc, maxc, tp, c, gf) if gf and type(gf) == "string" then gf = fusf.FindFuncCatch(catch, "gf", gf) end
mg = mg:SelectSubGroup(tp, fuef.PX_goal, Duel.IsSummonCancelable(), minc, maxc, tp, c, gf)
Auxiliary.GCheckAdditional = nil Auxiliary.GCheckAdditional = nil
if ex_op then
if type(ex_op) == "string" then ex_op = fusf.FindFuncCatch(catch, "ex_op", ex_op) end
ex_op(e, c, tp, 1)
end
if not mg or #mg == 0 then return false end if not mg or #mg == 0 then return false end
mg:KeepAlive() mg:KeepAlive()
e:SetLabelObject(mg) e:SetLabelObject(mg)
return true return true
end end
end end
---------------------------------------------------------------- fuef() ---------------------------------------------------------------- local
function fuef:__call(_cod, _handler, _ignore) --- 修正效果建立时的三个参数:赋予者(owner)、被赋予者(target)、是否强制注册(force)
fusf.Debug("") -- 根据参数类型推断调用者的意图,并统一为标准形式返回,用于 fuef.New
fusf.Debug("__call("..fusf.ValToDebug(_cod, _handler, _ignore)..")") -- @param owner Card/Effect/player/boolean/nil - 效果赋予者;若为 player/boolean/nil,将视为 target
-- _cod is owner (Creat and Register Noc -- @param target Card/Group/player/boolean/nil - 效果被赋予对象;若为 true 表示强制注册
if type(_cod) == "userdata" then return self:CreatNoc(_cod, _handler, _ignore) end -- @param force boolean/nil - 是否强制注册;预设为 false
-- Creat and Clone all key -- @return owner(Card/Effect/nil), target(Card/Group/player/nil), force(boolean)
local CE = setmetatable({ }, fuef) local function FixEffectAssignArgs(owner, target, force)
local keys = "typ,cod,des,cat,pro,ran,tran,ctl,val,con,cos,tg,op,res,lab,obj,handler" if owner == false or owner == 0 or owner == 1 then
for _,_key in keys:ForCut("fuef:__call") do owner, target = nil, owner
CE[_key] = self[_key] or nil else
fusf.CheckTypes(owner, "nil/Card/Effect")
end
if target == true then
target, force = nil, true
elseif target ~= false then
local typ = fusf.CheckTypes(target, "nil/Card/Group/table/player")
if typ == "Card" or typ == "Group" then
target = fusf.ToGroupTable(target)
end
end
force = fusf.CheckType(force or false, "boolean")
return owner, target, force
end
--- 检查 val 是否为有效的 value 格式,用于 fuef:Func
-- @param val any 欲检查的值
-- @param val_typ string 值的型别
-- @return boolean 是否符合格式
local function MatchValFormat(val, val_typ)
if val_typ ~= "string" then return true end
if val:match("%,") then return false end
return tonumber(val) or fucs.val[val] or (val:sub(-4, -2):lower() == "val")
end
----------------------------------------------------------------
--- 建立一个新的效果表(fuef 物件),初始化基本栏位
--
-- - 若 `owner` 为 nil,仅建立效果表而不创建 Effect 实体,需后续呼叫 `:InitSetOwner(owner)` 补足。
-- - 若 `owner` 为 Effect 或 Card,则立即创建 Effect 并进行注册。
----- 建立一个新的效果表(fuef 物件),初始化基本栏位
--
-- - 若 `owner` 为 nil,仅建立效果表而不创建 Effect 实体,需后续呼叫 `:InitSetOwner(owner)` 补足。
-- - 若 `owner` 为 Effect 或 Card,则立即创建 Effect 并进行注册。
--
-- @param log 日志对象或层级(用于调试记录)
-- @param typ string|number 效果类型(支援常数名或数值,将转换为 EFFECT_TYPE_* 常数)
-- @param cod string|number|nil 效果代码(支援常数名或数值,将转换为 EVENT_* 常数,可为 nil)
-- @param owner nil|Effect|Card 效果实体的持有者(若为 nil,仅建立表,不创建实体)
-- @param target boolean|Card|Group|player 注册目标(传入至 Reg 中),若为 boolean 则视为 force
-- @param force boolean 是否强制注册,跳过效果限制检查
-- @return table fuef 物件(含 typ, cod, handler, force 等栏位)
-- @raise 若 owner 非 nil 且无法转为卡片时,建立 Effect 可能触发错误
function fuef.New(log, typ, cod, owner, target, force)
local log = fudf.StartLog(log, "fuef.New", typ, cod, owner, target, force)
local E = setmetatable({}, fuef)
E.typ = fusf.ParseConstantKey("etyp", typ)
log:Info("set self.typ : "..fusf.CutHex(E.typ))
if cod then
E.cod = fusf.ParseConstantKey("cod", cod)
log:Info("set self.cod : "..E.cod)
end
owner, target, force = FixEffectAssignArgs(owner, target, force)
E.handler = target
log:Info("set handler : "..fusf.Type(target))
E.force = force
log:Info("set force : "..tostring(force))
log:Info("has owner : "..tostring(not not owner))
if not owner then return E end
E.e = Effect.CreateEffect(fusf.ToCard(owner))
log:Info("set self.e")
E.e:SetType(E.typ)
log:Info("self.e SetType : "..fusf.CutHex(E.typ))
if E.cod then
E.e:SetCode(E.cod)
log:Info("self.e SetCode : "..E.cod)
end end
-- Cover _cod
if CE.typ == EFFECT_TYPE_FIELD + EFFECT_TYPE_GRANT then return E:Reg(log)
CE:OBJ(_cod) end
elseif _cod then
CE.cod = fusf.Get_Constant("cod", _cod) -- 注册 fuef 给 self.handler, 没有则注册给 owner
-- @param log 日志对象或层级(用于调试记录)
-- @return table 返回调用者 self,支持链式调用
function fuef:Reg(log, target, force)
if self.isinit then return self end
local log = fudf.StartLog(log, "fuef:Reg")
if self.handler == false then
log:Info("no RegisterEffect")
self.handler = false
return self
end
local tg_typ = fusf.CheckTypes(self.handler, "nil/table/player")
if tg_typ == "player" then
log:Info("RegisterEffect to player")
Duel.RegisterEffect(self.e, self.handler)
return self
elseif tg_typ == "nil" then
self.handler = { self.e:GetOwner() }
log:Info("set self.handler is owner")
end end
-- Clone and return Clone
if self.e then if self.force == nil then
CE.e = self.e:Clone() self.force = false
-- Set Key and Register Effect log:Info("set self.force is false")
return CE:SetKey():Reg(_handler, _ignore)
end end
-- Clone Noc (
CE.pre = self local rg = self.handler
self.aft = CE local fc = rg[1]
return CE fc:RegisterEffect(self.e, self.force)
end if #rg > 1 then
-------------------------------------------------------------------------- self.clones = { }
-- Creat and Register Effect for i = 2, #rg do
function fuef:Creat(_typ, _cod, _owner, _handler, _ignore) local e = self.e:Clone()
fusf.Debug("") table.insert(self.clones, e)
fusf.Debug("Creat("..fusf.ValToDebug(fusf.CutHex(_typ), _cod, _owner, _handler, _ignore)..")") local c = rg[i]
local E = setmetatable({ }, fuef) c:RegisterEffect(e, self.force)
-- Set type and code and handler end
E.typ = fusf.Get_Constant("etyp", _typ) end
E.cod = fusf.Get_Constant("cod", _cod)
E.handler = _handler log:Info("RegisterEffect to "..(#rg).." Card")
-- use in no owner (Creat and Register in __call return self
if not _owner then return E end end
-- Create Effect
E.e = Effect.CreateEffect(fusf.ToCard(_owner)) --- 支援语法糖:fuef物件可直接以 () 调用以复制自身
-- Set type and code -- 等同于 self:Clone(...)
if _typ then E.e:SetType(E.typ) end function fuef:__call(cod, target, force)
if _cod then E.e:SetCode(E.cod) end return self:Clone(cod, target, force)
return E:Reg(_handler, _ignore) end
end
function fuef:CreatNoc(_owner, _handler, _ignore) --- 复制当前 fuef 效果对象,可用于复制已有效果结构
fusf.Debug("CreatNoc("..fusf.ValToDebug(_owner, _handler, _ignore)..")") -- @param cod string|number|fuef 替换的 cod, 赋予效果会将 cod 放到 OBJ
-- @param target 注册目标,同 Reg 函数
-- @param force 是否强制注册,同 Reg 函数
-- @return table 新的 fuef 对象,可链式调用
-- @raise cod 为 number 且用于 GRANT 类型时抛错;self.e 类型不正确时报错
function fuef:Clone(cod, target, force)
local log = fudf.StartLog(0, "fuef:Clone", cod, target, force)
local cod_typ = fusf.CheckArgType("Clone", 1, cod, "string/number/fuef")
local E = setmetatable({}, fuef)
log:Info("try Clone All key")
local keys = "typ,des,cat,pro,ran,tran,ctl,val,con,cos,tg,op,func,res,lab,obj,pl,handler,force"
for _,key in keys:ForCut() do
E[key] = self[key] or nil
end
log:Info("check self.typ is F+G")
if E.typ == EFFECT_TYPE_FIELD + EFFECT_TYPE_GRANT then
E:OBJ(cod)
else
E.cod = fusf.ParseConstantKey("cod", cod)
log:Info("set self.cod : "..E.cod)
end
local e_typ, e = fusf.CheckTypes(self.e, "nil/Effect")
if e_typ == "Effect" then
log:Info("Clone Effect E")
E.e = e:Clone()
local _, target, force = FixEffectAssignArgs(nil, target, force)
if target then
E.handler = target
log:Info("set E.handler : "..fusf.Type(target))
end
E.force = force
log:Info("set E.force : "..tostring(force))
E.depth = log.depth
return E:SetKey(log):Reg(log)
end
E.pre = self
self.aft = E
log:Info("set E.pre and self.aft")
return E
end
--- 初始化 fuef 链条的 Effect 实体,并设置所有字段属性
--
-- - 本方法用于延迟注册效果表(fuef),在 `initial_effect` 中设定持有者(owner)并依序初始化整条链。
-- - 链的起点是最早创建的 fuef(无 pre),终点为当前对象或后续的 aft。
-- - 每个节点会调用 `fuef.New` 创建 Effect 实体,依照字段依序设置属性(des、cat、val 等)。
-- - 所有链条节点都会生成独立实体效果,并注册(呼叫 `:Reg()`)。
--
-- ⚠ 若创建时未传入 owner,此函数为唯一可创建 Effect 实体的注册点。
--
-- @param name string 名称(用于日志打印)
-- @param owner Card|Effect 效果持有者(会被转为卡片用作 Effect.CreateEffect)
-- @param target nil|player 注册目标(用于设置 handler 字段,或 Reg 注册位置)
-- @return fuef 链尾节点(最后一个完成注册的效果表)
function fuef:InitSetOwner(name, owner, target)
local log = fudf.StartLog(1, "fuef:InitSetOwner", name, owner, target)
local tg_typ = fusf.CheckArgType("InitSetOwner", 2, target, "nil/player")
log:Info("find root")
local root = self local root = self
while root.pre do while root.pre do
root = root.pre root = root.pre
end end
local keys = "des,cat,pro,ran,tran,ctl,val,con,cos,tg,op,res,lab,obj"
log:Info("set root owner")
local keys = "des,cat,pro,ran,tran,ctl,val,con,cos,tg,op,func,res,lab,obj,pl"
local last local last
repeat repeat
if type(root.typ) == "table" then root.typ = root.typ[1] end if tg_typ == "player" then
if root.handler ~= nil and not _handler then _handler = root.handler end root.handler = target
last = fuef:Creat(root.typ, root.cod, _owner, _handler, _ignore) end
for _, key in keys:ForCut("CreatNoc") do last = fuef.New(log, root.typ, root.cod, owner, root.handler)
if root[key] then last.isinit = true
fuef[key:upper()](last, table.unpack(root[key])) for _, key in keys:ForCut() do
if root[key] then
local method = key:sub(1,1):upper()..key:sub(2)
log:Info("try call fuef:"..method)
fuef[method](last, table.unpack(root[key], 1, root[key].n))
end end
end end
last.isinit = nil
last:Reload(log)
root = root.aft root = root.aft
until not root until not root
log:Info(name.." set owner down")
return last return last
end end
-- Register Effect
function fuef:Reg(_handler, _ignore, _isreload) -- 设置单个 Effect 属性(适用于非解包参数)
if not (_isreload or fuef.StepReg) then -- @param log 日志对象或层级(用于调试记录)
fusf.Debug("Reg("..fusf.ValToDebug(_handler, _ignore)..")") -- @param set_key Effect 的方法名,例如 "SetType"
end -- @param val_key 当前对象中的字段名,例如 "typ"
-- not Reg (use in FG -- @param val_typ 允许的类型,可以是字符串("number")或多个类型的字符串("function/number")或表
if self.handler == false or _handler == false then -- @return fuef 返回调用者 self,支持链式调用
self.handler = false function fuef:SetEffVal(log, set_key, val_key, val_typ)
return self local val = self[val_key]
end if not val then return self end
-- get handler and ignore fusf.CheckTypes(val, val_typ)
local handler, ignore = self.handler or self.e:GetOwner(), _ignore Effect[set_key](self.e, val)
if _handler == true then -- handler equal owner and ignore == true log:Info(set_key)
ignore = true
elseif _handler then -- handler not equal owner and handler is Card, Group or tp
handler = _handler
end
-- cover handler
self.handler = handler
-- Handler is player
if type(handler) == "number" then
Duel.RegisterEffect(self.e, handler)
return self
end
-- Handler is c or g
-- get handler group
handler = fusf.ToGroup(handler)
-- check and cover ignore
if type(ignore) ~= "boolean" then ignore = self.ignore or false end -- not input _ignore
self.ignore = ignore
-- Register First Card
local fc = handler:GetFirst()
fc:RegisterEffect(self.e, ignore)
handler:RemoveCard(fc)
-- handler is group
if #handler > 0 then
-- Register other card
self.gclo = { }
for c in aux.Next(handler) do
local E = self.e:Clone()
self.gclo[#self.gclo + 1] = E
c:RegisterEffect(E, ignore)
end
end
return self return self
end end
-- Set all Key
function fuef:SetKey() -- 设置需要 unpack 参数的 Effect 属性(适用于参数为 table 的字段)
if self.typ then self.e:SetType(self.typ) end -- @param log 日志对象或层级(用于调试记录)
if self.cod then self.e:SetCode(self.cod) end -- @param set_key Effect 的方法名,例如 "SetTargetRange"
if self.des then self.e:SetDescription(self.des) end -- @param val_key 当前对象中的字段名,例如 "tran"
if self.cat then self.e:SetCategory(self.cat) end -- @return fuef 返回调用者 self,支持链式调用
if self.pro then self.e:SetProperty(self.pro) end function fuef:SetEffValUnpack(log, set_key, val_key)
if self.ran then self.e:SetRange(self.ran) end local val = self[val_key]
if self.tran then self.e:SetTargetRange(table.unpack(self.tran)) end if not val then return self end
if self.ctl then self.e:SetCountLimit(table.unpack(self.ctl)) end fusf.CheckType(val, "table")
if self.val then self.e:SetValue(self.val) end Effect[set_key](self.e, table.unpack(val))
if self.con then self.e:SetCondition(self.con) end log:Info(set_key)
if self.cos then self.e:SetCost(self.cos) end
if self.tg then self.e:SetTarget(self.tg) end
if self.op then self.e:SetOperation(self.op) end
if self.res then self.e:SetReset(table.unpack(self.res)) end
if self.lab then self.e:SetLabel(table.unpack(self.lab)) end
if self.obj then self.e:SetLabelObject(self.obj) end
return self return self
end end
-- Reset and Creat Effect and SetKey and Reg (use in every set key final return
function fuef:Reload(de) -- 主设置函数:设置当前对象(fuef)中所有已定义的 Effect 关键字段
-- Reset self -- 支持类型检查、空值跳过、调试输出
local _owner = self.e:GetOwner() -- @param log 日志对象或层级(用于调试记录)
self.e:Reset() -- @return fuef 返回调用者 self,支持链式调用
self.e = Effect.CreateEffect(_owner) function fuef:SetKey(log)
-- Reset if handler is group local log = fudf.StartLog(log, "fuef:SetKey")
if self.gclo then
for _, gcloe in ipairs(self.gclo) do self:SetEffVal(log, "SetType", "typ", "number")
gcloe:Reset() self:SetEffVal(log, "SetCode", "cod", "number")
end self:SetEffVal(log, "SetDescription", "des", "number")
self.gclo = nil self:SetEffVal(log, "SetCategory", "cat", "number")
end self:SetEffVal(log, "SetProperty", "pro", "number")
return self:SetKey(de):Reg(nil, nil, true) self:SetEffVal(log, "SetRange", "ran", "number")
end self:SetEffValUnpack(log, "SetTargetRange", "tran")
function fuef:IsNil(from, ...) self:SetEffValUnpack(log, "SetCountLimit", "ctl")
local res = fusf.IsNil(...) self:SetEffVal(log, "SetValue", "val", "function/number/boolean")
if res then fusf.Debug("... IsNil <- "..from) end self:SetEffVal(log, "SetCondition", "con", "function")
return res self:SetEffVal(log, "SetCost", "cos", "function")
end self:SetEffVal(log, "SetTarget", "tg", "function")
function fuef:PreChk(from, ...) self:SetEffVal(log, "SetOperation", "op", "function")
fusf.Debug("set "..from.." : "..fusf.ValToDebug(...)) self:SetEffValUnpack(log, "SetReset", "res")
if not self.e then --is Noc self:SetEffValUnpack(log, "SetLabel", "lab")
self[from:lower()] = {...} self:SetEffVal(log, "SetLabelObject", "obj", "Card/Group/Effect")
return false self:SetEffVal(log, "SetOwnerPlayer", "pl", "player")
end
return not self:IsNil("PreChk <- "..from, ...) return self
end end
-- 输出当前 fuef 对象的字段信息,用于调试
function fuef:Info() function fuef:Info()
Debug.Message("") if self.typ then Debug.Message("typ : "..fusf.CutHex(self.typ))end
Debug.Message("Info")
if self.typ then Debug.Message("typ : "..fusf.CutHex(self.typ, ", "))end
if self.cod then Debug.Message("cod : "..self.cod) end if self.cod then Debug.Message("cod : "..self.cod) end
if self.des then Debug.Message("des : "..(self.des//16)..", "..(self.des%16)) end if self.des then Debug.Message("des : "..(self.des//16)..", "..(self.des%16)) end
if self.cat then Debug.Message("cat : "..fusf.CutHex(self.cat, ", ")) end if self.cat then Debug.Message("cat : "..fusf.CutHex(self.cat)) end
if self.pro then Debug.Message("pro : "..fusf.CutHex(self.pro, ", ")) end if self.pro then Debug.Message("pro : "..fusf.CutHex(self.pro)) end
if self.ran then Debug.Message("ran : "..self.ran) end if self.ran then Debug.Message("ran : "..self.ran) end
if self.tran then Debug.Message("tran : "..table.concat(self.tran, ", ")) end if self.tran then Debug.Message("tran : "..table.concat(self.tran, ", ")) end
if self.ctl then Debug.Message("ctl : "..table.concat(self.ctl, ", ")) end if self.ctl then Debug.Message("ctl : "..table.concat(self.ctl, ", ")) end
...@@ -248,245 +460,447 @@ function fuef:Info() ...@@ -248,245 +460,447 @@ function fuef:Info()
if self.cos then Debug.Message("cos : "..tostring(self.cos)) end if self.cos then Debug.Message("cos : "..tostring(self.cos)) end
if self.tg then Debug.Message("tg : "..tostring(self.tg)) end if self.tg then Debug.Message("tg : "..tostring(self.tg)) end
if self.op then Debug.Message("op : "..tostring(self.op)) end if self.op then Debug.Message("op : "..tostring(self.op)) end
if self.res then Debug.Message("res : "..fusf.CutHex(self.res[1])..", "..self.res[2], ", ") end if self.res then Debug.Message("res : "..fusf.CutHex(self.res[1])..", "..self.res[2]) end
if self.lab then Debug.Message("lab : "..table.concat(self.lab, ", ")) end if self.lab then Debug.Message("lab : "..table.concat(self.lab, ", ")) end
if self.obj then Debug.Message("obj : "..aux.GetValueType(self.obj)) end if self.obj then Debug.Message("obj : "..fusf.Type(self.obj)) end
if self.handler then Debug.Message("handler : "..(handler == false and "false" or aux.GetValueType(self.handler))) end if self.handler then Debug.Message("handler : "..fusf.Type(self.handler)) end
end end
----------------------------------------------------------------DES
function fuef:DES(_code, _id) -- (0), ("n"), (m), ("+1") --- initial 检查,仅当尚未创建效果实体(self.e 为 nil)时执行初始化
if not self:PreChk("DES", _code, _id) then return self end -- @param log 日志对象或层级(用于调试记录)
self.des = fusf.GetDES(_code, _id, self.e:GetOwner():GetOriginalCode()) -- @param key string 要初始化的字段名(会转为小写)
return self:Reload() -- @param ... any 初始化值,将作为 table 存入字段
end -- @return boolean 是否在 initial 调用
----------------------------------------------------------------TYP, COD, CAT and PRO function fuef:InitCheck(log, key, ...)
function fuef:Cons_Model(_key, _val) if self.e then return false end
if not self:PreChk(_key:upper(), _val) then return self end local log = fudf.StartLog(log, "fuef:InitCheck", key, ...)
local _keytype = _key == "typ" and "etyp" or _key
local val, des = fusf.Get_Constant(_keytype, _val) self[key] = table.pack(...)
self[_key] = val log:Info("set self."..key)
if _key == "cat" and des then self.des = self.des or des end return true
return self:Reload() end
end
function fuef:TYP(_val) --- 重置 fuef.e 并以 fuef.e 的 owner 再创建一个效果并重新应用 Key
return self:Cons_Model("typ", _val) -- 会先 Reset 原本的效果实体并重新创建,清除 clones
end -- @param log 日志对象或层级(用于调试记录)
function fuef:COD(_val) -- @return fuef 返回 self(可链式调用)
return self:Cons_Model("cod", _val) function fuef:Reload(log)
end if self.isinit then return self end
function fuef:CAT(_val) local log = fudf.StartLog(log, "fuef:Reload")
return self:Cons_Model("cat", _val)
end log:Info("recreate Effect")
function fuef:PRO(_val) local owner = self.e:GetOwner()
return self:Cons_Model("pro", _val) self.e:Reset()
end self.e = Effect.CreateEffect(owner)
----------------------------------------------------------------RAN and TRAN
function fuef:RAN(_loc) if self.clones and #self.clones > 0 then
if not self:PreChk("RAN", _loc) then return self end log:Info("clean self.clones")
self.ran = fusf.Get_Loc(_loc, nil, "fuef:RAN()") for _, e in ipairs(self.clones) do
return self:Reload() e:Reset()
end
function fuef:TRAN(_loc1, _loc2)
if not self:PreChk("TRAN", _loc1, _loc2) then return self end
self.tran = {fusf.Get_Loc(_loc1, _loc2, "fuef:TRAN()")}
return self:Reload()
end
----------------------------------------------------------------CTL
function fuef:CTL(_count, _code, _pro) --count, code, pro
if not self:PreChk("CTL", _count, _code, _pro) then return self end
if type(_count) == "string" or _count > 99 then -- ("n+D") or (m) -> (1, "n+D") or (1, m)
_count, _code, _pro = 1, _count, _code
end
if _code == "m" then _code = self.e:GetOwner():GetOriginalCode() end
local res, ctl_val = {_code or 0, _pro or 0}, {
O = EFFECT_COUNT_CODE_OATH,
D = EFFECT_COUNT_CODE_DUEL,
C = EFFECT_COUNT_CODE_CHAIN,
}
if _pro then -- (1, n, "D")
res = {fusf.M_chk(_code), ctl_val[_pro:match("[ODC]")]}
elseif type(_code) == "string" then -- (1, "n+D")
res = _code:Cut("CTL_1", "+") -- (n), (n, d), (d)
if res[1]:match("[ODC]") then
res = {0, res[1]}
elseif res[1]:match("m") then
res[1] = self.e:GetOwner():GetOriginalCode()
else
res[1] = fusf.M_chk(tonumber(res[1]))
end end
if res[2] then res[2] = ctl_val[res[2]:match("[ODC]")] end self.clones = nil
if res[2] & 0x30000000 > 0 and res[1] == 0 then res[1] = self.e:GetOwner():GetOriginalCode() end -- is O or D
end end
self.ctl = {_count, res[1] + res[2]}
return self:Reload() return self:SetKey(log):Reg(log)
end end
----------------------------------------------------------------VAL, CON, COS, TG and OP
function fuef:Func(_val, _func, ...) ----------------------------------------------------------------DES
-- func = ("val,con,cos(v1,v2),tg,op") or ("con(v1,v2),op") or (val, "con,op(v1, v2)"), if v = %1~n then { ... } is value table
if fusf.IsNil(_val, _func) then -- nil chk --- 设置描述字段(des),支持延迟初始化
fusf.Debug("_val, _func IsNil <- Func".._from) -- 若尚未创建效果实体,则记录并延后设置;否则立即设置并重载
return self -- @param code string|number 描述代码(将传入 ResolveDescription)
-- @param id string|number 描述 ID(将传入 ResolveDescription)
-- @return fuef 返回 self(可链式调用)
function fuef:Des(code, id)
local log = fudf.StartLog(self, "fuef:Des", code, id)
fusf.CheckEmptyArgs("Des", code, id)
if self:InitCheck(log, "des", code, id) then return self end
local m = self.e:GetOwner():GetOriginalCode()
self.des = fusf.ResolveDescription(code, id, m)
log:Info("set self.des : "..self.des)
return self:Reload(log)
end
----------------------------------------------------------------Const
--- 设定常数型栏位(如 typ、cod、cat 等),若尚未建立效果物件则先记录初始值
-- 若已存在效果物件则立即重新加载
-- @param log 日志对象或层级(用于调试记录)
-- @param key string 栏位名称(如 "typ", "cod", "cat" 等)
-- @param val any 欲设定的常数值(支援名称字串或数值)
-- @return self fuef 物件
function fuef:SetConstField(log, key, val)
local log = fudf.StartLog(log, "fuef:SetConstField", key, val)
fusf.CheckArgType(key, 1, val, "number/string")
key = key:lower()
if self:InitCheck(log, key, val) then return self end
local table_key = (key == "typ") and "etyp" or key
local val, des = fusf.ParseConstantKey(table_key, val)
self[key] = val
log:Info(("set self.%s : %s"):format(key, val))
if key == "cat" and des then
self.des = self.des or des
log:Info("set self.des : "..self.des)
end end
local vals = {...}
if not (type(_val) == "string" and _val:match("%,")) then -- check _val is val return self:Reload(log)
local val = { _val } end
if type(_val) == "string" and _val:match("%%") then val = { _val , ... } end
self.val = val --- 设定 type
else -- _val is _func function fuef:Typ(typ)
vals, _func = {_func, ...}, _val local log = fudf.StartLog(self, "fuef:Typ", typ)
return self:SetConstField(log, "Typ", typ)
end
--- 设定 code
function fuef:Cod(code)
local log = fudf.StartLog(self, "fuef:Cod", code)
return self:SetConstField(log, "Cod", code)
end
--- 设定 category
function fuef:Cat(category)
local log = fudf.StartLog(self, "fuef:Cat", category)
return self:SetConstField(log, "Cat", category)
end
--- 设定 property
function fuef:Pro(property)
local log = fudf.StartLog(self, "fuef:Pro", property)
return self:SetConstField(log, "Pro", property)
end
----------------------------------------------------------------Range
--- 设定效果适用的区域(Range)
-- @param loc string|number 区域常数或其字串名称
-- @return self fuef 物件
function fuef:Ran(loc)
local log = fudf.StartLog(self, "fuef:Ran", loc)
fusf.CheckArgType("Ran", 1, loc, "number/string")
if self:InitCheck(log, "ran", loc) then return self end
loc = fusf.GetLoc(loc)
self.ran = loc
log:Info("set self.ran : "..loc)
return self:Reload(log)
end
--- 设定效果于自己与对手区域的作用范围(TargetRange)
-- @param self_loc string|number 自己场地的区域
-- @param oppo_loc string|number 对手场地的区域
-- @return self fuef 物件
function fuef:Tran(self_loc, oppo_loc)
local log = fudf.StartLog(self, "fuef:Tran", self_loc, oppo_loc)
fusf.CheckEmptyArgs("Tran", self_loc, oppo_loc)
if self:InitCheck(log, "tran", self_loc, oppo_loc) then return self end
self_loc, oppo_loc = fusf.GetLoc(self_loc, oppo_loc)
self.tran = {self_loc, oppo_loc}
log:Info(("set self.tran : %s / %s"):format(self_loc, oppo_loc))
return self:Reload(log)
end
----------------------------------------------------------------CountLimit
--- 设定效果限制条件(Count Limit),支援多种输入格式。
-- @param count number|string 可为数字(使用次数)或字串(如 "100+O")
-- @param code number|string|nil 可为卡号、字符串(含限制类型 "O/D/C"),或留空
-- @param pro string|nil 限制类型("O"=OATH, "D"=DUEL, "C"=CHAIN)
-- @return fuef 返回自身以支援链式调用
function fuef:Ctl(count, code, pro)
local log = fudf.StartLog(self, "fuef:Ctl", count, code, pro)
fusf.CheckEmptyArgs("Ctl", count, code, pro)
if self:InitCheck(log, "ctl", count, code, pro) then return self end
local ct_typ = fusf.CheckArgType("Ctl", 1, count, "number/string")
if ct_typ == "string" or count > 99 then -- ("n+D") or (m) -> (1, "n+D") or (1, m)
count, code, pro = 1, count, code
end end
-- "val,con,cos,tg,op" or "con,op" , if cant match then follow a sequence
local seqs, place, sets = {"val", "con", "cos", "tg", "op"}, 1, { } local cod_typ = fusf.CheckArgType("Ctl", 2, code, "nil/number/string")
-- "f1,f2(%1,v2),f3" -> {"f1", {"f2", vals[1], "v2"}, "f3"}, ... use in vi = %i local m = self.e:GetOwner():GetOriginalCode()
for i, func in fusf.ForTable(fusf.Val_Cuts(_func, table.unpack(vals))) do local ctl_consts = fusf.Findfucs("ctl")
local fname, fval = func, func local _code, _pro = 0, 0
if type(fname) == "table" then
fname = table.remove(fval,1) fusf.CheckArgType("Ctl", 3, pro, "nil/string")
else if pro then
fval = nil _pro = fusf.FindTables(pro, ctl_consts)
end end
-- find fname can match seqs
local match = 0 if cod_typ == "number" then
for j = place, 5 do _code = fusf.NormalizeID(code, m)
local temp = fname:find(seqs[j]) elseif cod_typ == "string" then
if temp and temp > match then for _, val in code:ForCut("+") do
place, match = j, temp local match = val:match("[ODC]")
if match then
if _pro ~= 0 then
error("repeat set fuef:Ctl pro in string", 2)
end
_pro = fusf.FindTables(match, ctl_consts)
else
_code = fusf.NormalizeID(val, m)
end end
end end
-- cant match seqs
if match == 0 then place = i end
-- set self[key] and save key
func = seqs[place]
self[func], sets[#sets + 1] = {fname, fval}, func -- self[func] = {name, {...}} or {name}
end end
if not self.e then return self end
-- self[key] = {func, ...} if _code == 0 and (_pro == ctl_consts["O"] or _pro == ctl_consts["D"]) then
if sets[1] == "val" then _code = m
table.remove(sets, 1) end
local val = self.val[1]
if type(val) == "string" then self.ctl = {count, _code + _pro}
self.val = tonumber(val) or fucs.val[val] or fusf.Get_Func(self.e:GetOwner(), table.unpack(self.val)) log:Info(("set self.ctl : %s / %s"):format(count, self.ctl[2]))
if not self.val then fusf.Debug("val Func value is nil") end return self:Reload(log)
else -- number or function end
----------------------------------------------------------------VAL, CON, COS, TG and OP
--- 设定函数型栏位,如 val、con、tar、op 等,可接受函数名、表达式或函数本体
-- @param log 日志对象或层级(用于调试记录)
-- @param key string 欲设定的栏位名称
-- @param func string|function|number 欲指定的函数或值
-- @param ... 可选的参数,用于传递给 ResolveFunction 或 ParseCallExprString
-- @return fuef 返回自身以支援链式调用
function fuef:SetFuncField(log, key, func, ...)
local log = fudf.StartLog(log, "fuef:SetFuncField", key, func, ...)
fusf.CheckEmptyArgs(key, func, ...)
key = key:lower()
local types = "string/function"
if key == "val" then types = types.."/number" end
local f_typ = fusf.CheckArgType(key, 1, func, types)
if self:InitCheck(log, key, func, ...) then return self end
local has_arg = select("#", ...) > 0
if f_typ == "function" then
if has_arg then func = func(...) end
self[key] = func
log:Info(("set self.%s : %s"):format(key, tostring(func)))
return self:Reload(log)
end
if key == "val" then
local val = tonumber(func) or fucs.val[func] or aux[func]
if val ~= nil then
self.val = val self.val = val
log:Info("set self.val : "..tostring(val))
return self:Reload(log)
end end
end end
for _,set in ipairs(sets) do
local res = fusf.Get_Func(self.e:GetOwner(), table.unpack(self[set])) local f, args = func, nil
if not res then fusf.Debug(set.." Func value is nil") end if has_arg then args = table.pack(...) end
self[set] = res if func:match("%(") then
f, args = fusf.ParseCallExprString(func, args)
end end
return self:Reload() local c = self.e:GetOwner()
end f = fusf.ResolveFunction(f, args, fusf.Getcm(c), c.lib)
function fuef:Func_Model(_key, _func, ...)
if not self:PreChk(_key:upper(), _func, ...) then return self end self[key] = f
local val_chk = _key == "val" and (tonumber(_func) or fucs.val[_func]) or nil log:Info(("set self.%s : %s"):format(key, tostring(f)))
local vals = select("#", ...) > 0 and { ... } or nil return self:Reload(log)
if type(_func) == "string" and _func:match("%(") then end
_func = fusf.Val_Cuts(_func, ...)[1]
vals = _func --- 设定效果的 value(数值或函数),可为 number|string|function
if type(_func) == "table" then -- @param val number|string|function 数值或函数(或名称)
_func = table.remove(vals,1) -- @param ... 可选的额外参数(若 val 是函数字串会带入)
else -- @return fuef 返回自身以支援链式调用
vals = nil function fuef:Val(val, ...)
local log = fudf.StartLog(self, "fuef:Val", val, ...)
return self:SetFuncField(log, "Val", val, ...)
end
--- 设定效果的 condition(条件),可为 string|function
-- @param condition function|string 条件函数或其名称
-- @param ... 可选的额外参数(若为函数字串会带入)
-- @return fuef 返回自身以支援链式调用
function fuef:Con(condition, ...)
local log = fudf.StartLog(self, "fuef:Con", condition, ...)
return self:SetFuncField(log, "Con", condition, ...)
end
--- 设定效果的 cost(代价),可为 string|function
-- @param cost function|string 条件函数或其名称
-- @param ... 可选的额外参数(若为函数字串会带入)
-- @return fuef 返回自身以支援链式调用
function fuef:Cos(cost, ...)
local log = fudf.StartLog(self, "fuef:Cos", cost, ...)
return self:SetFuncField(log, "Cos", cost, ...)
end
--- 设定效果的 target(目标),可为 string|function
-- @param target function|string 条件函数或其名称
-- @param ... 可选的额外参数(若为函数字串会带入)
-- @return fuef 返回自身以支援链式调用
function fuef:Tg(target, ...)
local log = fudf.StartLog(self, "fuef:Tg", target, ...)
return self:SetFuncField(log, "Tg", target, ...)
end
--- 设定效果的 operation(执行动作),可为 string|function
-- @param operation function|string 条件函数或其名称
-- @param ... 可选的额外参数(若为函数字串会带入)
-- @return fuef 返回自身以支援链式调用
function fuef:Op(operation, ...)
local log = fudf.StartLog(self, "fuef:Op", operation, ...)
return self:SetFuncField(log, "Op", operation, ...)
end
--- 依据传入的函数结构设定 fuef 物件的多个栏位(val/con/cos/tg/op)
-- 支援多种格式的输入,并自动解析每一段功能模块,依照顺序填入栏位
-- @param val 可能是 val 值,或实际的函数名(视情况而定)
-- @param func 字串描述或 table 结构,代表要设置的功能函数模块
-- @param ... 其他额外参数,可能为 val 的对应值,或函数模块的参数
-- @return fuef 返回自身以支援链式调用
function fuef:Func(val, func, ...)
local log = fudf.StartLog(self, "fuef:Func", val, func, ...)
fusf.CheckEmptyArgs("Func", val, func, ...)
if self:InitCheck(log, "func", val, func, ...) then return self end
local val_typ = fusf.CheckArgType(up_key, 1, val, "string/function/number")
log:Info("try match val")
local args = {...}
if MatchValFormat(val, val_typ) then
self:SetFuncField(log, "val", val, ...)
else
func, args = val, {func, ...}
end
local c = self.e:GetOwner()
local cm = fusf.Getcm(c)
local keys, key_ind = {"val", "con", "cos", "tg", "op"}, 1
local func_table = fusf.ParseCallGroupString(func, args)
if func_table.n > 5 then error("Func : invalid func len", 2) end
log:Info("try match keys")
for i, unit in fusf.ForTable(func_table) do
local fname, fargs = unit
if type(unit) == "table" then
fname, fargs = unit[1], unit[2]
end end
elseif vals and #vals == 1 and type(vals[1]) == "table" then log:Info(i.." : "..fname)
vals = vals[1] -- 若 vals 中只有一个表,则直接解包表
local f = fusf.ResolveFunction(fname, fargs, cm, c.lib)
local match = 0
for j = key_ind, 5 do
local ind = fname:find(keys[j])
if ind and ind > match then
key_ind, match = j, ind
end
end
if match == 0 then key_ind = i end
local key = keys[key_ind]
log:Info("match "..key)
self:SetFuncField(log, key, f)
end end
self[_key] = val_chk or fusf.Get_Func(self.e:GetOwner(), _func, vals) log:Info("all match down")
if not self[_key] then fusf.Debug(_key.." Func value is nil") end
return self:Reload() return self
end
function fuef:VAL(_func, ...)
return self:Func_Model("val", _func, ...)
end
function fuef:CON(_func, ...)
return self:Func_Model("con", _func, ...)
end
function fuef:COS(_func, ...)
return self:Func_Model("cos", _func, ...)
end
function fuef:TG(_func, ...)
return self:Func_Model("tg", _func, ...)
end
function fuef:OP(_func, ...)
return self:Func_Model("op", _func, ...)
end end
----------------------------------------------------------------RES ----------------------------------------------------------------RES
function fuef:RES(_flag, _count) -- _flag = a + b/b1/b2 + c | 1
if not self:PreChk("RES", _flag, _count) then return self end --- 设定效果的 reset(重置条件)
self.res = fusf.GetRES(_flag, _count) -- @param flag string|number 条件描述(如 "a + b - c , 1")
return self:Reload() -- @param count number? 可选的重置次数,若省略则从字串中解析
end -- @return fuef 返回自身以支援链式调用
----------------------------------------------------------------LAB function fuef:Res(flag, count)
function fuef:LAB(...) local log = fudf.StartLog(self, "fuef:Res", flag, count)
if not self:PreChk("LAB", ...) then return self end
local elabs = { } fusf.CheckEmptyArgs("Res", flag, count)
for _, labs in ipairs({...}) do
if type(labs) == "string" then if self:InitCheck(log, "res", flag, count) then return self end
for _, lab in labs:ForCut("LAB", "+") do
elabs[#elabs + 1] = (lab == "m") and self.e:GetOwner():GetOriginalCode() or tonumber(lab) flag, count = fusf.ResolveReset(flag, count)
self.res = {flag, count}
log:Info(("set self.res : %s / %d"):format(fusf.CutHex(flag), count))
return self:Reload(log)
end
----------------------------------------------------------------LAB & OBJ
--- 设定 label 参数,支援数字、字串(可用 "+" 拆分)与特别标记 "m"
-- @param ... 可为数字、字串(如 "1+2+m")等,会转为数字阵列
-- @return fuef 返回自身,用于链式调用
function fuef:Lab(...)
local log = fudf.StartLog(self, "fuef:Lab", ...)
fusf.CheckEmptyArgs("Lab", ...)
if self:InitCheck(log, "lab", ...) then return self end
local m = self.e:GetOwner():GetOriginalCode()
local args = {}
for i, val in ipairs{...} do
local typ = fusf.CheckArgType("Lab", i, val, "string/number")
if typ == "string" then
for _, lab in val:ForCut("+") do
args[#args + 1] = (lab == "m") and m or tonumber(lab)
end end
else else
elabs[#elabs + 1] = labs args[#args + 1] = val
end end
end end
self.lab = elabs
return self:Reload() self.lab = args
end log:Info(("set self.lab : %d arg"):format(#args))
----------------------------------------------------------------OBJ return self:Reload(log)
function fuef:OBJ(_val) end
if not self:PreChk("OBJ", _val) then return self end
if type(_val) == "string" then -- ex: cm.e3 = fuef.FG("e1") -> obj == cm.e1 --- 设置效果的关联对象(object),可为字符串代号或实际对象
_val = fusf.Getcm(self)["es"][_val].e -- @param val string|Card|Group|Effect 关联对象,字符串将解析为 cm.elist 的键
end -- @return fuef 返回自身,用于链式调用
self.obj = _val -- @raise 类型不符时抛出错误
return self:Reload(1) function fuef:Obj(val)
end local log = fudf.StartLog(self, "fuef:Obj", val)
--------------------------------------------------------------------------"Support Effect function"
function fuef.initial(_lib, _glo, _exop_func, ...) local typ = fusf.CheckArgType("Obj", 1, val, "string/fuef/Card/Group/Effect")
local cm, m = GetID()
local exop_val = { ... } if self:InitCheck(log, "obj", val) then return self end
cm.es, cm.lib = {}, _lib
cm.initial_effect = cm.initial_effect or function(c) if typ == "string" then
-- do ex_op local e = fusf.Getcm(self).elist[val]
if _exop_func then if not e or not e.e then
local place = 1 error("Obj: elist entry for '" .. val .. "' is missing or invalid", 2)
if type(_exop_func) ~= "table" then _exop_func = { _exop_func } end
for _, exop_func in ipairs(_exop_func) do
if type(exop_func) == "string" then
for _, func in exop_func:ForCut("fuef.initial") do
local f = fucf[func] or Card[func]
if f then
f(c, exop_val[place])
else
cm[func] = exop_val[place](c)
end
place = place + 1
end
else
exop_func(c, exop_val[place])
place = place + 1
end
end
end
local dof = function(_name, _exval)
local n = 1
while cm[_name..n] do
cm.es[_name..n] = cm[_name..n](c, _exval)
n = n + 1
end
end end
dof("e") -- do e1 ~ en val = fusf.CheckType(e.e, "Effect")
dof("pe") -- do e1 ~ en in lib pre set
-- if cm[_glo] then do ge1 ~ gen
if not (_glo and not cm[_glo]) then return end
cm[_glo] = {0, 0}
dof("ge", 1)
end end
return cm, m
self.obj = val
log:Info("set self.obj : "..typ)
return self:Reload(log)
end
---------------------------------------------------------------- OwnerPlayer
--- 设置效果的 OwnerPlayer 属性为 player
-- @param p player 玩家
-- @return self fuef 物件
function fuef:Pl(p)
local log = fudf.StartLog(self, "fuef:Pl", p)
fusf.CheckArgType("Pl", 1, p, "player")
if self:InitCheck(log, "Pl", p) then return self end
self.pl = p
log:Info("set self.pl : "..p)
return self:Reload(log)
end end
function fuef.tg_is_cos(e,tp,eg,ep,ev,re,r,rp,chk)
e:SetLabel(100)
if chk==0 then return true end
end
\ No newline at end of file
dofile("expansions/script/c20099998.lua")
if fucf then return end if fucf then return end
fucf, fugf = { }, { } fucf, fugf = { }, { }
dofile("expansions/script/c20099998.lua")
-------------------------------------- Group function -------------------------------------- Group function
--- 根据卡片过滤条件构造一个群组过滤器(可回传过滤后的卡片群组或判断数量)
-- @param f string|function 过滤函数或名称,传入 MakeCardFilter 使用
-- @param v any 传入过滤函数的参数,可为单值或表
-- @param ... 可选占位参数,传给 MakeCardFilter
-- @return function function(Group, number?): Group | boolean
-- 若不提供 n,返回符合条件的子群组;
-- 若提供正整数 n,返回群组中符合条件的卡片数量是否 ≥ n;
-- 若提供负整数 -n,返回是否 ≤ -n。
function fugf.MakeGroupFilter(f, v)
return function(g, n, ...)
fusf.CheckArgType("MakeGroupFilter", 1, g, "Group")
local ok, res = pcall(fusf.CheckArgType,"MakeGroupFilter", 2, n, "nil/number")
if not ok then
error(res, 2)
end
g = g:Filter(fucf.MakeCardFilter(f, v, ...), nil)
if not n then return g end
return n > 0 and #g >= n or #g <= -n
end
end
--- 返回以 p 来看的 loc (自己以及对方区域以+分开)位置的卡片组
-- @param p number 玩家编号(必须是 0 或 1)
-- @param loc string 表示区域的字符串(如 "H+HM" 等)
-- @return Group 返回该区域内所有卡片的 Group
function fugf.Get(p, loc) function fugf.Get(p, loc)
return Duel.GetFieldGroup(p, fusf.Get_Loc(loc)) fusf.CheckArgType("Get", 1, p, "player")
return Duel.GetFieldGroup(p, fusf.GetLoc(loc))
end end
--- 以指定条件过滤 Group 中的卡片(支持数量判断)
-- @param g Group 要过滤的卡片群组
-- @param f string|function 用于 MakeCardFilter 的过滤函数或名称
-- @param v any 用于传入过滤器的参数(可为单值、表等)
-- @param n number|nil 可选值:
-- - 若为 nil,返回过滤后的 Group;
-- - 若为正数,判断是否有 ≥ n 张符合条件的卡片,返回 boolean;
-- - 若为负数,判断是否有 ≤ n 张符合条件的卡片,返回 boolean。
-- @param ... any 可选参数,传入 MakeCardFilter,用于额外参数或占位
-- @return Group|boolean 返回过滤后的 Group,或符合数量条件的布尔值
function fugf.Filter(g, f, v, n, ...) function fugf.Filter(g, f, v, n, ...)
return fusf.Creat_GF(f, v, ...)(g, n) return fugf.MakeGroupFilter(f, v)(g, n, ...)
end end
--- 获取并过滤指定玩家区域内的卡片
-- @param p number 玩家编号(必须是 0 或 1)
-- @param loc string 表示区域的字符串(如 "H+HM" 等)
-- @param f string|function 过滤函数或名称,传入 MakeCardFilter 使用
-- @param v any 传入过滤函数的参数(可为单值或表)
-- @param n number|nil 可选数量条件(正数:≥n,负数:≤n,nil:返回过滤后的 Group)
-- @param ... 可选额外参数,传给 MakeCardFilter
-- @return Group|boolean 返回过滤后的 Group,或是否符合数量条件
function fugf.GetFilter(p, loc, f, v, n, ...) function fugf.GetFilter(p, loc, f, v, n, ...)
return fugf.Filter(fugf.Get(p, loc), f, v, n, ...) return fugf.Filter(fugf.Get(p, loc), f, v, n, ...)
end end
function fugf.GetNoP(loc, f, v, n, ...) --- 构造一个带默认位置与过滤条件的 Group 过滤器函数
local val = {...} -- @param loc string 预设区域字符串(如 "M", "H+M")
return function(p) -- @param f string|function 过滤函数或名称,用于 MakeCardFilter
return fugf.GetFilter(p, loc, f, v, n, table.unpack(val)) -- @param v any 传给过滤函数的参数
-- @param n number|nil 数量要求(正:≥n,负:≤n,nil:返回过滤后的 Group)
-- @return function(p: number, ...): Group|boolean
-- 返回一个函数,该函数接受 p 及 ... 并执行过滤
function fugf.MakeFilter(loc, f, v, n)
return function(p, ...)
return fugf.GetFilter(p, loc, f, v, n, ...)
end end
end end
--- 从卡片组中选择卡片(带筛选、数量控制)
-- @param p number 控制玩家编号(0或1)
-- @param g Group|string 卡片组,或为关键字字符串(如 "HAND+MONSTER")
-- @param f function|number 筛选函数或最小选择数量
-- @param v any 若 f 为函数时传入的首个额外参数
-- @param min number? 最小选择数量(若 f 为 number,此值会从 f 推出)
-- @param max number? 最大选择数量(默认与 min 相同)
-- @param ... any 筛选函数的其它额外参数
-- @return Group 返回选择的卡片组(Group 类型)
function fugf.Select(p, g, f, v, min, max, ...) function fugf.Select(p, g, f, v, min, max, ...)
if type(g) == "string" then g = fugf.Get(p, g) end -- _g is loc local g_typ = fusf.CheckArgType("Select", 2, g, "Group/string")
if g_typ == "string" then g = fugf.Get(p, g) end
if type(f) == "number" then -- f is min if type(f) == "number" then -- f is min
min, max = f, v min, max = f, v
elseif f then -- f is func elseif f then -- f is func
...@@ -29,136 +88,369 @@ function fugf.Select(p, g, f, v, min, max, ...) ...@@ -29,136 +88,369 @@ function fugf.Select(p, g, f, v, min, max, ...)
if #g == min then return g end if #g == min then return g end
return g:Select(p, min, max, nil) return g:Select(p, min, max, nil)
end end
--- 从指定卡组中选择目标卡并设定为效果目标
-- @param p number 玩家编号(0 或 1)
-- @param g Group|string 卡片群组,或表示卡片来源的字符串(会调用 fugf.Get)
-- @param f function|string|number 可选过滤函数或数量
-- - 若为 number,代表 min 数量,v 将视为 max;
-- - 若为 function/string,则视为过滤器(将用于 Filter)
-- @param v any 过滤器附加参数
-- @param min number 最小选择数量(默认 1)
-- @param max number 最大选择数量(默认等于 min)
-- @param ... 其他传给过滤器的参数
-- @return Group 被选择并设定为目标的卡片群组
function fugf.SelectTg(p, g, f, v, min, max, ...) function fugf.SelectTg(p, g, f, v, min, max, ...)
local g = fugf.Select(p, g, f, v, min, max, ...) local g = fugf.Select(p, g, f, v, min, max, ...)
Duel.SetTargetCard(g) Duel.SetTargetCard(g)
return g return g
end end
--------------------------------------"Card function" (use in initial (no return --------------------------------------"Card function"
function fucf.AddCode(c, ...)
local codes = { } --- 根据函数与参数构造一个卡片过滤器(返回一个 function(Card) -> bool)
for _, _code in ipairs({...}) do -- @param func string|function 过滤函数或其名称,支援组合逻辑与反向(如 "~IsType+IsRace")
if type(_code) == "string" then -- @param args table|string|number 传入的参数,可为字符串(含占位符)或具体值
for _, cod in _code:ForCut("fucf.AddCode") do -- @param ... 可选的占位参数(会传给 %1、%2 等)
codes[#codes + 1] = fusf.M_chk(cod) -- @return function 过滤器函数,接受卡片并返回布林值
function fucf.MakeCardFilter(func, args, ...)
if not func then return function(c) return true end end
local typ = fusf.CheckArgType("MakeCardFilter", 1, func, "string/function")
-- trans args
if type(args) ~= "table" then args = { args } end
local arg_table, arg_count = {}, 0
for _, arg in ipairs(args) do
if type(arg) == "string" then
for _, v in fusf.ForTable(fusf.ParseCallGroupString(arg, { ... })) do
arg_count = arg_count + 1
arg_table[arg_count] = v
end end
else else
codes[#codes + 1] = fusf.M_chk(_code) arg_count = arg_count + 1
arg_table[arg_count] = arg
end
end
-- func is function
if typ == "function" then
return function(c)
fusf.CheckArgType("MakeCardFilter", 1, c, "Card")
return func(c, table.unpack(arg_table, 1, arg_count))
end end
end end
aux.AddCodeList(c, table.unpack(codes)) -- func is string
end local func_expr = fusf.InfixToPostfix(func, ...)
fucf.ReviveLimit = Card.EnableReviveLimit local fucf, Card, aux = fucf, Card, aux
--------------------------------------"Card function" (use in Filter if #func_expr == 1 then -- func just one
function fucf.Filter(c, _func, ...) local find_func = fusf.FindTables(func_expr[1], fucf, Card, aux)
return fusf.Creat_CF(_func, {...})(c) fusf.CheckType(find_func, "function")
--return fugf.Filter(Group.FromCards(c), func, {...}, 1) return function(c)
end fusf.CheckArgType("MakeCardFilter", 1, c, "Card")
fucf.IsRk = fusf.IsN("GetRank") return find_func(c, table.unpack(arg_table, 1, arg_count))
fucf.IsLv = fusf.IsN("GetLevel") end
fucf.IsRLv = fusf.IsN("GetRitualLevel") end
fucf.IsLk = fusf.IsN("GetLink") -- func is multi
fucf.IsAtk = fusf.IsN("GetAttack") return function(c)
fucf.IsDef = fusf.IsN("GetDefense") fusf.CheckArgType("MakeCardFilter", 1, c, "Card")
fucf.IsSeq = fusf.IsN("GetSequence") local stack, arg_ind = {}, 1
fucf.IsPSeq = fusf.IsN("GetPreviousSequence") for _, func in ipairs(func_expr) do
function fucf.Not(c,val) if func == "~" then
if aux.GetValueType(val) == "Card" then stack[#stack] = not stack[#stack]
elseif type(func) == "string" and #func == 1 then
local valR, valL = table.remove(stack), table.remove(stack)
local Cal = {
["+"] = valL and valR,
["-"] = valL and not valR,
["/"] = valL or valR
}
local temp = Cal[func]
if temp == nil then
error("invalid operators : " .. func)
end
stack[#stack + 1] = temp
else
if type(func) == "string" then
func = fusf.FindTables(func, fucf, Card, aux)
fusf.CheckType(func, "function")
end
local arg = arg_table[arg_ind]
arg_ind = arg_ind + 1
if type(arg) ~= "table" then arg = { arg, n = 1 } end
stack[#stack + 1] = func(c, table.unpack(arg, 1, arg.n))
end
end
return table.remove(stack)
end
end
--- 判断卡片是否满足给定的过滤条件
-- @param c Card 欲判断的卡片对象
-- @param f string|function 过滤器(可为函数或其名称)
-- @param args table|string|number 传入的参数,可为字符串(含占位符)或具体值
-- @param ... 可选的占位参数(会传给 %1、%2 等)
-- @return boolean 若卡片符合条件,返回 true,否则返回 false
function fucf.Filter(c, f, v, ...)
fusf.CheckArgType("Filter", 1, c, "Card")
return fucf.MakeCardFilter(f, v, ...)(c)
end
fucf.IsRk = fusf.MakeValCheck("GetRank")
fucf.IsLv = fusf.MakeValCheck("GetLevel")
fucf.IsRLv = fusf.MakeValCheck("GetRitualLevel")
fucf.IsLk = fusf.MakeValCheck("GetLink")
fucf.IsAtk = fusf.MakeValCheck("GetAttack")
fucf.IsDef = fusf.MakeValCheck("GetDefense")
fucf.IsSeq = fusf.MakeValCheck("GetSequence")
fucf.IsPSeq = fusf.MakeValCheck("GetPreviousSequence")
--- 判断卡片 c 是否“不等于”给定的 val
-- @param c Card 需要判断的卡片对象
-- @param val Card|Effect|Group|function 参考值,可以是卡片、效果、卡片组或过滤函数
-- @return boolean 如果 c 与 val 不匹配则返回 true,否则 false
--
-- - 若 val 是 Card,则比较是否为不同卡片
-- - 若 val 是 Effect,则比较 c 是否不是该效果的持有者
-- - 若 val 是 Group,则判断 c 是否不包含在该组内
-- - 若 val 是 function,则调用该函数传入 c,结果取反
-- - 其他情况返回 false
function fucf.Not(c, val)
fusf.CheckArgType("Not", 1, c, "Card")
local typ = fusf.CheckArgType("Not", 2, val, "Card/Effect/function")
if typ == "Card" then
return c ~= val return c ~= val
elseif aux.GetValueType(val) == "Effect" then elseif typ == "Effect" then
return c ~= val:GetHandler() return c ~= val:GetHandler()
elseif aux.GetValueType(val) == "Group" then elseif typ == "function" then
return not val:IsContains(c)
elseif aux.GetValueType(val) == "function" then
return not val(c) return not val(c)
end end
return false
end end
--- 判断卡片是否属于指定系列(Set)
-- @param c Card 要检查的卡片
-- @param sets number|string 系列编号或由多个系列编号组成的字串(用 "/" 分隔)
-- @return boolean 若属于任一指定系列则返回 true,否则返回 false
--
-- fucf.IsSet(c, 0xfd1) → 检查是否属于系列 0xfd1
-- fucf.IsSet(c, "fd1+fd2") → 检查是否属于 0xfd1 或 0xfd2
function fucf.IsSet(c, sets) function fucf.IsSet(c, sets)
if type(sets) == "number" then return c:IsSetCard(sets) end fusf.CheckArgType("IsSet", 1, c, "Card")
for _, set in sets:ForCut("fucf.IsSet", "/") do local typ = fusf.CheckArgType("IsSet", 2, sets, "number/string")
if typ == "number" then return c:IsSetCard(sets) end
for _, set in sets:ForCut("+") do
set = tonumber(set, 16) set = tonumber(set, 16)
if set and c:IsSetCard(set) then return true end if set and c:IsSetCard(set) then return true end
end end
return false return false
end end
function fucf.AbleTo(c,loc) --- 判断卡片是否能以指定方式送去特定区域
local func = { -- @param c Card 要检查的卡片
-- @param loc string 目标区域代号,可选前缀 "*" 表示作为 cost
-- 可用区域代号:
-- "H" = 手牌(Hand)
-- "D" = 卡组(Deck)
-- "G" = 墓地(Grave)
-- "R" = 除外(Remove)
-- "E" = 额外卡组(Extra)
-- 例:"*G" 表示是否能作为 cost 被送去墓地
-- @return boolean 若能送去指定区域,则返回 true,否则返回 false
-- @raise 若 loc 非法,将抛出错误
function fucf.AbleTo(c, loc)
fusf.CheckArgType("AbleTo", 1, c, "Card")
fusf.CheckArgType("AbleTo", 2, loc, "string")
local iscos = loc:match("*")
loc = loc:match("[HDGRE]")
if not loc then error("InfixToPostfix : param 1 is invalid param", 2) end
local locs = {
["H"] = "Hand" , ["H"] = "Hand" ,
["D"] = "Deck" , ["D"] = "Deck" ,
["G"] = "Grave" , ["G"] = "Grave" ,
["R"] = "Remove", ["R"] = "Remove",
["E"] = "Extra" , ["E"] = "Extra" ,
} }
local iscos = string.sub(loc,1,1) == "*" return Card["IsAbleTo"..locs[loc]..(iscos and "AsCost" or "")](c)
if iscos then loc = string.sub(loc,2) end
return Card["IsAbleTo"..func[loc]..(iscos and "AsCost" or "")](c)
end end
function fucf.CanSp(c, e, typ, tp, nochk, nolimit, pos, totp, zone) --- 检查 c 是否可以特殊召唤
if not tp then tp = e:GetHandlerPlayer() end -- @param c Card 要特殊召唤的卡片
if typ == SUMMON_TYPE_RITUAL or typ == "RI" then -- @param e Effect 用于特殊召唤的效果
-- @param typ number|string 特召方式类型(数值或缩写,如 "RI" 表示仪式召唤)
-- @param tp number 特召的执行玩家(预设为 e:GetHandlerPlayer())
-- @param pos number|string 特召时卡片的表示形式(预设为 POS_FACEUP,可用字串)
-- @param lg Card |Group|nil 检查 lg 离开后的区域数量(有的话)
-- @param nochk boolean 是否忽略召唤条件(预设视 typ 而定)
-- @param nolimit boolean 是否忽略召唤次数限制(预设视 typ 而定)
-- @param totp number 特召后控制该卡的玩家(预设为 tp)
-- @param zone number 特召位置的区域 mask(预设为 0xff,即所有主怪兽区)
-- @return boolean 是否可以被特殊召唤
function fucf.CanSp(c, e, typ, tp, pos, lg, nochk, nolimit, totp, zone)
fusf.CheckArgType("CanSp", 1, c, "Card")
if not c:IsType(TYPE_MONSTER) then return false end
fusf.CheckArgType("CanSp", 2, e, "Effect")
local _, tp = fusf.CheckArgType("CanSp", 4, tp or e:GetHandlerPlayer(), "player")
fusf.CheckArgType("CanSp", 6, lg, "nil/Card/Group")
if c:IsLocation(LOCATION_EXTRA) then
if Duel.GetMZoneCount(tp, lg) == 0 then return false end
else
if Duel.GetLocationCountFromEx(tp, tp, lg, c) == 0 then return false end
end
-- default chk
local _, nochk = fusf.CheckArgType("CanSp", 7, nochk, "nil/boolean")
local _, nolimit = fusf.CheckArgType("CanSp", 8, nolimit, "nil/boolean")
-- special default
local _, typ = fusf.CheckArgType("CanSp", 3, typ or 0, "number/string")
if typ == "RI" then
typ = SUMMON_TYPE_RITUAL typ = SUMMON_TYPE_RITUAL
nochk = nochk or false if nochk == nil then nochk = false end
nolimit = nolimit or true if nolimit == nil then nolimit = true end
end end
return c:IsCanBeSpecialSummoned(e, typ, tp, nochk or false, nolimit or false, pos or POS_FACEUP, totp or tp,zone or 0xff) -- normal default
if nochk == nil then nochk = false end
if nolimit == nil then nolimit = false end
--
local _, pos = fusf.CheckArgType("CanSp", 5, pos or POS_FACEUP, "number/string")
pos = fusf.ParseConstantKey("pos", pos)
local _, totp = fusf.CheckArgType("CanSp", 9, totp or tp, "player")
local _, zone = fusf.CheckArgType("CanSp", 10, zone or 0xff, "number")
return c:IsCanBeSpecialSummoned(e, typ, tp, nochk, nolimit, pos, totp, zone)
end end
function fucf.IsCode(c, _cod) --- 判断 c 是否属于指定的卡号
local cod -- @param c Card 要检查的卡片
if aux.GetValueType(_cod) == "number" then -- @param cod number|string|table|Effect|Card|Group 可为单个卡号、以 "+" 分隔的字符串、卡号数组,或包含卡的 Group
cod = {_cod} -- @return boolean 是否匹配任意一个卡号
elseif aux.GetValueType(_cod) == "string" then function fucf.IsCode(c, cod)
cod = _cod:Cut("fucf.IsCode", "+") fusf.CheckArgType("IsCode", 1, c, "Card")
elseif aux.GetValueType(_cod) == "table" then return c:IsCode(table.unpack(fusf.GetCodeTable(cod)))
cod = _cod end
--- 判断 c 是否有卡名记述
-- @param c Card 要检查的卡片
-- @param cod number|string|table|Effect|Card|Group 为单个卡号、以 "+" 分隔的字符串、卡号数组,或包含卡的 Group
-- @return boolean 是否匹配任意一个卡名记述
function fucf.HasCode(c, cod)
fusf.CheckArgType("HasCode", 1, c, "Card")
local code_list = c.card_code_list
if not code_list then return false end
for _, code in ipairs(fusf.GetCodeTable(cod)) do
if code_list[code] then return true end
end end
for i,v in ipairs(cod) do return false
cod[i] = fusf.M_chk(tonumber(v)) end
--- 判断是否能将多张装备卡(eg)装备到指定怪兽卡 c
-- @param c Card 欲装备的目标怪兽
-- @param eg Effect|Card|Group 欲装备的卡(可为单一卡片或卡片群组)
-- @param tp number? 控制玩家(预设为 c 的控制者)
-- @return boolean 是否所有卡片都能合法装备给 c
function fucf.CanEq(c, eg, tp)
fusf.CheckArgType("CanEq", 1, c, "Card")
eg = fusf.ToGroup(eg)
tp = tp or c:GetControler()
fusf.CheckArgType("CanEq", 3, tp, "player")
if Duel.GetLocationCount(tp, LOCATION_SZONE) < #eg then return false end
for ec in aux.Next(eg) do
if not fucf.CanBeEq(ec, tp, c, true) then return false end
end end
return c:IsCode(table.unpack(cod)) return true
end end
function fucf.HasCode(c, _cod) --- 判断卡片是否可以作为装备卡装备给指定对象
if not c.card_code_list then return false end -- @param c Card 欲检查的装备卡(可为怪兽或装备魔法)
local cod, has -- @param tp number? 预设视为控制装备卡的玩家,若 ec 存在则预设为 ec 的控制者
if aux.GetValueType(_cod) == "number" then -- @param ec Card? 欲装备的目标怪兽卡
cod = {_cod} -- @param chk_loc boolean? 若为 true,跳过地区检查(例如已有预留 zone)
elseif aux.GetValueType(_cod) == "string" then -- @return boolean 是否可被当作装备卡使用
cod = _cod:Cut("fucf.HasCode", "+") function fucf.CanBeEq(c, tp, ec, chk_loc)
fusf.CheckArgType("CanBeEq", 1, c, "Card")
if ec then
fusf.CheckArgType("CanBeEq", 3, ec, "Card")
tp = tp or ec:GetControler()
end end
for i,v in ipairs(cod) do fusf.CheckArgType("CanBeEq", 2, tp, "player")
has = has or c.card_code_list[fusf.M_chk(tonumber(v))] if not (chk_loc or Duel.GetLocationCount(tp, LOCATION_SZONE) > 0) then return false end
if c:IsLocation(LOCATION_ONFIELD) then
if not c:IsFaceup() then return false end
else
if not c:CheckUniqueOnField(tp) then return false end
end end
return has if c:IsType(TYPE_MONSTER) then
return c:IsControler(tp) or c:IsAbleToChangeControler()
elseif c:IsType(TYPE_EQUIP) then
return c:CheckEquipTarget(ec)
end
error("CanBeEq : mismatch card type", 2)
end end
function fucf.CanEq(c, tp) --- 检查卡片 c 的种类为 cod 的标识效果的数量比较 n 的结果
return c:CheckUniqueOnField(tp) and Duel.GetLocationCount(tp, LOCATION_SZONE) > 0 -- @param c Card 要检查的卡片
-- @param cod number|string 旗标代码,可为数值或字串(将会正规化)
-- @param n number 可选,若提供则检查是否具有至少 n 层该 Flag
-- @return boolean Flag count 或 count 比较 n
function fucf.IsFlag(c, cod, n)
fusf.CheckArgType("IsFlag", 1, c, "Card")
fusf.CheckArgType("IsFlag", 3, n, "number")
return fusf.GetFlag(c, cod, n)
end end
function fucf.IsFlagLab(c, _cod, _lab) --- 检查卡片 c 的种类为 cod 的标识效果的 Label 是否是 lab
return c:GetFlagEffectLabel(_cod) == _lab -- @param c Card 要检查的卡片
-- @param cod number|string 旗标代码,可为数值或字串(将会正规化)
-- @param lab number 要比较的 Label
-- @return boolean Label 或 Label == lab
function fucf.IsFlagLab(c, cod, lab)
fusf.CheckArgType("IsFlagLab", 1, c, "Card")
fusf.CheckArgType("IsFlagLab", 3, lab, "number")
return fusf.GetFlagLabel(c, cod, lab)
end end
--- 检查卡片 c 的当前控制者是否是 p
-- @param c Card 要检查的卡片
-- @param p number 要比较的控制者玩家(0 或 1)
-- @return boolean 卡片 c 的当前控制者是否是 p
function fucf.IsCon(c, p) function fucf.IsCon(c, p)
if type(p) == "string" then p = tonumber(p) end fusf.CheckArgType("IsCon", 1, c, "Card")
fusf.CheckArgType("IsCon", 2, p, "player")
return c:IsControler(p) return c:IsControler(p)
end end
fucf.InGroup = function(c, g) return g:IsContains(c) end --- 检查卡片组 g 中是否存在卡片 c
-- @param c Card 要检查的卡片
-- @param g Group 要检查的卡片组
-- @return boolean 卡片组 g 中是否存在卡片 c
function fucf.InG(c, g)
fusf.CheckArgType("InG", 1, c, "Card")
fusf.CheckArgType("InG", 2, g, "Group")
return g:IsContains(c)
end
--- 检查卡片 c 没有受王家长眠之谷的影响,并且检查当前连锁能否被无效
-- @param c Card 要检查的卡片
-- @return boolean 卡片 c 没有受王家长眠之谷的影响,并且当前连锁能被无效
function fucf.GChk(c)
fusf.CheckArgType("GChk", 1, c, "Card")
return not c:IsHasEffect(EFFECT_NECRO_VALLEY) and Duel.IsChainDisablable(0)
end
--- 检查卡片 c 当前位置是否是 loc
-- 注:loc == M 时,怪兽召唤(广义的)之际或被无效会返回 false
-- loc == S 时,魔陷发动无效会返回false
-- @param c Card 要检查的卡片
-- @param loc string|number 区域表示
-- @return boolean 检查卡片 c 当前位置是否是 loc
function fucf.IsLoc(c, loc)
fusf.CheckArgType("IsLoc", 1, c, "Card")
loc = fusf.GetLoc(loc)
return c:IsLocation(loc)
end
--- 检查卡片 c 之前的位置是否是 loc
-- @param c Card 要检查的卡片
-- @param loc string|number 区域表示
-- @return boolean 检查卡片 c 之前的位置是否是 loc
function fucf.IsPLoc(c, loc)
fusf.CheckArgType("IsPLoc", 1, c, "Card")
loc = fusf.GetLoc(loc)
return c:IsPreviousLocation(loc)
end
fucf.TgChk = Card.IsCanBeEffectTarget fucf.TgChk = Card.IsCanBeEffectTarget
fucf.GChk = function(c) return not c:IsHasEffect(EFFECT_NECRO_VALLEY) end
fucf.IsImm = Card.IsImmuneToEffect fucf.IsImm = Card.IsImmuneToEffect
fucf.IsPCon = Card.IsPreviousControler fucf.IsPCon = Card.IsPreviousControler
fucf.IsLoc = function(c,loc) return c:IsLocation(fusf.Get_Loc(loc)) end fucf.IsRea = fusf.MakeConsCheck("GetReason", "rea", "&")
fucf.IsPLoc = function(c,loc) return c:IsPreviousLocation(fusf.Get_Loc(loc)) end fucf.IsTyp = fusf.MakeConsCheck("GetType", "typ", "&")
fucf.IsRea = fusf.Is_Cons("GetReason", "rea") fucf.IsSTyp = fusf.MakeConsCheck("GetSummonType", "styp", "&")
fucf.IsTyp = fusf.Is_Cons("GetType", "typ") fucf.IsOTyp = fusf.MakeConsCheck("GetOriginalType", "typ", "&")
fucf.IsSTyp = fusf.Is_Cons("GetSummonType", "styp") fucf.IsAtt = fusf.MakeConsCheck("GetAttribute", "att", "&")
fucf.IsOTyp = fusf.Is_Cons("GetOriginalType", "typ") fucf.IsRac = fusf.MakeConsCheck("GetRace", "rac", "&")
fucf.IsAtt = fusf.Is_Cons("GetAttribute", "att") fucf.IsPos = fusf.MakeConsCheck("GetPosition", "pos", "|")
fucf.IsRac = fusf.Is_Cons("GetRace", "rac") fucf.IsPPos = fusf.MakeConsCheck("GetPreviousPosition", "pos", "|")
fucf.IsPos = fusf.Is_Cons("GetPosition", "pos", function(card_val, val) return card_val | val == val end) --[[
fucf.IsPPos = fusf.Is_Cons("GetPreviousPosition", "pos", function(card_val, val) return card_val | val == val end)
---------------------------------------------------------------- procedure ---------------------------------------------------------------- procedure
function fucf.RMFilter(c, rf, e, tp, g1, g2, level_function, greater_or_equal, chk) function fucf.RMFilter(c, rf, e, tp, g1, g2, level_function, greater_or_equal, chk)
if rf and not rf(c, e, tp, chk) then return false end if rf and not rf(c, e, tp, chk) then return false end
if not fucf.Filter(rc, "IsTyp+CanSp", "RI+M", {e, SUMMON_TYPE_RITUAL, tp, false, true}) then return false end if not fucf.Filter(rc, "IsTyp+CanSp", "RI+M", {e, "RI"}) then return false end
local g = g1:Filter(Card.IsCanBeRitualMaterial, c, c) + (g2 or Group.CreateGroup()) local g = g1:Filter(Card.IsCanBeRitualMaterial, c, c) + (g2 or Group.CreateGroup())
g = g:Filter(c.mat_filter or aux.TRUE, c, tp) g = g:Filter(c.mat_filter or aux.TRUE, c, tp)
local lv = level_function(c) local lv = level_function(c)
...@@ -166,4 +458,5 @@ function fucf.RMFilter(c, rf, e, tp, g1, g2, level_function, greater_or_equal, c ...@@ -166,4 +458,5 @@ function fucf.RMFilter(c, rf, e, tp, g1, g2, level_function, greater_or_equal, c
local res = g:CheckSubGroup(Auxiliary.RitualCheck, 1, lv, tp, c, lv, greater_or_equal) local res = g:CheckSubGroup(Auxiliary.RitualCheck, 1, lv, tp, c, lv, greater_or_equal)
Auxiliary.GCheckAdditional = nil Auxiliary.GCheckAdditional = nil
return res return res
end end
\ No newline at end of file --]]
\ No newline at end of file
dofile("expansions/script/c20099999.lua")
if fusf then return end if fusf then return end
fusf = { } dofile("expansions/script/c20099999.lua")
fusf = {}
fudf = {}
fudf.__index = fudf
--------------------------------------"Debug function"
--- 若处于调试模式则输出函数调用信息和参数
-- @param log fudf|fuef|number log 实例/fuef 实例/层级数字
-- @param name string 函数名称
-- @param ... any 参数列表
-- @return fudf log 实例
function fudf.StartLog(log, name, ...)
if not fuef.DebugMode then return fudf end
local typ = fusf.CheckArgType("StartLog", 1, log, "number/fudf/fuef")
fusf.CheckArgType("StartLog", 2, name, "string")
local lv
if typ == "number" then
lv = log
elseif typ == "fuef" then
lv = log.isinit and 2 or 0
else
lv = log.depth
end
local indent = ("\t"):rep(lv)
local arg_str = ""
local args = {...}
local len = select("#", ...)
if len > 0 then
local out = {}
for i = 1, len do
local val = args[i]
local typ = type(val)
if typ == "userdata" then
typ = fusf.Type(val)
elseif typ == "number" or typ == "boolean" then
typ = tostring(val)
elseif typ == "string" then
typ = '"'..val..'"'
end
table.insert(out, typ)
end
arg_str = table.concat(out, ", ")
end
Debug.Message(("\t%s[CALL] : %s(%s)"):format(indent, name, arg_str))
return setmetatable({ depth = lv + 1 }, fudf)
end
--- 若处于调试模式则印出 msg
-- @param msg any 调试信息
function fudf:Info(msg)
if not fuef.DebugMode then return end
local indent = ("\t"):rep(self.depth)
Debug.Message("\t"..indent.."[INFO] : "..msg)
end
--- 若处于调试模式则印出 msg
-- @param msg any 调试信息
function fusf.Info(msg)
if not fuef.DebugMode then return end
Debug.Message("\t[INFO] : "..msg)
end
--------------------------------------"String function" --------------------------------------"String function"
function string:Cut(_from, _cut) --- 将字串以指定字元切割,保留空字串片段
_cut = _cut or "," -- default -- @param cut string 分隔符,预设为逗号 ","
if type(self) ~= "string" or type(_cut) ~= "string" then -- @return table 字串片段阵列,连续分隔符中间的空字串也会被保留
local _p = (type(self) ~= "string" and "1" or "")..(type(_cut) ~= "string" and "2" or "") -- @raise 当 self 或 cut 非字串型态时抛出错误
Debug.Message("Invalid parameter ".._p.." in string:Cut <- ".._from) function string:Cut(cut)
return nil cut = cut or ","
end if type(cut) ~= "string" then
local str, list, char = self.._cut, {}, "" error("Cut : param 1 should be string, got "..type(cut), 2)
for unit in str:gmatch(".") do end
if unit == _cut then local res, part = {}, ""
table.insert(list, char) for char in (self .. cut):gmatch(".") do
char = "" if char == cut then
table.insert(res, part)
part = ""
else else
char = char..unit part = part .. char
end end
end end
return list return res
end end
function string:ForCut(_from, _cut)
_cut = _cut or "," -- default --- 返回一个迭代器,遍历按指定分隔符切割后的字符串片段
if type(self) ~= "string" or type(_cut) ~= "string" then -- @param cut string 分隔符,默认值为逗号 ","
local _p = (type(self) ~= "string" and "1" or "")..(type(_cut) ~= "string" and "2" or "") -- @return function 迭代函数,每次调用返回当前索引和对应的字符串片段
Debug.Message("Invalid parameter ".._p.." in string:ForCut <- ".._from) -- @usage
return nil -- for i, s in ("a,b,,c"):ForCut(",") do
end -- print(i, s)
local list = self:Cut("string:ForCut <- ".._from, _cut) -- end
function string:ForCut(cut)
local list = self:Cut(cut)
local ind, max = 0, #list local ind, max = 0, #list
return function() return function()
if ind >= max then return nil end if ind >= max then return nil end
...@@ -35,159 +101,320 @@ function string:ForCut(_from, _cut) ...@@ -35,159 +101,320 @@ function string:ForCut(_from, _cut)
return ind, list[ind] return ind, list[ind]
end end
end end
--------------------------------------"Error function"
--- 检查 from 函数的参数是否为空,若为空则报错
-- @param from string 呼叫来源,用于错误提示
-- @param ... any 任意数量的参数
-- @raise 若参数皆为空,则触发错误,提示呼叫位置
function fusf.CheckEmptyArgs(from, ...)
if not fusf.IsEmpty(...) then return end
error(from.." : Argument cannot be empty", 3)
end
--- 检查 from 函数的第 i 个参数 val 的类型是否为 typs,否则报错
-- @param from string 呼叫来源,用于错误提示
-- @param i number 参数位置(从 1 开始)
-- @param val any 要检查的值
-- @param typs string 允许的类型,类型名以 `/` 分隔(如 "string/number")
-- @return string, any 若匹配,返回其匹配的类型及原值
-- @raise 若类型不符,报错并显示位置与类型资讯
function fusf.CheckArgType(from, i, val, typs)
local is_typ, typ = pcall(fusf.CheckTypes, val, typs)
if is_typ then return typ, val end
local err_msg = "%s : param %d should be %s, got %s"
err_msg = err_msg:format(from, i, typs, fusf.Type(val))
error(err_msg, 3)
end
--------------------------------------"Support function" --------------------------------------"Support function"
function fusf.Debug(msg) --- 更精确地取得物件的类型名称,支援 Card/Effect/Group/fuef 等
if fuef.DebugMode then Debug.Message(msg) end -- @param val 任意值
end -- @return string 自定义类型名称或 Lua 原生类型名称
function fusf.ValToDebug(...) function fusf.Type(val)
local tab, res = {...}, "" local typ = type(val)
for i = 1, select("#", ...) do if typ == "userdata" then
if type(tab[i]) == "userdata" then return aux.GetValueType(val)
res = res..", "..aux.GetValueType(tab[i]) elseif typ == "table" then
else local metatable = getmetatable(val)
res = res..", "..tostring(tab[i]) if metatable == fuef then
return "fuef"
elseif metatable == fudf then
return "fudf"
end end
end end
return res:sub(3) return typ
end end
function fusf.Getcm(val)
local c = fusf.ToCard(val, true) --- 验证 val 的类型是否为 typ,若为 "player" 类型则进一步检查值是否合法(0 或 1)
if getmetatable(val) == fuef then -- @param val any 欲检查的值
c = val.e:GetOwner() -- @param typ string 预期的类型名称(如 "Card", "string", "number", "player" 等)
end -- @return any 若类型正确,返回原值
if not c then -- @raise 若类型不符,会根据 arg_ind 抛出更明确的错误(包含参数编号)
Debug.Message("Cant Get cm "..tostring(val)) function fusf.CheckType(val, typ)
return { } if type(typ) ~= "string" then
end error(("param %d should be %s, got %s"):format(2, "string", type(typ)), 2)
return _G["c"..val.e:GetOwner():GetCode()] end
end if typ == "player" then
function fusf.CutHex(val, add) if val == 0 or val == 1 then
-- 转换 typ 等并分割 return val
if type(val) == "string" then return val end else
add = add or "+" error("invalid player index '"..val.."' (expected 0 or 1)", 3)
local parts = {}
local bit = 1
while val > 0 do
if val % 2 == 1 then
table.insert(parts, string.format("0x%X", bit))
end end
val = math.floor(val / 2)
bit = bit * 2
end end
for i = 1, math.floor(#parts / 2) do local val_type = fusf.Type(val)
parts[i], parts[#parts - i + 1] = parts[#parts - i + 1], parts[i] if val_type == typ then return val end
error(("should be %s, got %s"):format(typ, val_type), 3)
end
--- 验证 val 的 type 是否在 typs 内(以 "/" 分隔)
-- @param val any 欲检查的值
-- @param typs string 多个类型名称组成的字符串,如 "number/string"
-- @return string, any 若匹配,返回其匹配的类型及原值
-- @raise 若不符合任何类型,会抛出详细错误信息
function fusf.CheckTypes(val, typs)
typs = fusf.CheckType(typs, "string")
local val_type = fusf.Type(val)
for _, typ in typs:ForCut("/") do
if pcall(fusf.CheckType, val, typ) then return typ, val end
end end
return table.concat(parts, add) error(("should be %s, got %s"):format(typs, val_type), 3)
end end
function fusf.ToCard(val, is_owner)
local g = fusf.ToGroup(val, is_owner) --- 从 fucs 下指定子表中查找常量值,或返回整个表
if g then return g:GetFirst() end -- @param table_key string 欲查找的子表名称(如 "cod")
return false -- @param key? string 欲查找的键名称(可省略,省略时返回整个子表)
-- @return any 找到的值或整个子表
-- @raise 若子表不存在、键无效,则报错
function fusf.Findfucs(table_key, key)
fusf.CheckArgType("Findfucs", 1, table_key, "string")
local const_table = fusf.CheckType(fucs[table_key], "table")
if not key then return const_table end
return fusf.FindTables(key, const_table)
end end
--- 在多个表中依序查找键值
-- @param key string 欲查找的键名称
-- @param ... table 可变参数,每个都是待查找的表格
-- @return any 若找到键,返回对应的值;否则抛出错误
function fusf.FindTables(key, ...)
fusf.CheckArgType("FindTables", 1, key, "string")
for i, tab in ipairs{ ... } do
fusf.CheckArgType("FindTables", i + 1, tab, "table")
if tab[key] then return tab[key] end
end
error("unknown constant key '"..key.."' in table", 2)
end
--- 将 val 转为对应的 Group
-- @param val Card|Effect|Group 欲处理的对象
-- @param is_owner boolean 若为 Effect 时,是否取其 owner 而非 handler
-- @return Group 对应的 Group
-- @raise 若类型非 Card/Effect/Group,则抛出错误
function fusf.ToGroup(val, is_owner) function fusf.ToGroup(val, is_owner)
local typ = aux.GetValueType(val) local typ = fusf.CheckArgType("ToGroup", 1, val, "Card/Effect/Group")
if typ == "Effect" then if typ == "Effect" then
return Group.FromCards(is_owner and val:GetOwner() or val:GetHandler()) return Group.FromCards(is_owner and val:GetOwner() or val:GetHandler())
elseif typ == "Card" then elseif typ == "Card" then
return Group.FromCards(val) return Group.FromCards(val)
elseif typ == "Group" then
return val
end end
return false return val -- typ == "Group"
end
--- 将 val 转为对应的卡片组 table
-- @param val Card|Effect|Group 欲处理的对象
-- @return table 对应的 table
-- @raise 若无法转换为非空 Group,则抛出错误
function fusf.ToGroupTable(val)
local g = fusf.ToGroup(val)
if #g == 0 then
error("ToGroup(" .. fusf.Type(val) .. ") is empty Group", 2)
end
local tab = {}
for c in aux.Next(g) do
table.insert(tab, c)
end
return tab
end
--- 将 val 转为对应的 Card
-- @param val Card|Effect|Group 欲处理的对象
-- @param is_owner boolean 若为 Effect 时,是否取其 owner 而非 handler
-- @return Card 对应的 Card
-- @raise 若无法转换为非空 Group,则抛出错误
function fusf.ToCard(val, is_owner)
local c = fusf.ToGroup(val, is_owner):GetFirst()
if c then return c end
error("ToGroup(" .. fusf.Type(val) .. ") is empty Group", 2)
end end
function fusf.IsNil(...)
local vals = {...} --- 判断传入值是否为 nil, "", {}
if #vals == 0 then return true end -- @param ... 任意数量的参数
-- @return boolean 是否为 nil, "", {}
function fusf.IsEmpty(...)
local vals = { ... }
if select("#", ...) == 0 then return true end
vals = #vals == 1 and vals[1] or vals vals = #vals == 1 and vals[1] or vals
if type(vals) == "string" then if type(vals) == "string" then
return vals == "" -- 非空字串 return vals == ""
elseif type(vals) == "table" then elseif type(vals) == "table" then
return not next(vals) -- 表有內容 return next(vals) == nil
end end
return not vals return vals == nil
end end
function fusf.NotNil(...)
return not fusf.IsNil(...) --- 根据 val 取得其对应的全局 cm 表
end -- @param val Card|Effect|Group|fuef
function fusf.Get_Constant(_constable, _vals) -- @return table 对应的 cm 表
-- string chk -- @raise 若无法取得卡片对象则抛出错误
if type(_vals) ~= "string" then return _vals end function fusf.Getcm(val)
local res = 0 local typ = fusf.CheckArgType("Getcm", 1, val, "Card/Effect/Group/fuef")
-- cod chk local c
if _constable == "cod" then if typ == "fuef" then
-- EVENT_CUSTOM c = fusf.CheckType(val.e, "Effect"):GetOwner()
if _vals:match("CUS") then else
_vals = _vals:sub(5) c = fusf.ToCard(val, true)
-- owner code or number end
res = EVENT_CUSTOM + fusf.M_chk(_vals) return fusf.CheckType(_G["c" .. c:GetCode()], "table")
-- EVENT_PHASE or EVENT_PHASE_START end
elseif _vals:match("PH") then
for _, val in _vals:ForCut("Get_Constant_1", "+") do --- 规范化卡号,若小于 1000,则加上 base (20000000)
local _constable = val:match("PH") and "cod" or "pha" -- @param id number|string
res = res + fucs[_constable][val] -- @param base number 可选,若卡号 < 1000,将加上此值(默认 20000000)
-- @return number 规范化后的卡号
-- @raise 若 id 无法转为数字,或 base 非数字,将抛出错误
function fusf.NormalizeID(id, base)
id = tonumber(id)
fusf.CheckArgType("NormalizeID", 1, id, "number")
fusf.CheckArgType("NormalizeID", 2, base, "nil/number")
base = base or 20000000
return id < 1000 and id + base or id
end
--- 解析 val 并回传一个对应的卡号 table
-- @param val any 可以是 Group、Card、Effect、number、string(用 + 分隔的代码)、table 等
-- @return table<number> 包含标准化过的卡号 table
function fusf.GetCodeTable(val)
local result = {}
local to_g, g = pcall(fusf.ToGroup, val)
if to_g then
for gc in aux.Next(g) do
for _, cod in ipairs{ gc:GetCode() } do
table.insert(result, cod)
end end
end end
if res ~= 0 then return res end return result
end end
-- find _constable
local vals, cons, des = _vals:Cut("Get_Constant_2", "+"), fucs[_constable] local code_table = {}
for i = #vals, 1, -1 do local typ = fusf.CheckTypes(val, "number/string/table")
local _val = vals[i] if typ == "number" then
des = fucs.des[_val] or des code_table = { val }
res = res + cons[_val] elseif typ == "string" then
code_table = val:Cut("+")
elseif typ == "table" then
code_table = val
end end
return res, des for _, cod in ipairs(code_table) do
table.insert(result, fusf.NormalizeID(cod))
end
if #result > 0 then return result end
error("GetCodeTable : get empty table", 3)
end end
function fusf.Get_Loc(_loc_s, _loc_o, _from)
-- nil chk --- 将整数转换为 16 进制 string 表示(以 ", " 或指定符号连接)
if not fusf.NotNil(_loc_s, _loc_o) then -- @param val number|string 欲转换的数值,若为字串则直接返回
Debug.Message("Get_Loc <- ".._from) -- @return string 分解后的 16 进制表示,如 "0x1, 0x2, 0x8"
return nil -- @raise 当参数类型不符时抛出错误
end function fusf.CutHex(val)
local p_loc = {0, 0} local typ = fusf.CheckArgType("CutHex", 1, val, "string/number")
-- _loc_o chk if typ == "string" then return val end
if _loc_o then p_loc[2] = _loc_o end
-- _loc_s string chk local parts, bit = {}, 1
if type(_loc_s) ~= "string" then while val > 0 do
p_loc[1] = _loc_s if val % 2 == 1 then
return table.unpack(p_loc) table.insert(parts, 1, string.format("0x%X", bit))
end
-- _loc_s is string and find fucs.ran
local _res = 0
for i, loc in _loc_s:ForCut("Get_Loc", "+") do
for j = 1, #loc do
p_loc[i] = p_loc[i] + fucs.ran[loc:sub(j,j):upper()]
end end
val = math.floor(val / 2)
bit = bit * 2
end end
return table.unpack(p_loc) return table.concat(parts, ", ")
end end
function fusf.M_chk(val) -- val : number|string
val = tonumber(val) --- 转换成前后两个区域后传回(self_loc包含两个区域时以+分开)
if val < 19999999 then return val + 20000000 end -- @param self_loc string|number 自己的区域表示,可为形如 "HM+M" 的字串,或直接为数值
return val -- @param oppo_loc number|nil 对方的区域数值
-- @return number, number 自己和对方的区域值
-- @raise 当 self_loc 和 oppo_loc 同时为空时抛出错误
-- @raise 当 oppo_loc 非 number or nil 时抛出错误
-- @raise 当 self_loc 字符无法在 fucs.ran 中找到对应值时抛出错误
function fusf.GetLoc(self_loc, oppo_loc)
fusf.CheckEmptyArgs("GetLoc", self_loc, oppo_loc)
local typ = fusf.CheckArgType("GetLoc", 1, self_loc, "string/number")
fusf.CheckArgType("GetLoc", 2, oppo_loc, "nil/number")
local loc_list = { 0, 0 }
if oppo_loc then
loc_list[2] = oppo_loc
end
if typ == "number" then
loc_list[1] = self_loc
return table.unpack(loc_list)
end
for i, locs in self_loc:ForCut("+") do
for j = 1, #locs do
local ch = locs:sub(j, j):upper()
loc_list[i] = loc_list[i] + fusf.Findfucs("ran", ch)
end
end
return table.unpack(loc_list)
end end
function fusf.PostFix_Trans(_str, ...)
local vals, res, temp, i = {...}, { }, { }, 1 --- 将带变量占位符的中缀表达式转换成后缀表达式(逆波兰表达式)
while i <= #_str do -- 支持字母变量、占位符 %n 替换参数、括号以及 + - / ~ 运算符
local ch = _str:sub(i, i) -- @param expr string 形如 "A+(B-%1)/C" 的表达式字符串
-- @param ... 传入参数,用于替换表达式中的 %n 占位符(n为数字)
-- @return table 后缀表达式数组,元素为字符串或函数
function fusf.InfixToPostfix(expr, ...)
fusf.CheckArgType("InfixToPostfix", 1, expr, "string")
if expr == "" then error("InfixToPostfix : param 1 is invalid param", 2) end
local args, res, temp, i = { ... }, {}, {}, 1
while i <= #expr do
local ch = expr:sub(i, i)
if ch:match("%a") then if ch:match("%a") then
_, i, ch = _str:find("(%a+)", i) _, i, ch = expr:find("(%a+)", i)
table.insert(res, ch) table.insert(res, ch)
elseif ch == "%" then elseif ch == "%" then
_, i, ch = _str:find("(%d+)", i) _, i, ch = expr:find("(%d+)", i)
ch = vals[tonumber(ch)] if not ch then
if type(ch) == "boolean" then error("'%' must be followed by a number at position : " .. expr, 2)
local b = ch
ch = function() return b end
end end
table.insert(res, ch) local val = args[tonumber(ch)]
if val == nil then
error("argument %" .. ch .. " is nil", 2)
elseif type(val) == "boolean" then
local b = val
val = function() return b end
end
table.insert(res, val)
elseif ch == "(" or ch == "~" then elseif ch == "(" or ch == "~" then
table.insert(temp, ch) table.insert(temp, ch)
elseif ch == ")" then elseif ch == ")" then
while #temp > 0 and temp[#temp] ~= "(" do local found_left_paren = false
table.insert(res, table.remove(temp)) while #temp > 0 do
local op = table.remove(temp)
if op == "(" then
found_left_paren = true
break
else
table.insert(res, op)
end
end
if not found_left_paren then
error("unexpected symbol near ')' : " .. expr, 2)
end end
table.remove(temp)
elseif ch == "+" or ch == "-" then elseif ch == "+" or ch == "-" then
while #temp > 0 and temp[#temp] ~= "(" do while #temp > 0 and temp[#temp] ~= "(" do
table.insert(res, table.remove(temp)) table.insert(res, table.remove(temp))
...@@ -198,6 +425,8 @@ function fusf.PostFix_Trans(_str, ...) ...@@ -198,6 +425,8 @@ function fusf.PostFix_Trans(_str, ...)
table.insert(res, table.remove(temp)) table.insert(res, table.remove(temp))
end end
table.insert(temp, ch) table.insert(temp, ch)
else
error("unexpected character '" .. ch .. "' : " .. expr, 2)
end end
if temp[#temp] == "~" and ch:match("^[%a%)%%]") then if temp[#temp] == "~" and ch:match("^[%a%)%%]") then
table.insert(res, table.remove(temp)) table.insert(res, table.remove(temp))
...@@ -205,260 +434,644 @@ function fusf.PostFix_Trans(_str, ...) ...@@ -205,260 +434,644 @@ function fusf.PostFix_Trans(_str, ...)
i = i + 1 i = i + 1
end end
while #temp > 0 do while #temp > 0 do
table.insert(res, table.remove(temp)) local op = table.remove(temp)
if op == "(" then
error("expected ')' to close '(' : " .. expr, 2)
end
table.insert(res, op)
end end
return res return res
end end
function fusf.IsN(_func)
return function(_c, _val, _exval) --- 构造一个用于判断卡片某个数值大小关系的函数
local c_val = Card[_func](_c, _exval) -- @param getter string Card 的函数名,如 "GetLevel"
if type(_val) == "string" then -- @return function(c, target, ...) -> boolean
local oper, _val = _val:match("[%+%-]"), _val:match("%d+") function fusf.MakeValCheck(getter)
_val = tonumber(_val) local card_func = fusf.CheckType(Card[getter], "function")
if oper == "+" then local from = "MakeValCheck("..getter
return c_val >= _val
elseif oper == "-" then return function(c, target, ...)
return c_val <= _val fusf.CheckArgType(from, 1, c, "Card")
end local typ = fusf.CheckArgType(from, 2, target, "number/string")
return c_val == _val local card_val = fusf.CheckType(card_func(c, ...), "number")
if typ == "number" then
return target > 0 and card_val == target or card_val <= -target
end
local oper = target:match("[%+%-]")
local num = tonumber(target:match("%d+"))
if oper == "+" then
return card_val >= num
elseif oper == "-" then
return card_val <= num
end end
if _val > 0 then return c_val == _val end return card_val == num
return c_val <= -_val -- _val = -n
end end
end end
function fusf.Is_Cons(_func, _key, _cal)
_cal = _cal or function(card_val, val) return card_val & val == val end --- 构造一个用于判断卡片某个数值是否符合常量条件的函数
return function(c, _cons) -- @param getter string 要呼叫的 Card 方法名称,例如 "GetType"
if type(_cons) ~= "string" then return _cal(Card[_func](c), _cons) end -- @param table_key string 常量表名称,如 "cod"、"pha"(会传给 fusf.FindTables)
local res, valL, valR = { } -- @param cal_type string? 校验类型("&" 代表包含、"|" 代表允许并集),预设为 "|"
for _, val in ipairs(fusf.PostFix_Trans(_cons)) do -- @return function(card: Card, value: string|number): boolean 回传是否符合条件
function fusf.MakeConsCheck(getter, table_key, cal_type)
local card_func = fusf.CheckType(Card[getter], "function")
local const_table = fusf.Findfucs(table_key)
cal_type = cal_type or "|"
local cal_func
if cal_type == "&" then
cal_func = function(c, target) return card_func(c) & target == target end
elseif cal_type == "|" then
cal_func = function(c, target) return card_func(c) | target == target end
end
return function(c, target)
local from = "MakeConsCheck("..getter
fusf.CheckArgType(from, 1, c, "Card")
local typ = fusf.CheckArgType(from, 2, target, "number/string")
if typ == "number" then return cal_func(c, target) end
local stack = {}
for _, val in ipairs(fusf.InfixToPostfix(target)) do
if val:match("[%-%~]") then if val:match("[%-%~]") then
res[#res] = not res[#res] stack[#stack] = not stack[#stack]
elseif val:match("[%+%/]") then elseif val:match("[%+%/]") then
valR = table.remove(res) local valR, valL = table.remove(stack), table.remove(stack)
valL = table.remove(res)
local Cal = { local Cal = {
["+"] = valL and valR, ["+"] = valL and valR,
["/"] = valL or valR ["/"] = valL or valR
} }
table.insert(res, Cal[val]) table.insert(stack, Cal[val])
else else
table.insert(res, _cal(Card[_func](c), fucs[_key][val:upper()])) local temp = fusf.FindTables(val:upper(), const_table)
table.insert(stack, cal_func(c, temp))
end end
end end
return res[#res] return stack[#stack]
end
end
function fusf.Get_Func(_c, _func, _val)
if type(_func) ~= "string" then return _func end
local lib = _c.lib or {}
local res = function(_func) return _func end
if _func:match("~") then
_func = _func:sub(2)
res = function(_func) return function(...) return not _func(...) end end
end
-- find cm, lib, fuef, aux
if not _val then
return res(_c[_func] or lib[_func] or fuef[_func] or aux[_func])
end
-- translate vals
for i, val in ipairs(_val) do
_val[i] = tonumber(val) or val
end
-- find cm, lib, fuef, aux
for _, Lib in ipairs({_c, lib, fuef, aux}) do
if Lib[_func] then return res(Lib[_func](table.unpack(_val))) end
end
Debug.Message("Get_Func not found : ".._func)
return nil
end
function fusf.Val_Cuts(_val, ...) -- "f1,f2(v1,v2),(v3)" -> {"f1", {"f2", "v1", "v2"}, {"v3"}}, ... use in vi = %i
local res_lst, res_ind, temp = { }, 0, { }
for _, val in _val:ForCut("Val_Cuts") do
res_ind = res_ind + 1
local is_st = val:match("%(")
local is_ed = val:match("%)")
-- is f(v1)
if is_st and is_ed then -- f(v1) -> {"f", "v1"}
res_lst[res_ind] = fusf.Val_Cuts_Table_Process(val, ...)
elseif is_st then -- f(v1,v2,v3) st f(v1
temp, res_ind = val, res_ind - 1
elseif is_ed then -- f(v1,v2,v3) ed v3) -> {"f", "v1", "v2", "v3"}
res_lst[res_ind] = fusf.Val_Cuts_Table_Process(temp..","..val, ...)
temp = ""
elseif #temp > 0 then -- f(v1,v2,v3) mid v2
temp, res_ind = temp..","..val, res_ind - 1
elseif val:match("%%") then
res_lst[res_ind] = ({...})[tonumber(val:sub(2))]
elseif val ~= "" then
res_lst[res_ind] = val
end
end end
res_lst.len = res_ind end
return res_lst
end --- 从常量表找寻对应 keys 合计值
function fusf.Val_Cuts_Table_Process(_str, ...) -- "f(%1,,3)" -> {"f", vals[1], nil, "3"} -- @param table_key string 常量表名称,如 "cod", "pha"
local vals, res_lst, st = {...}, { }, _str:find("%(") -- @param keys number|string 欲解析的常量名,多个以 "+" 连接
if st ~= 1 then res_lst[1] = _str:sub(1, st - 1) end -- has f -- @return number 合并的常量值, 可选返回常量描述
if st + 1 == #_str then return res_lst end -- "f()" -> {"f"} -- @raise 当参数类型错误或无法找到对应常量时抛出错误
_str = _str:sub(st + 1, #_str - 1) function fusf.ParseConstantKey(table_key, keys)
local res_ind = #res_lst local typ = fusf.CheckArgType("ParseConstantKey", 2, keys, "number/string")
for _, val in _str:ForCut("Val_Cuts_Table_Process") do if typ == "number" then return keys end
res_ind = res_ind + 1
if val:match("%%") then if keys == "" then error("ParseConstantKey : param 2 is invalid param", 2) end
res_lst[res_ind] = vals[tonumber(val:sub(2))]
elseif val ~= "" then local keys_list, res = keys:Cut("+"), 0
res_lst[res_ind] = val -- is special keys in cod table
if table_key == "cod" then
if keys_list[1] == "CUS" then
res = EVENT_CUSTOM + fusf.NormalizeID(keys_list[2])
-- EVENT_PHASE or EVENT_PHASE_START + PHASE_
elseif keys_list[1]:match("PH") then
for _, key in ipairs(keys_list) do
res = res + fusf.FindTables(key, fucs.cod, fucs.pha)
end
end end
if res > 0 then return res end
end end
res_lst.len = res_ind -- find table_key
return res_lst local const_table = fusf.Findfucs(table_key)
end local des
function fusf.Creat_CF(_func, _val, ...) for i = #keys_list, 1, -1 do
if not _func then return function(c) return true end end local key = keys_list[i]
-- trans _val res = res + fusf.FindTables(key, const_table)
if type(_val) ~= "table" then _val = { _val } end des = fucs.des[key] or des
local temp_val, v_ind = { }, 0 end
for _, f_val in ipairs(_val) do return res, des
if type(f_val) == "string" then end
for _, val in fusf.ForTable(fusf.Val_Cuts(f_val, ...)) do
v_ind = v_ind + 1 --- 查找并解析函数 func,支持反向逻辑
temp_val[v_ind] = val -- @param func string|function 函数名称或函数对象,若为字串则从 c/lib/fuef/aux 中查找,支持 "~" 前缀取反
end -- @param args table? 若存在则立即调用目标函数,并传入该参数表
-- @param ... table 可选优先查找表,最后搜索 fuef, aux
-- @return function|any 若有 args,返回函数执行结果
-- @raise 若 func 为字串且无法解析为有效函数,将抛出错误
function fusf.ResolveFunction(func, args, ...)
fusf.CheckArgType("ResolveFunction", 2, args, "nil/table")
local typ = fusf.CheckArgType("ResolveFunction", 1, func, "string/function")
if typ == "function" then return func end
local fix = function(f) return f end
local f = func
if func:match("~") then
f = func:sub(2)
fix = function(f) return function(...) return not f(...) end end
end
local tabs = {...}
table.insert(tabs, fuef)
table.insert(tabs, aux)
f = fusf.FindTables(f, table.unpack(tabs))
if func == "tgoval" then
Debug.Message(type(f))
end
fusf.CheckType(f, "function")
if args then
if args.n then
f = f(table.unpack(args, 1, args.n))
else else
v_ind = v_ind + 1 f = f(table.unpack(args))
temp_val[v_ind] = f_val
end end
end end
_val, temp_val = temp_val return fix(f)
-- _func is function end
if type(_func) == "function" then
return function(c) --- 将可能包含多个函数呼叫与括号参数的表达式字串解析为表结构(支援嵌套与占位符替换)
return _func(c, table.unpack(_val, 1, v_ind)) -- 如 "f1,,f2(%1,%2),(%3)" 会被解析为 { "f1", nil, { "f2", {replace[1], replace[2]} }, { replace[3] } }
end -- @param expr_str string 欲解析的整体表达式,如 "f1,,f2(%1,%2),(%3)"
end -- @param replace_table table 替换占位符用的参数表
-- _func is string -- @return table 解析结果为表结构,内含函数名与参数的混合列表,巢状呼叫以子表表示,附加栏位 n 表示数量
_func = fusf.PostFix_Trans(_func, ...) -- @raise 若有未关闭括号或非法占位符,将抛出错误
local fucf, Card, aux = fucf, Card, aux function fusf.ParseCallGroupString(expr_str, replace_table)
if #_func == 1 then -- _func just one local result, length, pending = {}, 0, ""
_func = fucf[_func[1] ] or Card[_func[1] ] or aux[_func[1] ] for _, unit in expr_str:ForCut() do
return function(c) length = length + 1
return _func(c, table.unpack(_val, 1, v_ind)) local is_st = unit:match("%(")
end local is_ed = unit:match("%)")
end -- is f(v1)
-- _func is multi if is_st and is_ed then
return function(c) local fname, args = fusf.ParseCallExprString(unit, replace_table)
local stack, v_ind, temp_val = { }, 1 if fname == "" then
for _, func in ipairs(_func) do result[length] = args
if func == "~" then
stack[#stack] = not stack[#stack]
elseif type(func) == "string" and #func == 1 then
local valR, valL = table.remove(stack), table.remove(stack)
local Cal = {
["+"] = valL and valR,
["-"] = valL and not valR,
["/"] = valL or valR
}
stack[#stack + 1] = Cal[func]
else else
if type(func) == "string" then result[length] = {fname, args}
func = fucf[func] or Card[func] or aux[func] end
end elseif is_st then
temp_val, v_ind = _val[v_ind], v_ind + 1 pending, length = unit, length - 1
if type(temp_val) ~= "table" then temp_val = {temp_val, len = 1} end elseif is_ed then
stack[#stack + 1] = func(c, table.unpack(temp_val, 1, temp_val.len)) local fname, args = fusf.ParseCallExprString(pending .. "," .. unit, replace_table)
if fname == "" then
result[length] = args
else
result[length] = {fname, args}
end
pending = ""
elseif #pending > 0 then
pending, length = pending .. "," .. unit, length - 1
elseif unit:match("%%") then
local ind = tonumber(unit:sub(2))
if not ind or ind < 1 then
error("invalid replace_table index : " .. expr_str)
end end
result[length] = replace_table[ind]
elseif unit ~= "" then
result[length] = unit
end end
return table.remove(stack)
end end
if pending ~= "" then
error("unclosed in ParseCallGroupString : " .. expr_str)
end
result.n = length
return result
end
--- 解析可能带有函数名称与括号参数的呼叫字串,并进行占位替换
-- 如 "Func(%1,,3)" 会被解析为 "Func",与参数表 { replace[1], nil, "3" }
-- @param expr_str string 表达式形式的呼叫字串,如 "Func(%1,,3)"
-- @param replace_table table 替换占位符用的参数表
-- @return string, table 函数名称以及对应参数表,附加栏位 len 表示参数数量
-- @raise 当占位符无效或格式错误时会报错
function fusf.ParseCallExprString(expr_str, replace_table)
local fname, start_pos = "", expr_str:find("%(")
if start_pos ~= 1 then
fname = expr_str:sub(1, start_pos - 1)
end
if start_pos + 1 == #expr_str then -- "f()" -> {"f"}
return fname, {len = 0}
end
local args_str = expr_str:sub(start_pos + 1, -2)
return fname, fusf.ParseArgsString(args_str, replace_table)
end end
function fusf.Creat_GF(_func, _val, ...)
local ex_val = {...} --- 解析以逗号分隔的参数字串,并替换其中的占位符(如 %1, %2 等)
return function(g, n) -- 如 "%1,,3" 会被解析为 { replace[1], nil, "3" }
g = g:Filter(fusf.Creat_CF(_func, _val, table.unpack(ex_val)), nil) -- @param args_str string 欲解析的字串,如 "%1,,3"
if not n then return g end -- @param replace_table table 替换占位符用的参数表
return n > 0 and #g >= n or #g <= -n -- @return table 解析后的参数 table ,附加栏位 n 表示参数数量
-- @raise 若占位符无效(非正整数)则触发错误
function fusf.ParseArgsString(args_str, replace_table)
local result, length = {}, 0
for _, arg in args_str:ForCut() do
length = length + 1
if arg:match("%%") then
local ind = tonumber(arg:sub(2))
if not ind or ind < 1 then
error("invalid replace_table index : " .. args_str)
end
result[length] = replace_table[ind]
elseif arg ~= "" then
result[length] = arg
end
end end
result.n = length
return result
end end
--- 遍历一个表(table),支援带 .n 栏位的自订长度
-- @param t table 欲遍历的表
-- @param n number? 若无 t.n,则使用此值作为最大索引(可选)
-- @return function 叠代器函数,返回 (index, value)
function fusf.ForTable(t, n) function fusf.ForTable(t, n)
local i, max = 0, t.len or n local i, max = 0, t.n or n
return function() return function()
if i >= max then return nil end if i >= max then return nil end
i = i + 1 i = i + 1
return i, t[i] return i, t[i]
end end
end end
function fusf.GetDES(_code, _id, m) -- (0), ("n"), (m), ("+1")
if _id then --- 解析文字讯息代码,支持多种输入格式(数字/字符串/偏移量)
if type(_code) == "number" then -- @param code number|string 原始代码或偏移字符串,如 "+1"、"-2"
_code = fusf.M_chk(_code) -- @param id number? 可选的消息编号(如 Stringid(code, id) 中的 id)
else -- ("-1", 0) -- @param m number? 可选基准卡号,用于计算相对偏移
_code = m + tonumber(_code) -- @return number 返回 aux.Stringid(code, id) 的值
function fusf.ResolveDescription(code, id, m) -- (0), ("n"), (m), ("+1")
local cod_typ = fusf.CheckArgType("ResolveDescription", 1, code, "number/string")
local id_typ = fusf.CheckArgType("ResolveDescription", 2, id, "nil/number")
fusf.CheckArgType("ResolveDescription", 3, m, "number")
if id_typ == "number" then
if id < 17 then
code = fusf.NormalizeID(code, m)
end end
elseif type(_code) == "number" then elseif cod_typ == "number" then
if _code < 17 then -- in cdb and code is owner card code if code < 17 then -- in cdb and code is owner card code
_code, _id = m, _code code, id = m, code
elseif code > 1000 then
code, id = 0, code
else else
_code, _id = fusf.M_chk(_code), 0 code, id = fusf.NormalizeID(code, m), 0
end end
elseif type(_code) == "string" then elseif cod_typ == "string" then
if tonumber(_code) then -- code = m +- _code if tonumber(code) then -- code = m +- code
_code, _id = m + tonumber(_code), 0 code, id = fusf.NormalizeID(code, m), 0
else -- in fucs.des else -- in fucs.des
_code, _id = 0, fucs.des[_code] code, id = 0, fusf.CheckType(fucs.des[code], "number")
end end
end end
return aux.Stringid(_code, _id) -- _code * 16 + _id return aux.Stringid(code, id) -- code * 16 + id
end end
function fusf.GetRES(_flag, _count) -- _flag = a + b/b1/b2 + c | 1
if type(_flag) ~= "string" then return {_flag or 0, _count} end --- 解析重置条件字串,支援简单运算与预设数量
if not _count then -- cut count -- @param flag string|number 条件描述(如 "a + b - c , 1")
_flag = _flag:Cut("fusf.GetRES", "|") -- @param count number? 可选的重置次数,若省略则从字串中解析
_flag, _count = _flag[1], tonumber(_flag[2] or 1) -- @return table {flag: number, count: number} 重置条件与次数 table
function fusf.ResolveReset(flag, count)
local typ = fusf.CheckArgType("ResolveReset", 1, flag, "number/string")
fusf.CheckArgType("ResolveReset", 2, count, "nil/number")
if typ == "number" then return flag, count end
if not count then -- cut count
local parts = flag:Cut()
flag, count = parts[1], tonumber(parts[2] or 1)
end end
local stack = { } local stack = {}
for _, unit in ipairs(fusf.PostFix_Trans(_flag)) do local res, pha = fucs.res, fucs.pha
if unit:match("[+-/]") then for _, unit in ipairs(fusf.InfixToPostfix(flag)) do
if unit:match("[+-]") then
local valR, valL = table.remove(stack), table.remove(stack) local valR, valL = table.remove(stack), table.remove(stack)
table.insert(stack, unit == "-" and valL - valR or valL | valR) local cal = (unit == "-") and (valL - valR) or (valL | valR)
table.insert(stack, cal)
else else
table.insert(stack, fucs.res[unit] or fucs.pha[unit]) table.insert(stack, fusf.FindTables(unit, res, pha))
end end
end end
_flag = table.remove(stack) flag = table.remove(stack)
if _flag & 0xfff0000 > 0 then _flag = _flag | RESET_EVENT end if flag & 0xfff0000 > 0 then flag = flag | RESET_EVENT end
if _flag & 0x00003ff > 0 then _flag = _flag | RESET_PHASE end if flag & 0x00003ff > 0 then flag = flag | RESET_PHASE end
return {_flag, _count} return flag, count
end end
--- 建立与事件 e 绑定的函数快取区(每个效果唯一识别),供函数查找与快取使用
-- @param e Effect 效果物件,用于识别对应的快取区
-- @return table 快取表,带栏位 lib 表示可供查找函数的函式库
function fusf.MakeFuncCatch(e)
local cm = fusf.Getcm(e)
local id = tostring(e):sub(-8)
cm[id] = cm[id] or {lib = cm}
return cm[id]
end
--- 查找指定键值对应的函数,若未快取则解析后快取
-- @param catch table 快取区(来自 MakeFuncCatch)
-- @param key string 作为函数的识别名称(快取键)
-- @param func string|function 欲查找的函数或其字串表示,可带 "~" 表示反向逻辑
-- @return function 查找到的函数物件(已快取)
function fusf.FindFuncCatch(catch, key, func)
if catch[key] then return catch[key] end
catch[key] = fusf.ResolveFunction(func, nil, catch.lib)
return catch[key]
end
--------------------------------------"Other Support function" --------------------------------------"Other Support function"
function fusf.RegFlag(val, cod, res, pro, lab, des) -- val : Card|Effect|player(number)
cod, res, pro = fusf.M_chk(cod), fusf.GetRES(res), fusf.Get_Constant("pro", pro) or 0 --- 为卡片、效果、玩家或卡片群组注册一个标识用效果(FlagEffect)
if des then des, pro = fusf.GetDES(des, nil, cod), (pro or 0)|EFFECT_FLAG_CLIENT_HINT end -- @param val Card|Group|Effect|number 目标对象,可为单张卡、卡组、效果对象,或玩家编号
local typ = aux.GetValueType(val) -- @param cod number|string 标识效果的代码,可为数值或偏移表达式(将被规范化)
if typ == "Card" then -- @param res string|number 标识的重置条件,可用表达式,如 "event1 + pha1 , 1"
val:RegisterFlagEffect(cod, res[1], pro, res[2] or 1, lab or 0, des) -- @param pro string|number? 效果的属性(效果标志),默认值为 0,可为常量名或数值
elseif typ == "Group" then -- @param des string|number? 效果提示描述(字符串ID),传入描述名或偏移,如 "+1"
for c in aux.Next(val) do -- @param lab number? 标签参数,可用于额外传值(如标记内容),默认 0
c:RegisterFlagEffect(cod, res[1], pro, res[2] or 1, lab or 0, des) function fusf.RegFlag(val, cod, res, pro, des, lab)
end local typ = fusf.CheckArgType("RegFlag", 1, val, "Card/Group/Effect/player")
elseif typ == "Effect" then fusf.CheckArgType("RegFlag", 6, lab, "nil/number")
val:GetHandler():RegisterFlagEffect(cod, res[1], pro, res[2] or 1, lab or 0, des)
else cod = fusf.NormalizeID(cod) -- 规范化代码(如字符串转数值)
res = {fusf.ResolveReset(res)} -- 转换表达式或数值为 {flag, count}
pro = fusf.ParseConstantKey("pro", pro or 0) -- 效果属性,默认为 0
if des then
des = fusf.ResolveDescription(des, nil, cod)
pro = pro|EFFECT_FLAG_CLIENT_HINT
end
if typ == "player" then
Duel.RegisterFlagEffect(val, cod, res[1], pro, res[2] or 1, lab or 0) Duel.RegisterFlagEffect(val, cod, res[1], pro, res[2] or 1, lab or 0)
return
end
for c in aux.Next(fusf.ToGroup(val)) do
c:RegisterFlagEffect(cod, res[1], pro, res[2] or 1, lab or 0, des)
end
end
--- 检查 val 的种类为 cod 的标识效果的数量, 有 n 则传回比较结果
-- @param val Card|Effect|number 目标对象,可为卡片、效果对象或玩家编号(0或1)
-- @param cod number|string FlagEffect 的代码,会被标准化(如偏移表达式 "+1")
-- @param n number? 可选,若指定则判断是否达到 n,负数则判断不到 -n
-- @return number|boolean 返回数量,或是否满足条件
function fusf.GetFlag(val, cod, n)
local typ = fusf.CheckArgType("GetFlag", 1, val, "Card/Effect/player")
fusf.CheckArgType("GetFlag", 3, n, "nil/number")
cod = fusf.NormalizeID(cod)
local count
if typ == "player" then
count = Duel.GetFlagEffect(val, cod)
else
count = fusf.ToCard(val):GetFlagEffect(cod)
end
if not n then return count end
return n > 0 and count >= n or count <= -n
end
--- 检查 val 的种类为 cod 的标识效果的 Label, 有 lab 則傳回是否相等
-- @param val Card|Effect|player 要查询的对象,可以是卡片、效果或玩家
-- @param cod number|string FlagEffect 的代码,会被标准化(如偏移表达式 "+1")
-- @param lab any? 可选,用于比较 label 是否等于特定值
-- @return any|boolean 若提供 lab,则回传是否相等;否则回传该 Label(或 nil)
function fusf.GetFlagLabel(val, cod, lab)
local typ = fusf.CheckArgType("GetFlagLabel", 1, val, "Card/Effect/player")
fusf.CheckArgType("GetFlagLabel", 3, lab, "nil/number")
cod = fusf.NormalizeID(cod)
local label
if typ == "player" then
label = {Duel.GetFlagEffectLabel(val, cod)}
else
label = {fusf.ToCard(val):GetFlagEffectLabel(cod)}
end
if lab then return label[1] == lab end
return table.unpack(label)
end
--- 取得成为对象的卡(若存在),并检测是否与 e 有联系
-- @param e Effect 当前效果物件
-- @param pos number|nil 过滤位置(可选,用于指定表示形式,如 POS_FACEUP)
-- @param is_imm boolean|nil 是否过滤能否被效果影响的卡片(可选)
-- @return Card|false 返回对象,若无或不满足条件则返回 false
function fusf.GetTarget(e, pos, is_imm)
local tg = fusf.GetTargets(e, pos, is_imm)
if tg then tg = tg:GetFirst() end
return tg
end
--- 取得成为对象的卡片组(若存在),并检测是否与 e 有联系
-- @param e Effect 当前效果物件
-- @param pos number|nil 过滤位置(可选,用于指定表示形式,如 POS_FACEUP)
-- @param is_imm boolean|nil 是否过滤能否被效果影响的卡片(可选)
-- @return Group|false 返回满足条件的对象卡片组,若无或都不满足条件则返回 false
function fusf.GetTargets(e, pos, is_imm)
local tg = Duel.GetChainInfo(0,CHAININFO_TARGET_CARDS):Filter(Card.IsRelateToEffect,nil,e)
if pos then tg = fugf.Filter(tg, "IsPos", pos) end
if is_imm then tg = fugf.Filter(tg, "~IsImm", e) end
if #tg == 0 then return false end
return tg
end
--- 让玩家 tp 把卡片或卡片组 eg 作为装备卡装备给卡片 c,返回值表示是否成功
-- @param e Effect 装备效果
-- @param tp number 装备的玩家,必须为 0 或 1
-- @param eg Group|Card 要装备的卡片,支持单张或群组
-- @param c nil|Card 装备目标卡片,必须为面朝上的卡
-- @return boolean 装备成功返回 true,失败返回 false
function fusf.Equip(e, tp, eg, c)
fusf.CheckArgType("Equip", 1, e, "Effect")
fusf.CheckArgType("Equip", 2, tp, "player")
local typ = fusf.CheckArgType("Equip", 3, eg, "Group/Card")
eg = fusf.ToGroup(eg)
if Duel.GetLocationCount(tp, LOCATION_SZONE) < #eg then return false end
c = fusf.CheckArgType("Equip", 4, c or e:GetHandler(), "Card")
if c:IsFacedown() then return false end
local limit = function(e, c) return c == e:GetLabelObject() end
if typ == "Card" then
local ec = eg:GetFirst()
if not Duel.Equip(tp, ec, c) then return false end
if ec:IsType(TYPE_MONSTER) then
fuef.S(e, EFFECT_EQUIP_LIMIT, ec):PRO("CD"):VAL(limit):OBJ(c):RES("STD")
end
return true
end
for ec in aux.Next(eg) do
Duel.Equip(tp, ec, c, true, true)
if ec:IsType(TYPE_MONSTER) then
fuef.S(e, EFFECT_EQUIP_LIMIT, ec):PRO("CD"):VAL(limit):OBJ(c):RES("STD")
end
end
Duel.EquipComplete()
return true
end
--- 检查计数器 id 的数量, 有 n 则传回比较结果
-- @param id number|string 计数器的 ID,会规范化
-- @param p number 玩家编号(0 或 1)
-- @param typ number|string 操作类型
-- @param n number? 可选,若指定则判断是否达到 n,负数则判断不到 -n
-- @return number|boolean 返回数量,或是否满足条件
function fusf.GetCounter(id, p, typ, n)
id = fusf.NormalizeID(id)
typ = fusf.ParseConstantKey("act", typ)
local ct = Duel.GetCustomActivityCount(id, p, typ)
if not n then return ct end
return n > 0 and ct >= n or ct <= -n
end
--- 判断目前是否处于指定的 Phase(支援逻辑运算)
-- 支援表达式:单一阶段(如 "BP")、多个阶段的 OR(如 "BP/M2")、NOT(如 "~EP")
-- @param pha number|string 阶段代码或逻辑表达式
-- @return boolean 是否处于该阶段
function fusf.IsPhase(pha)
local phase = Duel.GetCurrentPhase()
local typ = fusf.CheckArgType("IsPhase", 1, pha, "number/string")
if typ == "number" then return phase == pha end
local stack = {}
for _, val in ipairs(fusf.InfixToPostfix(pha)) do
if val:match("[%-%~]") then
stack[#stack] = not stack[#stack]
elseif val == "/" then
local valR, valL = table.remove(stack), table.remove(stack)
table.insert(stack, valL or valR)
elseif val == "BP" then
table.insert(stack, Duel.IsBattlePhase())
else
local _pha = fusf.Findfucs("pha", val)
table.insert(stack, phase == _pha)
end
end
return stack[#stack]
end
--------------------------------------------------------------------------"initial function"
--- 为卡片脚本提供统一初始化接口
-- @param lib table (可选)卡片使用的函式库
-- @param glo_key string (可选)表示是否有全域注册条件
-- @return cm 卡片表(即全局脚本的局部名 cm)
-- @return m 卡片 ID(编号)
function fusf.Initial(lib, glo_key)
local cm, m = GetID()
if cm.initial_effect then return cm, m end
local log = fudf.StartLog(0, "fusf.Initial", lib, glo_key)
log:Info(m)
fusf.CheckArgType("Initial", 1, lib, "nil/table")
fusf.CheckArgType("Initial", 2, glo_key, "nil/string")
cm.lib = lib or {}
cm.e_list = {}
cm.init_list = {}
local function apply(log, c, name, val)
log:Info("try InitSetOwner "..name)
local i = 1
local key = name .. i
while cm[key] do
local E = fusf.CheckType(cm[key], "fuef")
c.e_list[key] = E:InitSetOwner(key, c, val)
i = i + 1
key = name .. i
end
log:Info(("set %d %s"):format(i - 1, name))
end
cm.initial_effect = function(c)
local log = fudf.StartLog(0, "cm.initial_effect", c)
log:Info(m)
apply(log, c, "pe") -- pe1, pe2, ...
apply(log, c, "e") -- e1, e2, ...
log:Info("try ipairs cm.init_list")
for _, f in ipairs(cm.init_list) do
f(c)
end
log:Info("set cm.init_list down")
if not glo_key or cm[glo_key] then return end
cm[glo_key] = {0, 0}
apply(log, c, "ge", 1) -- ge1, ge2, ...
end
log:Info("set cm.initial_effect down")
return cm, m
end
--- 在卡片的 initial_effect 中插入额外初始化函数
-- @param func function 需要插入的初始化函数
-- @raise 如果 cm.initial_effect 不存在或不是函数,则报错 "INITIAL"
function fusf.InsertInitial(func, log)
log = fudf.StartLog(log or 0, "fusf.InsertInitial", func)
fusf.CheckArgType("InsertInitial", 1, func, "function")
local cm, m = GetID()
if not cm.init_list then error("You must call fusf.Initial first", 2) end
table.insert(cm.init_list, func)
end
--- 为卡片添加卡名记述 ...
-- @param ... number|string 可为卡号、字符串(如 "100+200")、或多个卡号
-- 字符串会用 "+" 切割后批量处理,转换为标准卡号格式
function fusf.AddCode(...)
local log = fudf.StartLog(0, "fusf.AddCode", ...)
fusf.CheckEmptyArgs("AddCode", ...)
local codes = { }
for i, val in ipairs{...} do
local typ = fusf.CheckArgType("AddCode", i, val, "string/number")
if typ == "string" then
for _, code in ipairs(fusf.GetCodeTable(val)) do
log:Info("add "..code)
table.insert(codes, code)
end
else
local code = fusf.NormalizeID(val)
log:Info("add "..code)
table.insert(codes, code)
end
end end
local function AddFunc(c)
aux.AddCodeList(c, table.unpack(codes))
end
fusf.InsertInitial(AddFunc, log)
end end
function fusf.GetFlag(val, cod) -- val : Card|Effect|player(number)
cod = fusf.M_chk(cod) --- 为卡片添加苏生限制
local typ = aux.GetValueType(val) function fusf.ReviveLimit()
if typ == "Card" then local log = fudf.StartLog(0, "fusf.ReviveLimit")
return val:GetFlagEffect(cod) local function AddFunc(c)
elseif typ == "Effect" then c:EnableReviveLimit()
return val:GetHandler():GetFlagEffect(cod)
end end
return Duel.GetFlagEffect(val, cod) fusf.InsertInitial(AddFunc, log)
end end
function fusf.Equip(e,tp,ec,c)
if not (ec and c and Duel.Equip(tp, ec, c)) then return false end --- 添加自定义计数器
local eq = function(e, c) return c == e:GetLabelObject() end -- @param id number|string 计数器的 ID,会规范化
return fuef.S(e, EFFECT_EQUIP_LIMIT, ec):PRO("CD"):VAL(eq):OBJ(c):RES("STD") -- @param typ number|string 操作类型
-- @param func function|string 判断计数的过滤函数
function fusf.AddCounter(id, typ, func)
local log = fudf.StartLog(0, "fusf.AddCounter", id, typ, func)
local id = fusf.NormalizeID(id)
log:Info("NormalizeID id : "..id)
local typ = fusf.ParseConstantKey("act", typ)
log:Info("got act typ : "..fusf.CutHex(typ))
if fusf.CheckArgType("AddCounter", 3, func, "function/string") == "string" then
func = "~"..func
else
func = function(...) return not func(...) end
end
local function AddFunc(c)
func = fusf.ResolveFunction(func, nil, fusf.Getcm(c), c.lib)
Duel.AddCustomActivityCounter(id, typ, func)
end
fusf.InsertInitial(AddFunc, log)
end end
\ No newline at end of file
...@@ -124,9 +124,9 @@ fucs.cod = { ...@@ -124,9 +124,9 @@ fucs.cod = {
RE = EVENT_REMOVE , RE = EVENT_REMOVE ,
MO = EVENT_MOVE , MO = EVENT_MOVE ,
--召唤 --召唤
PS = EVENT_SUMMON , --召唤之际(怪兽还没上场、神宣等时点) PS = EVENT_SUMMON , --召唤之际(怪兽还没上场、神宣等时点)
PSP = EVENT_SPSUMMON , --特殊召唤之际 PSP = EVENT_SPSUMMON , --特殊召唤之际
PFS = EVENT_FLIP_SUMMON , --翻转召唤之际 PFS = EVENT_FLIP_SUMMON , --翻转召唤之际
S = EVENT_SUMMON_SUCCESS , --通常召唤成功时 S = EVENT_SUMMON_SUCCESS , --通常召唤成功时
SP = EVENT_SPSUMMON_SUCCESS , --特殊召唤成功时 SP = EVENT_SPSUMMON_SUCCESS , --特殊召唤成功时
FS = EVENT_FLIP_SUMMON_SUCCESS , --翻转召唤成功时 FS = EVENT_FLIP_SUMMON_SUCCESS , --翻转召唤成功时
...@@ -150,30 +150,30 @@ fucs.cod = { ...@@ -150,30 +150,30 @@ fucs.cod = {
NEGS = EVENT_SUMMON_NEGATED , --召唤被无效时 NEGS = EVENT_SUMMON_NEGATED , --召唤被无效时
NEGFS = EVENT_FLIP_SUMMON_NEGATED , --反转召唤被无效时 NEGFS = EVENT_FLIP_SUMMON_NEGATED , --反转召唤被无效时
NEGSP = EVENT_SPSUMMON_NEGATED , --特殊召唤被无效时 NEGSP = EVENT_SPSUMMON_NEGATED , --特殊召唤被无效时
NEGATK = EVENT_ATTACK_DISABLED , --攻击无效时(翻倍机会)
--连锁 --连锁
CH = EVENT_CHAINING , --效果发动时 CH = EVENT_CHAINING , --效果发动时
CHED= EVENT_CHAIN_SOLVED , --连锁处理结束时 CHED= EVENT_CHAIN_SOLVED , --连锁处理结束时
----组合时点 --攻击
PHS = EVENT_PHASE_START , ATK = EVENT_ATTACK_ANNOUNCE , --攻击宣言时
BATK= EVENT_BE_BATTLE_TARGET , --被选为攻击对象时
--需组合 阶段时点
PH = EVENT_PHASE , --阶段结束时
PHS = EVENT_PHASE_START , --阶段开始时
--[[ --[[
EVENT_CHAIN_SOLVING =1020 --连锁处理开始时(EVENT_CHAIN_ACTIVATING之後) EVENT_CHAIN_SOLVING =1020 --连锁处理开始时(EVENT_CHAIN_ACTIVATING之後)
EVENT_CHAIN_ACTIVATING =1021 --连锁处理准备中 EVENT_CHAIN_ACTIVATING =1021 --连锁处理准备中
EVENT_CHAIN_ACTIVATED =1023 --N/A EVENT_CHAIN_ACTIVATED =1023 --N/A
EVENT_CHAIN_NEGATED =1024 --连锁发动无效时(EVENT_CHAIN_ACTIVATING之後)
EVENT_CHAIN_DISABLED =1025 --连锁效果无效时
EVENT_CHAIN_END =1026 --连锁串结束时 EVENT_CHAIN_END =1026 --连锁串结束时
EVENT_BECOME_TARGET =1028 --成为效果对象时 EVENT_BECOME_TARGET =1028 --成为效果对象时
EVENT_BREAK_EFFECT =1050 --Duel.BreakEffect()被调用时 EVENT_BREAK_EFFECT =1050 --Duel.BreakEffect()被调用时
EVENT_MSET =1106 --放置怪兽时 EVENT_MSET =1106 --放置怪兽时
EVENT_SSET =1107 --放置魔陷时 EVENT_SSET =1107 --放置魔陷时
EVENT_DRAW =1110 --抽卡时
EVENT_DAMAGE =1111 --造成战斗/效果伤害时 EVENT_DAMAGE =1111 --造成战斗/效果伤害时
EVENT_RECOVER =1112 --回复生命值时 EVENT_RECOVER =1112 --回复生命值时
EVENT_PREDRAW =1113 --抽卡阶段通常抽卡前 EVENT_PREDRAW =1113 --抽卡阶段通常抽卡前
EVENT_CONTROL_CHANGED =1120 --控制权变更 EVENT_CONTROL_CHANGED =1120 --控制权变更
EVENT_EQUIP =1121 --装备卡装备时 EVENT_EQUIP =1121 --装备卡装备时
EVENT_ATTACK_ANNOUNCE =1130 --攻击宣言时
EVENT_BE_BATTLE_TARGET =1131 --被选为攻击对象时
EVENT_BATTLE_START =1132 --伤害步骤开始时(反转前) EVENT_BATTLE_START =1132 --伤害步骤开始时(反转前)
EVENT_BATTLE_CONFIRM =1133 --伤害计算前(反转後) EVENT_BATTLE_CONFIRM =1133 --伤害计算前(反转後)
EVENT_PRE_DAMAGE_CALCULATE =1134 --伤害计算时(羽斬) EVENT_PRE_DAMAGE_CALCULATE =1134 --伤害计算时(羽斬)
...@@ -184,7 +184,6 @@ EVENT_BATTLED =1138 --伤害计算后(异女、同反转效果时点) ...@@ -184,7 +184,6 @@ EVENT_BATTLED =1138 --伤害计算后(异女、同反转效果时点)
EVENT_BATTLE_DESTROYING =1139 --以战斗破坏怪兽送去墓地时(BF-苍炎之修罗) EVENT_BATTLE_DESTROYING =1139 --以战斗破坏怪兽送去墓地时(BF-苍炎之修罗)
EVENT_BATTLE_DESTROYED =1140 --被战斗破坏送去墓地时(杀人番茄等) EVENT_BATTLE_DESTROYED =1140 --被战斗破坏送去墓地时(杀人番茄等)
EVENT_DAMAGE_STEP_END =1141 --伤害步骤结束时 EVENT_DAMAGE_STEP_END =1141 --伤害步骤结束时
EVENT_ATTACK_DISABLED =1142 --攻击无效时(翻倍机会)
EVENT_BATTLE_DAMAGE =1143 --造成战斗伤害时 EVENT_BATTLE_DAMAGE =1143 --造成战斗伤害时
EVENT_TOSS_DICE =1150 --掷骰子的结果产生后 EVENT_TOSS_DICE =1150 --掷骰子的结果产生后
EVENT_TOSS_COIN =1151 --抛硬币的结果产生后 EVENT_TOSS_COIN =1151 --抛硬币的结果产生后
...@@ -194,8 +193,6 @@ EVENT_LEVEL_UP =1200 --等级上升时 ...@@ -194,8 +193,6 @@ EVENT_LEVEL_UP =1200 --等级上升时
EVENT_PAY_LPCOST =1201 --支付生命值时 EVENT_PAY_LPCOST =1201 --支付生命值时
EVENT_RETURN_TO_GRAVE =1203 --回到墓地时 EVENT_RETURN_TO_GRAVE =1203 --回到墓地时
EVENT_TURN_END =1210 --回合结束时 EVENT_TURN_END =1210 --回合结束时
EVENT_PHASE =0x1000 --阶段结束时
EVENT_PHASE_START =0x2000 --阶段开始时
EVENT_ADD_COUNTER =0x10000 --增加指示物时 EVENT_ADD_COUNTER =0x10000 --增加指示物时
EVENT_REMOVE_COUNTER =0x20000 --去除指示物时(A指示物),Card.RemoveCounter()必須手動觸發此事件 EVENT_REMOVE_COUNTER =0x20000 --去除指示物时(A指示物),Card.RemoveCounter()必須手動觸發此事件
--]] --]]
...@@ -219,7 +216,7 @@ fucs.pro = { ...@@ -219,7 +216,7 @@ fucs.pro = {
CAL = EFFECT_FLAG_DAMAGE_CAL , --可以在伤害计算时发动 CAL = EFFECT_FLAG_DAMAGE_CAL , --可以在伤害计算时发动
OP = EFFECT_FLAG_EVENT_PLAYER , --发动/处理效果的玩家为触发事件的玩家而不是卡片的持有者,如仪式魔人,万魔殿 OP = EFFECT_FLAG_EVENT_PLAYER , --发动/处理效果的玩家为触发事件的玩家而不是卡片的持有者,如仪式魔人,万魔殿
NR = EFFECT_FLAG_NO_TURN_RESET , --发条等“这张卡在场上只能发动一次”的效果 NR = EFFECT_FLAG_NO_TURN_RESET , --发条等“这张卡在场上只能发动一次”的效果
OE = 0x40400 , --EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE(out effect) OE = 0x40400 , --EFFECT_FLAG_CANNOT_DISABLE+EFFECT_FLAG_UNCOPYABLE(out effect)
} }
--Location Variable --Location Variable
fucs.ran = { fucs.ran = {
...@@ -237,13 +234,19 @@ fucs.ran = { ...@@ -237,13 +234,19 @@ fucs.ran = {
["P"] = LOCATION_PZONE , ["P"] = LOCATION_PZONE ,
["A"] = 0xff ["A"] = 0xff
} }
--Countlimit Variable
fucs.ctl = {
O = EFFECT_COUNT_CODE_OATH,
D = EFFECT_COUNT_CODE_DUEL,
C = EFFECT_COUNT_CODE_CHAIN,
}
--Phase Variable --Phase Variable
fucs.pha = { fucs.pha = {
DP = PHASE_DRAW , --抽卡阶段 DP = PHASE_DRAW , --抽卡阶段
SP = PHASE_STANDBY , --准备阶段 SP = PHASE_STANDBY , --准备阶段
M1 = PHASE_MAIN1 , --主要阶段1 M1 = PHASE_MAIN1 , --主要阶段1
BPS = PHASE_BATTLE_START, --战斗阶段开始 BPS = PHASE_BATTLE_START, --战斗阶段开始
BP = PHASE_BATTLE_STEP , --战斗步驟 BS = PHASE_BATTLE_STEP , --战斗步驟
DS = PHASE_DAMAGE , --伤害步驟 DS = PHASE_DAMAGE , --伤害步驟
DC = PHASE_DAMAGE_CAL , --伤害计算时 DC = PHASE_DAMAGE_CAL , --伤害计算时
BPE = PHASE_BATTLE , --战斗阶段結束 BPE = PHASE_BATTLE , --战斗阶段結束
...@@ -396,5 +399,21 @@ fucs.val = { ...@@ -396,5 +399,21 @@ fucs.val = {
LI = SUMMON_TYPE_LINK , LI = SUMMON_TYPE_LINK ,
--Summon Value --特定的召唤方式 --Summon Value --特定的召唤方式
SELF = SUMMON_VALUE_SELF , SELF = SUMMON_VALUE_SELF ,
SYM = SUMMON_VALUE_SYNCHRO_MATERIAL SYM = SUMMON_VALUE_SYNCHRO_MATERIAL ,
} --location Value --离场重定向
\ No newline at end of file H = LOCATION_HAND ,
D = LOCATION_DECK ,
G = LOCATION_GRAVE ,
R = LOCATION_REMOVED,
E = LOCATION_EXTRA ,
}
--Value Variable
fucs.act = {
S = ACTIVITY_SUMMON , --召唤(不包括通常召唤的set)
NS = ACTIVITY_NORMALSUMMON , --通常召唤(包括通常召唤的set)
SP = ACTIVITY_SPSUMMON , --特殊召唤
FS = ACTIVITY_FLIPSUMMON , --反转召唤
ATK = ACTIVITY_ATTACK , --攻击
CH = ACTIVITY_CHAIN , --发动效果
}
...@@ -160,6 +160,10 @@ function s.fspop(e,tp,eg,ep,ev,re,r,rp) ...@@ -160,6 +160,10 @@ function s.fspop(e,tp,eg,ep,ev,re,r,rp)
if sg1:IsContains(tc) and (sg2==nil or not sg2:IsContains(tc) or ce and not Duel.SelectYesNo(tp,ce:GetDescription())) then if sg1:IsContains(tc) and (sg2==nil or not sg2:IsContains(tc) or ce and not Duel.SelectYesNo(tp,ce:GetDescription())) then
local mat1=Duel.SelectFusionMaterial(tp,tc,mg1,nil,chkf) local mat1=Duel.SelectFusionMaterial(tp,tc,mg1,nil,chkf)
if #mat1==0 then goto cancel end if #mat1==0 then goto cancel end
if mat1:IsExists(Card.IsFacedown,1,nil) then
Duel.ConfirmCards(1-tp,mat1)
end
Duel.HintSelection(mat1)
tc:SetMaterial(mat1) tc:SetMaterial(mat1)
Duel.SendtoGrave(mat1,REASON_EFFECT+REASON_MATERIAL+REASON_FUSION) Duel.SendtoGrave(mat1,REASON_EFFECT+REASON_MATERIAL+REASON_FUSION)
Duel.BreakEffect() Duel.BreakEffect()
...@@ -167,6 +171,10 @@ function s.fspop(e,tp,eg,ep,ev,re,r,rp) ...@@ -167,6 +171,10 @@ function s.fspop(e,tp,eg,ep,ev,re,r,rp)
elseif ce~=nil then elseif ce~=nil then
local mat2=Duel.SelectFusionMaterial(tp,tc,mg2,nil,chkf) local mat2=Duel.SelectFusionMaterial(tp,tc,mg2,nil,chkf)
if #mat2==0 then goto cancel end if #mat2==0 then goto cancel end
if mat2:IsExists(Card.IsFacedown,1,nil) then
Duel.ConfirmCards(1-tp,mat2)
end
Duel.HintSelection(mat2)
local fop=ce:GetOperation() local fop=ce:GetOperation()
fop(ce,e,tp,tc,mat2) fop(ce,e,tp,tc,mat2)
end end
......
...@@ -90,11 +90,21 @@ function c66620515.activate(e,tp,eg,ep,ev,re,r,rp) ...@@ -90,11 +90,21 @@ function c66620515.activate(e,tp,eg,ep,ev,re,r,rp)
if sg1:IsContains(tc) and (sg2==nil or not sg2:IsContains(tc) or not Duel.SelectYesNo(tp,ce:GetDescription())) then if sg1:IsContains(tc) and (sg2==nil or not sg2:IsContains(tc) or not Duel.SelectYesNo(tp,ce:GetDescription())) then
local mat1=Duel.SelectFusionMaterial(tp,tc,mg1,nil,chkf) local mat1=Duel.SelectFusionMaterial(tp,tc,mg1,nil,chkf)
tc:SetMaterial(mat1) tc:SetMaterial(mat1)
if mat1:IsExists(Card.IsFacedown, 1, nil) then
local g=mat1:Filter(Card.IsFacedown, nil)
Duel.ConfirmCards(1-tp, g)
end
Duel.HintSelection(mat1)
Duel.Remove(mat1,POS_FACEUP,REASON_EFFECT+REASON_MATERIAL+REASON_FUSION) Duel.Remove(mat1,POS_FACEUP,REASON_EFFECT+REASON_MATERIAL+REASON_FUSION)
Duel.BreakEffect() Duel.BreakEffect()
Duel.SpecialSummon(tc,SUMMON_TYPE_FUSION,tp,tp,false,false,POS_FACEUP) Duel.SpecialSummon(tc,SUMMON_TYPE_FUSION,tp,tp,false,false,POS_FACEUP)
else else
local mat2=Duel.SelectFusionMaterial(tp,tc,mg3,nil,chkf) local mat2=Duel.SelectFusionMaterial(tp,tc,mg3,nil,chkf)
if mat2:IsExists(Card.IsFacedown, 1, nil) then
local g=mat2:Filter(Card.IsFacedown, nil)
Duel.ConfirmCards(1-tp, g)
end
Duel.HintSelection(mat2)
local fop=ce:GetOperation() local fop=ce:GetOperation()
fop(ce,e,tp,tc,mat2) fop(ce,e,tp,tc,mat2)
end end
......
...@@ -2,111 +2,113 @@ ...@@ -2,111 +2,113 @@
local m=89390003 local m=89390003
local cm=_G["c"..m] local cm=_G["c"..m]
function cm.initial_effect(c) function cm.initial_effect(c)
c:EnableReviveLimit() c:EnableReviveLimit()
aux.AddFusionProcFunRep(c,cm.ffilter,3,true) aux.AddFusionProcFunRep(c,cm.ffilter,3,true)
local e1=Effect.CreateEffect(c) local e1=Effect.CreateEffect(c)
e1:SetType(EFFECT_TYPE_FIELD+EFFECT_TYPE_CONTINUOUS) e1:SetType(EFFECT_TYPE_FIELD+EFFECT_TYPE_CONTINUOUS)
e1:SetCode(EVENT_SUMMON_SUCCESS) e1:SetCode(EVENT_SUMMON_SUCCESS)
e1:SetRange(LOCATION_MZONE) e1:SetRange(LOCATION_MZONE)
e1:SetCondition(cm.limcon) e1:SetCondition(cm.limcon)
e1:SetOperation(cm.limop) e1:SetOperation(cm.limop)
c:RegisterEffect(e1) c:RegisterEffect(e1)
local e2=e1:Clone() local e2=e1:Clone()
e2:SetCode(EVENT_SPSUMMON_SUCCESS) e2:SetCode(EVENT_SPSUMMON_SUCCESS)
c:RegisterEffect(e2) c:RegisterEffect(e2)
local e0=e1:Clone() local e0=e1:Clone()
e0:SetCode(EVENT_FLIP_SUMMON_SUCCESS) e0:SetCode(EVENT_FLIP_SUMMON_SUCCESS)
c:RegisterEffect(e0) c:RegisterEffect(e0)
local e5=Effect.CreateEffect(c) local e5=Effect.CreateEffect(c)
e5:SetType(EFFECT_TYPE_FIELD+EFFECT_TYPE_CONTINUOUS) e5:SetType(EFFECT_TYPE_FIELD+EFFECT_TYPE_CONTINUOUS)
e5:SetRange(LOCATION_MZONE) e5:SetRange(LOCATION_MZONE)
e5:SetCode(EVENT_CHAIN_END) e5:SetCode(EVENT_CHAIN_END)
e5:SetOperation(cm.limop2) e5:SetOperation(cm.limop2)
c:RegisterEffect(e5) c:RegisterEffect(e5)
local e6=Effect.CreateEffect(c) local e6=Effect.CreateEffect(c)
e6:SetType(EFFECT_TYPE_FIELD+EFFECT_TYPE_CONTINUOUS) e6:SetType(EFFECT_TYPE_FIELD+EFFECT_TYPE_CONTINUOUS)
e6:SetCode(EVENT_CHAINING) e6:SetCode(EVENT_CHAINING)
e6:SetRange(LOCATION_MZONE) e6:SetRange(LOCATION_MZONE)
e6:SetCondition(cm.limcon) e6:SetCondition(cm.limcon)
e6:SetOperation(cm.chainop) e6:SetOperation(cm.chainop)
c:RegisterEffect(e6) c:RegisterEffect(e6)
local e7=Effect.CreateEffect(c) local e7=Effect.CreateEffect(c)
e7:SetDescription(aux.Stringid(m,0)) e7:SetDescription(aux.Stringid(m,0))
e7:SetCategory(CATEGORY_REMOVE+CATEGORY_DRAW) e7:SetCategory(CATEGORY_REMOVE+CATEGORY_DRAW)
e7:SetType(EFFECT_TYPE_QUICK_O) e7:SetType(EFFECT_TYPE_QUICK_O)
e7:SetCode(EVENT_FREE_CHAIN) e7:SetCode(EVENT_FREE_CHAIN)
e7:SetProperty(EFFECT_FLAG_NO_TURN_RESET) e7:SetProperty(EFFECT_FLAG_NO_TURN_RESET)
e7:SetRange(LOCATION_MZONE) e7:SetRange(LOCATION_MZONE)
e7:SetCountLimit(1,EFFECT_COUNT_CODE_SINGLE) e7:SetCountLimit(1,EFFECT_COUNT_CODE_SINGLE)
e7:SetTarget(cm.destg) e7:SetTarget(cm.destg)
e7:SetOperation(cm.desop) e7:SetOperation(cm.desop)
c:RegisterEffect(e7) c:RegisterEffect(e7)
local e8=e7:Clone() local e8=e7:Clone()
e8:SetDescription(aux.Stringid(m,1)) e8:SetDescription(aux.Stringid(m,1))
e8:SetTarget(cm.destg2) e8:SetTarget(cm.destg2)
e8:SetOperation(cm.desop2) e8:SetOperation(cm.desop2)
c:RegisterEffect(e8) c:RegisterEffect(e8)
end end
function cm.ffilter(c,fc,sub,mg,sg) function cm.ffilter(c,fc,sub,mg,sg)
return c:IsRace(RACE_PSYCHO) and (not sg or not sg:IsExists(Card.IsFusionCode,1,c,c:GetFusionCode())) return c:IsRace(RACE_PSYCHO) and (not sg or not sg:IsExists(Card.IsFusionCode,1,c,c:GetFusionCode()))
end end
function cm.chainlm(e,rp,tp) function cm.chainlm(e,rp,tp)
return tp==rp return tp==rp
end end
function cm.limcon(e,tp,eg,ep,ev,re,r,rp) function cm.limcon(e,tp,eg,ep,ev,re,r,rp)
local c=e:GetHandler() local c=e:GetHandler()
local g=c:GetMaterial() local g=c:GetMaterial()
return c:IsSummonType(SUMMON_TYPE_FUSION) and g:IsExists(Card.IsFusionCode,1,nil,89390000) and g:IsExists(Card.IsFusionCode,1,nil,89390001) and g:IsExists(Card.IsFusionCode,1,nil,89390002) return c:IsSummonType(SUMMON_TYPE_FUSION) and g:IsExists(Card.IsFusionCode,1,nil,89390000) and g:IsExists(Card.IsFusionCode,1,nil,89390001) and g:IsExists(Card.IsFusionCode,1,nil,89390002)
end end
function cm.limop(e,tp,eg,ep,ev,re,r,rp) function cm.limop(e,tp,eg,ep,ev,re,r,rp)
if Duel.GetCurrentChain()==0 then if Duel.GetCurrentChain()==0 then
Duel.SetChainLimitTillChainEnd(cm.chainlm) Duel.SetChainLimitTillChainEnd(cm.chainlm)
elseif Duel.GetCurrentChain()==1 then elseif Duel.GetCurrentChain()==1 then
e:GetHandler():RegisterFlagEffect(m,RESET_EVENT+RESETS_STANDARD+RESET_PHASE+PHASE_END,0,1) e:GetHandler():RegisterFlagEffect(m,RESET_EVENT+RESETS_STANDARD+RESET_PHASE+PHASE_END,0,1)
end end
end end
function cm.limop2(e,tp,eg,ep,ev,re,r,rp) function cm.limop2(e,tp,eg,ep,ev,re,r,rp)
local c=e:GetHandler() local c=e:GetHandler()
local g=c:GetMaterial() local g=c:GetMaterial()
if c:IsSummonType(SUMMON_TYPE_FUSION) and g:IsExists(Card.IsFusionCode,1,nil,89390000) and g:IsExists(Card.IsFusionCode,1,nil,89390001) and g:IsExists(Card.IsFusionCode,1,nil,89390002) and c:GetFlagEffect(m)>0 then if c:IsSummonType(SUMMON_TYPE_FUSION) and g:IsExists(Card.IsFusionCode,1,nil,89390000) and g:IsExists(Card.IsFusionCode,1,nil,89390001) and g:IsExists(Card.IsFusionCode,1,nil,89390002) and c:GetFlagEffect(m)>0 then
Duel.SetChainLimitTillChainEnd(cm.chainlm) Duel.SetChainLimitTillChainEnd(cm.chainlm)
end end
c:ResetFlagEffect(m) c:ResetFlagEffect(m)
end end
function cm.chainop(e,tp,eg,ep,ev,re,r,rp) function cm.chainop(e,tp,eg,ep,ev,re,r,rp)
Duel.SetChainLimit(cm.chainlm) Duel.SetChainLimit(cm.chainlm)
end end
function cm.destg(e,tp,eg,ep,ev,re,r,rp,chk) function cm.destg(e,tp,eg,ep,ev,re,r,rp,chk)
local g=Duel.GetFieldGroup(tp,LOCATION_HAND,0) local g=Duel.GetFieldGroup(tp,LOCATION_HAND,0)
local gc=g:GetCount() local gc=g:GetCount()
if chk==0 then return gc>0 and g:FilterCount(Card.IsAbleToRemove,nil)==gc and Duel.IsPlayerCanDraw(tp,gc) end if chk==0 then return gc>0 and g:FilterCount(Card.IsAbleToRemove,nil)==gc and Duel.IsPlayerCanDraw(tp,gc) end
Duel.SetOperationInfo(0,CATEGORY_REMOVE,g,gc,0,0) Duel.Hint(HINT_OPSELECTED,1-tp,e:GetDescription())
Duel.SetOperationInfo(0,CATEGORY_DRAW,nil,0,tp,gc) Duel.SetOperationInfo(0,CATEGORY_REMOVE,g,gc,0,0)
Duel.SetOperationInfo(0,CATEGORY_DRAW,nil,0,tp,gc)
end end
function cm.desop(e,tp,eg,ep,ev,re,r,rp) function cm.desop(e,tp,eg,ep,ev,re,r,rp)
local g=Duel.GetFieldGroup(tp,LOCATION_HAND,0) local g=Duel.GetFieldGroup(tp,LOCATION_HAND,0)
local gc=g:GetCount() local gc=g:GetCount()
if gc>0 and g:FilterCount(Card.IsAbleToRemove,nil)==gc then if gc>0 and g:FilterCount(Card.IsAbleToRemove,nil)==gc then
local oc=Duel.Remove(g,POS_FACEUP,REASON_EFFECT) local oc=Duel.Remove(g,POS_FACEUP,REASON_EFFECT)
if oc>0 then if oc>0 then
Duel.Draw(tp,oc,REASON_EFFECT) Duel.Draw(tp,oc,REASON_EFFECT)
end end
end end
end end
function cm.destg2(e,tp,eg,ep,ev,re,r,rp,chk) function cm.destg2(e,tp,eg,ep,ev,re,r,rp,chk)
local g=Duel.GetFieldGroup(tp,0,LOCATION_HAND) local g=Duel.GetFieldGroup(tp,0,LOCATION_HAND)
local gc=g:GetCount() local gc=g:GetCount()
if chk==0 then return gc>0 and g:FilterCount(Card.IsAbleToRemove,nil)==gc and Duel.IsPlayerCanDraw(1-tp) end if chk==0 then return gc>0 and g:FilterCount(Card.IsAbleToRemove,nil)==gc and Duel.IsPlayerCanDraw(1-tp) end
Duel.SetOperationInfo(0,CATEGORY_REMOVE,g,gc,0,0) Duel.Hint(HINT_OPSELECTED,1-tp,e:GetDescription())
Duel.SetOperationInfo(0,CATEGORY_DRAW,nil,0,1-tp,gc) Duel.SetOperationInfo(0,CATEGORY_REMOVE,g,gc,0,0)
Duel.SetOperationInfo(0,CATEGORY_DRAW,nil,0,1-tp,gc)
end end
function cm.desop2(e,tp,eg,ep,ev,re,r,rp) function cm.desop2(e,tp,eg,ep,ev,re,r,rp)
local g=Duel.GetFieldGroup(tp,0,LOCATION_HAND) local g=Duel.GetFieldGroup(tp,0,LOCATION_HAND)
local gc=g:GetCount() local gc=g:GetCount()
if gc>0 and g:FilterCount(Card.IsAbleToRemove,nil)==gc then if gc>0 and g:FilterCount(Card.IsAbleToRemove,nil)==gc then
local oc=Duel.Remove(g,POS_FACEUP,REASON_EFFECT) local oc=Duel.Remove(g,POS_FACEUP,REASON_EFFECT)
if oc>0 then if oc>0 then
Duel.Draw(1-tp,oc,REASON_EFFECT) Duel.Draw(1-tp,oc,REASON_EFFECT)
end end
end end
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