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.
183 lines
5.8 KiB
183 lines
5.8 KiB
local MAJ, _, T = 1, ...
|
|
if T.SkipLocalActionBook then return end
|
|
if T.TenEnv then T.TenEnv() end
|
|
|
|
local EV, AB, KR, RW = T.Evie, T.ActionBook:compatible(2,36), T.ActionBook:compatible("Kindred", 1,22), T.ActionBook:compatible("Rewire", 1, 31)
|
|
assert(EV and AB and KR and RW and 1, "Incompatible library bundle")
|
|
|
|
local FM, core, cenv = {}, CreateFrame("Frame", nil, nil, "SecureHandlerBaseTemplate")
|
|
core:SetFrameRef("KR", KR:seclib())
|
|
core:SetAttribute("seed", math.random(2^24)-1)
|
|
core:Execute([=[-- ActionBook:flag-init
|
|
KR, flags, cargcache, crand, crm = self:GetFrameRef('KR'), newtable(), newtable(), newtable(self:GetAttribute('seed')), 2^24
|
|
]=])
|
|
cenv = GetManagedEnvironment(core)
|
|
core:SetAttribute("RunSlashCmd", [=[-- flag-RunSlashCmd
|
|
local slash, clause, target = ...
|
|
local flag, nv
|
|
if (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 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, flags, crand, crm = false, ... return function(...) %s end"):format(core:GetAttribute("RunSlashCmd")))(flagProxy, crandProxy, cenv.crm)
|
|
|
|
function flagHint(...)
|
|
local _; _, _, _, _, currentFutureID = ...
|
|
return flagHintI(...)
|
|
end
|
|
function flagCommandHint(slash, _, args2, target, _, _, _, speculationID)
|
|
currentFutureID = speculationID
|
|
runSlashI(slash, args2, target)
|
|
end
|
|
end
|
|
|
|
local pendingRestoreState, DoRestoreState = nil do
|
|
local function RestoreFlags(flags)
|
|
if type(flags) ~= "table" then
|
|
return
|
|
end
|
|
for k,v in pairs(flags) do
|
|
if type(k) == 'string' and type(v) == 'string' then
|
|
core:SetAttribute('setflag-name', k)
|
|
core:SetAttribute('setflag-value', v)
|
|
core:Execute([[-- flag-RestoreFlagState
|
|
flags[self:GetAttribute('setflag-name')] = self:GetAttribute('setflag-value')
|
|
]])
|
|
end
|
|
end
|
|
core:SetAttribute('setflag-name', nil)
|
|
core:SetAttribute('setflag-value', nil)
|
|
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
|
|
|
|
KR:SetSecureExternalConditional("flag", core, flagHint)
|
|
RW:RegisterCommand("/setflag", true, true, core)
|
|
RW:RegisterCommand("/cycleflag", true, true, core)
|
|
RW:RegisterCommand("/randflag", true, true, core)
|
|
RW:SetCommandHint("/setflag", 9e9, flagCommandHint)
|
|
RW:SetCommandHint("/cycleflag", 9e9, flagCommandHint)
|
|
RW:SetCommandHint("/randflag", 9e9, flagCommandHint)
|
|
|
|
function FM:compatible(maj)
|
|
return MAJ == maj and FM or nil
|
|
end
|
|
|
|
AB:RegisterModule("FlagMast", FM)
|