Compare commits

...

10 Commits

Author SHA1 Message Date
João Fidalgo 6280196711 feat: add spell traits 9 months ago
4n0n c0c8ab8362 Fix? 11 months ago
4n0n fad3d76d8a 11.0 ItemName 11 months ago
4n0n e6b2b8f42f Merge pull request '11.0' (#27) from 4n0n/Bastion:main into main 11 months ago
4n0n 86e7aeccec 11.0 11 months ago
4n0n f9583a85d8 11.0 11 months ago
4n0n d0cad5746d 11.0 11 months ago
4n0n 010d2b4111 11.0 11 months ago
4n0n 7442498326 11.0 11 months ago
4n0n 83086a9b57 11.0 11 months ago
  1. 34
      src/Aura/Aura.lua
  2. 43
      src/Item/Item.lua
  3. 18
      src/MythicPlusUtils/MythicPlusUtils.lua
  4. 151
      src/Spell/Spell.lua
  5. 10
      src/SpellBook/SpellBook.lua
  6. 589
      src/_bastion.lua

@ -75,6 +75,40 @@ function Aura:New(unit, index, type)
return self return self
end end
if C_UnitAuras.GetAuraDataByIndex then
local unitAuraInfo = C_UnitAuras.GetAuraDataByIndex(unit:GetOMToken(), index, type)
if not unitAuraInfo then
local self = setmetatable({}, Aura)
self.aura = {
name = nil,
icon = nil,
count = 0,
dispelType = nil,
duration = 0,
expirationTime = 0,
source = nil,
isStealable = false,
nameplateShowPersonal = false,
spellId = 0,
canApplyAura = false,
isBossDebuff = false,
castByPlayer = false,
nameplateShowAll = false,
timeMod = 0,
index = nil,
type = nil
}
if self.aura.spellId then
Bastion.Globals.SpellBook:GetSpell(self.aura.spellId)
end
return self
end
return Aura:CreateFromUnitAuraInfo(unitAuraInfo)
end
local name, icon, count, dispelType, duration, expirationTime, source, isStealable, nameplateShowPersonal, spellId, local name, icon, count, dispelType, duration, expirationTime, source, isStealable, nameplateShowPersonal, spellId,
canApplyAura, isBossDebuff, castByPlayer, nameplateShowAll, timeMod = UnitAura(unit:GetOMToken(), index, type) canApplyAura, isBossDebuff, castByPlayer, nameplateShowAll, timeMod = UnitAura(unit:GetOMToken(), index, type)

@ -51,7 +51,13 @@ function Item:New(id)
self.ItemID = id self.ItemID = id
-- Register spell in spellbook -- Register spell in spellbook
local name, spellID = GetItemSpell(self:GetID()) local name, spellID
if C_Item.GetItemSpell then
name, spellID = C_Item.GetItemSpell(self:GetID())
else
name, spellID = GetItemSpell(self:GetID())
end
if spellID then if spellID then
self.spellID = spellID self.spellID = spellID
Bastion.Globals.SpellBook:GetSpell(spellID) Bastion.Globals.SpellBook:GetSpell(spellID)
@ -69,18 +75,27 @@ end
-- Get the Items name -- Get the Items name
---@return string ---@return string
function Item:GetName() function Item:GetName()
if C_Item.GetItemInfo then
return C_Item.GetItemInfo(self:GetID())
end
return GetItemInfo(self:GetID()) return GetItemInfo(self:GetID())
end end
-- Get the Items icon -- Get the Items icon
---@return number ---@return number
function Item:GetIcon() function Item:GetIcon()
if C_Item.GetItemIconByID then
return C_Item.GetItemIconByID(self:GetID())
end
return select(3, GetItemInfo(self:GetID())) return select(3, GetItemInfo(self:GetID()))
end end
-- Get the Items cooldown -- Get the Items cooldown
---@return number ---@return number
function Item:GetCooldown() function Item:GetCooldown()
if C_Item.GetItemCooldown then
return select(2, C_Item.GetItemCooldown(self:GetID()))
end
return select(2, C_Container.GetItemCooldown(self:GetID())) return select(2, C_Container.GetItemCooldown(self:GetID()))
end end
@ -105,6 +120,10 @@ end
-- Get the Items cooldown remaining -- Get the Items cooldown remaining
---@return number ---@return number
function Item:GetCooldownRemaining() function Item:GetCooldownRemaining()
if C_Item.GetItemCooldown then
local start, duration = C_Item.GetItemCooldown(self:GetID())
return start + duration - GetTime()
end
local start, duration = C_Container.GetItemCooldown(self:GetID()) local start, duration = C_Container.GetItemCooldown(self:GetID())
return start + duration - GetTime() return start + duration - GetTime()
end end
@ -131,7 +150,11 @@ function Item:Use(unit, condition)
self.wasLooking = IsMouselooking() self.wasLooking = IsMouselooking()
-- Use the Item -- Use the Item
UseItemByName(self:GetName(), unit:GetOMToken()) if C_Item.UseItemByName then
C_Item.UseItemByName(self:GetName(), unit:GetOMToken())
else
UseItemByName(self:GetName(), unit:GetOMToken())
end
Bastion:Debug("Using", self) Bastion:Debug("Using", self)
@ -161,18 +184,28 @@ end
-- Check if the Item is known -- Check if the Item is known
---@return boolean ---@return boolean
function Item:IsEquipped() function Item:IsEquipped()
if C_Item.IsEquippedItem then
return C_Item.IsEquippedItem(self:GetID())
end
return IsEquippedItem(self:GetID()) return IsEquippedItem(self:GetID())
end end
-- Check if the Item is on cooldown -- Check if the Item is on cooldown
---@return boolean ---@return boolean
function Item:IsOnCooldown() function Item:IsOnCooldown()
if C_Item.GetItemCooldown then
return select(2, C_Item.GetItemCooldown(self:GetID())) > 0
end
return select(2, C_Container.GetItemCooldown(self:GetID())) > 0 return select(2, C_Container.GetItemCooldown(self:GetID())) > 0
end end
-- Check if the Item is usable -- Check if the Item is usable
---@return boolean ---@return boolean
function Item:IsUsable() function Item:IsUsable()
if C_Item.IsUsableItem then
local usable, noMana = C_Item.IsUsableItem(self:GetID())
return usable or usableExcludes[self:GetID()]
end
local usable, noMana = IsUsableItem(self:GetID()) local usable, noMana = IsUsableItem(self:GetID())
return usable or usableExcludes[self:GetID()] return usable or usableExcludes[self:GetID()]
end end
@ -187,6 +220,9 @@ end
-- Is equippable -- Is equippable
---@return boolean ---@return boolean
function Item:IsEquippable() function Item:IsEquippable()
if C_Item.IsEquippableItem then
return C_Item.IsEquippableItem(self:GetID())
end
return IsEquippableItem(self:GetID()) return IsEquippableItem(self:GetID())
end end
@ -317,6 +353,9 @@ end
-- Get the Items charges -- Get the Items charges
---@return number ---@return number
function Item:GetCharges() function Item:GetCharges()
if C_Item.GetItemCount then
return C_Item.GetItemCount(self:GetID())
end
return GetItemCharges(self:GetID()) return GetItemCharges(self:GetID())
end end

@ -462,7 +462,14 @@ function MythicPlusUtils:New()
return return
end end
local name = GetSpellInfo(spellID) local name
if C_Spell.GetSpellInfo then
local info = C_Spell.GetSpellInfo(spellID)
name = info and info.name or ''
else
name = GetSpellInfo(spellID)
end
self.loggedCasts[spellID] = true self.loggedCasts[spellID] = true
@ -481,7 +488,14 @@ function MythicPlusUtils:New()
return return
end end
local name = GetSpellInfo(spellID) local name
if C_Spell.GetSpellInfo then
local info = C_Spell.GetSpellInfo(spellID)
name = info and info.name or ''
else
name = GetSpellInfo(spellID)
end
self.loggedCasts[spellID] = true self.loggedCasts[spellID] = true

@ -12,7 +12,15 @@ local Spell = {
lastCastAt = false, lastCastAt = false,
conditions = {}, conditions = {},
target = false, target = false,
release_at = false release_at = false,
traits = {
ignoreChanneling = false,
ignoreFacing = false,
ignoreLoS = false,
ignoreGCD = false,
ignoreMoving = false,
targeted = false
}
} }
local usableExcludes = { local usableExcludes = {
@ -48,12 +56,20 @@ end
-- Constructor -- Constructor
---@param id number ---@param id number
---@param traits? table
---@return Spell ---@return Spell
function Spell:New(id) function Spell:New(id, traits)
local self = setmetatable({}, Spell) local self = setmetatable({}, Spell)
self.spellID = id self.spellID = id
if traits == nil then traits = {} end
for k in pairs(traits) do
if self.traits[k] ~= nil and traits[k] ~= nil then
self.traits[k] = traits[k]
end
end
return self return self
end end
@ -80,24 +96,53 @@ end
-- Get the spells name -- Get the spells name
---@return string ---@return string
function Spell:GetName() function Spell:GetName()
if C_Spell.GetSpellInfo then
local info = C_Spell.GetSpellInfo(self:GetID())
return info and info.name or nil
end
return GetSpellInfo(self:GetID()) return GetSpellInfo(self:GetID())
end end
-- Get the spells icon -- Get the spells icon
---@return number ---@return number
function Spell:GetIcon() function Spell:GetIcon()
if C_Spell.GetSpellInfo then
local info = C_Spell.GetSpellInfo(self:GetID())
return info and info.iconID or nil
end
return select(3, GetSpellInfo(self:GetID())) return select(3, GetSpellInfo(self:GetID()))
end end
-- Get the spells cooldown -- Get the spells cooldown
---@return number ---@return number
function Spell:GetCooldown() function Spell:GetCooldown()
if C_Spell.GetSpellCooldown then
local info = C_Spell.GetSpellCooldown(self:GetID())
return info and info.duration or nil
end
return select(2, GetSpellCooldown(self:GetID())) return select(2, GetSpellCooldown(self:GetID()))
end end
-- Get the full cooldown (time until all charges are available) -- Get the full cooldown (time until all charges are available)
---@return number ---@return number
function Spell:GetFullRechargeTime() function Spell:GetFullRechargeTime()
if C_Spell.GetSpellCooldown then
local info = C_Spell.GetSpellCooldown(self:GetID())
if info.isEnabled == 0 then
return 0
end
local chargeInfo = C_Spell.GetSpellCharges(self:GetID())
if chargeInfo.currentCharges == chargeInfo.maxCharges then
return 0
end
if chargeInfo.currentCharges == 0 then
return info.startTime + info.duration - GetTime()
end
return chargeInfo.cooldownStartTime + chargeInfo.cooldownDuration - GetTime()
end
local start, duration, enabled = GetSpellCooldown(self:GetID()) local start, duration, enabled = GetSpellCooldown(self:GetID())
if enabled == 0 then if enabled == 0 then
return 0 return 0
@ -136,6 +181,10 @@ end
-- Get the spells cooldown remaining -- Get the spells cooldown remaining
---@return number ---@return number
function Spell:GetCooldownRemaining() function Spell:GetCooldownRemaining()
if C_Spell.GetSpellCooldown then
local info = C_Spell.GetSpellCooldown(self:GetID())
return info and info.startTime + info.duration - GetTime() or nil
end
local start, duration = GetSpellCooldown(self:GetID()) local start, duration = GetSpellCooldown(self:GetID())
return start + duration - GetTime() return start + duration - GetTime()
end end
@ -143,6 +192,9 @@ end
-- Get the spell count -- Get the spell count
---@return number ---@return number
function Spell:GetCount() function Spell:GetCount()
if C_Spell.GetSpellCastCount then
return C_Spell.GetSpellCastCount(self:GetID())
end
return GetSpellCount(self:GetID()) return GetSpellCount(self:GetID())
end end
@ -252,6 +304,8 @@ end
-- Check if the spell is known -- Check if the spell is known
---@return boolean ---@return boolean
function Spell:IsKnown() function Spell:IsKnown()
local IsSpellKnown = C_Spell.IsSpellKnown and C_Spell.IsSpellKnown or IsSpellKnown
local IsPlayerSpell = C_Spell.IsPlayerSpell and C_Spell.IsPlayerSpell or IsPlayerSpell
local isKnown = IsSpellKnown(self:GetID()) local isKnown = IsSpellKnown(self:GetID())
local isPlayerSpell = IsPlayerSpell(self:GetID()) local isPlayerSpell = IsPlayerSpell(self:GetID())
return isKnown or isPlayerSpell return isKnown or isPlayerSpell
@ -260,12 +314,20 @@ end
-- Check if the spell is on cooldown -- Check if the spell is on cooldown
---@return boolean ---@return boolean
function Spell:IsOnCooldown() function Spell:IsOnCooldown()
if C_Spell.GetSpellCooldown then
local info = C_Spell.GetSpellCooldown(self:GetID())
return info and info.duration > 0
end
return select(2, GetSpellCooldown(self:GetID())) > 0 return select(2, GetSpellCooldown(self:GetID())) > 0
end end
-- Check if the spell is usable -- Check if the spell is usable
---@return boolean ---@return boolean
function Spell:IsUsable() function Spell:IsUsable()
if C_Spell.IsSpellUsable then
local usable, noMana = C_Spell.IsSpellUsable(self:GetID())
return usable or usableExcludes[self:GetID()] and not noMana
end
local usable, noMana = IsUsableSpell(self:GetID()) local usable, noMana = IsUsableSpell(self:GetID())
return usable or usableExcludes[self:GetID()] and not noMana return usable or usableExcludes[self:GetID()] and not noMana
end end
@ -283,7 +345,44 @@ function Spell:Castable()
return self:GetCastableFunction()(self) return self:GetCastableFunction()(self)
end end
return self:IsKnownAndUsable() if not self:IsKnownAndUsable() then return false end
local player = Bastion.UnitManager:Get("player")
if self.traits.targeted then
local target = self:GetTarget()
if not target or
not target:Exists() then return false end
if not self:IsInRange(target) then return false end
if not self.traits.ignoreFacing then
if not player:IsFacing(target) then return false end
end
if not self.traits.ignoreLoS then
if not player:CanSee(target) then return false end
end
end
if not self.traits.ignoreCasting then
if player:IsCasting() then return false end
end
if not self.traits.ignoreChanneling then
if player:IsChanneling() then return false end
end
if not self.traits.ignoreGCD then
if player:GetGCD() > C_Spell.GetSpellQueueWindow() then return false end
end
if not self.traits.ignoreMoving then
if self:GetCastLength() > 0 and player:IsMoving() then return false end
end
return true
end end
-- Set a script to check if the spell is castable -- Set a script to check if the spell is castable
@ -350,6 +449,9 @@ end
-- Check if the spell is castable and cast it -- Check if the spell is castable and cast it
---@return boolean ---@return boolean
function Spell:HasRange() function Spell:HasRange()
if C_Spell.SpellHasRange then
return C_Spell.SpellHasRange(self:GetID())
end
return SpellHasRange(self:GetName()) return SpellHasRange(self:GetName())
end end
@ -357,6 +459,10 @@ end
---@return number ---@return number
---@return number ---@return number
function Spell:GetRange() function Spell:GetRange()
if C_Spell.GetSpellInfo then
local info = C_Spell.GetSpellInfo(self:GetID())
return info and info.minRange or nil, info and info.maxRange or nil
end
local name, rank, icon, castTime, minRange, maxRange, spellID, originalIcon = GetSpellInfo(self:GetID()) local name, rank, icon, castTime, minRange, maxRange, spellID, originalIcon = GetSpellInfo(self:GetID())
return maxRange, minRange return maxRange, minRange
end end
@ -365,6 +471,7 @@ end
---@param unit Unit ---@param unit Unit
---@return boolean ---@return boolean
function Spell:IsInRange(unit) function Spell:IsInRange(unit)
local IsSpellInRange = C_Spell.IsSpellInRange and C_Spell.IsSpellInRange or IsSpellInRange
local hasRange = self:HasRange() local hasRange = self:HasRange()
local inRange = IsSpellInRange(self:GetName(), unit:GetOMToken()) local inRange = IsSpellInRange(self:GetName(), unit:GetOMToken())
@ -406,20 +513,50 @@ end
-- Get the spells charges -- Get the spells charges
---@return number ---@return number
function Spell:GetCharges() function Spell:GetCharges()
if C_Spell.GetSpellCharges then
local info = C_Spell.GetSpellCharges(self:GetID())
return info and info.currentCharges or nil
end
return GetSpellCharges(self:GetID()) return GetSpellCharges(self:GetID())
end end
function Spell:GetMaxCharges() function Spell:GetMaxCharges()
if C_Spell.GetSpellCharges then
local info = C_Spell.GetSpellCharges(self:GetID())
return info and info.maxCharges or nil
end
return select(2, GetSpellCharges(self:GetID())) return select(2, GetSpellCharges(self:GetID()))
end end
function Spell:GetCastLength() function Spell:GetCastLength()
if C_Spell.GetSpellInfo then
local info = C_Spell.GetSpellInfo(self:GetID())
return info and info.castTime or nil
end
return select(4, GetSpellInfo(self:GetID())) return select(4, GetSpellInfo(self:GetID()))
end end
-- Get the spells charges -- Get the spells charges
---@return number ---@return number
function Spell:GetChargesFractional() function Spell:GetChargesFractional()
if C_Spell.GetSpellCharges then
local info = C_Spell.GetSpellCharges(self:GetID())
if info.currentCharges == info.maxCharges then
return info.maxCharges
end
if info.currentCharges == 0 then
return 0
end
local timeSinceStart = GetTime() - info.cooldownStartTime
local timeLeft = info.cooldownDuration - timeSinceStart
local timePerCharge = info.cooldownDuration / info.maxCharges
local chargesFractional = info.currentCharges + (timeLeft / timePerCharge)
return chargesFractional
end
local charges, maxCharges, start, duration = GetSpellCharges(self:GetID()) local charges, maxCharges, start, duration = GetSpellCharges(self:GetID())
if charges == maxCharges then if charges == maxCharges then
@ -441,6 +578,10 @@ end
-- Get the spells charges remaining -- Get the spells charges remaining
---@return number ---@return number
function Spell:GetChargesRemaining() function Spell:GetChargesRemaining()
if C_Spell.GetSpellCharges then
local info = C_Spell.GetSpellCharges(self:GetID())
return info and info.currentCharges or nil
end
local charges, maxCharges, start, duration = GetSpellCharges(self:GetID()) local charges, maxCharges, start, duration = GetSpellCharges(self:GetID())
return charges return charges
end end
@ -546,6 +687,10 @@ end
-- GetCost -- GetCost
---@return number ---@return number
function Spell:GetCost() function Spell:GetCost()
if C_Spell.GetSpellPowerCost then
local info = C_Spell.GetSpellPowerCost(self:GetID())
return info and info.cost or 0
end
local cost = GetSpellPowerCost(self:GetID()) local cost = GetSpellPowerCost(self:GetID())
return cost and cost.cost or 0 return cost and cost.cost or 0
end end

@ -14,10 +14,12 @@ function SpellBook:New()
end end
-- Get a spell from the spellbook -- Get a spell from the spellbook
---@param id number
---@param traits? table
---@return Spell ---@return Spell
function SpellBook:GetSpell(id) function SpellBook:GetSpell(id, traits)
if self.spells[id] == nil then if self.spells[id] == nil then
self.spells[id] = Bastion.Spell:New(id) self.spells[id] = Bastion.Spell:New(id, traits)
end end
return self.spells[id] return self.spells[id]
@ -48,6 +50,10 @@ end
---@param name string ---@param name string
---@return Spell ---@return Spell
function SpellBook:GetSpellByName(name) function SpellBook:GetSpellByName(name)
if C_Spell.GetSpellInfo then
local info = C_Spell.GetSpellInfo(name)
return self:GetSpell(info.spellID)
end
local _, rank, icon, castTime, minRange, maxRange, spellID, originalIcon = GetSpellInfo(name) local _, rank, icon, castTime, minRange, maxRange, spellID, originalIcon = GetSpellInfo(name)
return self:GetSpell(spellID) return self:GetSpell(spellID)
end end

@ -1,9 +1,9 @@
local Tinkr = ... local Tinkr = ...
local Evaulator = Tinkr.Evaluator
---@class Bastion ---@class Bastion
local Bastion = { local Bastion = {DebugMode = false}
DebugMode = false
}
Bastion.__index = Bastion Bastion.__index = Bastion
function Bastion:Require(file) function Bastion:Require(file)
@ -50,348 +50,363 @@ function Bastion.require(class)
return Bastion:Require("~/src/" .. class .. "/" .. class) return Bastion:Require("~/src/" .. class .. "/" .. class)
end end
Bastion.Globals = {} -- fenv for all required files
function Bastion.Bootstrap()
---@type ClassMagic
Bastion.ClassMagic = Bastion.require("ClassMagic") Bastion.Globals = {}
---@type List
Bastion.List = Bastion.require("List") ---@type ClassMagic
---@type Library Bastion.ClassMagic = Bastion.require("ClassMagic")
Bastion.Library = Bastion.require("Library") ---@type List
---@type NotificationsList, Notification Bastion.List = Bastion.require("List")
Bastion.NotificationsList, Bastion.Notification = Bastion.require("NotificationsList") ---@type Library
---@type Vector3 Bastion.Library = Bastion.require("Library")
Bastion.Vector3 = Bastion.require("Vector3") ---@type NotificationsList, Notification
---@type Sequencer Bastion.NotificationsList, Bastion.Notification = Bastion.require(
Bastion.Sequencer = Bastion.require("Sequencer") "NotificationsList")
---@type Command ---@type Vector3
Bastion.Command = Bastion.require("Command") Bastion.Vector3 = Bastion.require("Vector3")
---@type Cache ---@type Sequencer
Bastion.Cache = Bastion.require("Cache") Bastion.Sequencer = Bastion.require("Sequencer")
---@type Cacheable ---@type Command
Bastion.Cacheable = Bastion.require("Cacheable") Bastion.Command = Bastion.require("Command")
---@type Refreshable ---@type Cache
Bastion.Refreshable = Bastion.require("Refreshable") Bastion.Cache = Bastion.require("Cache")
---@type Unit ---@type Cacheable
Bastion.Unit = Bastion.require("Unit") Bastion.Cacheable = Bastion.require("Cacheable")
---@type Aura ---@type Refreshable
Bastion.Aura = Bastion.require("Aura") Bastion.Refreshable = Bastion.require("Refreshable")
---@type APL, APLActor, APLTrait ---@type Unit
Bastion.APL, Bastion.APLActor, Bastion.APLTrait = Bastion.require("APL") Bastion.Unit = Bastion.require("Unit")
---@type Module ---@type Aura
Bastion.Module = Bastion.require("Module") Bastion.Aura = Bastion.require("Aura")
---@type UnitManager ---@type APL, APLActor, APLTrait
Bastion.UnitManager = Bastion.require("UnitManager"):New() Bastion.APL, Bastion.APLActor, Bastion.APLTrait = Bastion.require("APL")
---@type ObjectManager ---@type Module
Bastion.ObjectManager = Bastion.require("ObjectManager"):New() Bastion.Module = Bastion.require("Module")
---@type EventManager ---@type UnitManager
Bastion.EventManager = Bastion.require("EventManager") Bastion.UnitManager = Bastion.require("UnitManager"):New()
Bastion.Globals.EventManager = Bastion.EventManager:New() ---@type ObjectManager
---@type Spell Bastion.ObjectManager = Bastion.require("ObjectManager"):New()
Bastion.Spell = Bastion.require("Spell") ---@type EventManager
---@type SpellBook Bastion.EventManager = Bastion.require("EventManager")
Bastion.SpellBook = Bastion.require("SpellBook") Bastion.Globals.EventManager = Bastion.EventManager:New()
Bastion.Globals.SpellBook = Bastion.SpellBook:New() ---@type Spell
---@type Item Bastion.Spell = Bastion.require("Spell")
Bastion.Item = Bastion.require("Item") ---@type SpellBook
---@type ItemBook Bastion.SpellBook = Bastion.require("SpellBook")
Bastion.ItemBook = Bastion.require("ItemBook") Bastion.Globals.SpellBook = Bastion.SpellBook:New()
Bastion.Globals.ItemBook = Bastion.ItemBook:New() ---@type Item
---@type AuraTable Bastion.Item = Bastion.require("Item")
Bastion.AuraTable = Bastion.require("AuraTable") ---@type ItemBook
---@type Class Bastion.ItemBook = Bastion.require("ItemBook")
Bastion.Class = Bastion.require("Class") Bastion.Globals.ItemBook = Bastion.ItemBook:New()
---@type Timer ---@type AuraTable
Bastion.Timer = Bastion.require("Timer") Bastion.AuraTable = Bastion.require("AuraTable")
---@type Timer ---@type Class
Bastion.CombatTimer = Bastion.Timer:New('combat') Bastion.Class = Bastion.require("Class")
---@type MythicPlusUtils ---@type Timer
Bastion.MythicPlusUtils = Bastion.require("MythicPlusUtils"):New() Bastion.Timer = Bastion.require("Timer")
---@type NotificationsList ---@type Timer
Bastion.Notifications = Bastion.NotificationsList:New() Bastion.CombatTimer = Bastion.Timer:New('combat')
---@type MythicPlusUtils
local LIBRARIES = {} Bastion.MythicPlusUtils = Bastion.require("MythicPlusUtils"):New()
local MODULES = {} ---@type NotificationsList
Bastion.Notifications = Bastion.NotificationsList:New()
Bastion.Enabled = false
local LIBRARIES = {}
Bastion.Globals.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras) local MODULES = {}
local u = Bastion.UnitManager[unit]
Bastion.Enabled = false
if u then
u:GetAuras():OnUpdate(auras) Bastion.Globals.EventManager:RegisterWoWEvent('UNIT_AURA',
end function(unit, auras)
end) local u = Bastion.UnitManager[unit]
Bastion.Globals.EventManager:RegisterWoWEvent("UNIT_SPELLCAST_SUCCEEDED", function(...) if u then u:GetAuras():OnUpdate(auras) end
local unit, castGUID, spellID = ... end)
local spell = Bastion.Globals.SpellBook:GetIfRegistered(spellID) Bastion.Globals.EventManager:RegisterWoWEvent("UNIT_SPELLCAST_SUCCEEDED",
function(...)
if unit == "player" and spell then local unit, castGUID, spellID = ...
spell.lastCastAt = GetTime()
local spell = Bastion.Globals.SpellBook:GetIfRegistered(spellID)
if spell:GetPostCastFunction() then
spell:GetPostCastFunction()(spell) if unit == "player" and spell then
spell.lastCastAt = GetTime()
if spell:GetPostCastFunction() then
spell:GetPostCastFunction()(spell)
end
end end
end end)
end)
local pguid = UnitGUID("player") local pguid = UnitGUID("player")
local missed = {} local missed = {}
Bastion.Globals.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function() Bastion.Globals.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED",
local args = {CombatLogGetCurrentEventInfo()} function()
local args = {CombatLogGetCurrentEventInfo()}
local subEvent = args[2] local subEvent = args[2]
local sourceGUID = args[4] local sourceGUID = args[4]
local destGUID = args[8] local destGUID = args[8]
local spellID = args[12] local spellID = args[12]
-- if sourceGUID == pguid then -- if sourceGUID == pguid then
-- local args = { CombatLogGetCurrentEventInfo() } -- local args = { CombatLogGetCurrentEventInfo() }
-- for i = 1, #args do -- for i = 1, #args do
-- Log(tostring(args[i])) -- Log(tostring(args[i]))
-- end -- end
-- end -- end
local u = Bastion.UnitManager[sourceGUID] local u = Bastion.UnitManager[sourceGUID]
local u2 = Bastion.UnitManager[destGUID] local u2 = Bastion.UnitManager[destGUID]
local t = GetTime() local t = GetTime()
if u then if u then u:SetLastCombatTime(t) end
u:SetLastCombatTime(t)
end
if u2 then if u2 then
u2:SetLastCombatTime(t) u2:SetLastCombatTime(t)
if subEvent == "SPELL_MISSED" and sourceGUID == pguid and spellID == 408 then if subEvent == "SPELL_MISSED" and sourceGUID == pguid and spellID ==
local missType = args[15] 408 then
local missType = args[15]
if missType == "IMMUNE" then if missType == "IMMUNE" then
local castingSpell = u:GetCastingOrChannelingSpell() local castingSpell = u:GetCastingOrChannelingSpell()
if castingSpell then if castingSpell then
if not missed[castingSpell:GetID()] then if not missed[castingSpell:GetID()] then
missed[castingSpell:GetID()] = true missed[castingSpell:GetID()] = true
end
end end
end end
end end
end end
end end)
end)
Bastion.Ticker = C_Timer.NewTicker(0.1, function()
if not Bastion.CombatTimer:IsRunning() and UnitAffectingCombat("player") then
Bastion.CombatTimer:Start()
elseif Bastion.CombatTimer:IsRunning() and
not UnitAffectingCombat("player") then
Bastion.CombatTimer:Reset()
end
Bastion.Ticker = C_Timer.NewTicker(0.1, function() if Bastion.Enabled then
if not Bastion.CombatTimer:IsRunning() and UnitAffectingCombat("player") then Bastion.ObjectManager:Refresh()
Bastion.CombatTimer:Start() for i = 1, #MODULES do MODULES[i]:Tick() end
elseif Bastion.CombatTimer:IsRunning() and not UnitAffectingCombat("player") then end
Bastion.CombatTimer:Reset() end)
function Bastion:Register(module)
table.insert(MODULES, module)
Bastion:Print("Registered", module)
end end
if Bastion.Enabled then -- Find a module by name
Bastion.ObjectManager:Refresh() function Bastion:FindModule(name)
for i = 1, #MODULES do for i = 1, #MODULES do
MODULES[i]:Tick() if MODULES[i].name == name then return MODULES[i] end
end end
end
end)
function Bastion:Register(module)
table.insert(MODULES, module)
Bastion:Print("Registered", module)
end
-- Find a module by name return nil
function Bastion:FindModule(name)
for i = 1, #MODULES do
if MODULES[i].name == name then
return MODULES[i]
end
end end
return nil function Bastion:Print(...)
end local args = {...}
local str = "|cFFDF362D[Bastion]|r |cFFFFFFFF"
function Bastion:Print(...) for i = 1, #args do str = str .. tostring(args[i]) .. " " end
local args = {...} print(str)
local str = "|cFFDF362D[Bastion]|r |cFFFFFFFF"
for i = 1, #args do
str = str .. tostring(args[i]) .. " "
end end
print(str)
end
function Bastion:Debug(...) function Bastion:Debug(...)
if not Bastion.DebugMode then if not Bastion.DebugMode then return end
return local args = {...}
end local str = "|cFFDF6520[Bastion]|r |cFFFFFFFF"
local args = {...} for i = 1, #args do str = str .. tostring(args[i]) .. " " end
local str = "|cFFDF6520[Bastion]|r |cFFFFFFFF" print(str)
for i = 1, #args do
str = str .. tostring(args[i]) .. " "
end end
print(str)
end
local Command = Bastion.Command:New('bastion') local Command = Bastion.Command:New('bastion')
Command:Register('toggle', 'Toggle bastion on/off', function() Command:Register('toggle', 'Toggle bastion on/off', function()
Bastion.Enabled = not Bastion.Enabled Bastion.Enabled = not Bastion.Enabled
if Bastion.Enabled then if Bastion.Enabled then
Bastion:Print("Enabled") Bastion:Print("Enabled")
else else
Bastion:Print("Disabled") Bastion:Print("Disabled")
end end
end) end)
Command:Register('debug', 'Toggle debug mode on/off', function() Command:Register('debug', 'Toggle debug mode on/off', function()
Bastion.DebugMode = not Bastion.DebugMode Bastion.DebugMode = not Bastion.DebugMode
if Bastion.DebugMode then if Bastion.DebugMode then
Bastion:Print("Debug mode enabled") Bastion:Print("Debug mode enabled")
else else
Bastion:Print("Debug mode disabled") Bastion:Print("Debug mode disabled")
end
end)
Command:Register('dumpspells', 'Dump spells to a file', function()
local i = 1
local rand = math.random(100000, 999999)
while true do
local spellName, spellSubName = GetSpellBookItemName(i, BOOKTYPE_SPELL)
if not spellName then
do
break
end
end end
end)
Command:Register('dumpspells', 'Dump spells to a file', function()
local i = 1
local rand = math.random(100000, 999999)
local BOOKTYPE_SPELL = BOOKTYPE_SPELL or (Enum.SpellBookSpellBank.Player and Enum.SpellBookSpellBank.Player or 'spell')
while true do
local spellName, spellSubName
if C_SpellBook.GetSpellBookItemName then
spellName, spellSubName = C_SpellBook.GetSpellBookItemName(i, BOOKTYPE_SPELL)
else
spellName, spellSubName = GetSpellBookItemName(i, BOOKTYPE_SPELL)
end
if not spellName then do break end end
-- use spellName and spellSubName here -- use spellName and spellSubName here
local spellID = select(7, GetSpellInfo(spellName)) local spellID
if spellID then if C_Spell.GetSpellInfo then
spellName = spellName:gsub("[%W%s]", "") local info = C_Spell.GetSpellInfo(spellName)
WriteFile('bastion-' .. UnitClass('player') .. '-' .. rand .. '.lua', spellID = info.spellID
"local " .. spellName .. " = Bastion.Globals.SpellBook:GetSpell(" .. spellID .. ")\n", true) else
spellID = select(7, GetSpellInfo(spellName))
end
if spellID then
spellName = spellName:gsub("[%W%s]", "")
WriteFile('bastion-' .. UnitClass('player') .. '-' .. rand ..
'.lua',
"local " .. spellName ..
" = Bastion.Globals.SpellBook:GetSpell(" ..
spellID .. ")\n", true)
end
i = i + 1
end end
i = i + 1 end)
end
end) Command:Register('module', 'Toggle a module on/off', function(args)
local module = Bastion:FindModule(args[2])
Command:Register('module', 'Toggle a module on/off', function(args) if module then
local module = Bastion:FindModule(args[2]) module:Toggle()
if module then if module.enabled then
module:Toggle() Bastion:Print("Enabled", module.name)
if module.enabled then else
Bastion:Print("Enabled", module.name) Bastion:Print("Disabled", module.name)
end
else else
Bastion:Print("Disabled", module.name) Bastion:Print("Module not found")
end
end)
Command:Register('mplus', 'Toggle m+ module on/off', function(args)
local cmd = args[2]
if cmd == 'debuffs' then
Bastion.MythicPlusUtils:ToggleDebuffLogging()
Bastion:Print("Debuff logging", Bastion.MythicPlusUtils
.debuffLogging and "enabled" or "disabled")
return
end end
else
Bastion:Print("Module not found")
end
end)
Command:Register('mplus', 'Toggle m+ module on/off', function(args)
local cmd = args[2]
if cmd == 'debuffs' then
Bastion.MythicPlusUtils:ToggleDebuffLogging()
Bastion:Print("Debuff logging", Bastion.MythicPlusUtils.debuffLogging and "enabled" or "disabled")
return
end
if cmd == 'casts' then if cmd == 'casts' then
Bastion.MythicPlusUtils:ToggleCastLogging() Bastion.MythicPlusUtils:ToggleCastLogging()
Bastion:Print("Cast logging", Bastion.MythicPlusUtils.castLogging and "enabled" or "disabled") Bastion:Print("Cast logging",
return Bastion.MythicPlusUtils.castLogging and "enabled" or
end "disabled")
return
end
Bastion:Print("[MythicPlusUtils] Unknown command") Bastion:Print("[MythicPlusUtils] Unknown command")
Bastion:Print("Available commands:") Bastion:Print("Available commands:")
Bastion:Print("debuffs") Bastion:Print("debuffs")
Bastion:Print("casts") Bastion:Print("casts")
end) end)
Command:Register('missed', 'Dump the list of immune kidney shot spells', function() Command:Register('missed', 'Dump the list of immune kidney shot spells',
for k, v in pairs(missed) do function()
Bastion:Print(k) for k, v in pairs(missed) do Bastion:Print(k) end
end end)
end)
---@param library Library ---@param library Library
function Bastion:RegisterLibrary(library) function Bastion:RegisterLibrary(library)
LIBRARIES[library.name] = library LIBRARIES[library.name] = library
end end
function Bastion:CheckLibraryDependencies() function Bastion:CheckLibraryDependencies()
for k, v in pairs(LIBRARIES) do for k, v in pairs(LIBRARIES) do
if v.dependencies then if v.dependencies then
for i = 1, #v.dependencies do for i = 1, #v.dependencies do
local dep = v.dependencies[i] local dep = v.dependencies[i]
if LIBRARIES[dep] then if LIBRARIES[dep] then
if LIBRARIES[dep].dependencies then if LIBRARIES[dep].dependencies then
for j = 1, #LIBRARIES[dep].dependencies do for j = 1, #LIBRARIES[dep].dependencies do
if LIBRARIES[dep].dependencies[j] == v.name then if LIBRARIES[dep].dependencies[j] == v.name then
Bastion:Print("Circular dependency detected between " .. v.name .. " and " .. dep) Bastion:Print(
return false "Circular dependency detected between " ..
v.name .. " and " .. dep)
return false
end
end end
end end
else
Bastion:Print("Library " .. v.name .. " depends on " ..
dep .. " but it's not registered")
return false
end end
else
Bastion:Print("Library " .. v.name .. " depends on " .. dep .. " but it's not registered")
return false
end end
end end
end end
return true
end end
return true function Bastion:Import(library)
end local lib = self:GetLibrary(library)
function Bastion:Import(library) if not lib then error("Library " .. library .. " not found") end
local lib = self:GetLibrary(library)
if not lib then return lib:Resolve()
error("Library " .. library .. " not found")
end end
return lib:Resolve() function Bastion:GetLibrary(name)
end if not LIBRARIES[name] then
error("Library " .. name .. " not found")
end
function Bastion:GetLibrary(name) local library = LIBRARIES[name]
if not LIBRARIES[name] then
error("Library " .. name .. " not found") -- if library.dependencies then
-- for i = 1, #library.dependencies do
-- local dep = library.dependencies[i]
-- if LIBRARIES[dep] then
-- if LIBRARIES[dep].dependencies then
-- for j = 1, #LIBRARIES[dep].dependencies do
-- if LIBRARIES[dep].dependencies[j] == library.name then
-- Bastion:Print("Circular dependency detected between " .. library.name .. " and " .. dep)
-- return false
-- end
-- end
-- end
-- else
-- Bastion:Print("Library " .. v.name .. " depends on " .. dep .. " but it's not registered")
-- return false
-- end
-- end
-- end
return library
end end
local library = LIBRARIES[name] -- if not Bastion:CheckLibraryDependencies() then
-- return
-- if library.dependencies then
-- for i = 1, #library.dependencies do
-- local dep = library.dependencies[i]
-- if LIBRARIES[dep] then
-- if LIBRARIES[dep].dependencies then
-- for j = 1, #LIBRARIES[dep].dependencies do
-- if LIBRARIES[dep].dependencies[j] == library.name then
-- Bastion:Print("Circular dependency detected between " .. library.name .. " and " .. dep)
-- return false
-- end
-- end
-- end
-- else
-- Bastion:Print("Library " .. v.name .. " depends on " .. dep .. " but it's not registered")
-- return false
-- end
-- end
-- end -- end
return library Load("@Libraries/")
Load("@Modules/")
Load("@")
end end
-- if not Bastion:CheckLibraryDependencies() then Bastion.Bootstrap()
-- return
-- end
Load("@Libraries/")
Load("@Modules/")
Load("@")

Loading…
Cancel
Save