Various updates to types.

main
ck 1 year ago
parent 46f2f1381d
commit d69fd5d46a
  1. 5
      .editorconfig
  2. 67
      src/APL/APL.lua
  3. 8
      src/Aura/Aura.lua
  4. 2
      src/AuraTable/AuraTable.lua
  5. 6
      src/Cacheable/Cacheable.lua
  6. 45
      src/EventManager/EventManager.lua
  7. 30
      src/List/List.lua
  8. 8
      src/ObjectManager/ObjectManager.lua
  9. 5
      src/Refreshable/Refreshable.lua
  10. 23
      src/Spell/Spell.lua
  11. 277
      src/Unit/Unit.lua
  12. 39
      src/UnitManager/UnitManager.lua
  13. 38
      src/Vector3/Vector3.lua
  14. 8
      src/_bastion.lua
  15. 10
      stylua.toml

@ -4,6 +4,11 @@
root = true
[*.lua]
indent_type = Spaces
column_width = 180
indent_width = 4
quote_style = AutoPreferDouble
call_parentheses = Always
indent_style = space
indent_size = 4
end_of_line = lf

@ -45,6 +45,7 @@ end
---@class APLActor
---@field actor APLActorTable
---@field traits APLTrait[]
---@field name string
local APLActor = {}
APLActor.__index = APLActor
@ -52,7 +53,21 @@ APLActor.__index = APLActor
---@param actor APLActorTable
function APLActor:New(actor)
local self = setmetatable({}, APLActor)
if actor.type == "spell" then
self.name = string.format("[%s] `%s`<%s>", actor.type, actor.spell:GetName(), actor.spell:GetID())
elseif actor.type == "item" then
self.name = string.format("[%s] `%s`<%s>", actor.type, actor.item:GetName(), actor.item:GetID())
elseif actor.type == "apl" then
self.name = string.format("[%s] `%s`", actor.type, actor.apl.name)
elseif actor.type == "sequencer" then
self.name = string.format("[%s]", actor.type)
elseif actor.type == "variable" then
self.name = string.format("[%s] `%s`", actor.type, actor.variable)
elseif actor.type == "action" then
self.name = string.format("[%s] `%s`", actor.type, actor.action)
else
self.name = string.format("[%s] Unknown", actor.type)
end
self.actor = actor
self.traits = {}
@ -120,31 +135,11 @@ function APLActor:Execute()
end
if actorTable.type == "spell" then
---@cast actorTable APLActorSpellTable
return actorTable.spell
:CastableIf(actorTable.castableFunc)
:OnCast(actorTable.onCastFunc)
:Cast(actorTable.target, actorTable.condition)
--[[ if actorTable.condition then
-- print("Bastion: APL:Execute: Condition for spell " .. actorTable.spell:GetName())
actorTable.spell
:CastableIf(actorTable.castableFunc)
:OnCast(actorTable.onCastFunc)
:Cast(actorTable.target, actorTable.condition)
else
-- print("Bastion: APL:Execute: No condition for spell " .. actorTable.spell:GetName())
actorTable.spell:CastableIf(actorTable.castableFunc):OnCast(actorTable.onCastFunc):Cast(actorTable.target)
end ]]
return actorTable.spell:CastableIf(actorTable.castableFunc):OnCast(actorTable.onCastFunc):Cast(actorTable.target, actorTable.condition)
end
if actorTable.type == "item" then
---@cast actorTable APLActorItemTable
return actorTable.item:UsableIf(actorTable.usableFunc):Use(actorTable.target, actorTable.condition)
--[[ if actorTable.condition and type(actorTable.condition) == "string" then
-- print("Bastion: APL:Execute: Condition for spell " .. actorTable.spell:GetName())
actorTable.item:UsableIf(actorTable.usableFunc):Use(actorTable.target, actorTable.condition)
else
-- print("Bastion: APL:Execute: No condition for spell " .. actorTable.spell:GetName())
actorTable.item:UsableIf(actorTable.usableFunc):Use(actorTable.target)
end ]]
end
if actorTable.type == "action" then
---@cast actorTable APLActorActionTable
@ -168,7 +163,7 @@ end
-- tostring
---@return string
function APLActor:__tostring()
return "Bastion.__APLActor"
return string.format("Bastion.__APLActor(%s)", self.name)
end
-- APL (Attack priority list) class
@ -176,6 +171,7 @@ end
---@field apl 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
@ -188,6 +184,7 @@ function APL:New(name)
self.apl = {}
self.variables = {}
self.name = name
self.last = {}
return self
end
@ -282,7 +279,7 @@ end
-- Add an item to the APL
---@param item Item
---@param condition? string
---@param condition? string | fun(self: Item): boolean
---@return APLActor
function APL:AddItem(item, condition)
local usableFunc = item.UsableIfFunc
@ -324,17 +321,19 @@ end
-- Execute the APL
function APL:Execute()
for _, actor in ipairs(self.apl) do
if actor:HasTraits() then
if actor:Evaluate() and actor:Execute() then
for i, actor in ipairs(self.apl) do
self.last.attempted = {
name = actor.name,
time = GetTime(),
index = i,
}
if (not actor:HasTraits() or actor:Evaluate()) and actor:Execute() then
self.last.successful = {
name = actor.name,
time = GetTime(),
index = i,
}
return true
--break
end
else
if actor:Execute() then
return true
--break
end
end
end
end

