Compare commits

..

No commits in common. 'main' and '4n0n-patch-1' have entirely different histories.

  1. 6
      .gitignore
  2. 6
      README.md
  3. 24
      scripts/ExampleModule.lua
  4. 21
      scripts/Libraries/ExampleDependency.lua
  5. 15
      scripts/Libraries/ExampleDependencyError.lua
  6. 25
      scripts/Libraries/ExampleLibrary.lua
  7. 60
      src/APL/APL.lua
  8. 54
      src/Aura/Aura.lua
  9. 359
      src/AuraTable/AuraTable.lua
  10. 15
      src/Class/Class.lua
  11. 7
      src/Command/Command.lua
  12. 51
      src/Item/Item.lua
  13. 115
      src/Library/Library.lua
  14. 10
      src/List/List.lua
  15. 29
      src/MythicPlusUtils/MythicPlusUtils.lua
  16. 7
      src/ObjectManager/ObjectManager.lua
  17. 3
      src/Sequencer/Sequencer.lua
  18. 177
      src/Spell/Spell.lua
  19. 23
      src/SpellBook/SpellBook.lua
  20. 32
      src/Unit/Unit.lua
  21. 46
      src/UnitManager/UnitManager.lua
  22. 572
      src/_bastion.lua

6
.gitignore vendored

