Compare commits

...

44 Commits

Author SHA1 Message Date
mrmoo 8eb4a620e5 Fixed function Unit:PredictHealth(time) 1 year ago
4n0n a22aa67d2a Merge pull request 'main' (#19) from CiscOH/Bastion:main into main 1 year ago
Ciscoh Bellic 3877c58b0c Removed return in load(dir) function. it was only loading the first file and no more 1 year ago
CiscOH 8a6308c584 Merge pull request 'main' (#7) from Bastion/Bastion:main into main 1 year ago
4n0n b43166be76 Era 1 year ago
4n0n ede085dd13 Merge pull request 'Bug Fix on APL traits' (#18) from LyLoLoq/Bastion:main into main 1 year ago
LyLoLoq 15920cecb3 Typing fix 1 year ago
LyLoLoq 8e5268229a Bug Fix on APL traits 1 year ago
CiscOH b1d34f113d Merge pull request 'main' (#6) from Bastion/Bastion:main into main 1 year ago
4n0n cadb7df64e Merge pull request 'Fix APL + Change to Spell:Cast' (#17) from LyLoLoq/Bastion:main into main 1 year ago
LyLoLoq a84930cef2 Change Spell:Cast 1 year ago
LyLoLoq 1bdf96e5ca Fix APL 1 year ago
CiscOH 4680344e6f Merge pull request 'main' (#5) from Bastion/Bastion:main into main 1 year ago
4n0n f722d17306 Merge branch 'main' of https://git.tinkr.site/Bastion/Bastion 1 year ago
4n0n 5db2f059d8 Add Spell:Fresh() 1 year ago
4n0n 910387c775 Merge pull request 'main' (#16) from CiscOH/Bastion:main into main 1 year ago
CiscOH 2994e8d1dd remove UnitManager:Validate(token) method 1 year ago
CiscOH eab3bb3a8a Merge pull request 'main' (#4) from Bastion/Bastion:main into main 1 year ago
4n0n e4d4270b60 add bastion requires 1 year ago
4n0n 025c0c5c88 remove 1 year ago
CiscOH 5dc90ce113 Merge pull request 'main' (#3) from Bastion/Bastion:main into main 1 year ago
4n0n bfdd70359d Fix typo 1 year ago
4n0n 5472aa1998 Merge pull request 'main' (#15) from CiscOH/Bastion:main into main 1 year ago
CiscOH ba9de7753f added line break to dump spells 1 year ago
CiscOH 94b584a99b Merge pull request 'Update 'README.md'' (#1) from Bastion/Bastion:main into main 1 year ago
4n0n 6924780785 Update 'README.md' 1 year ago
4n0n febee39182 Add highest/leastof functions to auratable, remove print 1 year ago
4n0n a99e71dd8e Aura table updates 1 year ago
4n0n 36ab641a13 Merge branch 'main' of https://git.tinkr.site/Bastion/Bastion 1 year ago
4n0n e8913d3ab8 Spellbook get list 1 year ago
4n0n 9d594366dd Merge pull request 'Change Unit.ttd_ticker initialization state' (#13) from abunai/Bastion:abunai-ttd-fix into main 1 year ago
abunai 2200a36bdf Change Unit.ttd_ticker initialization state 1 year ago
4n0n 559c4339a4 Fix aura list finding 1 year ago
4n0n 7b3b714d39 Add findanyof 1 year ago
4n0n 1cc8b541f8 Cleanup 1 year ago
4n0n 677229738d Move spellbook and itembook out of globals, remove prints 1 year ago
4n0n 9d47758f8c Merge branch 'main' of https://git.tinkr.site/Bastion/Bastion 1 year ago
4n0n 06916f6bc6 Spellbook and Itembook no longer shared through the engine 1 year ago
4n0n 4c138f1c9f Merge pull request 'More types' (#11) from lyloloq/Bastion:main into main 1 year ago
4n0n f5367327e6 Updated library handling 1 year ago
LyLoLoq 630fcfc3d9 More types 1 year ago
4n0n d5b0ccf42b Merge branch 'main' of https://git.tinkr.site/Bastion/Bastion 1 year ago
4n0n 5f0affd907 Add Bastion Libraries 1 year ago
4n0n 356cc78dd1 Merge pull request 'Remove rogue print' (#9) from 4n0n-patch-1 into main 1 year ago
  1. 6
      .gitignore
  2. 4
      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. 58
      src/APL/APL.lua
  8. 20
      src/Aura/Aura.lua
  9. 357
      src/AuraTable/AuraTable.lua
  10. 15
      src/Class/Class.lua
  11. 7
      src/Command/Command.lua
  12. 8
      src/Item/Item.lua
  13. 115
      src/Library/Library.lua
  14. 10
      src/List/List.lua
  15. 11
      src/MythicPlusUtils/MythicPlusUtils.lua
  16. 7
      src/ObjectManager/ObjectManager.lua
  17. 3
      src/Sequencer/Sequencer.lua
  18. 28
      src/Spell/Spell.lua
  19. 13
      src/SpellBook/SpellBook.lua
  20. 40
      src/Unit/Unit.lua
  21. 46
      src/UnitManager/UnitManager.lua
  22. 173
      src/_bastion.lua

6
.gitignore vendored

@ -7,7 +7,13 @@ 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/*

@ -11,3 +11,7 @@ Feel free to browse around the [Wiki](https://git.tinkr.site/4n0n/bastion/wiki)
- [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)

@ -0,0 +1,24 @@
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)

@ -0,0 +1,21 @@
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
}
}))

@ -0,0 +1,15 @@
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
}
}))

@ -0,0 +1,25 @@
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,5 +1,4 @@
-- 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 = {}
@ -55,7 +54,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
@ -85,13 +84,11 @@ 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
@ -111,24 +108,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().target, self:GetActor().condition)
self:GetActor().condition) else
end
-- print("Bastion: APL:Execute: No condition for spell " .. self:GetActor().spell:GetName()) -- 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 self:GetActor().spell:CastableIf(self:GetActor().castableFunc):OnCast(self:GetActor().onCastFunc):Cast(
:GetActor().target) self:GetActor().target)
end
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)
end else
-- print("Bastion: APL:Execute: No condition for spell " .. self:GetActor().spell:GetName()) -- print("Bastion: APL:Execute: No 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)
end 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)
self:GetActor().cb(self) self:GetActor().cb(self)
@ -189,7 +185,11 @@ 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({ variable = name, cb = cb, _apl = self }) local actor = APLActor:New({
variable = name,
cb = cb,
_apl = self
})
table.insert(self.apl, actor) table.insert(self.apl, actor)
return actor return actor
end end
@ -199,14 +199,17 @@ 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({ action = action, cb = cb }) local actor = APLActor:New({
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? fun(...):boolean ---@param condition? string|fun(...):boolean
---@return APLActor ---@return APLActor
function APL:AddSpell(spell, condition) function APL:AddSpell(spell, condition)
local castableFunc = spell.CastableIfFunc local castableFunc = spell.CastableIfFunc
@ -228,13 +231,18 @@ 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({ item = item, condition = condition, usableFunc = usableFunc, target = target }) local actor = APLActor:New({
item = item,
condition = condition,
usableFunc = usableFunc,
target = target
})
table.insert(self.apl, actor) table.insert(self.apl, actor)
@ -249,7 +257,10 @@ 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({ apl = apl, condition = condition }) local actor = APLActor:New({
apl = apl,
condition = condition
})
table.insert(self.apl, actor) table.insert(self.apl, actor)
return actor return actor
end end
@ -257,14 +268,12 @@ 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() and actor:Evaluate() then if actor:HasTraits() then
if actor:Execute() then if actor:Evaluate() and 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
@ -276,7 +285,10 @@ 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({ sequencer = sequencer, condition = condition }) local actor = APLActor:New({
sequencer = sequencer,
condition = condition
})
table.insert(self.apl, actor) table.insert(self.apl, actor)
return actor return actor
end end

@ -1,5 +1,4 @@
-- 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
@ -66,19 +65,18 @@ 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.SpellBook:GetSpell(self.aura.spellId) Bastion.Globals.SpellBook:GetSpell(self.aura.spellId)
end end
return self return self
end end
local name, icon, count, dispelType, duration, expirationTime, source, isStealable, nameplateShowPersonal, local name, icon, count, dispelType, duration, expirationTime, source, isStealable, nameplateShowPersonal, spellId,
spellId, canApplyAura, isBossDebuff, castByPlayer, nameplateShowAll, timeMod = UnitAura(unit:GetOMToken(), index, canApplyAura, isBossDebuff, castByPlayer, nameplateShowAll, timeMod = UnitAura(unit:GetOMToken(), index, type)
type)
local self = setmetatable({}, Aura) local self = setmetatable({}, Aura)
self.aura = { self.aura = {
@ -100,10 +98,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.SpellBook:GetSpell(self.aura.spellId) Bastion.Globals.SpellBook:GetSpell(self.aura.spellId)
end end
return self return self
end end
@ -132,11 +130,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.SpellBook:GetSpell(self.aura.spellId) Bastion.Globals.SpellBook:GetSpell(self.aura.spellId)
return self return self
end end
@ -239,7 +237,7 @@ end
-- Get the auras spell id -- Get the auras spell id
---@return Spell ---@return Spell
function Aura:GetSpell() function Aura:GetSpell()
return Bastion.SpellBook:GetSpell(self.aura.spellId) return Bastion.Globals.SpellBook:GetSpell(self.aura.spellId)
end end
-- Get the auras can apply aura status -- Get the auras can apply aura status

@ -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 then if Tinkr.classic or Tinkr.era 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 then if Tinkr.classic or Tinkr.era 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 then if not Tinkr.classic or Tinkr.era 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 then if not Tinkr.classic or Tinkr.era 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 then if not Tinkr.classic or Tinkr.era 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 then if not Tinkr.classic or Tinkr.era then
self:RemoveInstanceID(a:GetAuraInstanceID()) self:RemoveInstanceID(a:GetAuraInstanceID())
end end
end end
@ -384,6 +384,351 @@ 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,12 +18,21 @@ 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,
@ -50,10 +59,16 @@ 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,6 +1,13 @@
-- 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

@ -54,7 +54,7 @@ function Item:New(id)
local name, spellID = GetItemSpell(self:GetID()) local name, spellID = GetItemSpell(self:GetID())
if spellID then if spellID then
self.spellID = spellID self.spellID = spellID
Bastion.SpellBook:GetSpell(spellID) Bastion.Globals.SpellBook:GetSpell(spellID)
end end
return self return self
@ -239,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 IsItemPending() == 64 then if IsSpellPending() == 64 then
MouselookStop() MouselookStop()
Click(x, y, z) Click(x, y, z)
if self:GetWasLooking() then if self:GetWasLooking() then
@ -302,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.SpellBook:GetSpell(self:GetID()):GetLastCastTime() return Bastion.Globals.SpellBook:GetSpell(self:GetID()):GetLastCastTime()
end end
-- Get time since last use -- Get time since last use
@ -430,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.SpellBook:GetSpell(self.spellID) return Bastion.Globals.SpellBook:GetSpell(self.spellID)
end end
return nil return nil

@ -0,0 +1,115 @@
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,5 +1,3 @@
local Tinkr, Bastion = ...
---@class List ---@class List
local List = { local List = {
-- Add overload -- Add overload
@ -116,8 +114,12 @@ 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 = callback(result, v) result, done = callback(result, v)
if done then
break
end
end end
return result return result
end end
@ -144,7 +146,7 @@ function List:findIndex(callback)
return nil return nil
end end
---@param callback fun(value: any): boolean ---@param callback fun(...): boolean
---@return nil ---@return nil
function List:sort(callback) function List:sort(callback)
table.sort(self._list, callback) table.sort(self._list, callback)

@ -17,6 +17,7 @@ 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 = {
@ -429,7 +430,7 @@ function MythicPlusUtils:New()
} }
} }
Bastion.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras) Bastion.Globals.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras)
if not self.debuffLogging then if not self.debuffLogging then
return return
end end
@ -452,7 +453,7 @@ function MythicPlusUtils:New()
end end
end) end)
Bastion.EventManager:RegisterWoWEvent('UNIT_SPELLCAST_START', function(unitTarget, castGUID, spellID) Bastion.Globals.EventManager:RegisterWoWEvent('UNIT_SPELLCAST_START', function(unitTarget, castGUID, spellID)
if not self.castLogging then if not self.castLogging then
return return
end end
@ -471,7 +472,7 @@ function MythicPlusUtils:New()
]], true) ]], true)
end) end)
Bastion.EventManager:RegisterWoWEvent('UNIT_SPELLCAST_CHANNEL_START', function(unitTarget, castGUID, spellID) Bastion.Globals.EventManager:RegisterWoWEvent('UNIT_SPELLCAST_CHANNEL_START', function(unitTarget, castGUID, spellID)
if not self.castLogging then if not self.castLogging then
return return
end end
@ -567,8 +568,4 @@ 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,6 +1,11 @@
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
@ -20,7 +25,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 ---@return List | false
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,5 +1,4 @@
-- 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
@ -45,12 +44,10 @@ 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

@ -12,11 +12,11 @@ local Spell = {
lastCastAt = false, lastCastAt = false,
conditions = {}, conditions = {},
target = false, target = false,
release_at = false, release_at = false
} }
local usableExcludes = { local usableExcludes = {
[18562] = true, [18562] = true
} }
function Spell:__index(k) function Spell:__index(k)
@ -57,6 +57,12 @@ function Spell:New(id)
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()
@ -155,11 +161,15 @@ end
-- Cast the spell -- Cast the spell
---@param unit Unit ---@param unit Unit
---@param condition string ---@param condition? string|function
---@return boolean ---@return boolean
function Spell:Cast(unit, condition) function Spell:Cast(unit, condition)
if condition and not self:EvaluateCondition(condition) then if 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
@ -307,9 +317,9 @@ function Spell:GetWasLooking()
end end
-- Click the spell -- Click the spell
---@param x number ---@param x number|Vector3
---@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
@ -523,9 +533,7 @@ end
-- IsDiseaseDispel -- IsDiseaseDispel
---@return boolean ---@return boolean
function Spell:IsDiseaseDispel() function Spell:IsDiseaseDispel()
return ({ return ({})[self:GetID()]
})[self:GetID()]
end end
-- IsSpell -- IsSpell

@ -27,13 +27,24 @@ 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)

@ -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 = 0, ttd_ticker = false,
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.SpellBook:GetSpell(spellId) return Bastion.Globals.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 then if Tinkr.classic or Tinkr.era 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 then if Tinkr.classic or Tinkr.era 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 then if Tinkr.classic or Tinkr.era 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()
@ -784,7 +784,8 @@ function Unit:PredictHealth(time)
table.remove(self.regression_history, 1) table.remove(self.regression_history, 1)
end end
table.insert(self.regression_history, { time = GetTime(), percent = self:GetHP() }) local currentTime = GetTime()
table.insert(self.regression_history, { time = currentTime, percent = self:GetHP() })
for i = 1, #self.regression_history do for i = 1, #self.regression_history do
local entry = self.regression_history[i] local entry = self.regression_history[i]
@ -793,9 +794,12 @@ function Unit:PredictHealth(time)
end end
local slope, intercept = self:LinearRegression(x, y) local slope, intercept = self:LinearRegression(x, y)
return slope * time + intercept
return slope * (currentTime + time) + intercept
end end
-- Use linear regression to guess the time until a given health percent -- Use linear regression to guess the time until a given health percent
---@param percent number ---@param percent number
---@return number ---@return number
@ -838,7 +842,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 = nil self.ttd_ticker = false
end end
return 0 return 0
end end
@ -926,13 +930,12 @@ end
-- IsStealthed -- IsStealthed
---@return boolean ---@return boolean
function Unit:IsStealthed() function Unit:IsStealthed()
local Stealth = Bastion.SpellBook:GetSpell(1784) local Stealth = Bastion.Globals.SpellBook:GetSpell(1784)
local Vanish = Bastion.SpellBook:GetSpell(1856) local Vanish = Bastion.Globals.SpellBook:GetSpell(1856)
local ShadowDance = Bastion.SpellBook:GetSpell(185422) local ShadowDance = Bastion.Globals.SpellBook:GetSpell(185422)
local Subterfuge = Bastion.SpellBook:GetSpell(115192) local Subterfuge = Bastion.Globals.SpellBook:GetSpell(115192)
local Shadowmeld = Bastion.SpellBook:GetSpell(58984) local Shadowmeld = Bastion.Globals.SpellBook:GetSpell(58984)
local Sepsis = Bastion.SpellBook:GetSpell(328305) local Sepsis = Bastion.Globals.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
@ -960,7 +963,7 @@ end
---@return nil ---@return nil
function Unit:WatchForSwings() function Unit:WatchForSwings()
Bastion.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function() Bastion.Globals.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()
@ -1107,6 +1110,7 @@ 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 +1118,7 @@ function Unit:IsWithinCone(Target, Angle, Distance, rotation)
end end
local angle = self:GetAngle(Target) local angle = self:GetAngle(Target)
local rotation = rotation or self:GetFacing() rotation = rotation or self:GetFacing()
local diff = math.abs(angle - rotation) local diff = math.abs(angle - rotation)

@ -4,49 +4,6 @@ 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 = {
@ -108,9 +65,6 @@ 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

@ -6,14 +6,58 @@ local Bastion = {
} }
Bastion.__index = Bastion Bastion.__index = Bastion
function Bastion:Require(file)
-- If require starts with an @ then we require from the scripts/bastion/scripts folder
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
local function Load(dir)
local dir = dir
if dir:sub(1, 1) == '@' then
dir = dir:sub(2)
dir = 'scripts/bastion/scripts/' .. dir
end
if dir:sub(1, 1) == '~' then
dir = dir:sub(2)
dir = 'scripts/bastion/' .. dir
end
local files = ListFiles(dir)
for i = 1, #files do
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) function Bastion.require(class)
return Tinkr:require("scripts/bastion/src/" .. class .. "/" .. class, Bastion) -- return require("scripts/bastion/src/" .. class .. "/" .. class, Bastion)
return Bastion:Require("~/src/" .. class .. "/" .. class)
end end
Bastion.Globals = {}
---@type ClassMagic ---@type ClassMagic
Bastion.ClassMagic = Bastion.require("ClassMagic") Bastion.ClassMagic = Bastion.require("ClassMagic")
---@type List ---@type List
Bastion.List = Bastion.require("List") Bastion.List = Bastion.require("List")
---@type Library
Bastion.Library = Bastion.require("Library")
---@type NotificationsList, Notification ---@type NotificationsList, Notification
Bastion.NotificationsList, Bastion.Notification = Bastion.require("NotificationsList") Bastion.NotificationsList, Bastion.Notification = Bastion.require("NotificationsList")
---@type Vector3 ---@type Vector3
@ -41,15 +85,18 @@ Bastion.UnitManager = Bastion.require("UnitManager"):New()
---@type ObjectManager ---@type ObjectManager
Bastion.ObjectManager = Bastion.require("ObjectManager"):New() Bastion.ObjectManager = Bastion.require("ObjectManager"):New()
---@type EventManager ---@type EventManager
Bastion.EventManager = Bastion.require("EventManager"):New() Bastion.EventManager = Bastion.require("EventManager")
Bastion.Globals.EventManager = Bastion.EventManager:New()
---@type Spell ---@type Spell
Bastion.Spell = Bastion.require("Spell") Bastion.Spell = Bastion.require("Spell")
---@type SpellBook ---@type SpellBook
Bastion.SpellBook = Bastion.require("SpellBook"):New() Bastion.SpellBook = Bastion.require("SpellBook")
Bastion.Globals.SpellBook = Bastion.SpellBook:New()
---@type Item ---@type Item
Bastion.Item = Bastion.require("Item") Bastion.Item = Bastion.require("Item")
---@type ItemBook ---@type ItemBook
Bastion.ItemBook = Bastion.require("ItemBook"):New() Bastion.ItemBook = Bastion.require("ItemBook")
Bastion.Globals.ItemBook = Bastion.ItemBook:New()
---@type AuraTable ---@type AuraTable
Bastion.AuraTable = Bastion.require("AuraTable") Bastion.AuraTable = Bastion.require("AuraTable")
---@type Class ---@type Class
@ -62,10 +109,13 @@ Bastion.CombatTimer = Bastion.Timer:New('combat')
Bastion.MythicPlusUtils = Bastion.require("MythicPlusUtils"):New() Bastion.MythicPlusUtils = Bastion.require("MythicPlusUtils"):New()
---@type NotificationsList ---@type NotificationsList
Bastion.Notifications = Bastion.NotificationsList:New() Bastion.Notifications = Bastion.NotificationsList:New()
Bastion.modules = {}
local LIBRARIES = {}
local MODULES = {}
Bastion.Enabled = false Bastion.Enabled = false
Bastion.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras) Bastion.Globals.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras)
local u = Bastion.UnitManager[unit] local u = Bastion.UnitManager[unit]
if u then if u then
@ -73,10 +123,10 @@ Bastion.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras)
end end
end) end)
Bastion.EventManager:RegisterWoWEvent("UNIT_SPELLCAST_SUCCEEDED", function(...) Bastion.Globals.EventManager:RegisterWoWEvent("UNIT_SPELLCAST_SUCCEEDED", function(...)
local unit, castGUID, spellID = ... local unit, castGUID, spellID = ...
local spell = Bastion.SpellBook:GetIfRegistered(spellID) local spell = Bastion.Globals.SpellBook:GetIfRegistered(spellID)
if unit == "player" and spell then if unit == "player" and spell then
spell.lastCastAt = GetTime() spell.lastCastAt = GetTime()
@ -89,8 +139,9 @@ end)
local pguid = UnitGUID("player") local pguid = UnitGUID("player")
local missed = {} local missed = {}
Bastion.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function()
local args = { CombatLogGetCurrentEventInfo() } Bastion.Globals.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]
@ -132,6 +183,7 @@ Bastion.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function()
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()
@ -141,22 +193,22 @@ Bastion.Ticker = C_Timer.NewTicker(0.1, function()
if Bastion.Enabled then if Bastion.Enabled then
Bastion.ObjectManager:Refresh() Bastion.ObjectManager:Refresh()
for i = 1, #Bastion.modules do for i = 1, #MODULES do
Bastion.modules[i]:Tick() MODULES[i]:Tick()
end end
end end
end) end)
function Bastion:Register(module) function Bastion:Register(module)
table.insert(Bastion.modules, module) table.insert(MODULES, module)
Bastion:Print("Registered", module) Bastion:Print("Registered", module)
end end
-- Find a module by name -- Find a module by name
function Bastion:FindModule(name) function Bastion:FindModule(name)
for i = 1, #Bastion.modules do for i = 1, #MODULES do
if Bastion.modules[i].name == name then if MODULES[i].name == name then
return Bastion.modules[i] return MODULES[i]
end end
end end
@ -164,7 +216,7 @@ function Bastion:FindModule(name)
end end
function Bastion:Print(...) function Bastion:Print(...)
local args = { ... } local args = {...}
local str = "|cFFDF362D[Bastion]|r |cFFFFFFFF" local str = "|cFFDF362D[Bastion]|r |cFFFFFFFF"
for i = 1, #args do for i = 1, #args do
str = str .. tostring(args[i]) .. " " str = str .. tostring(args[i]) .. " "
@ -176,7 +228,7 @@ function Bastion:Debug(...)
if not Bastion.DebugMode then if not Bastion.DebugMode then
return return
end end
local args = { ... } local args = {...}
local str = "|cFFDF6520[Bastion]|r |cFFFFFFFF" local str = "|cFFDF6520[Bastion]|r |cFFFFFFFF"
for i = 1, #args do for i = 1, #args do
str = str .. tostring(args[i]) .. " " str = str .. tostring(args[i]) .. " "
@ -203,13 +255,16 @@ Command:Register('debug', 'Toggle debug mode on/off', function()
Bastion:Print("Debug mode disabled") Bastion:Print("Debug mode disabled")
end end
end) end)
Command:Register('dumpspells', 'Dump spells to a file', function() Command:Register('dumpspells', 'Dump spells to a file', function()
local i = 1 local i = 1
local rand = math.random(100000, 999999) local rand = math.random(100000, 999999)
while true do while true do
local spellName, spellSubName = GetSpellBookItemName(i, BOOKTYPE_SPELL) local spellName, spellSubName = GetSpellBookItemName(i, BOOKTYPE_SPELL)
if not spellName then if not spellName then
do break end do
break
end
end end
-- use spellName and spellSubName here -- use spellName and spellSubName here
@ -218,7 +273,7 @@ Command:Register('dumpspells', 'Dump spells to a file', function()
if spellID then if spellID then
spellName = spellName:gsub("[%W%s]", "") spellName = spellName:gsub("[%W%s]", "")
WriteFile('bastion-' .. UnitClass('player') .. '-' .. rand .. '.lua', WriteFile('bastion-' .. UnitClass('player') .. '-' .. rand .. '.lua',
"local " .. spellName .. " = Bastion.SpellBook:GetSpell(" .. spellID .. ")", true) "local " .. spellName .. " = Bastion.Globals.SpellBook:GetSpell(" .. spellID .. ")\n", true)
end end
i = i + 1 i = i + 1
end end
@ -264,11 +319,79 @@ Command:Register('missed', 'Dump the list of immune kidney shot spells', functio
end end
end) end)
local files = ListFiles("scripts/bastion/scripts") ---@param library Library
function Bastion:RegisterLibrary(library)
LIBRARIES[library.name] = library
end
for i = 1, #files do function Bastion:CheckLibraryDependencies()
local file = files[i] for k, v in pairs(LIBRARIES) do
if file:sub(-4) == ".lua" or file:sub(-5) == '.luac' then if v.dependencies then
Tinkr:require("scripts/bastion/scripts/" .. file:sub(1, -5), Bastion) for i = 1, #v.dependencies do
local dep = v.dependencies[i]
if LIBRARIES[dep] then
if LIBRARIES[dep].dependencies then
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
end
else
Bastion:Print("Library " .. v.name .. " depends on " .. dep .. " but it's not registered")
return false
end
end
end
end
return true
end
function Bastion:Import(library)
local lib = self:GetLibrary(library)
if not lib then
error("Library " .. library .. " not found")
end
return lib:Resolve()
end end
function Bastion:GetLibrary(name)
if not LIBRARIES[name] then
error("Library " .. name .. " not found")
end
local library = LIBRARIES[name]
-- 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
-- if not Bastion:CheckLibraryDependencies() then
-- return
-- end
Load("@Libraries/")
Load("@Modules/")
Load("@")

Loading…
Cancel
Save