@ -266,7 +266,7 @@ function Aura:GetRemainingTime()
end
function Aura:GetElapsedPercent()
return ((self:GetDuration() - self:GetRemainingTime()) / self:GetDuration()) * 100
return self:IsValid() and ((self:GetDuration() - self:GetRemainingTime()) / self:GetDuration()) * 100 or 0
end
-- Get the auras expiration time
@ -350,11 +350,7 @@ end
-- Check if the aura is dispelable by a spell
---@param spell Spell
function Aura:IsDispelableBySpell(spell)
if
(self:GetDispelType() == "" or self:GetDispelType() == nil)
and self:GetIsStealable()
and spell:IsEnrageDispel()
then
if (self:GetDispelType() == "" or self:GetDispelType() == nil) and self:GetIsStealable() and spell:IsEnrageDispel() then
return true
end

@ -104,7 +104,7 @@ function AuraTable:AddOrUpdateAuraInstanceID(instanceID, aura)
self.instanceIDLookup[instanceID] = spellId
if Bastion.UnitManager["player"]:IsUnit(aura:GetSource()) then
if Bastion.UnitManager["player"] and Bastion.UnitManager["player"]:IsUnit(aura:GetSource()) then
if not self.playerAuras[spellId] then
self.playerAuras[spellId] = {}
end

@ -40,8 +40,10 @@ function Cacheable:__tostring()
end
-- Create
---@param value any
---@param cb fun():any
---@generic V: Cacheable, V
---@param value V
---@param cb fun(): V
---@return V
function Cacheable:New(value, cb)
local self = setmetatable({}, Cacheable)

@ -7,11 +7,14 @@ local Tinkr, Bastion = ...
---@field events table<string, { [number]: fun(...) }>
---@field eventHandlers table<string, { [number]: fun(...) }>
---@field wowEventHandlers table<string, { [number]: fun(...) }>
---@field selfCLEUHandlers table<string, { [number]: fun(...) }>
---@field selfCombatEventHandlers table<string, { [number]: fun(...) }>
---@field CombatEventHandlers table<string, { [number]: fun(...) }>
local EventManager = {
events = {},
eventHandlers = {},
wowEventHandlers = {},
selfCombatEventHandlers = {},
CombatEventHandlers = {},
frame = nil,
}
EventManager.__index = EventManager
@ -23,7 +26,8 @@ function EventManager:New()
self.events = {}
self.eventHandlers = {}
self.wowEventHandlers = {}
self.selfCLEUHandlers = {}
self.selfCombatEventHandlers = {}
self.CombatEventHandlers = {}
-- Frame for wow events
self.frame = CreateFrame("Frame")
@ -93,21 +97,31 @@ end
---@param subevent string | string[]
---@param handler fun(...)
function EventManager:RegisterSelfCLEUEvent(subevent, handler)
if type(subevent) == "table" then
function EventManager:RegisterSelfCombatEvent(subevent, handler)
if type(subevent) == "string" then
subevent = { subevent }
end
for _, e in ipairs(subevent) do
if not self.selfCLEUHandlers[e] then
self.selfCLEUHandlers[e] = {}
if not self.selfCombatEventHandlers[e] then
self.selfCombatEventHandlers[e] = {}
end
table.insert(self.selfCLEUHandlers[e], handler)
table.insert(self.selfCombatEventHandlers[e], handler)
end
else
if not self.selfCLEUHandlers[subevent] then
self.selfCLEUHandlers[subevent] = {}
end
table.insert(self.selfCLEUHandlers[subevent], handler)
---@param subevent string | string[]
---@param handler fun(...)
function EventManager:RegisterCombatEvent(subevent, handler)
if type(subevent) == "string" then
subevent = { subevent }
end
for _, e in ipairs(subevent) do
if not self.CombatEventHandlers[e] then
self.CombatEventHandlers[e] = {}
end
table.insert(self.CombatEventHandlers[e], handler)
end
end
@ -116,12 +130,15 @@ end
---@param subevent string
---@param ... any
function EventManager:CLEUHandler(event, timestamp, subevent, ...)
if self.selfCLEUHandlers[subevent] then
if select(2, ...) == UnitGUID("player") then
for _, handler in pairs(self.selfCLEUHandlers[subevent]) do
if self.selfCombatEventHandlers[subevent] and select(2, ...) == UnitGUID("player") then
for _, handler in pairs(self.selfCombatEventHandlers[subevent]) do
handler(timestamp, subevent, ...)
end
end
if self.CombatEventHandlers[subevent] then
for _, handler in pairs(self.CombatEventHandlers[subevent]) do
handler(timestamp, subevent, ...)
end
end
end