@ -7,13 +7,7 @@ DS_Store
## ignore all files in scripts ## ignore all files in scripts
scripts/* scripts/*
!scripts/Libraries
scripts/Libraries/*
!scripts/.gitkeep !scripts/.gitkeep
!scripts/ExampleModule.lua
!scripts/Libraries/ExampleLibrary.lua
!scripts/Libraries/ExampleDependency.lua
!scripts/Libraries/ExampleDependencyError.lua
## ignore vscode settings ## ignore vscode settings
.vscode/* .vscode/*

@ -10,8 +10,4 @@ Feel free to browse around the [Wiki](https://git.tinkr.site/4n0n/bastion/wiki)
## Quick Start ## Quick Start
- [Download](https://git.tinkr.site/4n0n/bastion/archive/main.zip) or clone the repository. - [Download](https://git.tinkr.site/4n0n/bastion/archive/main.zip) or clone the repository.
- Move the bastion folder to your `Tinkr/scripts` folder. - Move the bastion folder to your `Tinkr/scripts` folder.
- Once in-game type `/bastion toggle` to enable the engine. - Once in-game type `/bastion toggle` to enable the engine.
## Developer Information
- [Issue Template](https://git.tinkr.site/Bastion/Bastion/wiki/Issues)
- [Pull Requests](https://git.tinkr.site/Bastion/Bastion/wiki/Pull-Requests)

@ -1,24 +0,0 @@
local Tinkr, Bastion = ...
local ExampleModule = Bastion.Module:New('ExampleModule')
local Player = Bastion.UnitManager:Get('player')
-- Create a local spellbook
local SpellBook = Bastion.SpellBook:New()
local FlashHeal = SpellBook:GetSpell(2061)
-- Get a global spell (this can collide with other modules, so be careful)
-- This is useful for caching common spells that you might not actually cast, and to avoid needless spell creation inline
local FlashHeal = Bastion.Globals.SpellBook:GetSpell(2061)
local AdvancedMath = Bastion:Import('AdvancedMath')
print(AdvancedMath:Add(1, 2))
ExampleModule:Sync(function()
if Player:GetHP() <= 50 then
FlashHeal:Cast(Player)
end
end)
Bastion:Register(ExampleModule)

@ -1,21 +0,0 @@
local Tinkr, Bastion = ...
local Player = Bastion.UnitManager:Get('player')
Bastion:RegisterLibrary(Bastion.Library:New({
name = 'Dependable',
exports = {
default = function()
local Dependable = {}
Dependable.__index = Dependable
function Dependable:Test(a)
print(a)
end
return Dependable
end,
Test = 5
}
}))

@ -1,15 +0,0 @@
local Tinkr, Bastion = ...
Bastion:RegisterLibrary(Bastion.Library:New({
name = 'Circular',
exports = {
default = function(self)
-- Return default first, and then the remaining exports
local Math, OtherExports = self:Import('AdvancedMath')
print(Math:Add(1, 2))
return 'Circular'
end
}
}))

@ -1,25 +0,0 @@
local Tinkr, Bastion = ...
Bastion:RegisterLibrary(Bastion.Library:New({
name = 'AdvancedMath',
exports = {
default = function(self) -- Function exports are called when the library is loaded
-- Return default first, and then the remaining exports
local Dependable, OtherExports = self:Import('Dependable')
local CircularDependency = self:Import('Circular') -- Causes a circular dependency error
Dependable:Test(OtherExports.Test)
local AdvancedMath = {}
AdvancedMath.__index = AdvancedMath
function AdvancedMath:Add(a, b)
return a + b
end
return AdvancedMath
end
}
}))

@ -1,4 +1,5 @@
-- Document with emmy lua: https://emmylua.github.io/ -- Document with emmy lua: https://emmylua.github.io/
-- Create an APL trait for the APL class -- Create an APL trait for the APL class
---@class APLTrait ---@class APLTrait
local APLTrait = {} local APLTrait = {}
@ -54,7 +55,7 @@ end
---@param ... APLTrait ---@param ... APLTrait
---@return APLActor ---@return APLActor
function APLActor:AddTraits(...) function APLActor:AddTraits(...)
for _, trait in ipairs({...}) do for _, trait in ipairs({ ... }) do
table.insert(self.traits, trait) table.insert(self.traits, trait)
end end
@ -84,11 +85,13 @@ function APLActor:Execute()
-- If the actor is a sequencer we don't want to continue executing the APL if the sequencer is not finished -- If the actor is a sequencer we don't want to continue executing the APL if the sequencer is not finished
if self:GetActor().sequencer then if self:GetActor().sequencer then
if self:GetActor().condition and self:GetActor().condition() and not self:GetActor().sequencer:Finished() then if self:GetActor().condition and self:GetActor().condition() and not self:GetActor().sequencer:Finished() then
print("Execute?")
self:GetActor().sequencer:Execute() self:GetActor().sequencer:Execute()
return true return true
end end
if not self:GetActor().condition and not self:GetActor().sequencer:Finished() then if not self:GetActor().condition and not self:GetActor().sequencer:Finished() then
print("Execute?")
self:GetActor().sequencer:Execute() self:GetActor().sequencer:Execute()
return true return true
end end
@ -108,22 +111,23 @@ function APLActor:Execute()
if self:GetActor().condition then if self:GetActor().condition then
-- print("Bastion: APL:Execute: Condition for spell " .. self:GetActor().spell:GetName()) -- print("Bastion: APL:Execute: Condition for spell " .. self:GetActor().spell:GetName())
self:GetActor().spell:CastableIf(self:GetActor().castableFunc):OnCast(self:GetActor().onCastFunc):Cast( self:GetActor().spell:CastableIf(self:GetActor().castableFunc):OnCast(self:GetActor().onCastFunc):Cast(
self:GetActor().target, self:GetActor().condition) self:GetActor().target,
else self:GetActor().condition)
-- print("Bastion: APL:Execute: No condition for spell " .. self:GetActor().spell:GetName())
self:GetActor().spell:CastableIf(self:GetActor().castableFunc):OnCast(self:GetActor().onCastFunc):Cast(
self:GetActor().target)
end end
-- print("Bastion: APL:Execute: No condition for spell " .. self:GetActor().spell:GetName())
self:GetActor().spell:CastableIf(self:GetActor().castableFunc):OnCast(self:GetActor().onCastFunc):Cast(self
:GetActor().target)
end end
if self:GetActor().item then if self:GetActor().item then
if self:GetActor().condition then if self:GetActor().condition then
-- print("Bastion: APL:Execute: Condition for spell " .. self:GetActor().spell:GetName()) -- print("Bastion: APL:Execute: Condition for spell " .. self:GetActor().spell:GetName())
self:GetActor().item:UsableIf(self:GetActor().usableFunc):Use(self:GetActor().target, self:GetActor().item:UsableIf(self:GetActor().usableFunc):Use(self:GetActor().target,
self:GetActor().condition) self:GetActor().condition)
else
-- print("Bastion: APL:Execute: No condition for spell " .. self:GetActor().spell:GetName())
self:GetActor().item:UsableIf(self:GetActor().usableFunc):Use(self:GetActor().target)
end end
-- print("Bastion: APL:Execute: No condition for spell " .. self:GetActor().spell:GetName())
self:GetActor().item:UsableIf(self:GetActor().usableFunc):Use(self:GetActor().target)
end end
if self:GetActor().action then if self:GetActor().action then
-- print("Bastion: APL:Execute: Executing action " .. self:GetActor().action) -- print("Bastion: APL:Execute: Executing action " .. self:GetActor().action)
@ -185,11 +189,7 @@ end
---@param cb fun(...):any ---@param cb fun(...):any
---@return APLActor ---@return APLActor
function APL:AddVariable(name, cb) function APL:AddVariable(name, cb)
local actor = APLActor:New({ local actor = APLActor:New({ variable = name, cb = cb, _apl = self })
variable = name,
cb = cb,
_apl = self
})
table.insert(self.apl, actor) table.insert(self.apl, actor)
return actor return actor
end end
@ -199,17 +199,14 @@ end
---@param cb fun(...):any ---@param cb fun(...):any
---@return APLActor ---@return APLActor
function APL:AddAction(action, cb) function APL:AddAction(action, cb)
local actor = APLActor:New({ local actor = APLActor:New({ action = action, cb = cb })
action = action,
cb = cb
})
table.insert(self.apl, actor) table.insert(self.apl, actor)
return actor return actor
end end
-- Add a spell to the APL -- Add a spell to the APL
---@param spell Spell ---@param spell Spell
---@param condition? string|fun(...):boolean ---@param condition? fun(...):boolean
---@return APLActor ---@return APLActor
function APL:AddSpell(spell, condition) function APL:AddSpell(spell, condition)
local castableFunc = spell.CastableIfFunc local castableFunc = spell.CastableIfFunc
@ -231,18 +228,13 @@ end
-- Add an item to the APL -- Add an item to the APL
---@param item Item ---@param item Item
---@param condition? fun(...):boolean ---@param condition fun(...):boolean
---@return APLActor ---@return APLActor
function APL:AddItem(item, condition) function APL:AddItem(item, condition)
local usableFunc = item.UsableIfFunc local usableFunc = item.UsableIfFunc
local target = item:GetTarget() local target = item:GetTarget()
local actor = APLActor:New({ local actor = APLActor:New({ item = item, condition = condition, usableFunc = usableFunc, target = target })
item = item,
condition = condition,
usableFunc = usableFunc,
target = target
})
table.insert(self.apl, actor) table.insert(self.apl, actor)
@ -257,10 +249,7 @@ function APL:AddAPL(apl, condition)
if not condition then if not condition then
error("Bastion: APL:AddAPL: No condition for APL " .. apl.name) error("Bastion: APL:AddAPL: No condition for APL " .. apl.name)
end end
local actor = APLActor:New({ local actor = APLActor:New({ apl = apl, condition = condition })
apl = apl,
condition = condition
})
table.insert(self.apl, actor) table.insert(self.apl, actor)
return actor return actor
end end
@ -268,12 +257,14 @@ end
-- Execute the APL -- Execute the APL
function APL:Execute() function APL:Execute()
for _, actor in ipairs(self.apl) do for _, actor in ipairs(self.apl) do
if actor:HasTraits() then if actor:HasTraits() and actor:Evaluate() then
if actor:Evaluate() and actor:Execute() then if actor:Execute() then
print("BREAQK", actor)
break break
end end
else else
if actor:Execute() then if actor:Execute() then
print("BREAQK", actor)
break break
end end
end end
@ -285,10 +276,7 @@ end
---@param condition fun(...):boolean ---@param condition fun(...):boolean
---@return APLActor ---@return APLActor
function APL:AddSequence(sequencer, condition) function APL:AddSequence(sequencer, condition)
local actor = APLActor:New({ local actor = APLActor:New({ sequencer = sequencer, condition = condition })
sequencer = sequencer,
condition = condition
})
table.insert(self.apl, actor) table.insert(self.apl, actor)
return actor return actor
end end

@ -1,4 +1,5 @@
-- Document with emmy lua: https://emmylua.github.io/ -- Document with emmy lua: https://emmylua.github.io/
local Tinkr, Bastion = ... local Tinkr, Bastion = ...
-- Create a new Aura class -- Create a new Aura class
@ -65,52 +66,19 @@ function Aura:New(unit, index, type)
timeMod = 0, timeMod = 0,
index = nil, index = nil,
type = nil type = nil,
} }
if self.aura.spellId then if self.aura.spellId then
Bastion.Globals.SpellBook:GetSpell(self.aura.spellId) Bastion.SpellBook:GetSpell(self.aura.spellId)
end end
return self return self
end end
if C_UnitAuras.GetAuraDataByIndex then local name, icon, count, dispelType, duration, expirationTime, source, isStealable, nameplateShowPersonal,
local unitAuraInfo = C_UnitAuras.GetAuraDataByIndex(unit:GetOMToken(), index, type) spellId, canApplyAura, isBossDebuff, castByPlayer, nameplateShowAll, timeMod = UnitAura(unit:GetOMToken(), index,
if not unitAuraInfo then type)
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,
canApplyAura, isBossDebuff, castByPlayer, nameplateShowAll, timeMod = UnitAura(unit:GetOMToken(), index, type)
local self = setmetatable({}, Aura) local self = setmetatable({}, Aura)
self.aura = { self.aura = {
@ -132,10 +100,10 @@ function Aura:New(unit, index, type)
auraInstanceID = nil, auraInstanceID = nil,
index = index, index = index,
type = type type = type,
} }
if self.aura.spellId then if self.aura.spellId then
Bastion.Globals.SpellBook:GetSpell(self.aura.spellId) Bastion.SpellBook:GetSpell(self.aura.spellId)
end end
return self return self
end end
@ -164,11 +132,11 @@ function Aura:CreateFromUnitAuraInfo(unitAuraInfo)
auraInstanceID = unitAuraInfo.auraInstanceID, auraInstanceID = unitAuraInfo.auraInstanceID,
index = nil, index = nil,
type = unitAuraInfo.isHarmful and "HARMFUL" or "HELPFUL" type = unitAuraInfo.isHarmful and "HARMFUL" or "HELPFUL",
} }
-- Register spell in spellbook -- Register spell in spellbook
Bastion.Globals.SpellBook:GetSpell(self.aura.spellId) Bastion.SpellBook:GetSpell(self.aura.spellId)
return self return self
end end
@ -271,7 +239,7 @@ end
-- Get the auras spell id -- Get the auras spell id
---@return Spell ---@return Spell
function Aura:GetSpell() function Aura:GetSpell()
return Bastion.Globals.SpellBook:GetSpell(self.aura.spellId) return Bastion.SpellBook:GetSpell(self.aura.spellId)
end end
-- Get the auras can apply aura status -- Get the auras can apply aura status

@ -53,7 +53,7 @@ function AuraTable:OnUpdate(auras)
if updatedAuras and #updatedAuras > 0 then if updatedAuras and #updatedAuras > 0 then
for i = 1, #updatedAuras do for i = 1, #updatedAuras do
local id = updatedAuras[i] local id = updatedAuras[i]
local newAura = C_UnitAuras.GetAuraDataByAuraInstanceID(self.unit:GetOMToken(), id); local newAura = C_UnitAuras_GetAuraDataByAuraInstanceID(self.unit:GetOMToken(), id);
if newAura then if newAura then
local aura = Bastion.Aura:CreateFromUnitAuraInfo(newAura) local aura = Bastion.Aura:CreateFromUnitAuraInfo(newAura)
self:AddOrUpdateAuraInstanceID(aura:GetAuraInstanceID(), aura) self:AddOrUpdateAuraInstanceID(aura:GetAuraInstanceID(), aura)
@ -118,7 +118,7 @@ end
-- Get a units buffs -- Get a units buffs
---@return nil ---@return nil
function AuraTable:GetUnitBuffs() function AuraTable:GetUnitBuffs()
if Tinkr.classic or Tinkr.era then if Tinkr.classic then
for i = 1, 40 do for i = 1, 40 do
local aura = Bastion.Aura:New(self.unit, i, 'HELPFUL') local aura = Bastion.Aura:New(self.unit, i, 'HELPFUL')
@ -157,7 +157,7 @@ end
-- Get a units debuffs -- Get a units debuffs
---@return nil ---@return nil
function AuraTable:GetUnitDebuffs() function AuraTable:GetUnitDebuffs()
if Tinkr.classic or Tinkr.era then if Tinkr.classic then
for i = 1, 40 do for i = 1, 40 do
local aura = Bastion.Aura:New(self.unit, i, 'HARMFUL') local aura = Bastion.Aura:New(self.unit, i, 'HARMFUL')
@ -279,7 +279,7 @@ function AuraTable:Find(spell)
if a:IsUp() then -- Handle expired and non refreshed dropoffs not coming in UNIT_AURA if a:IsUp() then -- Handle expired and non refreshed dropoffs not coming in UNIT_AURA
return a return a
else else
if not Tinkr.classic or Tinkr.era then if not Tinkr.classic then
self:RemoveInstanceID(a:GetAuraInstanceID()) self:RemoveInstanceID(a:GetAuraInstanceID())
end end
end end
@ -305,7 +305,7 @@ function AuraTable:FindMy(spell)
if a:IsUp() then -- Handle expired and non refreshed dropoffs not coming in UNIT_AURA if a:IsUp() then -- Handle expired and non refreshed dropoffs not coming in UNIT_AURA
return a return a
else else
if not Tinkr.classic or Tinkr.era then if not Tinkr.classic then
self:RemoveInstanceID(a:GetAuraInstanceID()) self:RemoveInstanceID(a:GetAuraInstanceID())
end end
end end
@ -334,7 +334,7 @@ function AuraTable:FindFrom(spell, source)
return a return a
end end
else else
if not Tinkr.classic or Tinkr.era then if not Tinkr.classic then
self:RemoveInstanceID(a:GetAuraInstanceID()) self:RemoveInstanceID(a:GetAuraInstanceID())
end end
end end
@ -362,7 +362,7 @@ function AuraTable:FindTheirs(spell)
return a return a
end end
else else
if not Tinkr.classic or Tinkr.era then if not Tinkr.classic then
self:RemoveInstanceID(a:GetAuraInstanceID()) self:RemoveInstanceID(a:GetAuraInstanceID())
end end
end end
@ -384,351 +384,6 @@ function AuraTable:FindAny(spell)
return self:FindMy(spell) return self:FindMy(spell)
end end
-- FindAnyOf
---@param spells List
---@return Aura
function AuraTable:FindAnyOf(spells)
return spells:reduce(function(acc, cur)
local aura = self:FindAny(cur)
if aura:IsValid() then
return aura, true
end
return acc
end, Bastion.Aura:New())
end
-- FindAnyOfMy
---@param spells List
---@return Aura
function AuraTable:FindAnyOfMy(spells)
return spells:reduce(function(acc, cur)
local aura = self:FindMy(cur)
if aura:IsValid() then
return aura, true
end
return acc
end, Bastion.Aura:New())
end
-- FindAnyOfTheirs
---@param spells List
---@return Aura
function AuraTable:FindAnyOfTheirs(spells)
return spells:reduce(function(acc, cur)
local aura = self:FindTheirs(cur)
if aura:IsValid() then
return aura, true
end
return acc
end, Bastion.Aura:New())
end
-- FindAnyFrom
---@param spells List
---@param source Unit
---@return Aura
function AuraTable:FindAnyFrom(spells, source)
return spells:reduce(function(acc, cur)
local aura = self:FindFrom(cur, source)
if aura:IsValid() then
return aura, true
end
return acc
end, Bastion.Aura:New())
end
-- FindLongestOf
---@param spells List
---@return Aura
function AuraTable:FindLongestOf(spells)
return spells:reduce(function(acc, cur)
local aura = self:Find(cur)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetRemainingTime() > acc:GetRemainingTime() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindLongestOfMy
---@param spells List
---@return Aura
function AuraTable:FindLongestOfMy(spells)
return spells:reduce(function(acc, cur)
local aura = self:FindMy(cur)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetRemainingTime() > acc:GetRemainingTime() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindLongestOfTheirs
---@param spells List
---@return Aura
function AuraTable:FindLongestOfTheirs(spells)
return spells:reduce(function(acc, cur)
local aura = self:FindTheirs(cur)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetRemainingTime() > acc:GetRemainingTime() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindLongestOfFrom
---@param spells List
---@param source Unit
---@return Aura
function AuraTable:FindLongestOfFrom(spells, source)
return spells:reduce(function(acc, cur)
local aura = self:FindFrom(cur, source)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetRemainingTime() > acc:GetRemainingTime() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindShortestOf
---@param spells List
---@return Aura
function AuraTable:FindShortestOf(spells)
return spells:reduce(function(acc, cur)
local aura = self:Find(cur)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetRemainingTime() < acc:GetRemainingTime() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindShortestOfMy
---@param spells List
---@return Aura
function AuraTable:FindShortestOfMy(spells)
return spells:reduce(function(acc, cur)
local aura = self:FindMy(cur)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetRemainingTime() < acc:GetRemainingTime() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindShortestOfTheirs
---@param spells List
---@return Aura
function AuraTable:FindShortestOfTheirs(spells)
return spells:reduce(function(acc, cur)
local aura = self:FindTheirs(cur)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetRemainingTime() < acc:GetRemainingTime() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindShortestOfFrom
---@param spells List
---@param source Unit
---@return Aura
function AuraTable:FindShortestOfFrom(spells, source)
return spells:reduce(function(acc, cur)
local aura = self:FindFrom(cur, source)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetRemainingTime() < acc:GetRemainingTime() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindMostOf
---@param spells List
---@return Aura
function AuraTable:FindMostOf(spells)
return spells:reduce(function(acc, cur)
local aura = self:Find(cur)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetCount() > acc:GetCount() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindMostOfMy
---@param spells List
---@return Aura
function AuraTable:FindMostOfMy(spells)
return spells:reduce(function(acc, cur)
local aura = self:FindMy(cur)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetCount() > acc:GetCount() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindMostOfTheirs
---@param spells List
---@return Aura
function AuraTable:FindMostOfTheirs(spells)
return spells:reduce(function(acc, cur)
local aura = self:FindTheirs(cur)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetCount() > acc:GetCount() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindMostOfFrom
---@param spells List
---@param source Unit
---@return Aura
function AuraTable:FindMostOfFrom(spells, source)
return spells:reduce(function(acc, cur)
local aura = self:FindFrom(cur, source)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetCount() > acc:GetCount() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindLeastOf
---@param spells List
---@return Aura
function AuraTable:FindLeastOf(spells)
return spells:reduce(function(acc, cur)
local aura = self:Find(cur)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetCount() < acc:GetCount() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindLeastOfMy
---@param spells List
---@return Aura
function AuraTable:FindLeastOfMy(spells)
return spells:reduce(function(acc, cur)
local aura = self:FindMy(cur)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetCount() < acc:GetCount() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindLeastOfTheirs
---@param spells List
---@return Aura
function AuraTable:FindLeastOfTheirs(spells)
return spells:reduce(function(acc, cur)
local aura = self:FindTheirs(cur)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetCount() < acc:GetCount() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- FindLeastOfFrom
---@param spells List
---@param source Unit
---@return Aura
function AuraTable:FindLeastOfFrom(spells, source)
return spells:reduce(function(acc, cur)
local aura = self:FindFrom(cur, source)
if aura:IsValid() then
if not acc:IsValid() then
return aura
end
if aura:GetCount() < acc:GetCount() then
return aura
end
end
return acc
end, Bastion.Aura:New())
end
-- Has any stealable aura -- Has any stealable aura
---@return boolean ---@return boolean
function AuraTable:HasAnyStealableAura() function AuraTable:HasAnyStealableAura()

@ -18,21 +18,12 @@ function Class:__index(k)
return response return response
end end
---@class Class
---@field class Class.class
---@class Class.class
---@field locale string
---@field name string
---@field id number
-- Constructor -- Constructor
---@param locale string ---@param locale string
---@param name string ---@param name string
---@param id number ---@param id number
function Class:New(locale, name, id) function Class:New(locale, name, id)
local self = setmetatable({}, Class) local self = setmetatable({}, Class)
self.class = { self.class = {
locale = locale, locale = locale,
name = name, name = name,
@ -59,16 +50,10 @@ function Class:GetID()
return self.class.id return self.class.id
end end
---@class ColorMixin
---@field r number
---@field g number
---@field b number
-- Return the classes color -- Return the classes color
---@return ColorMixin classColor ---@return ColorMixin classColor
function Class:GetColor() function Class:GetColor()
return C_ClassColor.GetClassColor(self.class.name) return C_ClassColor.GetClassColor(self.class.name)
end end
return Class return Class

@ -1,13 +1,6 @@
-- Create a wow command handler class -- Create a wow command handler class
---@class Command ---@class Command
---@field command string
---@field commands Command.commands[]
local Command = {} local Command = {}
---@class Command.commands
---@field helpmsg string
---@field cb fun(args: table)
Command.__index = Command Command.__index = Command
---@return string ---@return string

@ -51,16 +51,10 @@ function Item:New(id)
self.ItemID = id self.ItemID = id
-- Register spell in spellbook -- Register spell in spellbook
local name, spellID local name, spellID = GetItemSpell(self:GetID())
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.SpellBook:GetSpell(spellID)
end end
return self return self
@ -75,27 +69,18 @@ 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
@ -120,10 +105,6 @@ 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
@ -150,11 +131,7 @@ function Item:Use(unit, condition)
self.wasLooking = IsMouselooking() self.wasLooking = IsMouselooking()
-- Use the Item -- Use the Item
if C_Item.UseItemByName then UseItemByName(self:GetName(), unit:GetOMToken())
C_Item.UseItemByName(self:GetName(), unit:GetOMToken())
else
UseItemByName(self:GetName(), unit:GetOMToken())
end
Bastion:Debug("Using", self) Bastion:Debug("Using", self)
@ -184,28 +161,18 @@ 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
@ -220,9 +187,6 @@ 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
@ -275,7 +239,7 @@ function Item:Click(x, y, z)
if type(x) == 'table' then if type(x) == 'table' then
x, y, z = x.x, x.y, x.z x, y, z = x.x, x.y, x.z
end end
if IsSpellPending() == 64 then if IsItemPending() == 64 then
MouselookStop() MouselookStop()
Click(x, y, z) Click(x, y, z)
if self:GetWasLooking() then if self:GetWasLooking() then
@ -338,7 +302,7 @@ end
-- Get the last use time -- Get the last use time
---@return number ---@return number
function Item:GetLastUseTime() function Item:GetLastUseTime()
return Bastion.Globals.SpellBook:GetSpell(self:GetID()):GetLastCastTime() return Bastion.SpellBook:GetSpell(self:GetID()):GetLastCastTime()
end end
-- Get time since last use -- Get time since last use
@ -353,9 +317,6 @@ 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
@ -469,7 +430,7 @@ end
---@return Spell | nil ---@return Spell | nil
function Item:GetSpell() function Item:GetSpell()
if self.spellID then if self.spellID then
return Bastion.Globals.SpellBook:GetSpell(self.spellID) return Bastion.SpellBook:GetSpell(self.spellID)
end end
return nil return nil

@ -1,115 +0,0 @@
local Tinkr, Bastion = ...
---@class Library
---@field name string
---@field dependencies table
---@field exports table
---@field resolved table
local Library = {
name = nil,
dependencies = {},
exports = {
default = function()
return nil
end
},
resolved = nil
}
Library.__index = Library
---@param name string
---@param library table
---@return Library
function Library:New(library)
local self = {
name = library.name or nil,
dependencies = {},
exports = library.exports or {
default = function()
return nil
end
},
resolved = nil
}
self = setmetatable(self, Library)
return self
end
function Library:ResolveExport(export)
if type(export) == 'function' then
return export(self)
end
return export
end
function Library:Resolve()
if not self.exports then
error("Library " .. self.name .. " has no exports")
end
if self.resolved then
if self.exports.default then
return self.resolved[1], self.resolved[2]
end
return unpack(self.resolved)
end
if self.exports.default then
-- return default first if it exists
local default = self.exports.default
local remaining = {}
for k, v in pairs(self.exports) do
if k ~= 'default' then
remaining[k] = self:ResolveExport(v)
end
end
self.resolved = {self:ResolveExport(default), remaining}
return self.resolved[1], self.resolved[2]
end
self.resolved = {}
for k, v in pairs(self.exports) do
self.resolved[k] = self:ResolveExport(v)
end
return unpack(self.resolved)
end
function Library:DependsOn(other)
for _, dependency in pairs(self.dependencies) do
if dependency == other then
return true
end
end
return false
end
---@param library string
function Library:Import(library)
local lib = Bastion:GetLibrary(library)
if not lib then
error("Library " .. library .. " does not exist")
end
if not table.contains(self.dependencies, library) then
table.insert(self.dependencies, library)
end
if lib:DependsOn(self.name) then
error("Circular dependency detected between " .. self.name .. " and " .. library)
end
return lib:Resolve()
end
return Library

@ -1,3 +1,5 @@
local Tinkr, Bastion = ...
---@class List ---@class List
local List = { local List = {
-- Add overload -- Add overload
@ -114,12 +116,8 @@ end
---@return boolean ---@return boolean
function List:reduce(callback, initialValue) function List:reduce(callback, initialValue)
local result = initialValue local result = initialValue
local done = false
for _, v in ipairs(self._list) do for _, v in ipairs(self._list) do
result, done = callback(result, v) result = callback(result, v)
if done then
break
end
end end
return result return result
end end
@ -146,7 +144,7 @@ function List:findIndex(callback)
return nil return nil
end end
---@param callback fun(...): boolean ---@param callback fun(value: any): boolean
---@return nil ---@return nil
function List:sort(callback) function List:sort(callback)
table.sort(self._list, callback) table.sort(self._list, callback)

@ -17,7 +17,6 @@ MythicPlusUtils.__index = MythicPlusUtils
function MythicPlusUtils:New() function MythicPlusUtils:New()
local self = setmetatable({}, MythicPlusUtils) local self = setmetatable({}, MythicPlusUtils)
---@diagnostic disable-next-line: assign-type-mismatch
self.random = math.random(1000000, 9999999) self.random = math.random(1000000, 9999999)
self.aoeBosses = { self.aoeBosses = {
@ -430,7 +429,7 @@ function MythicPlusUtils:New()
} }
} }
Bastion.Globals.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras) Bastion.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras)
if not self.debuffLogging then if not self.debuffLogging then
return return
end end
@ -453,7 +452,7 @@ function MythicPlusUtils:New()
end end
end) end)
Bastion.Globals.EventManager:RegisterWoWEvent('UNIT_SPELLCAST_START', function(unitTarget, castGUID, spellID) Bastion.EventManager:RegisterWoWEvent('UNIT_SPELLCAST_START', function(unitTarget, castGUID, spellID)
if not self.castLogging then if not self.castLogging then
return return
end end
@ -462,14 +461,7 @@ function MythicPlusUtils:New()
return return
end end
local name local name = GetSpellInfo(spellID)
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
@ -479,7 +471,7 @@ function MythicPlusUtils:New()
]], true) ]], true)
end) end)
Bastion.Globals.EventManager:RegisterWoWEvent('UNIT_SPELLCAST_CHANNEL_START', function(unitTarget, castGUID, spellID) Bastion.EventManager:RegisterWoWEvent('UNIT_SPELLCAST_CHANNEL_START', function(unitTarget, castGUID, spellID)
if not self.castLogging then if not self.castLogging then
return return
end end
@ -488,14 +480,7 @@ function MythicPlusUtils:New()
return return
end end
local name local name = GetSpellInfo(spellID)
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
@ -582,4 +567,8 @@ function MythicPlusUtils:IsAOEBoss(unit)
return self.aoeBosses[unit:GetID()] return self.aoeBosses[unit:GetID()]
end end
function MythicPlusUtils:IsTankBuster(spell)
return self.tankBusters[spell:GetID()]
end
return MythicPlusUtils return MythicPlusUtils

@ -1,11 +1,6 @@
local Tinkr, Bastion = ... local Tinkr, Bastion = ...
---@class ObjectManager ---@class ObjectManager
---@field _lists table
---@field enemies List
---@field friends List
---@field activeEnemies List
---@field explosives List
local ObjectManager = {} local ObjectManager = {}
ObjectManager.__index = ObjectManager ObjectManager.__index = ObjectManager
@ -25,7 +20,7 @@ end
-- Register a custom list with a callback -- Register a custom list with a callback
---@param name string ---@param name string
---@param cb function ---@param cb function
---@return List | false ---@return List
function ObjectManager:RegisterList(name, cb) function ObjectManager:RegisterList(name, cb)
if self._lists[name] then if self._lists[name] then
return false return false

@ -1,4 +1,5 @@
-- Create a sequencer class that takes a table of actions and executes them in order -- Create a sequencer class that takes a table of actions and executes them in order
---@class Sequencer ---@class Sequencer
---@field resetCondition fun(): boolean ---@field resetCondition fun(): boolean
---@field abortCondition fun(): boolean ---@field abortCondition fun(): boolean
@ -44,10 +45,12 @@ end
---@return boolean ---@return boolean
function Sequencer:Next() function Sequencer:Next()
if self:Finished() then if self:Finished() then
print("Its finished?")
return false return false
end end
local action = self.actions[self.index] local action = self.actions[self.index]
print("Attempting action: " .. self.index .. "")
if action(self) then if action(self) then
self.index = self.index + 1 self.index = self.index + 1
return true return true

@ -13,18 +13,10 @@ local Spell = {
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 = {
[18562] = true [18562] = true,
} }
function Spell:__index(k) function Spell:__index(k)
@ -56,29 +48,15 @@ end
-- Constructor -- Constructor
---@param id number ---@param id number
---@param traits? table
---@return Spell ---@return Spell
function Spell:New(id, traits) function Spell:New(id)
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
-- Duplicator
---@return Spell
function Spell:Fresh()
return Spell:New(self:GetID())
end
-- Get the spells id -- Get the spells id
---@return number ---@return number
function Spell:GetID() function Spell:GetID()
@ -96,53 +74,24 @@ 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
@ -181,10 +130,6 @@ 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
@ -192,9 +137,6 @@ 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
@ -213,15 +155,11 @@ end
-- Cast the spell -- Cast the spell
---@param unit Unit ---@param unit Unit
---@param condition? string|function ---@param condition string
---@return boolean ---@return boolean
function Spell:Cast(unit, condition) function Spell:Cast(unit, condition)
if condition then if condition and not self:EvaluateCondition(condition) then
if type(condition) == "string" and not self:EvaluateCondition(condition) then return false
return false
elseif type(condition) == "function" and not condition(self) then
return false
end
end end
if not self:Castable() then if not self:Castable() then
@ -304,8 +242,6 @@ 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
@ -314,20 +250,12 @@ 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
@ -345,44 +273,7 @@ function Spell:Castable()
return self:GetCastableFunction()(self) return self:GetCastableFunction()(self)
end end
if not self:IsKnownAndUsable() then return false end return self:IsKnownAndUsable()
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
@ -416,9 +307,9 @@ function Spell:GetWasLooking()
end end
-- Click the spell -- Click the spell
---@param x number|Vector3 ---@param x number
---@param y? number ---@param y number
---@param z? number ---@param z number
---@return boolean ---@return boolean
function Spell:Click(x, y, z) function Spell:Click(x, y, z)
if type(x) == 'table' then if type(x) == 'table' then
@ -449,9 +340,6 @@ 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
@ -459,10 +347,6 @@ 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
@ -471,7 +355,6 @@ 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())
@ -513,50 +396,20 @@ 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
@ -578,10 +431,6 @@ 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
@ -674,7 +523,9 @@ end
-- IsDiseaseDispel -- IsDiseaseDispel
---@return boolean ---@return boolean
function Spell:IsDiseaseDispel() function Spell:IsDiseaseDispel()
return ({})[self:GetID()] return ({
})[self:GetID()]
end end
-- IsSpell -- IsSpell
@ -687,10 +538,6 @@ 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,12 +14,10 @@ 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, traits) function SpellBook:GetSpell(id)
if self.spells[id] == nil then if self.spells[id] == nil then
self.spells[id] = Bastion.Spell:New(id, traits) self.spells[id] = Bastion.Spell:New(id)
end end
return self.spells[id] return self.spells[id]
@ -29,31 +27,16 @@ end
---@return Spell, ... Spell ---@return Spell, ... Spell
function SpellBook:GetSpells(...) function SpellBook:GetSpells(...)
local spells = {} local spells = {}
for _, id in ipairs({...}) do for _, id in ipairs({ ... }) do
table.insert(spells, self:GetSpell(id)) table.insert(spells, self:GetSpell(id))
end end
return unpack(spells) return unpack(spells)
end end
---@param ... number[]
---@return List
function SpellBook:GetList(...)
local spells = {}
for _, id in ipairs({...}) do
table.insert(spells, self:GetSpell(id))
end
return Bastion.List:New(spells)
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

@ -13,7 +13,7 @@ local Unit = {
last_off_attack = 0, last_off_attack = 0,
last_main_attack = 0, last_main_attack = 0,
last_combat_time = 0, last_combat_time = 0,
ttd_ticker = false, ttd_ticker = 0,
ttd = 0, ttd = 0,
id = false, id = false,
} }
@ -422,7 +422,7 @@ function Unit:GetCastingOrChannelingSpell()
end end
if name then if name then
return Bastion.Globals.SpellBook:GetSpell(spellId) return Bastion.SpellBook:GetSpell(spellId)
end end
return nil return nil
@ -505,7 +505,7 @@ end
-- Check if unit is interruptible -- Check if unit is interruptible
---@param percent number ---@param percent number
---@param ignoreInterruptible? boolean ---@param ignoreInterruptible boolean
---@return boolean ---@return boolean
function Unit:IsInterruptibleAt(percent, ignoreInterruptible) function Unit:IsInterruptibleAt(percent, ignoreInterruptible)
if not ignoreInterruptible and not self:IsInterruptible() then if not ignoreInterruptible and not self:IsInterruptible() then
@ -596,7 +596,7 @@ end
---@param unit Unit | nil ---@param unit Unit | nil
---@return number ---@return number
function Unit:GetComboPoints(unit) function Unit:GetComboPoints(unit)
if Tinkr.classic or Tinkr.era then if Tinkr.classic then
if not unit then if not unit then
return 0 return 0
end end
@ -607,7 +607,7 @@ end
---@return number ---@return number
function Unit:GetComboPointsMax() function Unit:GetComboPointsMax()
if Tinkr.classic or Tinkr.era then if Tinkr.classic then
return 5 return 5
end end
return UnitPowerMax(self:GetOMToken(), 4) return UnitPowerMax(self:GetOMToken(), 4)
@ -617,7 +617,7 @@ end
---@param unit Unit | nil ---@param unit Unit | nil
---@return number ---@return number
function Unit:GetComboPointsDeficit(unit) function Unit:GetComboPointsDeficit(unit)
if Tinkr.classic or Tinkr.era then if Tinkr.classic then
return self:GetComboPointsMax() - self:GetComboPoints(unit) return self:GetComboPointsMax() - self:GetComboPoints(unit)
end end
return self:GetComboPointsMax() - self:GetComboPoints() return self:GetComboPointsMax() - self:GetComboPoints()
@ -838,7 +838,7 @@ function Unit:TimeToDie()
self.regression_history = {} self.regression_history = {}
if self.ttd_ticker then if self.ttd_ticker then
self.ttd_ticker:Cancel() self.ttd_ticker:Cancel()
self.ttd_ticker = false self.ttd_ticker = nil
end end
return 0 return 0
end end
@ -926,12 +926,13 @@ end
-- IsStealthed -- IsStealthed
---@return boolean ---@return boolean
function Unit:IsStealthed() function Unit:IsStealthed()
local Stealth = Bastion.Globals.SpellBook:GetSpell(1784) local Stealth = Bastion.SpellBook:GetSpell(1784)
local Vanish = Bastion.Globals.SpellBook:GetSpell(1856) local Vanish = Bastion.SpellBook:GetSpell(1856)
local ShadowDance = Bastion.Globals.SpellBook:GetSpell(185422) local ShadowDance = Bastion.SpellBook:GetSpell(185422)
local Subterfuge = Bastion.Globals.SpellBook:GetSpell(115192) local Subterfuge = Bastion.SpellBook:GetSpell(115192)
local Shadowmeld = Bastion.Globals.SpellBook:GetSpell(58984) local Shadowmeld = Bastion.SpellBook:GetSpell(58984)
local Sepsis = Bastion.Globals.SpellBook:GetSpell(328305) local Sepsis = Bastion.SpellBook:GetSpell(328305)
return self:GetAuras():FindAny(Stealth) or self:GetAuras():FindAny(ShadowDance) return self:GetAuras():FindAny(Stealth) or self:GetAuras():FindAny(ShadowDance)
end end
@ -959,7 +960,7 @@ end
---@return nil ---@return nil
function Unit:WatchForSwings() function Unit:WatchForSwings()
Bastion.Globals.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function() Bastion.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function()
local _, subtype, _, sourceGUID, sourceName, _, _, destGUID, destName, destFlags, _, spellID, spellName, _, amount, interrupt, a, b, c, d, offhand, multistrike = local _, subtype, _, sourceGUID, sourceName, _, _, destGUID, destName, destFlags, _, spellID, spellName, _, amount, interrupt, a, b, c, d, offhand, multistrike =
CombatLogGetCurrentEventInfo() CombatLogGetCurrentEventInfo()
@ -1106,7 +1107,6 @@ end
---@param Target Unit ---@param Target Unit
---@param Angle number ---@param Angle number
---@param Distance number ---@param Distance number
---@param rotation? number
---@return boolean ---@return boolean
function Unit:IsWithinCone(Target, Angle, Distance, rotation) function Unit:IsWithinCone(Target, Angle, Distance, rotation)
if not Target:Exists() then if not Target:Exists() then
@ -1114,7 +1114,7 @@ function Unit:IsWithinCone(Target, Angle, Distance, rotation)
end end
local angle = self:GetAngle(Target) local angle = self:GetAngle(Target)
rotation = rotation or self:GetFacing() local rotation = rotation or self:GetFacing()
local diff = math.abs(angle - rotation) local diff = math.abs(angle - rotation)

@ -4,6 +4,49 @@ local ObjectManager = Tinkr.Util.ObjectManager
local Unit = Bastion.Unit local Unit = Bastion.Unit
local prefixes = {
'^player',
'^pet',
'^vehicle',
'^target',
'^focus',
'^mouseover',
'^none',
'^npc',
'^party[1-4]',
'^raid[1-4]?[0-9]',
'^boss[1-5]',
'^arena[1-5]'
}
-- Validate a unit is a valid token
local function Validate(token)
local start, index
local length, offset = string.len(token), 0
for i = 1, #prefixes do
start, index = string.find(token, prefixes[i])
if start then
offset = index + 1
if offset > length then
return true
else
while true do
start, index = string.find(token, 'target', offset, true)
if start then
offset = index + 1
if offset > length then
return true
end
else
return false
end
end
end
end
end
return false
end
-- Create a new UnitManager class -- Create a new UnitManager class
---@class UnitManager ---@class UnitManager
local UnitManager = { local UnitManager = {
@ -65,6 +108,9 @@ function UnitManager:New()
return self return self
end end
function UnitManager:Validate(token)
return Validate(token)
end
-- Get or create a unit -- Get or create a unit
---@param token string ---@param token string

@ -1,412 +1,274 @@
local Tinkr = ... local Tinkr = ...
local Evaulator = Tinkr.Evaluator
---@class Bastion ---@class Bastion
local Bastion = {DebugMode = false} local Bastion = {
DebugMode = false
}
Bastion.__index = Bastion Bastion.__index = Bastion
function Bastion:Require(file) function Bastion.require(class)
-- If require starts with an @ then we require from the scripts/bastion/scripts folder return Tinkr:require("scripts/bastion/src/" .. class .. "/" .. class, Bastion)
if file:sub(1, 1) == '@' then
file = file:sub(2)
-- print('1')
return require('scripts/bastion/scripts/' .. file, Bastion)
elseif file:sub(1, 1) == "~" then
file = file:sub(2)
-- print("2")
return require('scripts/bastion/' .. file, Bastion)
else
-- print("Normal req")
return require(file, Bastion)
end
end end
local function Load(dir) ---@type ClassMagic
local dir = dir Bastion.ClassMagic = Bastion.require("ClassMagic")
---@type List
if dir:sub(1, 1) == '@' then Bastion.List = Bastion.require("List")
dir = dir:sub(2) ---@type NotificationsList, Notification
dir = 'scripts/bastion/scripts/' .. dir Bastion.NotificationsList, Bastion.Notification = Bastion.require("NotificationsList")
end ---@type Vector3
Bastion.Vector3 = Bastion.require("Vector3")
if dir:sub(1, 1) == '~' then ---@type Sequencer
dir = dir:sub(2) Bastion.Sequencer = Bastion.require("Sequencer")
dir = 'scripts/bastion/' .. dir ---@type Command
Bastion.Command = Bastion.require("Command")
---@type Cache
Bastion.Cache = Bastion.require("Cache")
---@type Cacheable
Bastion.Cacheable = Bastion.require("Cacheable")
---@type Refreshable
Bastion.Refreshable = Bastion.require("Refreshable")
---@type Unit
Bastion.Unit = Bastion.require("Unit")
---@type Aura
Bastion.Aura = Bastion.require("Aura")
---@type APL, APLActor, APLTrait
Bastion.APL, Bastion.APLActor, Bastion.APLTrait = Bastion.require("APL")
---@type Module
Bastion.Module = Bastion.require("Module")
---@type UnitManager
Bastion.UnitManager = Bastion.require("UnitManager"):New()
---@type ObjectManager
Bastion.ObjectManager = Bastion.require("ObjectManager"):New()
---@type EventManager
Bastion.EventManager = Bastion.require("EventManager"):New()
---@type Spell
Bastion.Spell = Bastion.require("Spell")
---@type SpellBook
Bastion.SpellBook = Bastion.require("SpellBook"):New()
---@type Item
Bastion.Item = Bastion.require("Item")
---@type ItemBook
Bastion.ItemBook = Bastion.require("ItemBook"):New()
---@type AuraTable
Bastion.AuraTable = Bastion.require("AuraTable")
---@type Class
Bastion.Class = Bastion.require("Class")
---@type Timer
Bastion.Timer = Bastion.require("Timer")
---@type Timer
Bastion.CombatTimer = Bastion.Timer:New('combat')
---@type MythicPlusUtils
Bastion.MythicPlusUtils = Bastion.require("MythicPlusUtils"):New()
---@type NotificationsList
Bastion.Notifications = Bastion.NotificationsList:New()
Bastion.modules = {}
Bastion.Enabled = false
Bastion.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras)
local u = Bastion.UnitManager[unit]
if u then
u:GetAuras():OnUpdate(auras)
end end
end)
local files = ListFiles(dir) Bastion.EventManager:RegisterWoWEvent("UNIT_SPELLCAST_SUCCEEDED", function(...)
local unit, castGUID, spellID = ...
for i = 1, #files do local spell = Bastion.SpellBook:GetIfRegistered(spellID)
local file = files[i]
if file:sub(-4) == ".lua" or file:sub(-5) == '.luac' then
Bastion:Require(dir .. file:sub(1, -5))
end
end
end
function Bastion.require(class) if unit == "player" and spell then
-- return require("scripts/bastion/src/" .. class .. "/" .. class, Bastion) spell.lastCastAt = GetTime()
return Bastion:Require("~/src/" .. class .. "/" .. class)
end
-- fenv for all required files if spell:GetPostCastFunction() then
function Bastion.Bootstrap() spell:GetPostCastFunction()(spell)
Bastion.Globals = {}
---@type ClassMagic
Bastion.ClassMagic = Bastion.require("ClassMagic")
---@type List
Bastion.List = Bastion.require("List")
---@type Library
Bastion.Library = Bastion.require("Library")
---@type NotificationsList, Notification
Bastion.NotificationsList, Bastion.Notification = Bastion.require(
"NotificationsList")
---@type Vector3
Bastion.Vector3 = Bastion.require("Vector3")
---@type Sequencer
Bastion.Sequencer = Bastion.require("Sequencer")
---@type Command
Bastion.Command = Bastion.require("Command")
---@type Cache
Bastion.Cache = Bastion.require("Cache")
---@type Cacheable
Bastion.Cacheable = Bastion.require("Cacheable")
---@type Refreshable
Bastion.Refreshable = Bastion.require("Refreshable")
---@type Unit
Bastion.Unit = Bastion.require("Unit")
---@type Aura
Bastion.Aura = Bastion.require("Aura")
---@type APL, APLActor, APLTrait
Bastion.APL, Bastion.APLActor, Bastion.APLTrait = Bastion.require("APL")
---@type Module
Bastion.Module = Bastion.require("Module")
---@type UnitManager
Bastion.UnitManager = Bastion.require("UnitManager"):New()
---@type ObjectManager
Bastion.ObjectManager = Bastion.require("ObjectManager"):New()
---@type EventManager
Bastion.EventManager = Bastion.require("EventManager")
Bastion.Globals.EventManager = Bastion.EventManager:New()
---@type Spell
Bastion.Spell = Bastion.require("Spell")
---@type SpellBook
Bastion.SpellBook = Bastion.require("SpellBook")
Bastion.Globals.SpellBook = Bastion.SpellBook:New()
---@type Item
Bastion.Item = Bastion.require("Item")
---@type ItemBook
Bastion.ItemBook = Bastion.require("ItemBook")
Bastion.Globals.ItemBook = Bastion.ItemBook:New()
---@type AuraTable
Bastion.AuraTable = Bastion.require("AuraTable")
---@type Class
Bastion.Class = Bastion.require("Class")
---@type Timer
Bastion.Timer = Bastion.require("Timer")
---@type Timer
Bastion.CombatTimer = Bastion.Timer:New('combat')
---@type MythicPlusUtils
Bastion.MythicPlusUtils = Bastion.require("MythicPlusUtils"):New()
---@type NotificationsList
Bastion.Notifications = Bastion.NotificationsList:New()
local LIBRARIES = {}
local MODULES = {}
Bastion.Enabled = false
Bastion.Globals.EventManager:RegisterWoWEvent('UNIT_AURA',
function(unit, auras)
local u = Bastion.UnitManager[unit]
if u then u:GetAuras():OnUpdate(auras) end
end)
Bastion.Globals.EventManager:RegisterWoWEvent("UNIT_SPELLCAST_SUCCEEDED",
function(...)
local unit, castGUID, spellID = ...
local spell = Bastion.Globals.SpellBook:GetIfRegistered(spellID)
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 missed = {}
Bastion.Globals.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", local pguid = UnitGUID("player")
function() local missed = {}
local args = {CombatLogGetCurrentEventInfo()} Bastion.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", 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 u:SetLastCombatTime(t) end if u then
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 == if subEvent == "SPELL_MISSED" and sourceGUID == pguid and spellID == 408 then
408 then local missType = args[15]
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() Bastion.Ticker = C_Timer.NewTicker(0.1, function()
if not Bastion.CombatTimer:IsRunning() and UnitAffectingCombat("player") then if not Bastion.CombatTimer:IsRunning() and UnitAffectingCombat("player") then
Bastion.CombatTimer:Start() Bastion.CombatTimer:Start()
elseif Bastion.CombatTimer:IsRunning() and elseif Bastion.CombatTimer:IsRunning() and not UnitAffectingCombat("player") then
not UnitAffectingCombat("player") then Bastion.CombatTimer:Reset()
Bastion.CombatTimer:Reset() end
end
if Bastion.Enabled then if Bastion.Enabled then
Bastion.ObjectManager:Refresh() Bastion.ObjectManager:Refresh()
for i = 1, #MODULES do MODULES[i]:Tick() end for i = 1, #Bastion.modules do
Bastion.modules[i]:Tick()
end end
end)
function Bastion:Register(module)
table.insert(MODULES, module)
Bastion:Print("Registered", module)
end end
end)
-- Find a module by name function Bastion:Register(module)
function Bastion:FindModule(name) table.insert(Bastion.modules, module)
for i = 1, #MODULES do Bastion:Print("Registered", module)
if MODULES[i].name == name then return MODULES[i] end end
end
return nil -- Find a module by name
function Bastion:FindModule(name)
for i = 1, #Bastion.modules do
if Bastion.modules[i].name == name then
return Bastion.modules[i]
end
end end
function Bastion:Print(...) return nil
local args = {...} end
local str = "|cFFDF362D[Bastion]|r |cFFFFFFFF"
for i = 1, #args do str = str .. tostring(args[i]) .. " " end function Bastion:Print(...)
print(str) local args = { ... }
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 return end if not Bastion.DebugMode then
local args = {...} return
local str = "|cFFDF6520[Bastion]|r |cFFFFFFFF" end
for i = 1, #args do str = str .. tostring(args[i]) .. " " end local args = { ... }
print(str) local str = "|cFFDF6520[Bastion]|r |cFFFFFFFF"
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
local spellID
if C_Spell.GetSpellInfo then -- use spellName and spellSubName here
local info = C_Spell.GetSpellInfo(spellName) local spellID = select(7, GetSpellInfo(spellName))
spellID = info.spellID
else
spellID = select(7, GetSpellInfo(spellName))
end
if spellID then if spellID then
spellName = spellName:gsub("[%W%s]", "") spellName = spellName:gsub("[%W%s]", "")
WriteFile('bastion-' .. UnitClass('player') .. '-' .. rand .. WriteFile('bastion-' .. UnitClass('player') .. '-' .. rand .. '.lua',
'.lua', "local " .. spellName .. " = Bastion.SpellBook:GetSpell(" .. spellID .. ")", true)
"local " .. spellName ..
" = Bastion.Globals.SpellBook:GetSpell(" ..
spellID .. ")\n", true)
end
i = i + 1
end end
end) i = i + 1
end
Command:Register('module', 'Toggle a module on/off', function(args) end)
local module = Bastion:FindModule(args[2])
if module then Command:Register('module', 'Toggle a module on/off', function(args)
module:Toggle() local module = Bastion:FindModule(args[2])
if module.enabled then if module then
Bastion:Print("Enabled", module.name) module:Toggle()
else if module.enabled then
Bastion:Print("Disabled", module.name) Bastion:Print("Enabled", module.name)
end
else else
Bastion:Print("Module not found") Bastion:Print("Disabled", module.name)
end end
end) else
Bastion:Print("Module not found")
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
Bastion.MythicPlusUtils:ToggleCastLogging()
Bastion:Print("Cast logging",
Bastion.MythicPlusUtils.castLogging and "enabled" or
"disabled")
return
end
Bastion:Print("[MythicPlusUtils] Unknown command")
Bastion:Print("Available commands:")
Bastion:Print("debuffs")
Bastion:Print("casts")
end)
Command:Register('missed', 'Dump the list of immune kidney shot spells',
function()
for k, v in pairs(missed) do Bastion:Print(k) end
end)
---@param library Library
function Bastion:RegisterLibrary(library)
LIBRARIES[library.name] = library
end end
end)
function Bastion:CheckLibraryDependencies()
for k, v in pairs(LIBRARIES) do Command:Register('mplus', 'Toggle m+ module on/off', function(args)
if v.dependencies then local cmd = args[2]
for i = 1, #v.dependencies do if cmd == 'debuffs' then
local dep = v.dependencies[i] Bastion.MythicPlusUtils:ToggleDebuffLogging()
if LIBRARIES[dep] then Bastion:Print("Debuff logging", Bastion.MythicPlusUtils.debuffLogging and "enabled" or "disabled")
if LIBRARIES[dep].dependencies then return
for j = 1, #LIBRARIES[dep].dependencies do
if LIBRARIES[dep].dependencies[j] == v.name then
Bastion:Print(
"Circular dependency detected between " ..
v.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 true
end end
function Bastion:Import(library) if cmd == 'casts' then
local lib = self:GetLibrary(library) Bastion.MythicPlusUtils:ToggleCastLogging()
Bastion:Print("Cast logging", Bastion.MythicPlusUtils.castLogging and "enabled" or "disabled")
if not lib then error("Library " .. library .. " not found") end return
return lib:Resolve()
end end
function Bastion:GetLibrary(name) Bastion:Print("[MythicPlusUtils] Unknown command")
if not LIBRARIES[name] then Bastion:Print("Available commands:")
error("Library " .. name .. " not found") Bastion:Print("debuffs")
end Bastion:Print("casts")
end)
local library = LIBRARIES[name] Command:Register('missed', 'Dump the list of immune kidney shot spells', function()
for k, v in pairs(missed) do
-- if library.dependencies then Bastion:Print(k)
-- 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
end)
-- if not Bastion:CheckLibraryDependencies() then local files = ListFiles("scripts/bastion/scripts")
-- return
-- end
Load("@Libraries/") for i = 1, #files do
Load("@Modules/") local file = files[i]
Load("@") if file:sub(-4) == ".lua" or file:sub(-5) == '.luac' then
Tinkr:require("scripts/bastion/scripts/" .. file:sub(1, -5), Bastion)
end
end end
Bastion.Bootstrap()

Loading…
Cancel
Save