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 root = true
[*.lua] [*.lua]
indent_type = Spaces
column_width = 180
indent_width = 4
quote_style = AutoPreferDouble
call_parentheses = Always
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
end_of_line = lf end_of_line = lf

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

@ -266,7 +266,7 @@ function Aura:GetRemainingTime()
end end
function Aura:GetElapsedPercent() 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 end
-- Get the auras expiration time -- Get the auras expiration time
@ -350,11 +350,7 @@ end
-- Check if the aura is dispelable by a spell -- Check if the aura is dispelable by a spell
---@param spell Spell ---@param spell Spell
function Aura:IsDispelableBySpell(spell) function Aura:IsDispelableBySpell(spell)
if if (self:GetDispelType() == "" or self:GetDispelType() == nil) and self:GetIsStealable() and spell:IsEnrageDispel() then
(self:GetDispelType() == "" or self:GetDispelType() == nil)
and self:GetIsStealable()
and spell:IsEnrageDispel()
then
return true return true
end end

@ -104,7 +104,7 @@ function AuraTable:AddOrUpdateAuraInstanceID(instanceID, aura)
self.instanceIDLookup[instanceID] = spellId 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 if not self.playerAuras[spellId] then
self.playerAuras[spellId] = {} self.playerAuras[spellId] = {}
end end

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

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

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

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

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

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