@ -1,4 +1,6 @@
---@class List
---@operator add(any): List
---@operator sub(any): List
local List = {
-- Add overload
---@param self List
@ -54,7 +56,8 @@ function List:clear()
self._list = {}
end
---@param value any
---@generic I : any
---@param value I
---@return boolean
function List:contains(value)
for _, v in ipairs(self._list) do
@ -65,7 +68,8 @@ function List:contains(value)
return false
end
---@param value any
---@generic I : any
---@param value I
---@return boolean
function List:remove(value)
for i, v in ipairs(self._list) do
@ -77,8 +81,8 @@ function List:remove(value)
return false
end
---@param callback fun(value: any): boolean
---@return nil
---@generic I : any
---@param callback fun(value: I): boolean
function List:each(callback)
for _, v in ipairs(self._list) do
if callback(v) then
@ -87,7 +91,8 @@ function List:each(callback)
end
end
---@param callback fun(value: any): boolean
---@generic I : any
---@param callback fun(value: I): boolean
---@return List
function List:map(callback)
local newList = List:New()
@ -97,7 +102,8 @@ function List:map(callback)
return newList
end
---@param callback fun(value: any): boolean
---@generic I : any
---@param callback fun(value: I): boolean
---@return List
function List:filter(callback)
local newList = List:New()
@ -109,10 +115,11 @@ function List:filter(callback)
return newList
end
---@generic I
---@param callback fun(result: I, value: I): I, boolean?
---@param initialValue I
---@return I
---@generic R : any
---@generic V : any
---@param callback fun(result: R, value: V): R, boolean?
---@param initialValue R
---@return R
function List:reduce(callback, initialValue)
local result = initialValue
local done = false
@ -125,7 +132,8 @@ function List:reduce(callback, initialValue)
return result
end
---@param callback fun(value: any): boolean
---@generic I
---@param callback fun(value: I): boolean
---@return boolean | nil
function List:find(callback)
for _, v in ipairs(self._list) do

@ -7,6 +7,7 @@ local Tinkr, Bastion = ...
---@field friends List
---@field activeEnemies List
---@field explosives List
---@field incorporeal List
local ObjectManager = {}
ObjectManager.__index = ObjectManager
@ -19,6 +20,7 @@ function ObjectManager:New()
self.friends = Bastion.List:New()
self.activeEnemies = Bastion.List:New()
self.explosives = Bastion.List:New()
self.incorporeal = Bastion.List:New()
return self
end
@ -74,6 +76,7 @@ function ObjectManager:Refresh()
self.friends:clear()
self.activeEnemies:clear()
self.explosives:clear()
self.incorporeal:clear()
self:ResetLists()
local objects = Objects()
@ -88,13 +91,14 @@ function ObjectManager:Refresh()
Bastion.UnitManager:SetObject(unit)
end
if unit:GetID() == 120651 then
if unit:GetID() == 204560 then
self.incorporeal:push(unit)
elseif unit:GetID() == 120651 then
self.explosives:push(unit)
elseif unit:IsPlayer() and (unit:IsInParty() or unit == Bastion.UnitManager["player"]) then
self.friends:push(unit)
elseif unit:IsEnemy() then
self.enemies:push(unit)
if unit:InCombatOdds() > 80 then
self.activeEnemies:push(unit)
end

@ -29,9 +29,10 @@ function Refreshable:__tostring()
end
-- Create
---@param value any
---@generic V
---@param value V
---@param cb function
---@return Refreshable
---@return V
function Refreshable:New(value, cb)
local self = setmetatable({}, Refreshable)

@ -71,6 +71,10 @@ function Spell:New(id)
return self
end
function Spell:GetDescription()
return GetSpellDescription(self:GetID()) or ""
end
-- Duplicator
---@return Spell
function Spell:Fresh()
@ -78,9 +82,10 @@ function Spell:Fresh()
end
-- Get the spells id
---@param ignoreOverride? boolean
---@return number
function Spell:GetID()
return self:IsOverridden() and self:OverrideSpellID() or self.spellID
function Spell:GetID(ignoreOverride)
return ignoreOverride and self.spellID or self:IsOverridden() and self:OverrideSpellID() or self.spellID
end
-- Add post cast func
@ -258,7 +263,7 @@ function Spell:GetPostCastFunction()
end
function Spell:OverrideSpellID()
return FindSpellOverrideByID(self.spellID)
return C_SpellBook.GetOverrideSpell(self.spellID)
end
function Spell:IsOverridden()
@ -266,9 +271,11 @@ function Spell:IsOverridden()
end
-- Check if the spell is known
---@param includeOverrides? boolean
---@return boolean
function Spell:IsKnown()
local isKnown = IsSpellKnownOrOverridesKnown(self:GetID())
function Spell:IsKnown(includeOverrides)
includeOverrides = includeOverrides ~= nil and includeOverrides or true
local isKnown = includeOverrides and IsSpellKnownOrOverridesKnown(self:GetID()) or IsSpellKnown(self:GetID())
local isPlayerSpell = IsPlayerSpell(self:GetID())
return isKnown or isPlayerSpell
end
@ -601,4 +608,10 @@ function Spell:Damage()
end
end
---@param unit Unit
---@param source? Unit
function Spell:GetAura(unit, source)
return source and unit:GetAuras():FindFrom(self, source) or unit:GetAuras():FindAny(self)
end
return Spell

@ -60,7 +60,7 @@ function Unit:__tostring()
end
-- Constructor
---@param unit TinkrObjectReference
---@param unit? TinkrObjectReference
---@return Unit
function Unit:New(unit)
local self = setmetatable({}, Unit)
@ -214,6 +214,17 @@ function Unit:IsPet()
return UnitIsUnit(self:GetOMToken(), "pet")
end
function Unit:IsOtherPet()
local petName = self:GetName()
local ownerName = ""
ownerName = (
string.match(petName, string.gsub(UNITNAME_TITLE_PET, "%%s", "(%.*)"))
or string.match(petName, string.gsub(UNITNAME_TITLE_MINION, "%%s", "(%.*)"))
or string.match(petName, string.gsub(UNITNAME_TITLE_GUARDIAN, "%%s", "(%.*)"))
)
return ownerName ~= nil
end
-- Is the unit a friendly unit
---@return boolean
function Unit:IsFriendly()
@ -300,6 +311,29 @@ function Unit:IsDamage()
return UnitGroupRolesAssigned(self:GetOMToken()) == "DAMAGER"
end
-- Get the units role
---@return "TANK" | "HEALER" | "DAMAGER"
function Unit:GetRole()
return UnitGroupRolesAssigned(self:GetOMToken())
end
function Unit:GetSpecializationID()
if CanInspect(self:GetOMToken(), false) then
return ObjectSpecializationID(self:GetOMToken())
end
return false
end
---@param fallback? boolean
---@return "TANK" | "HEALER" | "DAMAGER" | false
function Unit:GetSpecializationRole(fallback)
local specID = self:GetSpecializationID()
if specID then
return GetSpecializationRoleByID(specID)
end
return fallback and self:GetRole() or false
end
-- Is the unit a player
---@return boolean
function Unit:IsPlayer()
@ -344,6 +378,109 @@ local isClassicWow = select(4, GetBuildInfo()) < 40000
-- return UnitInMelee(self:GetOMToken(), unit:GetOMToken())
-- end
-- 1048593
local losBlacklist = {
[131863] = true, -- Raal the Gluttonous (WCM)
}
local AttachmentPoisitions = {
MountMain = 0,
HandRight = 1,
HandLeft = 2,
ElbowRight = 3,
ElbowLeft = 4,
ShoulderRight = 5,
ShoulderLeft = 6,
KneeRight = 7,
KneeLeft = 8,
HipRight = 9,
HipLeft = 10,
Helm = 11,
Back = 12,
ShoulderFlapRight = 13,
ShoulderFlapLeft = 14,
ChestBloodFront = 15,
ChestBloodBack = 16,
Breath = 17,
PlayerName = 18,
Base = 19,
Head = 20,
SpellLeftHand = 21,
SpellRightHand = 22,
Special1 = 23,
Special2 = 24,
Special3 = 25,
SheathMainHand = 26,
SheathOffHand = 27,
SheathShield = 28,
PlayerNameMounted = 29,
LargeWeaponLeft = 30,
LargeWeaponRight = 31,
HipWeaponLeft = 32,
HipWeaponRight = 33,
Chest = 34,
HandArrow = 35,
Bullet = 36,
SpellHandOmni = 37,
SpellHandDirected = 38,
VehicleSeat1 = 39,
VehicleSeat2 = 40,
VehicleSeat3 = 41,
VehicleSeat4 = 42,
VehicleSeat5 = 43,
VehicleSeat6 = 44,
VehicleSeat7 = 45,
VehicleSeat8 = 46,
LeftFoot = 47,
RightFoot = 48,
ShieldNoGlove = 49,
SpinLow = 50,
AlteredShoulderR = 51,
AlteredShoulderL = 52,
BeltBuckle = 53,
SheathCrossbow = 54,
HeadTop = 55,
VirtualSpellDirected = 56,
Backpack = 57,
Unknown = 60,
}
--[[
M2Collision = 1, -- 0x1
M2Render = 2, -- 0x2
WMOCollision = 16, -- 0x10
WMORender = 32, -- 0x20
Terrain = 256, -- 0x100
WaterWalkableLiquid = 65536, -- 0x10000
Liquid = 131072, -- 0x20000
WaterOrLiquid = 196608, -- 0x30000
EntityCollision = 1048576, -- 0x100000
Most = 1048849, -- 0x100201
Unknown = 2097152, -- 0x200000
All = 3211571, -- 0x310003
]]
--[[
public enum IntersectFlags {
None,
DoodadCollision = 0x00000001,
DoodadRender = 0x00000002,
WmoCollision = 0x00000010,
WmoRender = 0x00000020,
WmoNoCamCollision = 0x00000040,
Terrain = 0x00000100,
IgnoreWmoDoodad = 0x00002000,
LiquidWaterWalkable = 0x00010000,
LiquidAll = 0x00020000,
Cull = 0x00080000,
EntityCollision = 0x00100000,
EntityRender = 0x00200000,
Collision = DoodadCollision | WmoCollision | Terrain | EntityCollision,
LineOfSight = WmoCollision | EntityCollision
]]
--[[
M2Collision = 0x1
M2Render = 0x2
@ -352,45 +489,49 @@ local isClassicWow = select(4, GetBuildInfo()) < 40000
Terrain = 0x100
WaterWalkableLiquid = 0x10000
Liquid = 0x20000
WaterOrLiquid = 0x30000,
EntityCollision = 0x100000
Unknown = 0x200000
Most = 0x100201,
Unknown = 0x200000,
All = 0x310003,
]]
local losFlag = bit.bor(0x1, 0x10, 0x100000)
-- Check if the unit can see another unit
---@param unit Unit
---@return boolean
function Unit:CanSee(unit)
local ax, ay, az = ObjectPosition(self:GetOMToken())
local ah = ObjectHeight(self:GetOMToken())
local attx, atty, attz = GetUnitAttachmentPosition(unit:GetOMToken(), 18)
local alwaysLos = {
[189727] = true, -- Khajin the Unyielding
local attachmentOverride = {
[131863] = AttachmentPoisitions.Head, -- WCM Raal the Gluttonous
}
--if alwaysLos[unit:GetID()] then
--return true
--end
if not attx or not ax then
return false
function Unit:GetHitSphere()
--local srcX, srcY, srcZ = GetUnitAttachmentPosition(self:GetOMToken(), attachmentOverride[self:GetID()] or AttachmentPoisitions.PlayerName)
--local srcHeight = UnitIsMounted(self:GetOMToken()) and 3.081099 or 2.43808
return Bastion.Vector3:New(GetUnitAttachmentPosition(self:GetOMToken(), attachmentOverride[self:GetID()] or AttachmentPoisitions.PlayerName))
end
if not ah then
return false
function Unit:GetLOSSourcePosition()
local src = self:GetPosition()
src.z = UnitIsMounted(self:GetOMToken()) and 3.081099 or 2.43808
return src
end
if (ax == 0 and ay == 0 and az == 0) or (attx == 0 and atty == 0 and attz == 0) then
local losFlag = bit.bor(0x10)
-- Check if the unit can see another unit
---@param targetUnit Unit
---@return boolean
function Unit:CanSee(targetUnit)
local npcId = targetUnit:GetID()
if npcId and losBlacklist[npcId] then
return true
end
if not attx or not ax then
return false
local src = self:GetLOSSourcePosition()
local dst = targetUnit:GetHitSphere()
if (src.x == 0 and src.y == 0 and src.z == 0) or (dst.x == 0 and dst.y == 0 and dst.z == 0) then
return true
end
local x, y, z = TraceLine(ax, ay, az + ah, attx, atty, attz, losFlag)
local contactPoint = src + (dst - src):directionOrZero() * math.min(targetUnit:GetDistance(self), self:GetCombatReach())
local x, y, z = TraceLine(src.x, src.y, src.z, contactPoint.x, contactPoint.y, contactPoint.z, losFlag)
if x ~= 0 or y ~= 0 or z ~= 0 then
return false
else
@ -405,12 +546,10 @@ function Unit:IsCasting()
end
function Unit:GetTimeCastIsAt(percent)
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId =
UnitCastingInfo(self:GetOMToken())
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self:GetOMToken())
if not name then
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId =
UnitChannelInfo(self:GetOMToken())
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self:GetOMToken())
end
if name and startTimeMS and endTimeMS then
@ -427,12 +566,10 @@ end
-- Get Casting or channeling spell
---@return Spell | nil
function Unit:GetCastingOrChannelingSpell()
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId =
UnitCastingInfo(self:GetOMToken())
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self:GetOMToken())
if not name then
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId =
UnitChannelInfo(self:GetOMToken())
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self:GetOMToken())
end
if name then
@ -445,12 +582,10 @@ end
-- Get the end time of the cast or channel
---@return number
function Unit:GetCastingOrChannelingEndTime()
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId =
UnitCastingInfo(self:GetOMToken())
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self:GetOMToken())
if not name then
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId =
UnitChannelInfo(self:GetOMToken())
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self:GetOMToken())
end
if name then
@ -472,6 +607,15 @@ function Unit:IsCastingOrChanneling()
return self:IsCasting() or self:IsChanneling()
end
function Unit:CastTarget()
return self:IsCastingOrChanneling() and Bastion.UnitManager:Get(ObjectCastingTarget(self:GetOMToken()))
end
---@param unit Unit
function Unit:CastTargetIsUnit(unit)
return self:IsCastingOrChanneling() and self:CastTarget():IsUnit(unit)
end
function Unit:IsImmobilized()
return bit.band(self:GetMovementFlag(), 0x400) > 0
end
@ -485,12 +629,10 @@ end
---@return number
function Unit:GetChannelOrCastPercentComplete()
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId =
UnitCastingInfo(self:GetOMToken())
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self:GetOMToken())
if not name then
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId =
UnitChannelInfo(self:GetOMToken())
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self:GetOMToken())
end
if name and startTimeMS and endTimeMS then
@ -506,12 +648,10 @@ end
-- Check if unit is interruptible
---@return boolean
function Unit:IsInterruptible()
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId =
UnitCastingInfo(self:GetOMToken())
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self:GetOMToken())
if not name then
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId =
UnitChannelInfo(self:GetOMToken())
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self:GetOMToken())
end
if name then
@ -552,13 +692,7 @@ function Unit:GetEnemies(range)
local count = 0
Bastion.UnitManager:EnumEnemies(function(unit)
if
not self:IsUnit(unit)
and self:IsWithinCombatDistance(unit, range)
and unit:IsAlive()
and self:CanSee(unit)
and unit:IsEnemy()
then
if not self:IsUnit(unit) and self:IsWithinCombatDistance(unit, range) and unit:IsAlive() and self:CanSee(unit) and unit:IsEnemy() then
count = count + 1
end
return false
@ -569,8 +703,9 @@ function Unit:GetEnemies(range)
end
-- Get the number of melee attackers
---@param facing? boolean
---@return number
function Unit:GetMeleeAttackers()
function Unit:GetMeleeAttackers(facing)
local enemies = self.cache:Get("melee_attackers")
if enemies then
return enemies
@ -579,7 +714,7 @@ function Unit:GetMeleeAttackers()
local count = 0
Bastion.UnitManager:EnumEnemies(function(unit)
if not self:IsUnit(unit) and unit:IsAlive() and self:CanSee(unit) and self:InMelee(unit) and unit:IsEnemy() then
if not self:IsUnit(unit) and unit:IsAlive() and self:CanSee(unit) and self:InMelee(unit) and unit:IsEnemy() and (not facing or self:IsFacing(unit)) then
count = count + 1
end
return false
@ -596,13 +731,7 @@ function Unit:GetPartyHPAround(distance, percent)
local count = 0
Bastion.UnitManager:EnumFriends(function(unit)
if
not self:IsUnit(unit)
and unit:GetDistance(self) <= distance
and unit:IsAlive()
and self:CanSee(unit)
and unit:GetHP() <= percent
then
if not self:IsUnit(unit) and unit:GetDistance(self) <= distance and unit:IsAlive() and self:CanSee(unit) and unit:GetHP() <= percent then
count = count + 1
end
return false
@ -668,8 +797,7 @@ end
---@param unit Unit
---@return boolean
function Unit:IsTanking(unit)
local isTanking, status, threatpct, rawthreatpct, threatvalue =
UnitDetailedThreatSituation(self:GetOMToken(), unit:GetOMToken())
local isTanking, status, threatpct, rawthreatpct, threatvalue = UnitDetailedThreatSituation(self:GetOMToken(), unit:GetOMToken())
return isTanking
end
@ -742,6 +870,10 @@ function Unit:GetMeleeBoost()
return 0
end
function Unit:GetModelId()
return ObjectModelId(self:GetOMToken())
end
-- Melee calculation
-- float fMaxDist = fmaxf((float)(*(float*)((uintptr_t)this + 0x1BF8) + 1.3333) + *(float*)((uintptr_t)target + 0x1BF8), 5.0);
-- fMaxDist = fMaxDist + 1.0;
@ -790,6 +922,16 @@ function Unit:IsInParty()
return UnitInParty(self:GetOMToken())
end
-- In party
---@return boolean
function Unit:IsInRaid()
return UnitInRaid(self:GetOMToken()) ~= nil
end
function Unit:IsInPartyOrRaid()
return self:IsInParty() or self:IsInRaid()
end
-- Linear regression between time and percent to something
---@param time table
---@param percent table
@ -1110,9 +1252,9 @@ function Unit:GetStaggeredHealth()
end
-- get the units combat reach
---@return number | false
---@return number
function Unit:GetCombatReach()
return ObjectCombatReach(self:GetOMToken())
return ObjectCombatReach(self:GetOMToken()) or 0
end
-- Get the units combat distance (distance - combat reach (realized distance))
@ -1220,8 +1362,7 @@ function Unit:HasTarget()
return ObjectTarget(self:GetOMToken()) ~= false
end
function Unit:Target()
return self:HasTarget() and Bastion.UnitManager:Get(ObjectTarget(self:GetOMToken()):unit())
or Bastion.UnitManager:Get("none")
return self:HasTarget() and Bastion.UnitManager:Get(ObjectTarget(self:GetOMToken()):unit()) or Bastion.UnitManager:Get("none")
end
-- local empowering = {}

@ -5,8 +5,14 @@ local ObjectManager = Tinkr.Util.ObjectManager
local Unit = Bastion.Unit
---@class CacheableUnit : Cacheable, Unit
-- Create a new UnitManager class
---@class UnitManager
---@class UnitManager : { [UnitId]: Unit }
---@field units table<string, Unit>
---@field customUnits table<string, { unit: CacheableUnit, cb: fun(unit: Unit): Unit }>
---@field objects table<string, Unit>
---@field cache Cache
local UnitManager = {
units = {},
customUnits = {},
@ -14,6 +20,7 @@ local UnitManager = {
cache = {},
}
---@param k UnitId
function UnitManager:__index(k)
if k == "none" then
return self:Get("none")
@ -48,7 +55,7 @@ function UnitManager:__index(k)
if self.objects[kguid] == nil then
local o = Object(k)
if o then
local unit = Unit:New(Object(k))
local unit = Unit:New(o)
self:SetObject(unit)
end
end
@ -59,6 +66,7 @@ end
-- Constructor
---@return UnitManager
function UnitManager:New()
---@class UnitManager
local self = setmetatable({}, UnitManager)
self.units = {}
self.customUnits = {}
@ -67,7 +75,7 @@ function UnitManager:New()
end
-- Get or create a unit
---@param token string
---@param token UnitId
---@return Unit
function UnitManager:Get(token)
-- if not Validate(token) then
@ -107,7 +115,6 @@ end
-- Set a unit by guid
---@param unit Unit
---@return nil
function UnitManager:SetObject(unit)
self.objects[unit:GetGUID()] = unit
end
@ -115,9 +122,10 @@ end
-- Create a custom unit and cache it for .5 seconds
---@param token string
---@param cb fun(): Unit
---@return Unit
---@return CacheableUnit
function UnitManager:CreateCustomUnit(token, cb)
local unit = cb()
---@type CacheableUnit
local cachedUnit = Bastion.Cacheable:New(unit, cb)
if unit == nil then
@ -144,6 +152,7 @@ function UnitManager:EnumFriends(cb)
if cb(unit) then
return true
end
return false
end)
end
@ -155,6 +164,7 @@ function UnitManager:EnumEnemies(cb)
if cb(unit) then
return true
end
return false
end)
end
@ -166,12 +176,25 @@ function UnitManager:EnumUnits(cb)
if cb(unit) then
return true
end
return false
end)
end
-- Enum Incorporeal (object manager)
---@param cb fun(unit: Unit):boolean
---@return nil
function UnitManager:EnumIncorporeal(cb)
Bastion.ObjectManager.incorporeal:each(function(unit)
if cb(unit) then
return true
end
return false
end)
end
-- Get the number of enemies with a debuff
---@param spell Spell
---@param range number
---@param range? number
---@return number
function UnitManager:GetNumEnemiesWithDebuff(spell, range)
local count = 0
@ -216,8 +239,8 @@ end
-- Get the friend with the most friends within a given radius (party/raid members)
---@param radius number
---@return Unit
---@return table
---@return Unit | nil
---@return Unit[]
function UnitManager:GetFriendWithMostFriends(radius)
local unit = nil
local count = 0

@ -1,6 +1,11 @@
-- Create a Vector3 class
---@class Vector3
---@operator add(Vector3): Vector3
---@operator sub(Vector3): Vector3
---@operator mul(Vector3): Vector3
---@operator div(Vector3): Vector3
---@operator unm(): Vector3
local Vector3 = {}
Vector3.__index = Vector3
@ -242,13 +247,15 @@ function Vector3:Distance(b)
return FastDistance(self.x, self.y, self.z, b.x, b.y, b.z)
end
---@param to Vector3
function Vector3:GetAbsoluteAngle(to)
return self:NormalizeOrientation(math.atan2(to.y - self.y, to.x - self.x))
end
---@param to Vector3
---@return number
function Vector3:Angle(to)
return math.acos(self:Dot(to) /
(
math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z) *
math.sqrt(to.x * to.x + to.y * to.y + to.z * to.z)))
return math.acos(self:Dot(to) / (math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z) * math.sqrt(to.x * to.x + to.y * to.y + to.z * to.z)))
end
---@param maxLength number
@ -261,6 +268,18 @@ function Vector3:ClampMagnitude(maxLength)
return self
end
---@return Vector3
function Vector3:directionOrZero()
local mag = self.magnitude
if mag < 0.0000001 then
return self.zero
elseif mag < 1.00001 and mag > 0.99999 then
return self
else
return self * (1.0 / mag)
end
end
-- Implement a clamp function
---@param x number
---@param min number
@ -330,4 +349,15 @@ function Vector3:Normalize()
return Vector3:New(0, 0, 0)
end
---@param o number
function Vector3:NormalizeOrientation(o)
if o < 0 then
mod = o * -1
mod = math.fmod(mod, 2.0 * math.pi)
mod = -mod + 2.0 * math.pi
return mod
end
return math.fmod(o, 2.0 * math.pi)
end
return Vector3

@ -183,8 +183,11 @@ Bastion.Globals.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", fun
local args = { CombatLogGetCurrentEventInfo() }
local subEvent = args[2]
---@type string
local sourceGUID = args[4]
---@type string
local destGUID = args[8]
---@type number
local spellID = args[12]
-- if sourceGUID == pguid then
@ -253,8 +256,11 @@ function Bastion:FindModule(name)
return nil
end
Bastion.PrintEnabled = false
function Bastion:Print(...)
if not Bastion.PrintEnabled then
return
end
local args = { ... }
local str = "|cFFDF362D[Bastion]|r |cFFFFFFFF"
for i = 1, #args do

@ -0,0 +1,10 @@
column_width = 180
line_endings = "Unix"
indent_type = "Spaces"
indent_width = 4
quote_style = "AutoPreferDouble"
call_parentheses = "Always"
collapse_simple_statement = "Never"
[sort_requires]
enabled = false
Loading…
Cancel
Save