You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 lines
6.6 KiB

local MAJ, _, T = 1, ...
if T.SkipLocalActionBook then return end
if T.TenEnv then T.TenEnv() end
local EV, WR, AB, KR, RW = T.Evie, T.Ware, T.ActionBook:compatible(2,36), T.ActionBook:compatible("Kindred", 1,22), T.ActionBook:compatible("Rewire", 1, 31)
assert(EV and WR and AB and KR and RW and 1, "Incompatible library bundle")
local FM, core = {}, CreateFrame("Frame", nil, nil, "SecureHandlerBaseTemplate")
local cenvW, wnewtable = WR.GetRestrictedEnvironment(core), WR.newtable
local cenv = WR.GetBackingRestrictedTable(cenvW)
cenvW.KR, cenvW.flags, cenvW.cargcache, cenvW.crm = KR:seclib(), wnewtable, wnewtable, 2^24
wnewtable(cenvW, "crand")[1] = math.random(2^24)-1
cenvW.NO_FLAGS_MESSAGE = AB.L"No flags are active."
core:SetAttribute("RunSlashCmd", [=[-- flag-RunSlashCmd
local slash, clause, target = ...
local flag, nv
if slash == "/dumpflag" and clause then
local o, n,s,a = nil, pairs(flags)
if clause:match("([^=<%s/,:]+)%s*") then
n, s, a = clause:gmatch("([^=<%s/,:]+)%s*")
end
for k in n,s,a do
local v = flags[k]
local fv = v and "[flag:" .. k .. "=" .. v .. "]" or ("[noflag:" .. k .. "]")
o = o and o .. " " .. fv or fv
end
print(o or NO_FLAGS_MESSAGE)
elseif (clause or "") == "" then
elseif slash == "/setflag" then
local name, eq, v = clause:match("^%s*([^=<%s/,:]+)%s*(=?)%s*(.-)%s*$")
if name then
flag, nv = name:lower(), eq == "" and "1" or (v ~= "" and v ~= "0" and v:lower()) or nil
end
elseif slash == "/cycleflag" then
local name, eq, top, step = clause:match("^%s*([^=<%s/,:]+)%s*([<=]?)%s*(%d*)%+?(%-?%d*)%s*$")
if name and (top == "") == (eq == "")then
flag, top, step = name:lower(), top ~= "" and 0+top or 2, step ~= "" and 0+step or 1
nv = ((tonumber(flags[flag]) or 0) + step) % top
nv = nv > 0 and nv .. "" or nil
end
elseif slash == "/randflag" then
local name, top = clause:match("^%s*([^=<%s/,:]+)%s*<%s*(%d*)%s*$")
if not name then return end
nv, flag, top = 0, name:lower(), top ~= "" and 0+top or 2
if top > 1 then
local cr = crand[clause]
local rv = ((cr or crand[1]) * 12616645 + 16777213) % crm
if cr == nil then
crand[1] = rv
end
crand[clause], nv = rv, rv % top
end
nv = nv ~= 0 and nv .. "" or nil
end
if flag ~= nil and flags[flag] ~= nv then
flags[flag] = nv
if KR then
KR:RunAttribute("PokeConditional", "flag")
end
end
]=])
core:SetAttribute("EvaluateMacroConditional", [=[-- flag-EvaluateMacroConditional
local name, cv, target = ...
if name ~= "flag" or not cv then return end
local ca, ni = cargcache[cv]
if not ca then
ca, ni = newtable(), 1
for s in cv:gmatch("[^/]*") do
local name, eq, v = s:match("^%s*([^=%s]+)%s*(=?)%s*(.-)%s*$")
if name then
name, v = name:lower(), v:lower()
if eq == "=" then
ca[ni], ca[ni+1], ni = name, v ~= "0" and v, ni + 2
else
ca[ni], ca[ni+1], ni = name, false, ni + 2
end
end
end
cargcache[cv] = ca
end
for i=1, #ca, 2 do
local cv, dv = flags[ca[i]], ca[i+1]
if cv == dv or (dv == false and cv) then
return true
end
end
return false
]=])
local flagHint, flagCommandHint, dumpFlags do
local currentFutureID
local function newSpeculativeProxy(base)
local ov, ot = {}, {}
local function getValue(_, k)
if currentFutureID and ot[k] == currentFutureID then
return ov[k]
end
return base[k]
end
local function setValue(_, k, nv)
if k ~= nil and currentFutureID then
ov[k], ot[k] = nv, currentFutureID
end
end
return setmetatable({}, {__index=getValue, __newindex=setValue})
end
local flagProxy, crandProxy = newSpeculativeProxy(cenv.flags), newSpeculativeProxy(cenv.crand)
local flagHintI = loadstring(("local cargcache, flags, newtable = ... return function(...) %s end"):format(core:GetAttribute("EvaluateMacroConditional")))({}, flagProxy, function() return {} end)
local runSlashI = loadstring(("local KR, self, flags, crand, crm = false, ... return function(...) %s end"):format(core:GetAttribute("RunSlashCmd")))(core, flagProxy, crandProxy, cenv.crm)
function flagHint(...)
local _; _, _, _, _, currentFutureID = ...
return flagHintI(...)
end
function flagCommandHint(slash, _, args2, target, _, _, _, speculationID)
currentFutureID = speculationID
runSlashI(slash, args2, target)
end
function dumpFlags(clause)
runSlashI("/dumpflag", clause, nil)
end
end
local ownDumpCommand, ownDumpKey do
local suf = 1 repeat
ownDumpKey, suf = "ABFM_DUMP_FLAG_" .. suf .. "X", suf + 1
until SlashCmdList[ownDumpKey] == nil
ownDumpCommand = "/dumpflag" .. (suf-1)
_G["SLASH_" .. ownDumpKey .. "1"], _G["SLASH_" .. ownDumpKey .. "2"] = "/dumpflag", ownDumpCommand
SlashCmdList[ownDumpKey] = function(msg)
local cv = KR:EvaluateCmdOptions(msg)
if cv then
dumpFlags(cv)
end
end
end
local pendingRestoreState, DoRestoreState = nil do
local function RestoreFlags(flags)
if type(flags) ~= "table" then
return
end
local r = cenvW.flags
for k,v in pairs(flags) do
if type(k) == 'string' and type(v) == 'string' then
r[k] = v
end
end
end
local function RestoreReVars(revars)
if type(revars) ~= "table" then
return
end
for k,v in pairs(revars) do
if type(k) == 'string' and type(v) == 'string' then
RW:SetMacroVarValue(k, v)
end
end
end
function DoRestoreState(state)
pendingRestoreState = 0
RestoreFlags(state.flags)
RestoreReVars(state.revars)
end
end
function FM:GetState()
local rf, rv = {}, {}
for f, v in rtable.pairs(cenv.flags) do
rf[f] = v
end
for n, v in RW:AllMacroVars() do
rv[n] = v ~= "" and v or nil
end
rf, rv = next(rf) ~= nil and rf or nil, next(rv) ~= nil and rv or nil
return (rf or rv) and {flags=rf, revars=rv, at=GetServerTime()} or nil
end
function FM:RestoreState(state)
if type(state) == "table" and pendingRestoreState == nil and
(type(state.flags) == "table" or type(state.revars) == "table") then
pendingRestoreState = state
if InCombatLockdown() then
EV.PLAYER_REGEN_ENABLED = function()
DoRestoreState(pendingRestoreState)
return "remove"
end
else
DoRestoreState(state)
end
end
end
function FM:GetFlagDumpCommand()
return ownDumpCommand
end
KR:SetSecureExternalConditional("flag", core, flagHint)
RW:RegisterCommand("/setflag", true, true, core)
RW:RegisterCommand("/cycleflag", true, true, core)
RW:RegisterCommand("/randflag", true, true, core)
RW:RegisterCommand("/dumpflag", true, true, core)
RW:AddCommandAliases("/dumpflag", ownDumpCommand)
RW:SetCommandHint("/setflag", math.huge, flagCommandHint)
RW:SetCommandHint("/cycleflag", math.huge, flagCommandHint)
RW:SetCommandHint("/randflag", math.huge, flagCommandHint)
function FM:compatible(maj)
return MAJ == maj and FM or nil
end
AB:RegisterModule("FlagMast", FM)