Commit 14515cb1 authored by Satty's avatar Satty

fix

parent d3283871
Pipeline #39131 failed with stages
in 8 minutes and 12 seconds
...@@ -24,7 +24,7 @@ function cm.initial_effect(c) ...@@ -24,7 +24,7 @@ function cm.initial_effect(c)
c:RegisterEffect(e1) c:RegisterEffect(e1)
end end
function cm.spcfilter(c) function cm.spcfilter(c)
return c:IsRace(RACE_INSECT) and c:IsAbleToDeckOrExtraAsCost() return c:IsRace(RACE_INSECT) and c:IsAbleToDeckOrExtraAsCost() and c:IsFaceup()
end end
function cm.spcon(e,c) function cm.spcon(e,c)
if c==nil then return true end if c==nil then return true end
...@@ -35,7 +35,6 @@ end ...@@ -35,7 +35,6 @@ end
function cm.spop(e,tp,eg,ep,ev,re,r,rp,c) function cm.spop(e,tp,eg,ep,ev,re,r,rp,c)
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_TODECK) Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_TODECK)
local g=Duel.SelectMatchingCard(tp,cm.spcfilter,tp,LOCATION_GRAVE+LOCATION_REMOVED,0,1,2,c) local g=Duel.SelectMatchingCard(tp,cm.spcfilter,tp,LOCATION_GRAVE+LOCATION_REMOVED,0,1,2,c)
Duel.ConfirmCards(1-tp,g) Duel.HintSelection(g)
Duel.ConfirmCards(tp,g)
Duel.SendtoDeck(g,nil,2,REASON_COST) Duel.SendtoDeck(g,nil,2,REASON_COST)
end end
\ No newline at end of file
...@@ -59,7 +59,7 @@ function cm.sfilter(c) ...@@ -59,7 +59,7 @@ function cm.sfilter(c)
return c:IsSummonable(true,nil,1) and c:IsSetCard(0xcc5) return c:IsSummonable(true,nil,1) and c:IsSetCard(0xcc5)
end end
function cm.con(e,tp) function cm.con(e,tp)
return (Duel.GetCurrentPhase()==PHASE_MAIN1 and Duel.GetCurrentPhase()==PHASE_MAIN2) and Duel.IsExistingMatchingCard(cm.sfilter,tp,LOCATION_HAND,0,1,nil) return (Duel.GetCurrentPhase()==PHASE_MAIN1 or Duel.GetCurrentPhase()==PHASE_MAIN2) and Duel.IsExistingMatchingCard(cm.sfilter,tp,LOCATION_HAND,0,1,nil)
end end
function cm.op1(e,tp) function cm.op1(e,tp)
Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SUMMON) Duel.Hint(HINT_SELECTMSG,tp,HINTMSG_SUMMON)
......
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")
end if is_cod then
end owner, cod, target, force = nil, owner, cod, target
end end
---------------------------------------------------------------- procedure Register (just Noc
function fuef.Proc_XYZ(cf, gf, min, max, ex_loc) if i == 2 then cod = cod or "FC" end -- A,QO,QF
min, max = min or 1, max or 99
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) return fuef.New(log, typ, cod, owner, target, force)
end end
function fuef.PX_g_goal(g, tp, xyzc, gf) end
end
---------------------------------------------------------------- XYZ Proc
function fuef.ProcXyzLv(lv, cf, min, max)
fusf.CheckArgType("fuef.ProcXyzLv", 1, lv, "number")
fusf.CheckArgType("fuef.ProcXyzLv", 2, cf, "nil/function")
local lvf = fucf.MakeCardFilter("IsLv", lv)
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
end fusf.CheckTypes(owner, "nil/Card/Effect")
-- Cover _cod end
if CE.typ == EFFECT_TYPE_FIELD + EFFECT_TYPE_GRANT then
CE:OBJ(_cod) if target == true then
elseif _cod then target, force = nil, true
CE.cod = fusf.Get_Constant("cod", _cod) elseif target ~= false then
end local typ = fusf.CheckTypes(target, "nil/Card/Group/table/player")
-- Clone and return Clone if typ == "Card" or typ == "Group" then
if self.e then target = fusf.ToGroupTable(target)
CE.e = self.e:Clone() end
-- Set Key and Register Effect end
return CE:SetKey():Reg(_handler, _ignore)
end force = fusf.CheckType(force or false, "boolean")
-- Clone Noc (
CE.pre = self return owner, target, force
self.aft = CE end
return CE
end --- 检查 val 是否为有效的 value 格式,用于 fuef:Func
-------------------------------------------------------------------------- -- @param val any 欲检查的值
-- Creat and Register Effect -- @param val_typ string 值的型别
function fuef:Creat(_typ, _cod, _owner, _handler, _ignore) -- @return boolean 是否符合格式
fusf.Debug("") local function MatchValFormat(val, val_typ)
fusf.Debug("Creat("..fusf.ValToDebug(fusf.CutHex(_typ), _cod, _owner, _handler, _ignore)..")") if val_typ ~= "string" then return true end
local E = setmetatable({ }, fuef) if val:match("%,") then return false end
-- Set type and code and handler return tonumber(val) or fucs.val[val] or (val:sub(-4, -2):lower() == "val")
E.typ = fusf.Get_Constant("etyp", _typ) end
E.cod = fusf.Get_Constant("cod", _cod)
E.handler = _handler ----------------------------------------------------------------
-- use in no owner (Creat and Register in __call --- 建立一个新的效果表(fuef 物件),初始化基本栏位
if not _owner then return E end --
-- Create Effect -- - 若 `owner` 为 nil,仅建立效果表而不创建 Effect 实体,需后续呼叫 `:InitSetOwner(owner)` 补足。
E.e = Effect.CreateEffect(fusf.ToCard(_owner)) -- - 若 `owner` 为 Effect 或 Card,则立即创建 Effect 并进行注册。
-- Set type and code ----- 建立一个新的效果表(fuef 物件),初始化基本栏位
if _typ then E.e:SetType(E.typ) end --
if _cod then E.e:SetCode(E.cod) end -- - 若 `owner` 为 nil,仅建立效果表而不创建 Effect 实体,需后续呼叫 `:InitSetOwner(owner)` 补足。
return E:Reg(_handler, _ignore) -- - 若 `owner` 为 Effect 或 Card,则立即创建 Effect 并进行注册。
end --
function fuef:CreatNoc(_owner, _handler, _ignore) -- @param log 日志对象或层级(用于调试记录)
fusf.Debug("CreatNoc("..fusf.ValToDebug(_owner, _handler, _ignore)..")") -- @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
return E:Reg(log)
end
-- 注册 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
if self.force == nil then
self.force = false
log:Info("set self.force is false")
end
local rg = self.handler
local fc = rg[1]
fc:RegisterEffect(self.e, self.force)
if #rg > 1 then
self.clones = { }
for i = 2, #rg do
local e = self.e:Clone()
table.insert(self.clones, e)
local c = rg[i]
c:RegisterEffect(e, self.force)
end
end
log:Info("RegisterEffect to "..(#rg).." Card")
return self
end
--- 支援语法糖:fuef物件可直接以 () 调用以复制自身
-- 等同于 self:Clone(...)
function fuef:__call(cod, target, force)
return self:Clone(cod, target, force)
end
--- 复制当前 fuef 效果对象,可用于复制已有效果结构
-- @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)
last.isinit = true
for _, key in keys:ForCut() do
if root[key] then if root[key] then
fuef[key:upper()](last, table.unpack(root[key])) 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
--- initial 检查,仅当尚未创建效果实体(self.e 为 nil)时执行初始化
-- @param log 日志对象或层级(用于调试记录)
-- @param key string 要初始化的字段名(会转为小写)
-- @param ... any 初始化值,将作为 table 存入字段
-- @return boolean 是否在 initial 调用
function fuef:InitCheck(log, key, ...)
if self.e then return false end
local log = fudf.StartLog(log, "fuef:InitCheck", key, ...)
self[key] = table.pack(...)
log:Info("set self."..key)
return true
end end
----------------------------------------------------------------DES
function fuef:DES(_code, _id) -- (0), ("n"), (m), ("+1") --- 重置 fuef.e 并以 fuef.e 的 owner 再创建一个效果并重新应用 Key
if not self:PreChk("DES", _code, _id) then return self end -- 会先 Reset 原本的效果实体并重新创建,清除 clones
self.des = fusf.GetDES(_code, _id, self.e:GetOwner():GetOriginalCode()) -- @param log 日志对象或层级(用于调试记录)
return self:Reload() -- @return fuef 返回 self(可链式调用)
end function fuef:Reload(log)
----------------------------------------------------------------TYP, COD, CAT and PRO if self.isinit then return self end
function fuef:Cons_Model(_key, _val) local log = fudf.StartLog(log, "fuef:Reload")
if not self:PreChk(_key:upper(), _val) then return self end
local _keytype = _key == "typ" and "etyp" or _key log:Info("recreate Effect")
local val, des = fusf.Get_Constant(_keytype, _val) local owner = self.e:GetOwner()
self[_key] = val self.e:Reset()
if _key == "cat" and des then self.des = self.des or des end self.e = Effect.CreateEffect(owner)
return self:Reload()
end if self.clones and #self.clones > 0 then
function fuef:TYP(_val) log:Info("clean self.clones")
return self:Cons_Model("typ", _val) for _, e in ipairs(self.clones) do
end e:Reset()
function fuef:COD(_val)
return self:Cons_Model("cod", _val)
end
function fuef:CAT(_val)
return self:Cons_Model("cat", _val)
end
function fuef:PRO(_val)
return self:Cons_Model("pro", _val)
end
----------------------------------------------------------------RAN and TRAN
function fuef:RAN(_loc)
if not self:PreChk("RAN", _loc) then return self end
self.ran = fusf.Get_Loc(_loc, nil, "fuef:RAN()")
return self:Reload()
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)
end -- @param id string|number 描述 ID(将传入 ResolveDescription)
local vals = {...} -- @return fuef 返回 self(可链式调用)
if not (type(_val) == "string" and _val:match("%,")) then -- check _val is val function fuef:Des(code, id)
local val = { _val } local log = fudf.StartLog(self, "fuef:Des", code, id)
if type(_val) == "string" and _val:match("%%") then val = { _val , ... } end
self.val = val fusf.CheckEmptyArgs("Des", code, id)
else -- _val is _func
vals, _func = {_func, ...}, _val if self:InitCheck(log, "des", code, id) then return self end
end
-- "val,con,cos,tg,op" or "con,op" , if cant match then follow a sequence local m = self.e:GetOwner():GetOriginalCode()
local seqs, place, sets = {"val", "con", "cos", "tg", "op"}, 1, { } self.des = fusf.ResolveDescription(code, id, m)
-- "f1,f2(%1,v2),f3" -> {"f1", {"f2", vals[1], "v2"}, "f3"}, ... use in vi = %i log:Info("set self.des : "..self.des)
for i, func in fusf.ForTable(fusf.Val_Cuts(_func, table.unpack(vals))) do return self:Reload(log)
local fname, fval = func, func end
if type(fname) == "table" then
fname = table.remove(fval,1) ----------------------------------------------------------------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
return self:Reload(log)
end
--- 设定 type
function fuef:Typ(typ)
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
local cod_typ = fusf.CheckArgType("Ctl", 2, code, "nil/number/string")
local m = self.e:GetOwner():GetOriginalCode()
local ctl_consts = fusf.Findfucs("ctl")
local _code, _pro = 0, 0
fusf.CheckArgType("Ctl", 3, pro, "nil/string")
if pro then
_pro = fusf.FindTables(pro, ctl_consts)
end
if cod_typ == "number" then
_code = fusf.NormalizeID(code, m)
elseif cod_typ == "string" then
for _, val in code:ForCut("+") do
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 else
fval = nil _code = fusf.NormalizeID(val, m)
end end
-- find fname can match seqs
local match = 0
for j = place, 5 do
local temp = fname:find(seqs[j])
if temp and temp > match then
place, match = j, temp
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
if not self.e then return self end
-- self[key] = {func, ...}
if sets[1] == "val" then
table.remove(sets, 1)
local val = self.val[1]
if type(val) == "string" then
self.val = tonumber(val) or fucs.val[val] or fusf.Get_Func(self.e:GetOwner(), table.unpack(self.val))
if not self.val then fusf.Debug("val Func value is nil") end
else -- number or function
self.val = val
end end
end end
for _,set in ipairs(sets) do
local res = fusf.Get_Func(self.e:GetOwner(), table.unpack(self[set])) if _code == 0 and (_pro == ctl_consts["O"] or _pro == ctl_consts["D"]) then
if not res then fusf.Debug(set.." Func value is nil") end _code = m
self[set] = res
end end
return self:Reload()
self.ctl = {count, _code + _pro}
log:Info(("set self.ctl : %s / %s"):format(count, self.ctl[2]))
return self:Reload(log)
end end
function fuef:Func_Model(_key, _func, ...) ----------------------------------------------------------------VAL, CON, COS, TG and OP
if not self:PreChk(_key:upper(), _func, ...) then return self end
local val_chk = _key == "val" and (tonumber(_func) or fucs.val[_func]) or nil --- 设定函数型栏位,如 val、con、tar、op 等,可接受函数名、表达式或函数本体
local vals = select("#", ...) > 0 and { ... } or nil -- @param log 日志对象或层级(用于调试记录)
if type(_func) == "string" and _func:match("%(") then -- @param key string 欲设定的栏位名称
_func = fusf.Val_Cuts(_func, ...)[1] -- @param func string|function|number 欲指定的函数或值
vals = _func -- @param ... 可选的参数,用于传递给 ResolveFunction 或 ParseCallExprString
if type(_func) == "table" then -- @return fuef 返回自身以支援链式调用
_func = table.remove(vals,1) 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
log:Info("set self.val : "..tostring(val))
return self:Reload(log)
end
end
local f, args = func, nil
if has_arg then args = table.pack(...) end
if func:match("%(") then
f, args = fusf.ParseCallExprString(func, args)
end
local c = self.e:GetOwner()
f = fusf.ResolveFunction(f, args, fusf.Getcm(c), c.lib)
self[key] = f
log:Info(("set self.%s : %s"):format(key, tostring(f)))
return self:Reload(log)
end
--- 设定效果的 value(数值或函数),可为 number|string|function
-- @param val number|string|function 数值或函数(或名称)
-- @param ... 可选的额外参数(若 val 是函数字串会带入)
-- @return fuef 返回自身以支援链式调用
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 else
vals = nil 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
log:Info(i.." : "..fname)
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
elseif vals and #vals == 1 and type(vals[1]) == "table" then
vals = vals[1] -- 若 vals 中只有一个表,则直接解包表
end end
self[_key] = val_chk or fusf.Get_Func(self.e:GetOwner(), _func, vals) if match == 0 then key_ind = i end
if not self[_key] then fusf.Debug(_key.." Func value is nil") end
return self:Reload() local key = keys[key_ind]
end log:Info("match "..key)
function fuef:VAL(_func, ...) self:SetFuncField(log, key, f)
return self:Func_Model("val", _func, ...) end
end log:Info("all match down")
function fuef:CON(_func, ...)
return self:Func_Model("con", _func, ...) return self
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)
end self.res = {flag, count}
else log:Info(("set self.res : %s / %d"):format(fusf.CutHex(flag), count))
elabs[#elabs + 1] = labs return self:Reload(log)
end end
end ----------------------------------------------------------------LAB & OBJ
self.lab = elabs
return self:Reload() --- 设定 label 参数,支援数字、字串(可用 "+" 拆分)与特别标记 "m"
end -- @param ... 可为数字、字串(如 "1+2+m")等,会转为数字阵列
----------------------------------------------------------------OBJ -- @return fuef 返回自身,用于链式调用
function fuef:OBJ(_val) function fuef:Lab(...)
if not self:PreChk("OBJ", _val) then return self end local log = fudf.StartLog(self, "fuef:Lab", ...)
if type(_val) == "string" then -- ex: cm.e3 = fuef.FG("e1") -> obj == cm.e1
_val = fusf.Getcm(self)["es"][_val].e fusf.CheckEmptyArgs("Lab", ...)
end
self.obj = _val if self:InitCheck(log, "lab", ...) then return self end
return self:Reload(1)
end local m = self.e:GetOwner():GetOriginalCode()
--------------------------------------------------------------------------"Support Effect function" local args = {}
function fuef.initial(_lib, _glo, _exop_func, ...) for i, val in ipairs{...} do
local cm, m = GetID() local typ = fusf.CheckArgType("Lab", i, val, "string/number")
local exop_val = { ... } if typ == "string" then
cm.es, cm.lib = {}, _lib for _, lab in val:ForCut("+") do
cm.initial_effect = cm.initial_effect or function(c) args[#args + 1] = (lab == "m") and m or tonumber(lab)
-- do ex_op
if _exop_func then
local place = 1
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 end
else else
exop_func(c, exop_val[place]) args[#args + 1] = val
place = place + 1 end
end end
end
end self.lab = args
local dof = function(_name, _exval) log:Info(("set self.lab : %d arg"):format(#args))
local n = 1 return self:Reload(log)
while cm[_name..n] do end
cm.es[_name..n] = cm[_name..n](c, _exval)
n = n + 1 --- 设置效果的关联对象(object),可为字符串代号或实际对象
end -- @param val string|Card|Group|Effect 关联对象,字符串将解析为 cm.elist 的键
end -- @return fuef 返回自身,用于链式调用
dof("e") -- do e1 ~ en -- @raise 类型不符时抛出错误
dof("pe") -- do e1 ~ en in lib pre set function fuef:Obj(val)
-- if cm[_glo] then do ge1 ~ gen local log = fudf.StartLog(self, "fuef:Obj", val)
if not (_glo and not cm[_glo]) then return end
cm[_glo] = {0, 0} local typ = fusf.CheckArgType("Obj", 1, val, "string/fuef/Card/Group/Effect")
dof("ge", 1)
end if self:InitCheck(log, "obj", val) then return self end
return cm, m
end if typ == "string" then
function fuef.tg_is_cos(e,tp,eg,ep,ev,re,r,rp,chk) local e = fusf.Getcm(self).elist[val]
e:SetLabel(100) if not e or not e.e then
if chk==0 then return true end error("Obj: elist entry for '" .. val .. "' is missing or invalid", 2)
end
val = fusf.CheckType(e.e, "Effect")
end
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
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
else
arg_count = arg_count + 1
arg_table[arg_count] = arg
end
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
-- func is string
local func_expr = fusf.InfixToPostfix(func, ...)
local fucf, Card, aux = fucf, Card, aux
if #func_expr == 1 then -- func just one
local find_func = fusf.FindTables(func_expr[1], fucf, Card, aux)
fusf.CheckType(find_func, "function")
return function(c)
fusf.CheckArgType("MakeCardFilter", 1, c, "Card")
return find_func(c, table.unpack(arg_table, 1, arg_count))
end
end
-- func is multi
return function(c)
fusf.CheckArgType("MakeCardFilter", 1, c, "Card")
local stack, arg_ind = {}, 1
for _, func in ipairs(func_expr) do
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
}
local temp = Cal[func]
if temp == nil then
error("invalid operators : " .. func)
end
stack[#stack + 1] = temp
else else
codes[#codes + 1] = fusf.M_chk(_code) if type(func) == "string" then
end func = fusf.FindTables(func, fucf, Card, aux)
end fusf.CheckType(func, "function")
aux.AddCodeList(c, table.unpack(codes)) end
end local arg = arg_table[arg_ind]
fucf.ReviveLimit = Card.EnableReviveLimit arg_ind = arg_ind + 1
--------------------------------------"Card function" (use in Filter if type(arg) ~= "table" then arg = { arg, n = 1 } end
function fucf.Filter(c, _func, ...) stack[#stack + 1] = func(c, table.unpack(arg, 1, arg.n))
return fusf.Creat_CF(_func, {...})(c) end
--return fugf.Filter(Group.FromCards(c), func, {...}, 1) end
end return table.remove(stack)
fucf.IsRk = fusf.IsN("GetRank") end
fucf.IsLv = fusf.IsN("GetLevel") end
fucf.IsRLv = fusf.IsN("GetRitualLevel")
fucf.IsLk = fusf.IsN("GetLink") --- 判断卡片是否满足给定的过滤条件
fucf.IsAtk = fusf.IsN("GetAttack") -- @param c Card 欲判断的卡片对象
fucf.IsDef = fusf.IsN("GetDefense") -- @param f string|function 过滤器(可为函数或其名称)
fucf.IsSeq = fusf.IsN("GetSequence") -- @param args table|string|number 传入的参数,可为字符串(含占位符)或具体值
fucf.IsPSeq = fusf.IsN("GetPreviousSequence") -- @param ... 可选的占位参数(会传给 %1、%2 等)
function fucf.Not(c,val) -- @return boolean 若卡片符合条件,返回 true,否则返回 false
if aux.GetValueType(val) == "Card" then 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
--- 判断 c 是否属于指定的卡号
-- @param c Card 要检查的卡片
-- @param cod number|string|table|Effect|Card|Group 可为单个卡号、以 "+" 分隔的字符串、卡号数组,或包含卡的 Group
-- @return boolean 是否匹配任意一个卡号
function fucf.IsCode(c, cod)
fusf.CheckArgType("IsCode", 1, c, "Card")
return c:IsCode(table.unpack(fusf.GetCodeTable(cod)))
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.HasCode(c, cod)
cod = _cod:Cut("fucf.IsCode", "+") fusf.CheckArgType("HasCode", 1, c, "Card")
elseif aux.GetValueType(_cod) == "table" then local code_list = c.card_code_list
cod = _cod 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
fusf.CheckArgType("CanBeEq", 2, tp, "player")
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
for i,v in ipairs(cod) do if c:IsType(TYPE_MONSTER) then
has = has or c.card_code_list[fusf.M_chk(tonumber(v))] return c:IsControler(tp) or c:IsAbleToChangeControler()
elseif c:IsType(TYPE_EQUIP) then
return c:CheckEquipTarget(ec)
end end
return has 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)
...@@ -167,3 +459,4 @@ function fucf.RMFilter(c, rf, e, tp, g1, g2, level_function, greater_or_equal, c ...@@ -167,3 +459,4 @@ function fucf.RMFilter(c, rf, e, tp, g1, g2, level_function, greater_or_equal, c
Auxiliary.GCheckAdditional = nil Auxiliary.GCheckAdditional = nil
return res return res
end end
--]]
\ 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
local metatable = getmetatable(val)
if metatable == fuef then
return "fuef"
elseif metatable == fudf then
return "fudf"
end
end
return typ
end
--- 验证 val 的类型是否为 typ,若为 "player" 类型则进一步检查值是否合法(0 或 1)
-- @param val any 欲检查的值
-- @param typ string 预期的类型名称(如 "Card", "string", "number", "player" 等)
-- @return any 若类型正确,返回原值
-- @raise 若类型不符,会根据 arg_ind 抛出更明确的错误(包含参数编号)
function fusf.CheckType(val, typ)
if type(typ) ~= "string" then
error(("param %d should be %s, got %s"):format(2, "string", type(typ)), 2)
end
if typ == "player" then
if val == 0 or val == 1 then
return val
else else
res = res..", "..tostring(tab[i]) error("invalid player index '"..val.."' (expected 0 or 1)", 3)
end end
end end
return res:sub(3) local val_type = fusf.Type(val)
if val_type == typ then return val end
error(("should be %s, got %s"):format(typ, val_type), 3)
end end
function fusf.Getcm(val)
local c = fusf.ToCard(val, true) --- 验证 val 的 type 是否在 typs 内(以 "/" 分隔)
if getmetatable(val) == fuef then -- @param val any 欲检查的值
c = val.e:GetOwner() -- @param typs string 多个类型名称组成的字符串,如 "number/string"
end -- @return string, any 若匹配,返回其匹配的类型及原值
if not c then -- @raise 若不符合任何类型,会抛出详细错误信息
Debug.Message("Cant Get cm "..tostring(val)) function fusf.CheckTypes(val, typs)
return { } typs = fusf.CheckType(typs, "string")
end local val_type = fusf.Type(val)
return _G["c"..val.e:GetOwner():GetCode()] for _, typ in typs:ForCut("/") do
end if pcall(fusf.CheckType, val, typ) then return typ, val end
function fusf.CutHex(val, add) end
-- 转换 typ 等并分割 error(("should be %s, got %s"):format(typs, val_type), 3)
if type(val) == "string" then return val end
add = add or "+"
local parts = {}
local bit = 1
while val > 0 do
if val % 2 == 1 then
table.insert(parts, string.format("0x%X", bit))
end
val = math.floor(val / 2)
bit = bit * 2
end
for i = 1, math.floor(#parts / 2) do
parts[i], parts[#parts - i + 1] = parts[#parts - i + 1], parts[i]
end
return table.concat(parts, add)
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 end
function fusf.IsNil(...)
local vals = {...} --- 将 val 转为对应的卡片组 table
if #vals == 0 then return true end -- @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
--- 判断传入值是否为 nil, "", {}
-- @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
return not vals
end
function fusf.NotNil(...)
return not fusf.IsNil(...)
end
function fusf.Get_Constant(_constable, _vals)
-- string chk
if type(_vals) ~= "string" then return _vals end
local res = 0
-- cod chk
if _constable == "cod" then
-- EVENT_CUSTOM
if _vals:match("CUS") then
_vals = _vals:sub(5)
-- owner code or number
res = EVENT_CUSTOM + fusf.M_chk(_vals)
-- EVENT_PHASE or EVENT_PHASE_START
elseif _vals:match("PH") then
for _, val in _vals:ForCut("Get_Constant_1", "+") do
local _constable = val:match("PH") and "cod" or "pha"
res = res + fucs[_constable][val]
end
end
if res ~= 0 then return res end
end
-- find _constable
local vals, cons, des = _vals:Cut("Get_Constant_2", "+"), fucs[_constable]
for i = #vals, 1, -1 do
local _val = vals[i]
des = fucs.des[_val] or des
res = res + cons[_val]
end end
return res, des return vals == nil
end end
function fusf.Get_Loc(_loc_s, _loc_o, _from)
-- nil chk --- 根据 val 取得其对应的全局 cm 表
if not fusf.NotNil(_loc_s, _loc_o) then -- @param val Card|Effect|Group|fuef
Debug.Message("Get_Loc <- ".._from) -- @return table 对应的 cm 表
return nil -- @raise 若无法取得卡片对象则抛出错误
end function fusf.Getcm(val)
local p_loc = {0, 0} local typ = fusf.CheckArgType("Getcm", 1, val, "Card/Effect/Group/fuef")
-- _loc_o chk local c
if _loc_o then p_loc[2] = _loc_o end if typ == "fuef" then
-- _loc_s string chk c = fusf.CheckType(val.e, "Effect"):GetOwner()
if type(_loc_s) ~= "string" then else
p_loc[1] = _loc_s c = fusf.ToCard(val, true)
return table.unpack(p_loc)
end end
-- _loc_s is string and find fucs.ran return fusf.CheckType(_G["c" .. c:GetCode()], "table")
local _res = 0 end
for i, loc in _loc_s:ForCut("Get_Loc", "+") do
for j = 1, #loc do --- 规范化卡号,若小于 1000,则加上 base (20000000)
p_loc[i] = p_loc[i] + fucs.ran[loc:sub(j,j):upper()] -- @param id number|string
-- @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
return result
end
local code_table = {}
local typ = fusf.CheckTypes(val, "number/string/table")
if typ == "number" then
code_table = { val }
elseif typ == "string" then
code_table = val:Cut("+")
elseif typ == "table" then
code_table = val
end
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
--- 将整数转换为 16 进制 string 表示(以 ", " 或指定符号连接)
-- @param val number|string 欲转换的数值,若为字串则直接返回
-- @return string 分解后的 16 进制表示,如 "0x1, 0x2, 0x8"
-- @raise 当参数类型不符时抛出错误
function fusf.CutHex(val)
local typ = fusf.CheckArgType("CutHex", 1, val, "string/number")
if typ == "string" then return val end
local parts, bit = {}, 1
while val > 0 do
if val % 2 == 1 then
table.insert(parts, 1, string.format("0x%X", bit))
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 end
ch = function() return b end local val = args[tonumber(ch)]
end if val == nil then
table.insert(res, ch) 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")
local from = "MakeValCheck("..getter
return function(c, target, ...)
fusf.CheckArgType(from, 1, c, "Card")
local typ = fusf.CheckArgType(from, 2, target, "number/string")
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 if oper == "+" then
return c_val >= _val return card_val >= num
elseif oper == "-" then elseif oper == "-" then
return c_val <= _val return card_val <= num
end end
return c_val == _val return card_val == num
end
if _val > 0 then return c_val == _val end
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
end end
function fusf.Get_Func(_c, _func, _val)
if type(_func) ~= "string" then return _func end --- 从常量表找寻对应 keys 合计值
local lib = _c.lib or {} -- @param table_key string 常量表名称,如 "cod", "pha"
local res = function(_func) return _func end -- @param keys number|string 欲解析的常量名,多个以 "+" 连接
if _func:match("~") then -- @return number 合并的常量值, 可选返回常量描述
_func = _func:sub(2) -- @raise 当参数类型错误或无法找到对应常量时抛出错误
res = function(_func) return function(...) return not _func(...) end end function fusf.ParseConstantKey(table_key, keys)
end local typ = fusf.CheckArgType("ParseConstantKey", 2, keys, "number/string")
-- find cm, lib, fuef, aux if typ == "number" then return keys end
if not _val then
return res(_c[_func] or lib[_func] or fuef[_func] or aux[_func]) if keys == "" then error("ParseConstantKey : param 2 is invalid param", 2) end
local keys_list, res = keys:Cut("+"), 0
-- 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
if res > 0 then return res end
end
-- find table_key
local const_table = fusf.Findfucs(table_key)
local des
for i = #keys_list, 1, -1 do
local key = keys_list[i]
res = res + fusf.FindTables(key, const_table)
des = fucs.des[key] or des
end end
-- translate vals return res, des
for i, val in ipairs(_val) do end
_val[i] = tonumber(val) or val
--- 查找并解析函数 func,支持反向逻辑
-- @param func string|function 函数名称或函数对象,若为字串则从 c/lib/fuef/aux 中查找,支持 "~" 前缀取反
-- @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
f = f(table.unpack(args))
end 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 end
Debug.Message("Get_Func not found : ".._func) return fix(f)
return nil
end 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 -- 如 "f1,,f2(%1,%2),(%3)" 会被解析为 { "f1", nil, { "f2", {replace[1], replace[2]} }, { replace[3] } }
res_ind = res_ind + 1 -- @param expr_str string 欲解析的整体表达式,如 "f1,,f2(%1,%2),(%3)"
local is_st = val:match("%(") -- @param replace_table table 替换占位符用的参数表
local is_ed = val:match("%)") -- @return table 解析结果为表结构,内含函数名与参数的混合列表,巢状呼叫以子表表示,附加栏位 n 表示数量
-- @raise 若有未关闭括号或非法占位符,将抛出错误
function fusf.ParseCallGroupString(expr_str, replace_table)
local result, length, pending = {}, 0, ""
for _, unit in expr_str:ForCut() do
length = length + 1
local is_st = unit:match("%(")
local is_ed = unit:match("%)")
-- is f(v1) -- is f(v1)
if is_st and is_ed then -- f(v1) -> {"f", "v1"} if is_st and is_ed then
res_lst[res_ind] = fusf.Val_Cuts_Table_Process(val, ...) local fname, args = fusf.ParseCallExprString(unit, replace_table)
elseif is_st then -- f(v1,v2,v3) st f(v1 if fname == "" then
temp, res_ind = val, res_ind - 1 result[length] = args
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
res_lst.len = res_ind
return res_lst
end
function fusf.Val_Cuts_Table_Process(_str, ...) -- "f(%1,,3)" -> {"f", vals[1], nil, "3"}
local vals, res_lst, st = {...}, { }, _str:find("%(")
if st ~= 1 then res_lst[1] = _str:sub(1, st - 1) end -- has f
if st + 1 == #_str then return res_lst end -- "f()" -> {"f"}
_str = _str:sub(st + 1, #_str - 1)
local res_ind = #res_lst
for _, val in _str:ForCut("Val_Cuts_Table_Process") do
res_ind = res_ind + 1
if val:match("%%") then
res_lst[res_ind] = vals[tonumber(val:sub(2))]
elseif val ~= "" then
res_lst[res_ind] = val
end
end
res_lst.len = res_ind
return res_lst
end
function fusf.Creat_CF(_func, _val, ...)
if not _func then return function(c) return true end end
-- trans _val
if type(_val) ~= "table" then _val = { _val } end
local temp_val, v_ind = { }, 0
for _, f_val in ipairs(_val) do
if type(f_val) == "string" then
for _, val in fusf.ForTable(fusf.Val_Cuts(f_val, ...)) do
v_ind = v_ind + 1
temp_val[v_ind] = val
end
else else
v_ind = v_ind + 1 result[length] = {fname, args}
temp_val[v_ind] = f_val end
end elseif is_st then
end pending, length = unit, length - 1
_val, temp_val = temp_val elseif is_ed then
-- _func is function local fname, args = fusf.ParseCallExprString(pending .. "," .. unit, replace_table)
if type(_func) == "function" then if fname == "" then
return function(c) result[length] = args
return _func(c, table.unpack(_val, 1, v_ind))
end
end
-- _func is string
_func = fusf.PostFix_Trans(_func, ...)
local fucf, Card, aux = fucf, Card, aux
if #_func == 1 then -- _func just one
_func = fucf[_func[1] ] or Card[_func[1] ] or aux[_func[1] ]
return function(c)
return _func(c, table.unpack(_val, 1, v_ind))
end
end
-- _func is multi
return function(c)
local stack, v_ind, temp_val = { }, 1
for _, func in ipairs(_func) do
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
temp_val, v_ind = _val[v_ind], v_ind + 1 pending = ""
if type(temp_val) ~= "table" then temp_val = {temp_val, len = 1} end elseif #pending > 0 then
stack[#stack + 1] = func(c, table.unpack(temp_val, 1, temp_val.len)) 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
end if pending ~= "" then
function fusf.Creat_GF(_func, _val, ...) error("unclosed in ParseCallGroupString : " .. expr_str)
local ex_val = {...}
return function(g, n)
g = g:Filter(fusf.Creat_CF(_func, _val, table.unpack(ex_val)), nil)
if not n then return g end
return n > 0 and #g >= n or #g <= -n
end 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
--- 解析以逗号分隔的参数字串,并替换其中的占位符(如 %1, %2 等)
-- 如 "%1,,3" 会被解析为 { replace[1], nil, "3" }
-- @param args_str string 欲解析的字串,如 "%1,,3"
-- @param replace_table table 替换占位符用的参数表
-- @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
result.n = length
return result
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) 的值
end function fusf.ResolveDescription(code, id, m) -- (0), ("n"), (m), ("+1")
elseif type(_code) == "number" then local cod_typ = fusf.CheckArgType("ResolveDescription", 1, code, "number/string")
if _code < 17 then -- in cdb and code is owner card code local id_typ = fusf.CheckArgType("ResolveDescription", 2, id, "nil/number")
_code, _id = m, _code fusf.CheckArgType("ResolveDescription", 3, m, "number")
if id_typ == "number" then
if id < 17 then
code = fusf.NormalizeID(code, m)
end
elseif cod_typ == "number" then
if code < 17 then -- in cdb and code is owner card 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
end function fusf.ResolveReset(flag, count)
local stack = { } local typ = fusf.CheckArgType("ResolveReset", 1, flag, "number/string")
for _, unit in ipairs(fusf.PostFix_Trans(_flag)) do fusf.CheckArgType("ResolveReset", 2, count, "nil/number")
if unit:match("[+-/]") then
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
local stack = {}
local res, pha = fucs.res, fucs.pha
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
--- 建立与事件 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 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
function fusf.RegFlag(val, cod, res, pro, des, lab)
local typ = fusf.CheckArgType("RegFlag", 1, val, "Card/Group/Effect/player")
fusf.CheckArgType("RegFlag", 6, lab, "nil/number")
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)
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) c:RegisterFlagEffect(cod, res[1], pro, res[2] or 1, lab or 0, des)
end end
elseif typ == "Effect" then end
val:GetHandler():RegisterFlagEffect(cod, res[1], pro, res[2] or 1, lab or 0, des)
--- 检查 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 else
Duel.RegisterFlagEffect(val, cod, res[1], pro, res[2] or 1, lab or 0) count = fusf.ToCard(val):GetFlagEffect(cod)
end end
if not n then return count end
return n > 0 and count >= n or count <= -n
end end
function fusf.GetFlag(val, cod) -- val : Card|Effect|player(number)
cod = fusf.M_chk(cod) --- 检查 val 的种类为 cod 的标识效果的 Label, 有 lab 則傳回是否相等
local typ = aux.GetValueType(val) -- @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 if typ == "Card" then
return val:GetFlagEffect(cod) local ec = eg:GetFirst()
elseif typ == "Effect" then if not Duel.Equip(tp, ec, c) then return false end
return val:GetHandler():GetFlagEffect(cod) 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 end
return Duel.GetFlagEffect(val, cod) return stack[#stack]
end end
function fusf.Equip(e,tp,ec,c) --------------------------------------------------------------------------"initial function"
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 lib table (可选)卡片使用的函式库
return fuef.S(e, EFFECT_EQUIP_LIMIT, ec):PRO("CD"):VAL(eq):OBJ(c):RES("STD") -- @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
local function AddFunc(c)
aux.AddCodeList(c, table.unpack(codes))
end
fusf.InsertInitial(AddFunc, log)
end
--- 为卡片添加苏生限制
function fusf.ReviveLimit()
local log = fudf.StartLog(0, "fusf.ReviveLimit")
local function AddFunc(c)
c:EnableReviveLimit()
end
fusf.InsertInitial(AddFunc, log)
end
--- 添加自定义计数器
-- @param id number|string 计数器的 ID,会规范化
-- @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
...@@ -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()必須手動觸發此事件
--]] --]]
...@@ -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 --离场重定向
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 , --发动效果
} }
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