@ -60,7 +60,7 @@ function Unit:__tostring()
end end
-- Constructor -- Constructor
---@param unit TinkrObjectReference ---@param unit? TinkrObjectReference
---@return Unit ---@return Unit
function Unit:New(unit) function Unit:New(unit)
local self = setmetatable({}, Unit) local self = setmetatable({}, Unit)
@ -214,6 +214,17 @@ function Unit:IsPet()
return UnitIsUnit(self:GetOMToken(), "pet") return UnitIsUnit(self:GetOMToken(), "pet")
end 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 -- Is the unit a friendly unit
---@return boolean ---@return boolean
function Unit:IsFriendly() function Unit:IsFriendly()
@ -300,6 +311,29 @@ function Unit:IsDamage()
return UnitGroupRolesAssigned(self:GetOMToken()) == "DAMAGER" return UnitGroupRolesAssigned(self:GetOMToken()) == "DAMAGER"
end 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 -- Is the unit a player
---@return boolean ---@return boolean
function Unit:IsPlayer() function Unit:IsPlayer()
@ -344,6 +378,109 @@ local isClassicWow = select(4, GetBuildInfo()) < 40000
-- return UnitInMelee(self:GetOMToken(), unit:GetOMToken()) -- return UnitInMelee(self:GetOMToken(), unit:GetOMToken())
-- end -- 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 M2Collision = 0x1
M2Render = 0x2 M2Render = 0x2
@ -352,45 +489,49 @@ local isClassicWow = select(4, GetBuildInfo()) < 40000
Terrain = 0x100 Terrain = 0x100
WaterWalkableLiquid = 0x10000 WaterWalkableLiquid = 0x10000
Liquid = 0x20000 Liquid = 0x20000
WaterOrLiquid = 0x30000,
EntityCollision = 0x100000 EntityCollision = 0x100000
Unknown = 0x200000 Most = 0x100201,
Unknown = 0x200000,
All = 0x310003,
]] ]]
local losFlag = bit.bor(0x1, 0x10, 0x100000) local attachmentOverride = {
[131863] = AttachmentPoisitions.Head, -- WCM Raal the Gluttonous
-- 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
} }
--if alwaysLos[unit:GetID()] then function Unit:GetHitSphere()
--return true --local srcX, srcY, srcZ = GetUnitAttachmentPosition(self:GetOMToken(), attachmentOverride[self:GetID()] or AttachmentPoisitions.PlayerName)
--end --local srcHeight = UnitIsMounted(self:GetOMToken()) and 3.081099 or 2.43808
return Bastion.Vector3:New(GetUnitAttachmentPosition(self:GetOMToken(), attachmentOverride[self:GetID()] or AttachmentPoisitions.PlayerName))
if not attx or not ax then
return false
end end
if not ah then function Unit:GetLOSSourcePosition()
return false local src = self:GetPosition()
src.z = UnitIsMounted(self:GetOMToken()) and 3.081099 or 2.43808
return src
end 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 return true
end end
if not attx or not ax then local src = self:GetLOSSourcePosition()
return false 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 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 if x ~= 0 or y ~= 0 or z ~= 0 then
return false return false
else else
@ -405,12 +546,10 @@ function Unit:IsCasting()
end end
function Unit:GetTimeCastIsAt(percent) function Unit:GetTimeCastIsAt(percent)
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self:GetOMToken())
UnitCastingInfo(self:GetOMToken())
if not name then if not name then
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self:GetOMToken())
UnitChannelInfo(self:GetOMToken())
end end
if name and startTimeMS and endTimeMS then if name and startTimeMS and endTimeMS then
@ -427,12 +566,10 @@ end
-- Get Casting or channeling spell -- Get Casting or channeling spell
---@return Spell | nil ---@return Spell | nil
function Unit:GetCastingOrChannelingSpell() function Unit:GetCastingOrChannelingSpell()
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self:GetOMToken())
UnitCastingInfo(self:GetOMToken())
if not name then if not name then
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self:GetOMToken())
UnitChannelInfo(self:GetOMToken())
end end
if name then if name then
@ -445,12 +582,10 @@ end
-- Get the end time of the cast or channel -- Get the end time of the cast or channel
---@return number ---@return number
function Unit:GetCastingOrChannelingEndTime() function Unit:GetCastingOrChannelingEndTime()
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self:GetOMToken())
UnitCastingInfo(self:GetOMToken())
if not name then if not name then
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self:GetOMToken())
UnitChannelInfo(self:GetOMToken())
end end
if name then if name then
@ -472,6 +607,15 @@ function Unit:IsCastingOrChanneling()
return self:IsCasting() or self:IsChanneling() return self:IsCasting() or self:IsChanneling()
end 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() function Unit:IsImmobilized()
return bit.band(self:GetMovementFlag(), 0x400) > 0 return bit.band(self:GetMovementFlag(), 0x400) > 0
end end
@ -485,12 +629,10 @@ end
---@return number ---@return number
function Unit:GetChannelOrCastPercentComplete() function Unit:GetChannelOrCastPercentComplete()
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self:GetOMToken())
UnitCastingInfo(self:GetOMToken())
if not name then if not name then
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self:GetOMToken())
UnitChannelInfo(self:GetOMToken())
end end
if name and startTimeMS and endTimeMS then if name and startTimeMS and endTimeMS then
@ -506,12 +648,10 @@ end
-- Check if unit is interruptible -- Check if unit is interruptible
---@return boolean ---@return boolean
function Unit:IsInterruptible() function Unit:IsInterruptible()
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self:GetOMToken())
UnitCastingInfo(self:GetOMToken())
if not name then if not name then
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self:GetOMToken())
UnitChannelInfo(self:GetOMToken())
end end
if name then if name then
@ -552,13 +692,7 @@ function Unit:GetEnemies(range)
local count = 0 local count = 0
Bastion.UnitManager:EnumEnemies(function(unit) Bastion.UnitManager:EnumEnemies(function(unit)
if if not self:IsUnit(unit) and self:IsWithinCombatDistance(unit, range) and unit:IsAlive() and self:CanSee(unit) and unit:IsEnemy() then
not self:IsUnit(unit)
and self:IsWithinCombatDistance(unit, range)
and unit:IsAlive()
and self:CanSee(unit)
and unit:IsEnemy()
then
count = count + 1 count = count + 1
end end
return false return false
@ -569,8 +703,9 @@ function Unit:GetEnemies(range)
end end
-- Get the number of melee attackers -- Get the number of melee attackers
---@param facing? boolean
---@return number ---@return number
function Unit:GetMeleeAttackers() function Unit:GetMeleeAttackers(facing)
local enemies = self.cache:Get("melee_attackers") local enemies = self.cache:Get("melee_attackers")
if enemies then if enemies then
return enemies return enemies
@ -579,7 +714,7 @@ function Unit:GetMeleeAttackers()
local count = 0 local count = 0
Bastion.UnitManager:EnumEnemies(function(unit) 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 count = count + 1
end end
return false return false
@ -596,13 +731,7 @@ function Unit:GetPartyHPAround(distance, percent)
local count = 0 local count = 0
Bastion.UnitManager:EnumFriends(function(unit) Bastion.UnitManager:EnumFriends(function(unit)
if if not self:IsUnit(unit) and unit:GetDistance(self) <= distance and unit:IsAlive() and self:CanSee(unit) and unit:GetHP() <= percent then
not self:IsUnit(unit)
and unit:GetDistance(self) <= distance
and unit:IsAlive()
and self:CanSee(unit)
and unit:GetHP() <= percent
then
count = count + 1 count = count + 1
end end
return false return false
@ -668,8 +797,7 @@ end
---@param unit Unit ---@param unit Unit
---@return boolean ---@return boolean
function Unit:IsTanking(unit) function Unit:IsTanking(unit)
local isTanking, status, threatpct, rawthreatpct, threatvalue = local isTanking, status, threatpct, rawthreatpct, threatvalue = UnitDetailedThreatSituation(self:GetOMToken(), unit:GetOMToken())
UnitDetailedThreatSituation(self:GetOMToken(), unit:GetOMToken())
return isTanking return isTanking
end end
@ -742,6 +870,10 @@ function Unit:GetMeleeBoost()
return 0 return 0
end end
function Unit:GetModelId()
return ObjectModelId(self:GetOMToken())
end
-- Melee calculation -- Melee calculation
-- float fMaxDist = fmaxf((float)(*(float*)((uintptr_t)this + 0x1BF8) + 1.3333) + *(float*)((uintptr_t)target + 0x1BF8), 5.0); -- float fMaxDist = fmaxf((float)(*(float*)((uintptr_t)this + 0x1BF8) + 1.3333) + *(float*)((uintptr_t)target + 0x1BF8), 5.0);
-- fMaxDist = fMaxDist + 1.0; -- fMaxDist = fMaxDist + 1.0;
@ -790,6 +922,16 @@ function Unit:IsInParty()
return UnitInParty(self:GetOMToken()) return UnitInParty(self:GetOMToken())
end 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 -- Linear regression between time and percent to something
---@param time table ---@param time table
---@param percent table ---@param percent table
@ -1110,9 +1252,9 @@ function Unit:GetStaggeredHealth()
end end
-- get the units combat reach -- get the units combat reach
---@return number | false ---@return number
function Unit:GetCombatReach() function Unit:GetCombatReach()
return ObjectCombatReach(self:GetOMToken()) return ObjectCombatReach(self:GetOMToken()) or 0
end end
-- Get the units combat distance (distance - combat reach (realized distance)) -- Get the units combat distance (distance - combat reach (realized distance))
@ -1220,8 +1362,7 @@ function Unit:HasTarget()
return ObjectTarget(self:GetOMToken()) ~= false return ObjectTarget(self:GetOMToken()) ~= false
end end
function Unit:Target() function Unit:Target()
return self:HasTarget() and Bastion.UnitManager:Get(ObjectTarget(self:GetOMToken()):unit()) return self:HasTarget() and Bastion.UnitManager:Get(ObjectTarget(self:GetOMToken()):unit()) or Bastion.UnitManager:Get("none")
or Bastion.UnitManager:Get("none")
end end
-- local empowering = {} -- local empowering = {}

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

@ -1,6 +1,11 @@
-- Create a Vector3 class -- Create a Vector3 class
---@class Vector3 ---@class Vector3
---@operator add(Vector3): Vector3
---@operator sub(Vector3): Vector3
---@operator mul(Vector3): Vector3
---@operator div(Vector3): Vector3
---@operator unm(): Vector3
local Vector3 = {} local Vector3 = {}
Vector3.__index = 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) return FastDistance(self.x, self.y, self.z, b.x, b.y, b.z)
end 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 ---@param to Vector3
---@return number ---@return number
function Vector3:Angle(to) function Vector3:Angle(to)
return math.acos(self:Dot(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)))
(
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 end
---@param maxLength number ---@param maxLength number
@ -261,6 +268,18 @@ function Vector3:ClampMagnitude(maxLength)
return self return self
end 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 -- Implement a clamp function
---@param x number ---@param x number
---@param min number ---@param min number
@ -330,4 +349,15 @@ function Vector3:Normalize()
return Vector3:New(0, 0, 0) return Vector3:New(0, 0, 0)
end 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 return Vector3

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