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.

767 lines
32 KiB

5 months ago
local MAJ, REV, _, T = 1, 31, ...
if T.SkipLocalActionBook then return end
5 months ago
local KR, EV, WR = {}, T.Evie, T.Ware
assert(EV and WR and 1, "Incompatible library bundle")
5 years ago
local function assert(condition, err, ...)
return condition or error(tostring(err):format(...), 3)((0)[0])
5 years ago
end
5 months ago
local rtgsub, WareRun = string.rtgsub, WR.Run
local core = CreateFrame("Frame", nil, nil, "SecureHandlerStateTemplate")
local coreEnvW = WR.GetRestrictedEnvironment(core) do
5 years ago
core:SetFrameRef("sandbox", CreateFrame("Frame", nil, nil, "SecureFrameTemplate"))
local bindProxy = CreateFrame("Frame", nil, nil, "SecureFrameTemplate")
core:SetFrameRef("bindProxy", bindProxy)
core:WrapScript(bindProxy, "OnAttributeChanged", [=[--Kindred_Bind_OnAttributeChanged
5 years ago
local key = name:match("^state%-(bind%d+)$")
if bindingDrivers[key] then
owner:Run(BindingLink_Move, key, value)
end
5 years ago
]=])
function core:SetOptFrameRef(ref, frame)
if frame then
return self:SetFrameRef(ref, frame)
else
return self:SetAttributeNoHandler("_frameref-" .. ref, nil)
end
end
5 years ago
end
core:SetAttribute("SecureOptionEscapes", [[ \\\ ;\s [\l ]\r %\p /\f ,\c ]] .. " \n\\n ")
core:Execute([==[-- Kindred.Init
KR, pcache, nextDriverKey, sandbox = self, newtable(), 4200, self:GetFrameRef("sandbox")
cndType, cndState, cndDrivers, cndAlias, unitAlias = newtable(), newtable(), newtable(), newtable(), newtable()
modArgCache, modStateCache, modTokens, modHoldMap = newtable(), newtable(), newtable(6, "ctrl", "alt", "shift", "meta", "cmd"), newtable(".", "L", "R", "B")
modArgCache.any = newtable("any")
stateDrivers, driverWatch = newtable(), newtable()
driverWatch.mod = newtable("[mod] on; off", false, nil)
driverWatch.bonusbar = newtable(("0 1 2 3 4 5 6 7 8 9 no"):gsub("%d+", "[bonusbar:%0] %0;"), false, nil)
isInLockdown, cndInsecure = false, newtable()
5 years ago
bindingDrivers, bindingKeys, nextBindingKey, bindProxy, bindEscapeMap = newtable(), newtable(), 42000, self:GetFrameRef("bindProxy"), newtable()
bindEscapeMap.SEMICOLON, bindEscapeMap.OPEN, bindEscapeMap.CLOSE = ";", "[", "]"
soEscapeSeqToLiteral = newtable()
for c, e in (self:GetAttribute("SecureOptionEscapes")):gmatch("([^ ])(\\.)") do
soEscapeSeqToLiteral[e] = c
end
5 months ago
local mu = newtable()
futureRemappableUnits, mu.target, mu.pettarget, mu.focus = mu, 1,1,1
futureUnitMap, unitPrefixCache, fumOwner = newtable(), newtable(), nil
baseUnitCache = newtable()
baseUnitCache.target = newtable("target", "")
5 years ago
OptionParse = [=[-- Kindred_OptionParse
5 months ago
local ret, options = newtable(), ...
local no, ns, lp = options:gmatch("()%["), options:gmatch("();"), #options + 1
local po, lc, fi, pc, ps = no() or lp, 0, 0
5 years ago
repeat
5 months ago
ps = ns() or lp
5 years ago
while po < ps do
5 months ago
pc = options:match("()%]", po)
5 years ago
if pc then
5 months ago
local clause, ct = options:sub(po+1, pc-1):lower(), newtable()
5 years ago
for m in clause:gmatch("[^,%s][^,]*") do
m = m:match("^(.-)%s*$")
5 years ago
if m:sub(1,1) == "@" or m:sub(1,7) == "target=" then
local bu, suf = m:match("[=@]%s*([^-%d]*%d*)(.-)%s*$")
ct.target, ct.targetS = bu, suf ~= "" and suf or nil
else
local cvalparsed, mark, wname, inv, name, col, cval = nil, m:match("^([+]?)((n?o?)([^:=]*))([:=]?)(.-)%s*$")
if inv ~= "no" then inv, name = "", wname end
cval, name = col == ":" and cval and ("/" .. cval .. "/"):gsub("%s*/%s*", "/"):sub(2,-2) or nil, col == ":" and name or (name .. col .. cval)
if cval and cval ~= "" then
cvalparsed = newtable()
for s in cval:gmatch("[^/]+") do
if ((name == "form" or name == "stance") and tonumber(s) or 1) < 1 then
cvalparsed[0] = true -- treated as [noform]
else
cvalparsed[#cvalparsed+1] = s
5 years ago
end
end
end
cct = newtable(name, cvalparsed, inv ~= "no", mark, cval)
ct[#ct+1], cct[0] = cct, m
end
end
5 months ago
ret[#ret+1], lc, po = ct, pc, no() or lp
5 years ago
else
break
end
end
5 months ago
if fi == #ret then
ret[#ret+1] = newtable()
end
local v = options:sub(lc+1, ps-1):match("^%s*(.-)%s*$")
for i=fi+1, #ret do
ret[i].v, ret[i].idx = v, i
end
fi, lc = #ret, ps
5 years ago
until ps == lp
5 months ago
pcache[options] = ret
]=]
ParseRemapBaseUnit = [=[-- Kindred_ParseRemapBaseUnit
local r, unit = false, ...
local s1 = unit:match("^[Tt][Aa][Rr][Gg][Ee][Tt](.*)$")
local s2 = s1 or unit:match("^[Pp][Ee][Tt][Tt][Aa][Rr][Gg][Ee][Tt](.*)$")
local s3 = s2 or unit:match("^[Ff][Oo][Cc][Uu][Ss](.*)$")
baseUnitCache[unit] = s3 and newtable(s1 and "target" or s2 and "pettarget" or s3 and "focus", s3) or false
return s3 ~= nil
5 years ago
]=]
OptionConstruct = [=[-- Kindred_OptionConstruct
5 months ago
local mode, cond, cndLock, futureID = ...
local parse, out, outv = pcache[cond] or owner:Run(OptionParse, cond) or pcache[cond]
local cndLockUnchecked, modKeyState, buttonOverride = true
5 months ago
local cvk = mode == "eval" and "idx" or "v"
local fum = futureID and (_shadowFUM or fumOwner == futureID and futureUnitMap)
for i=1,#parse do
local chunk, clause, cnext, chunkv = parse[i], "", ""
local target, ts = chunk.target, chunk.targetS
while unitAlias[target] do target = unitAlias[target] end
target = ts and target and target .. ts or target
local fc = fum and (baseUnitCache[target or "target"] or self:Run(ParseRemapBaseUnit, target) and baseUnitCache[target])
target = fc and fum[fc[1]] and (fum[fc[1]] .. fc[2]) or target
for j=1,#chunk do
local c = chunk[j]
local name, argp, goal, flag = c[1], c[2], c[3], c[4]
if goal == false and (cndType[name] == nil and cndType["no" .. name]) then goal, name = true, "no" .. name end
if cndAlias[name] then name = cndAlias[name] end
if (name == "mod" or name == "btn") and cndLockUnchecked then
if cndLock == nil or (cndLock and type(cndLock) ~= "string") then
cndLock = owner:GetAttribute("cndLock")
cndLock = type(cndLock) == "string" and cndLock
end
5 months ago
buttonOverride = cndLock and cndLock:match(">(.+)$")
cndLockUnchecked = false
end
if name == "mod" then
if modKeyState == nil then
local t = wipe(modStateCache)
t.lalt, t.lshift, t.lctrl, t.lmeta = IsLeftAltKeyDown(), IsLeftShiftKeyDown(), IsLeftControlKeyDown(), IsModifiedClick("LMETA-X")
t.ralt, t.rshift, t.rctrl, t.rmeta = IsRightAltKeyDown(), IsRightShiftKeyDown(), IsRightControlKeyDown(), IsModifiedClick("RMETA-X")
if cndLock then
local a, s, c, m = cndLock:match("^([LRBK.])([LRBK.])([LRBK.])([LRBK.])")
t.lalt, t.ralt = a ~= "K" and (a == "B" or a == "L" or t.lalt), a ~= "K" and (a == "B" or a == "R" or t.ralt)
t.lshift, t.rshift = s ~= "K" and (s == "B" or s == "L" or t.lshift), s ~= "K" and (s == "B" or s == "R" or t.rshift)
t.lctrl, t.rctrl = c ~= "K" and (c == "B" or c == "L" or t.lctrl), c ~= "K" and (c == "B" or c == "R" or t.rctrl)
t.lmeta, t.rmeta = m ~= "K" and (m == "B" or m == "L" or t.lmeta), m ~= "K" and (m == "B" or m == "R" or t.rmeta)
end
5 months ago
t.alt, t.shift, t.ctrl, t.meta = t.lalt or t.ralt, t.lshift or t.rshift, t.lctrl or t.rctrl, t.lmeta or t.rmeta
t.lcmd, t.rcmd, t.cmd = t.lmeta, t.rmeta, t.meta
t.any, modKeyState = t.alt or t.shift or t.ctrl or t.meta, t
end
local ai, aa, matched, modArg = 1
repeat
aa, ai = argp == nil and "any" or c[2][ai], ai + 1
matched, modArg = true, modArgCache[aa]
if modArg == nil then
local r, a, p = newtable(), aa
for k=2, modTokens[1] do
p = "[rl]?" .. modTokens[k]
for m in a:gmatch(p) do
r[#r+1] = m
end
5 months ago
a = a:gsub(p, "")
end
5 months ago
modArg, modArgCache[aa] = r, r
end
5 months ago
for i=1, #modArg do
if not modKeyState[modArg[i]] then
matched = false
5 years ago
break
end
end
5 months ago
until matched or not argp or ai > #argp
if matched ~= goal then
clause = nil
break
end
elseif name == "btn" and buttonOverride then
local matched = argp == nil
for i=1, matched and 0 or #argp do
if argp[i] == buttonOverride then
matched = true
break
end
5 months ago
end
if matched ~= goal then
clause = nil
break
end
elseif name == "bonusbar" and argp == nil then
if (GetBonusBarIndex() == 0) == goal then
clause = nil
break
end
elseif cndType[name] == nil then
clause, cnext = clause .. cnext .. c[0], ","
else
local cres, ctype = false, cndType[name]
if ctype == "state" then
local cs, cval = cndState[name]
if argp == nil then
cval = cs and cs["*"] or false
else
for k=1,cs and #argp or 0 do
if cs[argp[k]] then
cval = true
break
5 years ago
end
end
5 months ago
cval = cval or (argp[0] and not (cs and cs["*"]))
end
cres = (not not cval) == goal
elseif ctype == "gt" then
local cs, cval = cndState[name]
if argp == nil then
cval = not not cs
elseif cs then
for k=1,#argp do
local n = tonumber(argp[k])
if n and n <= cs then
cval = true
break
5 years ago
end
end
5 months ago
end
cres = (not not cval) == goal
elseif ctype == "srun" then
local s, dv = cndState[name]
if type(s) == "string" then
cres = sandbox:Run(s, c[5], target, c[4])
elseif _shadowES and _shadowES[name] then
cres = _shadowES[name](name, c[5], target, c[4], futureID)
elseif s then
cres, dv = s:RunAttribute("EvaluateMacroConditional", name, c[5], target, c[4], futureID)
if cres == nil and dv == "use-scop" then
clause, cnext = clause .. cnext .. c[0], ","
cres = goal
5 years ago
end
end
5 months ago
cres = (not not cres) == goal
elseif ctype == "irun" then
local markType = c[4]
if isInLockdown then
cres = markType == "+"
elseif _shadowES and _shadowES[name] then
cres = (not not _shadowES[name](name, c[5], target, markType, futureID)) == goal
else
self:CallMethod("irun", name, c[5], target, markType)
cres = (not not self:GetAttribute("irun-result")) == goal
5 years ago
end
end
5 months ago
if not cres then
clause = nil
5 years ago
break
end
end
end
5 months ago
if clause then
clause, chunkv = "[" .. (target and "@" .. target .. cnext .. clause or clause) .. "]", chunk[cvk]
if outv == chunkv then
out = out .. clause
elseif clause == "[]" then
out, outv = out and out .. outv .. ";" or "", chunkv
break
else
out, outv = out and out .. outv .. ";" .. clause or clause, chunkv
end
if cnext == "" then
break
end
5 years ago
end
end
5 months ago
out = outv and (out .. outv) or out or "[form:42]"
if mode == "eval" then
local v, ct = SecureCmdOptionParse(out)
local chunk = v and parse[v+0]
if not chunk then return end
local target, ts = chunk.target, chunk.targetS
while unitAlias[target] do target = unitAlias[target] end
target = ts and target and target .. ts or target
return chunk.v, target, ct
end
5 years ago
return out
]=]
RefreshDrivers = [=[-- Kindred_RefreshDrivers
5 years ago
local name = ...
if cndDrivers[name] then
for key, info in pairs(cndDrivers[name]) do
5 months ago
local nv = owner:Run(OptionConstruct, "driver", info[3], false, "driver-construct")
5 years ago
if info[5] ~= nv then
info[5] = nv
5 months ago
RegisterStateDriver(info[1], info[2], nv == "" and "[]" or nv)
5 years ago
end
end
end
]=]
BindingLink_Move = [=[-- Kindred_BindingLink_Move
local ep, key, newValue = nil, ...
5 years ago
local link = bindingDrivers[key]
if not link then return end
ep, newValue = strmatch(newValue or "", "^%s*(!*)%s*(%S.*)$")
newValue = newValue and strmatch(rtgsub(rtgsub(newValue, "\\.", soEscapeSeqToLiteral), "[^%-]+$", bindEscapeMap), "^%s*(%S.-)%s*$") or nil
5 years ago
local up, down, value = link.up, link.down, link.value
if up then
up.down, link.up = down
end
if down then
down.up, link.down = up
end
if value and not up then
bindingKeys[value] = down
if down then
bindProxy:SetBindingClick(down.priority > 0, value, down.target, down.button)
if down.notify then
down.notify:SetAttribute("binding-" .. down.button, value)
5 years ago
end
else
bindProxy:ClearBinding(value)
end
end
link.priority, link.value = link.basePriority + (ep and #ep*1e3 or 0), newValue
if newValue then
local down, up = bindingKeys[newValue]
while down and down.priority > link.priority do
down, up = down.down, down
end
link.down, link.up = down, up
if down then
down.up = link
end
if up then
up.down = link
else
bindingKeys[newValue], link.down = link, down
bindProxy:SetBindingClick(link.priority > 0, newValue, link.target, link.button)
end
if down and down.notify and not up then
down.notify:SetAttribute("binding-" .. down.button, nil)
5 years ago
end
end
if link.notify then
link.notify:SetAttribute("binding-" .. link.button, not link.up and newValue or nil)
5 years ago
end
]=]
]==])
core:SetAttribute("RegisterStateDriver", [=[-- Kindred:RegisterStateDriver(*frame*, "state", "options")
5 years ago
local frame = owner:GetFrameRef("RegisterStateDriver-frame")
owner:SetAttribute("frameref-RegisterStateDriver-frame", nil)
if frame == nil then return owner:CallMethod("throw", 'Set the "RegisterStateDriver-frame" frameref before calling RegisterStateDriver.') end
local drivers, state, values = stateDrivers[frame], ...
local old = drivers and drivers[state]
if old then
drivers[state] = nil
RegisterStateDriver(frame, state, "")
for _, t in pairs(cndDrivers) do
t[old[4]] = nil
end
end
if values and type(state) == "string" and values ~= "" then
local info, key
drivers, info, key = drivers or newtable(), newtable(frame, state, values, nextDriverKey), nextDriverKey
stateDrivers[frame], drivers[state], nextDriverKey = drivers, info, nextDriverKey + 1
local parse = pcache[values] or owner:Run(OptionParse, values) or pcache[values]
5 months ago
local cv = owner:Run(OptionConstruct, "driver", values, false, "driver-construct")
5 years ago
info[5] = cv
5 months ago
RegisterStateDriver(frame, state, cv == "" and "[]" or cv)
for j=1,#parse do
local clause = parse[j]
for k=1,#clause do
local n = clause[k][1]
cndDrivers[n] = cndDrivers[n] or newtable()
cndDrivers[n][key] = info
end
local u = clause.target while u do
local n = "unit:" .. u
cndDrivers[n] = cndDrivers[n] or newtable()
cndDrivers[n][key], u = info, unitAlias[u]
5 years ago
end
end
end
for cnd, info in pairs(driverWatch) do
local cd = cndDrivers[cnd]
local wantWatch = cd and next(cd) ~= nil
if wantWatch and not info[2] then
info[2] = true
owner:SetAttribute("state-" .. cnd, nil)
RegisterStateDriver(owner, cnd, info[1])
elseif old and cd and not wantWatch then
info[2], info[3], cndDrivers[cnd] = false, nil
owner:SetAttribute("state-" .. cnd, nil)
RegisterStateDriver(owner, cnd, "")
end
end
5 years ago
]=])
5 months ago
core:SetAttribute("EvaluateCmdOptions", [=[-- Kindred:EvaluateCmdOptions("options"[, cndLock, futureID])
return owner:Run(OptionConstruct, "eval", ...)
5 years ago
]=])
core:SetAttribute("UpdateThresholdConditional", [=[-- Kindred:UpdateThresholdConditional("name", value or false)
5 years ago
local name, new = ...
if type(name) ~= "string" or (new ~= false and type(new) ~= "number") then
return owner:CallMethod("throw", 'Syntax: ("UpdateThresholdConditional", "name", value or false)')
end
local ch = cndDrivers[name] and (cndType[name] ~= "gt" or cndState[name] ~= new)
cndType[name], cndState[name] = "gt", new
if ch then
owner:Run(RefreshDrivers, name)
end
]=])
core:SetAttribute("UpdateStateConditional", [=[-- Kindred:UpdateStateConditional("name", "addSet", "remSet")
5 years ago
local name, new, kill = ...
local cs = cndState[name] or newtable()
cndType[name], cndState[name] = "state", cs
if kill == "*" then
wipe(cs)
else
for s in (kill and tostring(kill) or ""):lower():gmatch("[^/]+") do
cs[s] = nil
end
cs["*"] = nil
end
for s in (new and tostring(new) or ""):lower():gmatch("[^/]+") do
cs[s] = 1
end
cs["*"] = next(cs) and 2 or nil
if cndDrivers[name] then
owner:Run(RefreshDrivers, name)
end
]=])
core:SetAttribute("SetAliasUnit", [=[-- Kindred:SetAliasUnit("alias", "unit" or nil)
5 years ago
local alias, unit = ...
if unitAlias[alias] == unit then
return
elseif not (type(alias) == "string" and (type(unit) == "string" or unit == nil)) then
return owner:CallMethod("throw", 'Syntax: ("SetAliasUnit", "alias", "unit" or nil)')
end
local u = unit while unitAlias[u] and u ~= alias do u = unitAlias[u] end
if u == alias then
return owner:CallMethod("throw", ('Kindred:SetUnitAlias: would create a loop aliasing to %q'):format(alias))
end
unitAlias[alias] = unit
owner:Run(RefreshDrivers, "unit:" .. alias)
]=])
5 months ago
core:SetAttribute("ResolveUnit", [=[-- Kindred:ResolveUnit("unit"[, futureID])
local unit, futureID = ...
local fum = futureID and (_shadowFUM or fumOwner == futureID and futureUnitMap)
5 years ago
if type(unit) ~= "string" then
5 months ago
return owner:CallMethod("throw", 'Syntax: ("ResolveUnit", "unit"[, futureID])')
elseif fum and fum[unit] then
unit, fum = fum[unit], nil
5 years ago
end
5 months ago
local ua, usuf = unit:match("^([^-%d]*%d*)(.-)$")
while unitAlias[ua] do ua = unitAlias[ua] end
ua = ua and usuf and ua .. usuf or unit
local fc = fum and (baseUnitCache[ua] or self:Run(ParseRemapBaseUnit, ua) and baseUnitCache[ua])
if fc and fum[fc[1]] then
ua = fum[fc[1]] .. fc[2]
5 years ago
end
5 months ago
return ua
5 years ago
]=])
core:SetAttribute("PokeConditional", [=[-- Kindred:PokeConditional("name")
5 years ago
owner:Run(RefreshDrivers, (...))
]=])
core:SetAttribute("RegisterBindingDriver", [=[-- Kindred:RegisterBindingDriver(*target*, "button", "options", priority[, *notify*])
5 years ago
local target, notify, button, options, priority = self:GetFrameRef("RegisterBindingDriver-target"), self:GetFrameRef("RegisterBindingDriver-notify"), ...
self:SetAttribute("frameref-RegisterStateDriver-target", nil)
self:SetAttribute("frameref-RegisterStateDriver-notify", nil)
if not target then return owner:CallMethod("throw", 'Set the "RegisterStateDriver-target" frameref before calling RegisterStateDriver.') end
if type(options) ~= "string" then return owner:CallMethod("throw", 'Kindred:RegisterBindingDriver: options argument must be a string.') end
if options == "" and not (bindingDrivers[target] and bindingDrivers[target][button]) then return end
5 years ago
bindingDrivers[target] = bindingDrivers[target] or newtable()
local driver = bindingDrivers[target][button] or newtable()
if driver.id then
bindProxy:SetAttribute("state-" .. driver.id, nil)
else
nextBindingKey, driver.id, driver.target, driver.button = nextBindingKey + 1, "bind" .. nextBindingKey, target, button
5 years ago
bindingDrivers[target][button], bindingDrivers[driver.id] = driver, driver
end
driver.priority, driver.basePriority, driver.notify = priority, priority, notify
5 years ago
self:SetAttribute("frameref-RegisterStateDriver-frame", bindProxy)
self:RunAttribute("RegisterStateDriver", driver.id, options:match("[^;%s]%s*$") and options .. ";" or options)
5 years ago
]=])
core:SetAttribute("UnregisterBindingDriver", [=[-- Kindred:UnregisterBindingDriver(*target*, "button")
5 years ago
local target, button = self:GetFrameRef("UnregisterBindingDriver-target"), ...
self:SetAttribute("frameref-UnregisterBindingDriver-target", nil)
if not target then return owner:CallMethod("throw", 'Set the "UnregisterBindingDriver-target" frameref before calling UnregisterBindingDriver.') end
local drivers = bindingDrivers[target]
local driver = drivers and drivers[button]
if driver then
bindProxy:SetAttribute("state-" .. driver.id, nil)
self:SetAttribute("frameref-RegisterStateDriver-frame", bindProxy)
self:RunAttribute("RegisterStateDriver", driver.id, "")
drivers[button], bindingDrivers[driver.id] = nil
if not next(drivers) then
bindingDrivers[target] = nil
end
end
]=])
core:SetAttribute("ComputeConditionalLock", [=[-- Kindred:ComputeConditionalLock("bind"[, clickButton, "modState"])
local bind, clickButton, modState = ...
if not modState then
modState = modHoldMap[(IsLeftAltKeyDown() and 2 or 1) + (IsRightAltKeyDown() and 2 or 0)] ..
modHoldMap[(IsLeftShiftKeyDown() and 2 or 1) + (IsRightShiftKeyDown() and 2 or 0)] ..
modHoldMap[(IsLeftControlKeyDown() and 2 or 1) + (IsRightControlKeyDown() and 2 or 0)] ..
modHoldMap[(IsModifiedClick("LMETA-X") and 2 or 1) + (IsModifiedClick("RMETA-X") and 2 or 0)]
end
if clickButton == nil or clickButton == true then
clickButton = SecureCmdOptionParse("[btn:1] 1; [btn:2] 2; [btn:3] 3; [btn:4] 4; [btn:5] 5; 1")
end
local lock = modState
if bind and type(bind) == "string" then
lock = lock:gsub("^(.)(.)(.)(.)", (bind:match("ALT%-") and "K" or "%1") .. (bind:match("SHIFT%-") and "K" or "%2") .. (bind:match("CTRL%-") and "K" or "%3") .. (bind:match("META%-") and "K" or "%4"))
end
return clickButton and (lock .. ">" .. clickButton) or lock, modState
]=])
core:SetAttribute("UnescapeCmdOptionsValue", [=[-- Kindred:UnescapeCmdOptionsValue("str"])
local s = ...
return s and rtgsub(s, "\\.", soEscapeSeqToLiteral)
]=])
5 months ago
core:SetAttribute("StartFuture", [=[-- Kindred:StartFuture(futureID)
local futureID = ...
fumOwner = futureID
wipe(futureUnitMap)
]=])
core:SetAttribute("ReleaseFuture", [=[-- Kindred:ReleaseFuture(futureID)
if fumOwner == ... then
fumOwner = nil
wipe(futureUnitMap)
end
]=])
core:SetAttribute("SetFutureUnit", [=[-- Kindred:SetFutureUnit(futureID, "unit", "newunit")
local futureID, unit, newunit = ...
local fum = futureRemappableUnits[unit] and (_shadowFUM or futureID == fumOwner and futureUnitMap)
if fum then
local nu = newunit == "--clear" and "raid41" or self:RunAttribute("ResolveUnit", newunit, futureID)
local ot = unit == "target" and (fum[unit] or "target")
if ot and UnitExists(ot) then
local react = SecureCmdOptionParse("[@" .. ot .. ",harm] --last-enemy-target; [@" .. ot .. ",help] --last-friend-target; --last-void-target")
fum["--last-target"], fum[react] = ot, ot
end
fum[unit] = (nu == "raid41" or UnitExists(nu)) and nu or fum[unit] or nil
end
]=])
core:SetAttribute("ResolveUnitAlias", [=[-- DEPRECATED Kindred:ResolveUnitAlias("unit")
return self:RunAttribute("ResolveUnit", ..., nil)
]=])
core:SetAttribute("_onstate-lockdown", [[-- Kindred:SyncLockdownState
5 months ago
if newstate ~= nil then
isInLockdown = newstate
end
if isInLockdown then
return
end
for k in pairs(cndInsecure) do
if cndType[k] ~= "irun" then
cndInsecure[k] = nil
elseif cndDrivers[k] then
owner:Run(RefreshDrivers, k)
5 years ago
end
end
]])
core:SetAttribute("_onstate-mod", [[-- Kindred:SyncModifierState
if not newstate then return end
newstate = newstate ~= "on" and 0 or 0
+ (IsLeftAltKeyDown() and 1 or 0) + (IsRightAltKeyDown() and 2 or 0)
+ (IsLeftShiftKeyDown() and 4 or 0) + (IsRightShiftKeyDown() and 8 or 0)
+ (IsLeftControlKeyDown() and 16 or 0) + (IsRightControlKeyDown() and 32 or 0)
+ (IsModifiedClick("LMETA-X") and 64 or 0) + (IsModifiedClick("RMETA-X") and 128 or 0)
if newstate > 0 then
self:SetAttribute("state-mod", nil)
end
if driverWatch[stateid][3] ~= newstate then
driverWatch[stateid][3] = newstate
owner:Run(RefreshDrivers, "mod")
end
]])
core:SetAttribute("_onstate-bonusbar", [[-- Kindred:SyncBonusBarState
if not newstate then return end
if driverWatch[stateid][3] ~= newstate then
driverWatch[stateid][3] = newstate
owner:Run(RefreshDrivers, "bonusbar")
end
]])
5 months ago
local function syncLockdown(e)
-- Not a StateDriver: grace expires before SSDM updates
core:SetAttribute("state-lockdown", e == "PLAYER_REGEN_DISABLED")
end
EV.PLAYER_REGEN_DISABLED, EV.PLAYER_REGEN_ENABLED = syncLockdown, syncLockdown
function core:throw(err)
return error(err, 2)
5 years ago
end
5 months ago
local function RunCoreAttribute(an, ...)
return WareRun(coreEnvW, core:GetAttribute(an), ...)
end
local PackDefer do
local execQueue, cPack = {}
local function execPack()
return KR[cPack[1]](KR, unpack(cPack, 3, 2+cPack[2]))
5 years ago
end
function PackDefer(key, method, ...)
execQueue[key] = {method, select("#", ...), ...}
end
function EV:PLAYER_REGEN_ENABLED()
for k,v in pairs(execQueue) do
cPack, execQueue[k] = v, nil
securecall(execPack)
end
cPack = nil
5 years ago
end
end
5 years ago
5 months ago
local soEscapeSeqToLiteral = WR.GetBackingRestrictedTable(coreEnvW).soEscapeSeqToLiteral
local SetExternalShadow, RunShadowAttribute, WipeShadowFuture do
local ShadowEnvironment, ShadowRun do
local fcache, _R, _ENV, _FRAME = {}, {next=rtable.next, pairs=rtable.pairs, newtable=function(...) return {...} end}, {}, {}
5 years ago
local _shadow = {__index=function(t,k)
local v = _ENV[t] and _ENV[t][k]
if v == nil then
v = _R[k] or _G[k]
elseif type(v) == "userdata" then
v = IsFrameHandle(v) and ShadowEnvironment(GetFrameHandleFrame(v)) or setmetatable({}, {__index=v})
t[k] = v
end
return v
end}
5 months ago
function ShadowRun(self, f, ...)
local v = fcache[f] or loadstring(("-- shadow:%s\nreturn function(self, ...)\n%s\nend"):format(tostring(f):match("^[%s%-]*([^\n]*)"), f))()
5 years ago
fcache[f] = setfenv(v, _ENV[self])
return securecall(v, self, ...)
end
local function ShadowGetAttribute(self, ...)
return _FRAME[self]:GetAttribute(...)
end
5 months ago
local function ShadowRunAttribute(self, a, ...)
local c = _FRAME[self]:GetAttribute(a)
return ShadowRun(self, c, ...)
end
5 years ago
function ShadowEnvironment(h)
5 months ago
local e = _ENV[h] or setmetatable({owner={Run=ShadowRun, GetAttribute=ShadowGetAttribute, RunAttribute=ShadowRunAttribute}}, _shadow)
_ENV[h], _ENV[e], _ENV[e.owner], _FRAME[e.owner] = e, GetManagedEnvironment(h), e, h
5 years ago
return e.owner, e
end
end
5 months ago
local sFUM, _core, _env = {}, ShadowEnvironment(core)
_env._shadowES, _env._shadowFUM = {}, sFUM
function RunShadowAttribute(name, ...)
5 months ago
return securecall(ShadowRun, _core, core:GetAttribute(name), ...)
end
5 years ago
function SetExternalShadow(name, func)
_env._shadowES[name] = func
end
function core:irun(...)
self:SetAttribute("irun-result", _env._shadowES[...](...))
end
5 months ago
function WipeShadowFuture()
wipe(sFUM)
end
5 years ago
end
function KR:ClearConditional(name)
assert(type(name) == "string", 'Syntax: Kindred:ClearConditional("name")')
if InCombatLockdown() then return PackDefer(name, "ClearConditional", name) end
5 months ago
coreEnvW.cndAlias[name], coreEnvW.cndType[name], coreEnvW.cndState[name], coreEnvW.cndInsecure[name] = nil
WareRun(coreEnvW, coreEnvW.RefreshDrivers, name)
5 years ago
end
function KR:SetStateConditionalValue(name, value)
if type(value) == "boolean" then value = value and "*" or "" end
assert(type(name) == "string" and type(value) == "string", 'Syntax: Kindred:SetStateConditionalValue("name", "value")')
if InCombatLockdown() then return PackDefer(name, "SetStateConditionalValue", name, value) end
5 months ago
RunCoreAttribute("UpdateStateConditional", name, value, "*")
5 years ago
end
function KR:SetThresholdConditionalValue(name, value)
assert(type(name) == "string" and (value == false or type(value) == "number"), 'Syntax: Kindred:SetThresholdConditionalValue("name", value or false)')
if InCombatLockdown() then return PackDefer(name, "SetThresholdConditionalValue", name, value) end
5 months ago
RunCoreAttribute("UpdateThresholdConditional", name, value)
5 years ago
end
function KR:SetSecureExecConditional(name, snippet)
assert(type(name) == "string" and type(snippet) == "string", 'Syntax: Kindred:SetSecureExecConditional("name", "snippet")')
if InCombatLockdown() then return PackDefer(name, "SetSecureExecConditional", name, snippet) end
5 months ago
coreEnvW.cndType[name], coreEnvW.cndState[name] = "srun", snippet
WareRun(coreEnvW, coreEnvW.RefreshDrivers, name)
5 years ago
end
function KR:SetSecureExternalConditional(name, handler, hint)
assert(type(name) == "string" and type(handler) == "table" and handler[0] and type(hint) == "function", 'Syntax: Kindred:SetSecureExternalConditional("name", handlerFrame, hintFunc)')
assert(handler.IsProtected and select(2,handler:IsProtected()) and handler:GetAttribute("EvaluateMacroConditional"), "Handler frame must be explicitly protected; must have EvaluateMacroConditional attribute set")
if InCombatLockdown() then return PackDefer(name, "SetSecureExternalConditional", name, handler, hint) end
5 months ago
coreEnvW.cndType[name], coreEnvW.cndState[name] = handler and "srun", handler
WareRun(coreEnvW, coreEnvW.RefreshDrivers, name)
5 years ago
SetExternalShadow(name, hint)
end
function KR:SetNonSecureConditional(name, handler)
assert(type(name) == "string" and type(handler) == "function", 'Syntax: Kindred:SetNonSecureConditional("name", handlerFunc)')
if InCombatLockdown() then return PackDefer(name, "SetNonSecureConditional", name, handler) end
5 months ago
coreEnvW.cndType[name], coreEnvW.cndInsecure[name], coreEnvW.cndState[name] = "irun", true
WareRun(coreEnvW, coreEnvW.RefreshDrivers, name)
5 years ago
SetExternalShadow(name, handler)
end
function KR:SetAliasConditional(name, aliasFor)
assert(type(name) == "string" and type(aliasFor) == "string", 'Syntax: Kindred:SetAliasConditional("name", "aliasFor")')
if InCombatLockdown() then return PackDefer(name, "SetAliasConditional", name, aliasFor) end
5 months ago
coreEnvW.cndAlias[name] = aliasFor
WareRun(coreEnvW, coreEnvW.RefreshDrivers, name)
5 years ago
end
function KR:SetAliasUnit(alias, unit)
assert(type(alias) == "string" and (type(unit) == "string" or unit == nil), 'Syntax: Kindred:SetAliasUnit("alias", "unit" or nil)')
if InCombatLockdown() then return PackDefer("_alias-" .. alias, "SetAliasUnit", alias, unit) end
5 months ago
RunCoreAttribute("SetAliasUnit", alias, unit)
5 years ago
end
function KR:PokeConditional(name)
assert(type(name) == "string", 'Syntax: Kindred:PokeConditional("name")')
if InCombatLockdown() then return PackDefer("_poke-" .. name, "PokeConditional", name) end
5 months ago
WareRun(coreEnvW, coreEnvW.RefreshDrivers, name)
5 years ago
end
function KR:EvaluateCmdOptions(options, ...)
5 months ago
return RunShadowAttribute("EvaluateCmdOptions", options, ...)
5 years ago
end
5 months ago
function KR:ResolveUnit(unit, futureID)
return RunShadowAttribute("ResolveUnit", unit, futureID) or unit
end
function KR:UnescapeCmdOptionsValue(str)
return str and rtgsub(str, "\\.", soEscapeSeqToLiteral)
end
5 months ago
function KR:SetFutureUnit(futureID, unit, newunit)
return RunShadowAttribute("SetFutureUnit", futureID, unit, newunit)
end
function KR:ClearFuture(_futureID)
WipeShadowFuture()
end
5 years ago
function KR:RegisterStateDriver(frame, state, values)
assert(type(frame) == "table" and type(state) == "string" and (values == nil or type(values) == "string"), 'Syntax: Kindred:RegisterStateDriver(frame, "state"[, "values"])')
if InCombatLockdown() then return PackDefer("_sd-" .. #state .. ":" .. state .. tostring(frame), "RegisterStateDriver", frame, state, values) end
5 years ago
core:SetFrameRef("RegisterStateDriver-frame", frame)
5 months ago
RunCoreAttribute("RegisterStateDriver", state, values or "")
5 years ago
end
function KR:RegisterBindingDriver(target, button, options, priority, notify)
assert(type(target) == "table" and type(button) == "string" and type(options) == "string", 'Syntax: Kindred:RegisterBindingDriver(targetButton, "button", "options", priority, notifyFrame)')
assert(not notify or type(notify) == "table" and notify:IsProtected(), "If specified, notifyFrame must be a protected frame.")
assert(type(priority or 0) == "number", "Binding priority must be a number")
if InCombatLockdown() then return PackDefer("_bd-" .. #button .. ":" .. button .. tostring(target), "RegisterBindingDriver", target, button, options, priority, notify) end
core:SetOptFrameRef("RegisterBindingDriver-notify", notify)
core:SetFrameRef("RegisterBindingDriver-target", target)
5 months ago
RunCoreAttribute("RegisterBindingDriver", button, options, priority or 0)
5 years ago
end
function KR:UnregisterBindingDriver(target, button)
assert(type(target) == "table" and type(button) == "string", 'Syntax: Kindred:UnregisterBindingDriver(targetButton, "button")')
if InCombatLockdown() then return PackDefer("_bd-" .. #button .. ":" .. button .. tostring(target), "UnregisterBindingDriver", target, button) end
core:SetFrameRef("UnregisterBindingDriver-target", target)
5 months ago
RunCoreAttribute("UnregisterBindingDriver", button)
5 years ago
end
function KR:seclib()
return core
end
function KR:compatible(cmaj, crev)
return (cmaj == MAJ and crev <= REV) and KR or nil, MAJ, REV
end
5 months ago
function KR:ResolveUnitAlias(unit) -- DEPRECATED
return RunShadowAttribute("ResolveUnit", unit, nil) or unit
end
5 years ago
KR:SetAliasConditional("modifier", "mod")
KR:SetAliasConditional("button", "btn")
T.Kindred = {compatible=KR.compatible}