Bastion aims to serve as a highly performant, simplisitic, and expandable World of Warcraft data visualization framework.
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.
Bastion/src/APL/APL.lua

226 lines
5.7 KiB

---@type Tinkr, Bastion
local Tinkr, Bastion = ...
-- APL (Attack priority list) class
---@class Bastion.APL
---@field apl Bastion.APLActor[]
---@field variables table<string, any>
---@field name string
---@field last { successful: { name: string, time: number, index: number }, attempted: { name: string, time: number, index: number } }
local APL = {}
APL.__index = APL
-- Constructor
---@param name string
---@return Bastion.APL
function APL:New(name)
local self = setmetatable({}, APL)
self.apl = {}
self.variables = {}
self.name = name
self.last = {
successful = {
name = "",
time = -1,
index = -1,
},
attempted = {
name = "",
time = -1,
index = -1,
},
}
return self
end
-- Add a variable to the APL
---@param name string
---@param value any
function APL:SetVariable(name, value)
self.variables[name] = value
end
-- Get and evaluate a variable
---@param name string
---@return boolean
function APL:GetVariable(name)
return self.variables[name]
end
---@class Bastion.APL.Actor.Variable.Table : Bastion.APLActor.Table.Base
---@field variable string
---@field cb fun(...):any
---@field _apl Bastion.APL
-- Add variable
---@param name string
---@param cb fun(...):any
---@return Bastion.APLActor
function APL:AddVariable(name, cb)
local actor = Bastion.APLActor:New({
type = "variable",
variable = name,
cb = cb,
_apl = self,
})
table.insert(self.apl, actor)
return actor
end
---@class Bastion.APL.Actor.Action.Table : Bastion.APLActor.Table.Base
---@field action string
---@field cb fun(...):any
-- Add a manual action to the APL
---@param action string
---@param cb fun(...):any
---@return Bastion.APLActor
function APL:AddAction(action, cb)
local actor = Bastion.APLActor:New({
type = "action",
action = action,
cb = cb,
})
table.insert(self.apl, actor)
return actor
end
---@class Bastion.APL.Actor.Spell.Table : Bastion.APLActor.Table.Base
---@field spell Bastion.Spell
---@field condition? string|fun(self: Bastion.Spell): boolean
---@field castableFunc false | fun(self: Bastion.Spell): boolean
---@field target Bastion.Unit | false
---@field onCastFunc false | fun(self: Bastion.Spell):any
-- Add a spell to the APL
---@param spell Bastion.Spell
---@param condition? string|fun(self: Bastion.Spell):boolean
---@return Bastion.APLActor
function APL:AddSpell(spell, condition)
local castableFunc = spell.CastableIfFunc
local onCastFunc = spell.OnCastFunc
local target = spell:GetTarget()
local actor = Bastion.APLActor:New({
type = "spell",
spell = spell,
condition = condition,
castableFunc = castableFunc,
target = target,
onCastFunc = onCastFunc,
})
table.insert(self.apl, actor)
return actor
end
---@class Bastion.APL.Actor.Item.Table : Bastion.APLActor.Table.Base
---@field item Bastion.Item
---@field condition? string | fun(self: Bastion.Item): boolean
---@field usableFunc false | fun(...): boolean
---@field target Bastion.Unit | nil
-- Add an item to the APL
---@param item Bastion.Item
---@param condition? string | fun(self: Bastion.Item): boolean
---@return Bastion.APLActor
function APL:AddItem(item, condition)
local usableFunc = item.UsableIfFunc
local target = item:GetTarget()
local actor = Bastion.APLActor:New({
type = "item",
item = item,
condition = condition,
usableFunc = usableFunc,
target = target,
})
table.insert(self.apl, actor)
return actor
end
---@class Bastion.APL.Actor.APL.Table : Bastion.APLActor.Table.Base
---@field apl Bastion.APL
---@field condition? fun(...):boolean
-- Add an APL to the APL (for sub APLs)
---@param apl Bastion.APL
---@param condition fun(...):boolean
---@return Bastion.APLActor
function APL:AddAPL(apl, condition)
if not condition then
error("Bastion: APL:AddAPL: No condition for APL " .. apl.name)
end
local actor = Bastion.APLActor:New({
type = "apl",
apl = apl,
condition = condition,
})
table.insert(self.apl, actor)
return actor
end
---@param name string
---@param enabled? boolean
function APL:ToggleAPL(name, enabled)
for _, actor in ipairs(self.apl) do
if actor.actor.type == "apl" and actor.name == name then
actor.enabled = type(enabled) == "boolean" and enabled or not actor.enabled
break
end
end
end
function APL:UpdateLastAttempted(name, index)
self.last.attempted.name = name
self.last.attempted.time = GetTime()
self.last.attempted.index = index
end
function APL:UpdateLastSuccessful(name, index)
self.last.successful.name = name
self.last.successful.time = GetTime()
self.last.successful.index = index
end
-- Execute the APL
function APL:Execute()
for i, actor in ipairs(self.apl) do
self:UpdateLastAttempted(actor.name, i)
if actor.enabled and (not actor:HasTraits() or actor:Evaluate()) and actor:Execute() then
self:UpdateLastSuccessful(actor.name, i)
return true
end
end
end
---@class Bastion.APL.Actor.Sequencer.Table : Bastion.APLActor.Table.Base
---@field sequencer Bastion.Sequencer
---@field condition? fun(...):boolean
-- Add a Sequencer to the APL
---@param sequencer Bastion.Sequencer
---@param condition fun(...):boolean
---@return Bastion.APLActor
function APL:AddSequence(sequencer, condition)
local actor = Bastion.APLActor:New({
type = "sequencer",
sequencer = sequencer,
condition = condition,
})
table.insert(self.apl, actor)
return actor
end
-- tostring
---@return string
function APL:__tostring()
return "Bastion.__APL(" .. self.name .. ")"
end
return APL