diff --git a/.gitignore b/.gitignore index 87e8f31..dadad45 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,13 @@ DS_Store ## ignore all files in scripts scripts/* +!scripts/Libraries +scripts/Libraries/* !scripts/.gitkeep +!scripts/ExampleModule.lua +!scripts/Libraries/ExampleLibrary.lua +!scripts/Libraries/ExampleDependency.lua +!scripts/Libraries/ExampleDependencyError.lua ## ignore vscode settings .vscode/* diff --git a/scripts/ExampleModule.lua b/scripts/ExampleModule.lua new file mode 100644 index 0000000..4289a24 --- /dev/null +++ b/scripts/ExampleModule.lua @@ -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) diff --git a/scripts/Libraries/ExampleDependency.lua b/scripts/Libraries/ExampleDependency.lua new file mode 100644 index 0000000..87c1449 --- /dev/null +++ b/scripts/Libraries/ExampleDependency.lua @@ -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 + } +})) diff --git a/scripts/Libraries/ExampleDependencyError.lua b/scripts/Libraries/ExampleDependencyError.lua new file mode 100644 index 0000000..5fc4485 --- /dev/null +++ b/scripts/Libraries/ExampleDependencyError.lua @@ -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 + } +})) diff --git a/scripts/Libraries/ExampleLibrary.lua b/scripts/Libraries/ExampleLibrary.lua new file mode 100644 index 0000000..ddb7afa --- /dev/null +++ b/scripts/Libraries/ExampleLibrary.lua @@ -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 + } +})) diff --git a/src/APL/APL.lua b/src/APL/APL.lua index 95d2ebe..49f0659 100644 --- a/src/APL/APL.lua +++ b/src/APL/APL.lua @@ -1,5 +1,4 @@ -- Document with emmy lua: https://emmylua.github.io/ - -- Create an APL trait for the APL class ---@class APLTrait local APLTrait = {} @@ -55,7 +54,7 @@ end ---@param ... APLTrait ---@return APLActor function APLActor:AddTraits(...) - for _, trait in ipairs({ ... }) do + for _, trait in ipairs({...}) do table.insert(self.traits, trait) 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 self:GetActor().sequencer then if self:GetActor().condition and self:GetActor().condition() and not self:GetActor().sequencer:Finished() then - print("Execute?") self:GetActor().sequencer:Execute() return true end if not self:GetActor().condition and not self:GetActor().sequencer:Finished() then - print("Execute?") self:GetActor().sequencer:Execute() return true end @@ -111,13 +108,12 @@ function APLActor:Execute() if self:GetActor().condition then -- 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().target, - self:GetActor().condition) + self:GetActor().target, self:GetActor().condition) 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) + self:GetActor().spell:CastableIf(self:GetActor().castableFunc):OnCast(self:GetActor().onCastFunc):Cast( + self:GetActor().target) end if self:GetActor().item then if self:GetActor().condition then @@ -189,7 +185,11 @@ end ---@param cb fun(...):any ---@return APLActor 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) return actor end @@ -199,7 +199,10 @@ end ---@param cb fun(...):any ---@return APLActor 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) return actor end @@ -234,7 +237,12 @@ function APL:AddItem(item, condition) local usableFunc = item.UsableIfFunc 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) @@ -249,7 +257,10 @@ function APL:AddAPL(apl, condition) if not condition then error("Bastion: APL:AddAPL: No condition for APL " .. apl.name) end - local actor = APLActor:New({ apl = apl, condition = condition }) + local actor = APLActor:New({ + apl = apl, + condition = condition + }) table.insert(self.apl, actor) return actor end @@ -259,12 +270,10 @@ function APL:Execute() for _, actor in ipairs(self.apl) do if actor:HasTraits() and actor:Evaluate() then if actor:Execute() then - print("BREAQK", actor) break end else if actor:Execute() then - print("BREAQK", actor) break end end @@ -276,7 +285,10 @@ end ---@param condition fun(...):boolean ---@return APLActor 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) return actor end diff --git a/src/Aura/Aura.lua b/src/Aura/Aura.lua index 72bf052..056d488 100644 --- a/src/Aura/Aura.lua +++ b/src/Aura/Aura.lua @@ -1,5 +1,4 @@ -- Document with emmy lua: https://emmylua.github.io/ - local Tinkr, Bastion = ... -- Create a new Aura class @@ -66,19 +65,18 @@ function Aura:New(unit, index, type) timeMod = 0, index = nil, - type = nil, + type = nil } if self.aura.spellId then - Bastion.SpellBook:GetSpell(self.aura.spellId) + Bastion.Globals.SpellBook:GetSpell(self.aura.spellId) end return self end - local name, icon, count, dispelType, duration, expirationTime, source, isStealable, nameplateShowPersonal, - spellId, canApplyAura, isBossDebuff, castByPlayer, nameplateShowAll, timeMod = UnitAura(unit:GetOMToken(), index, - type) + 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) self.aura = { @@ -100,10 +98,10 @@ function Aura:New(unit, index, type) auraInstanceID = nil, index = index, - type = type, + type = type } if self.aura.spellId then - Bastion.SpellBook:GetSpell(self.aura.spellId) + Bastion.Globals.SpellBook:GetSpell(self.aura.spellId) end return self end @@ -132,11 +130,11 @@ function Aura:CreateFromUnitAuraInfo(unitAuraInfo) auraInstanceID = unitAuraInfo.auraInstanceID, index = nil, - type = unitAuraInfo.isHarmful and "HARMFUL" or "HELPFUL", + type = unitAuraInfo.isHarmful and "HARMFUL" or "HELPFUL" } -- Register spell in spellbook - Bastion.SpellBook:GetSpell(self.aura.spellId) + Bastion.Globals.SpellBook:GetSpell(self.aura.spellId) return self end @@ -239,7 +237,7 @@ end -- Get the auras spell id ---@return Spell function Aura:GetSpell() - return Bastion.SpellBook:GetSpell(self.aura.spellId) + return Bastion.Globals.SpellBook:GetSpell(self.aura.spellId) end -- Get the auras can apply aura status diff --git a/src/Class/Class.lua b/src/Class/Class.lua index b1f3d11..69db919 100644 --- a/src/Class/Class.lua +++ b/src/Class/Class.lua @@ -18,12 +18,21 @@ function Class:__index(k) return response end +---@class Class +---@field class Class.class + +---@class Class.class +---@field locale string +---@field name string +---@field id number + -- Constructor ---@param locale string ---@param name string ---@param id number function Class:New(locale, name, id) local self = setmetatable({}, Class) + self.class = { locale = locale, name = name, @@ -50,10 +59,16 @@ function Class:GetID() return self.class.id end +---@class ColorMixin +---@field r number +---@field g number +---@field b number + -- Return the classes color ---@return ColorMixin classColor function Class:GetColor() return C_ClassColor.GetClassColor(self.class.name) end + return Class diff --git a/src/Command/Command.lua b/src/Command/Command.lua index 0e04436..03af256 100644 --- a/src/Command/Command.lua +++ b/src/Command/Command.lua @@ -1,6 +1,13 @@ -- Create a wow command handler class ---@class Command +---@field command string +---@field commands Command.commands[] local Command = {} + +---@class Command.commands +---@field helpmsg string +---@field cb fun(args: table) + Command.__index = Command ---@return string diff --git a/src/Item/Item.lua b/src/Item/Item.lua index 72c8ca0..fe0d8ef 100644 --- a/src/Item/Item.lua +++ b/src/Item/Item.lua @@ -54,7 +54,7 @@ function Item:New(id) local name, spellID = GetItemSpell(self:GetID()) if spellID then self.spellID = spellID - Bastion.SpellBook:GetSpell(spellID) + Bastion.Globals.SpellBook:GetSpell(spellID) end return self @@ -302,7 +302,7 @@ end -- Get the last use time ---@return number function Item:GetLastUseTime() - return Bastion.SpellBook:GetSpell(self:GetID()):GetLastCastTime() + return Bastion.Globals.SpellBook:GetSpell(self:GetID()):GetLastCastTime() end -- Get time since last use @@ -430,7 +430,7 @@ end ---@return Spell | nil function Item:GetSpell() if self.spellID then - return Bastion.SpellBook:GetSpell(self.spellID) + return Bastion.Globals.SpellBook:GetSpell(self.spellID) end return nil diff --git a/src/Library/Library.lua b/src/Library/Library.lua new file mode 100644 index 0000000..3d0b2b8 --- /dev/null +++ b/src/Library/Library.lua @@ -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 diff --git a/src/List/List.lua b/src/List/List.lua index 421567f..1921466 100644 --- a/src/List/List.lua +++ b/src/List/List.lua @@ -1,5 +1,3 @@ -local Tinkr, Bastion = ... - ---@class List local List = { -- Add overload @@ -144,7 +142,7 @@ function List:findIndex(callback) return nil end ----@param callback fun(value: any): boolean +---@param callback fun(...): boolean ---@return nil function List:sort(callback) table.sort(self._list, callback) diff --git a/src/MythicPlusUtils/MythicPlusUtils.lua b/src/MythicPlusUtils/MythicPlusUtils.lua index f131c74..f3222b5 100644 --- a/src/MythicPlusUtils/MythicPlusUtils.lua +++ b/src/MythicPlusUtils/MythicPlusUtils.lua @@ -17,6 +17,7 @@ MythicPlusUtils.__index = MythicPlusUtils function MythicPlusUtils:New() local self = setmetatable({}, MythicPlusUtils) + ---@diagnostic disable-next-line: assign-type-mismatch self.random = math.random(1000000, 9999999) 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 return end @@ -452,7 +453,7 @@ function MythicPlusUtils:New() 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 return end @@ -471,7 +472,7 @@ function MythicPlusUtils:New() ]], true) 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 return end @@ -567,8 +568,4 @@ function MythicPlusUtils:IsAOEBoss(unit) return self.aoeBosses[unit:GetID()] end -function MythicPlusUtils:IsTankBuster(spell) - return self.tankBusters[spell:GetID()] -end - return MythicPlusUtils diff --git a/src/ObjectManager/ObjectManager.lua b/src/ObjectManager/ObjectManager.lua index 1aaca3d..8e21b53 100644 --- a/src/ObjectManager/ObjectManager.lua +++ b/src/ObjectManager/ObjectManager.lua @@ -1,6 +1,11 @@ local Tinkr, Bastion = ... ---@class ObjectManager +---@field _lists table +---@field enemies List +---@field friends List +---@field activeEnemies List +---@field explosives List local ObjectManager = {} ObjectManager.__index = ObjectManager @@ -20,7 +25,7 @@ end -- Register a custom list with a callback ---@param name string ---@param cb function ----@return List +---@return List | false function ObjectManager:RegisterList(name, cb) if self._lists[name] then return false diff --git a/src/Sequencer/Sequencer.lua b/src/Sequencer/Sequencer.lua index bb688e3..be1c567 100644 --- a/src/Sequencer/Sequencer.lua +++ b/src/Sequencer/Sequencer.lua @@ -1,5 +1,4 @@ -- Create a sequencer class that takes a table of actions and executes them in order - ---@class Sequencer ---@field resetCondition fun(): boolean ---@field abortCondition fun(): boolean @@ -45,12 +44,10 @@ end ---@return boolean function Sequencer:Next() if self:Finished() then - print("Its finished?") return false end local action = self.actions[self.index] - print("Attempting action: " .. self.index .. "") if action(self) then self.index = self.index + 1 return true diff --git a/src/Unit/Unit.lua b/src/Unit/Unit.lua index 400cb9c..8c10a46 100644 --- a/src/Unit/Unit.lua +++ b/src/Unit/Unit.lua @@ -422,7 +422,7 @@ function Unit:GetCastingOrChannelingSpell() end if name then - return Bastion.SpellBook:GetSpell(spellId) + return Bastion.Globals.SpellBook:GetSpell(spellId) end return nil @@ -505,7 +505,7 @@ end -- Check if unit is interruptible ---@param percent number ----@param ignoreInterruptible boolean +---@param ignoreInterruptible? boolean ---@return boolean function Unit:IsInterruptibleAt(percent, ignoreInterruptible) if not ignoreInterruptible and not self:IsInterruptible() then @@ -926,13 +926,12 @@ end -- IsStealthed ---@return boolean function Unit:IsStealthed() - local Stealth = Bastion.SpellBook:GetSpell(1784) - local Vanish = Bastion.SpellBook:GetSpell(1856) - local ShadowDance = Bastion.SpellBook:GetSpell(185422) - local Subterfuge = Bastion.SpellBook:GetSpell(115192) - local Shadowmeld = Bastion.SpellBook:GetSpell(58984) - local Sepsis = Bastion.SpellBook:GetSpell(328305) - + local Stealth = Bastion.Globals.SpellBook:GetSpell(1784) + local Vanish = Bastion.Globals.SpellBook:GetSpell(1856) + local ShadowDance = Bastion.Globals.SpellBook:GetSpell(185422) + local Subterfuge = Bastion.Globals.SpellBook:GetSpell(115192) + local Shadowmeld = Bastion.Globals.SpellBook:GetSpell(58984) + local Sepsis = Bastion.Globals.SpellBook:GetSpell(328305) return self:GetAuras():FindAny(Stealth) or self:GetAuras():FindAny(ShadowDance) end @@ -960,7 +959,7 @@ end ---@return nil 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 = CombatLogGetCurrentEventInfo() @@ -1107,6 +1106,7 @@ end ---@param Target Unit ---@param Angle number ---@param Distance number +---@param rotation? number ---@return boolean function Unit:IsWithinCone(Target, Angle, Distance, rotation) if not Target:Exists() then @@ -1114,7 +1114,7 @@ function Unit:IsWithinCone(Target, Angle, Distance, rotation) end local angle = self:GetAngle(Target) - local rotation = rotation or self:GetFacing() + rotation = rotation or self:GetFacing() local diff = math.abs(angle - rotation) diff --git a/src/_bastion.lua b/src/_bastion.lua index 7a887f2..d71d558 100644 --- a/src/_bastion.lua +++ b/src/_bastion.lua @@ -7,13 +7,17 @@ local Bastion = { Bastion.__index = Bastion function Bastion.require(class) - return Tinkr:require("scripts/bastion/src/" .. class .. "/" .. class, Bastion) + return require("scripts/bastion/src/" .. class .. "/" .. class, Bastion) end +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 @@ -41,15 +45,18 @@ Bastion.UnitManager = Bastion.require("UnitManager"):New() ---@type ObjectManager Bastion.ObjectManager = Bastion.require("ObjectManager"):New() ---@type EventManager -Bastion.EventManager = Bastion.require("EventManager"):New() +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"):New() +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"):New() +Bastion.ItemBook = Bastion.require("ItemBook") +Bastion.Globals.ItemBook = Bastion.ItemBook:New() ---@type AuraTable Bastion.AuraTable = Bastion.require("AuraTable") ---@type Class @@ -62,10 +69,13 @@ Bastion.CombatTimer = Bastion.Timer:New('combat') Bastion.MythicPlusUtils = Bastion.require("MythicPlusUtils"):New() ---@type NotificationsList Bastion.Notifications = Bastion.NotificationsList:New() -Bastion.modules = {} + +local LIBRARIES = {} +local MODULES = {} + 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] if u then @@ -73,10 +83,10 @@ Bastion.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras) end end) -Bastion.EventManager:RegisterWoWEvent("UNIT_SPELLCAST_SUCCEEDED", function(...) +Bastion.Globals.EventManager:RegisterWoWEvent("UNIT_SPELLCAST_SUCCEEDED", function(...) local unit, castGUID, spellID = ... - local spell = Bastion.SpellBook:GetIfRegistered(spellID) + local spell = Bastion.Globals.SpellBook:GetIfRegistered(spellID) if unit == "player" and spell then spell.lastCastAt = GetTime() @@ -89,8 +99,9 @@ end) local pguid = UnitGUID("player") 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 sourceGUID = args[4] @@ -132,6 +143,7 @@ Bastion.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function() end end end) + Bastion.Ticker = C_Timer.NewTicker(0.1, function() if not Bastion.CombatTimer:IsRunning() and UnitAffectingCombat("player") then Bastion.CombatTimer:Start() @@ -141,22 +153,22 @@ Bastion.Ticker = C_Timer.NewTicker(0.1, function() if Bastion.Enabled then Bastion.ObjectManager:Refresh() - for i = 1, #Bastion.modules do - Bastion.modules[i]:Tick() + for i = 1, #MODULES do + MODULES[i]:Tick() end end end) function Bastion:Register(module) - table.insert(Bastion.modules, module) + table.insert(MODULES, module) Bastion:Print("Registered", module) end -- 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] + for i = 1, #MODULES do + if MODULES[i].name == name then + return MODULES[i] end end @@ -164,7 +176,7 @@ function Bastion:FindModule(name) end function Bastion:Print(...) - local args = { ... } + local args = {...} local str = "|cFFDF362D[Bastion]|r |cFFFFFFFF" for i = 1, #args do str = str .. tostring(args[i]) .. " " @@ -176,7 +188,7 @@ function Bastion:Debug(...) if not Bastion.DebugMode then return end - local args = { ... } + local args = {...} local str = "|cFFDF6520[Bastion]|r |cFFFFFFFF" for i = 1, #args do str = str .. tostring(args[i]) .. " " @@ -203,13 +215,16 @@ Command:Register('debug', 'Toggle debug mode on/off', function() 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 + do + break + end end -- use spellName and spellSubName here @@ -218,7 +233,7 @@ Command:Register('dumpspells', 'Dump spells to a file', function() if spellID then spellName = spellName:gsub("[%W%s]", "") WriteFile('bastion-' .. UnitClass('player') .. '-' .. rand .. '.lua', - "local " .. spellName .. " = Bastion.SpellBook:GetSpell(" .. spellID .. ")", true) + "local " .. spellName .. " = Bastion.Globals.SpellBook:GetSpell(" .. spellID .. ")", true) end i = i + 1 end @@ -264,11 +279,91 @@ Command:Register('missed', 'Dump the list of immune kidney shot spells', functio end end) -local files = ListFiles("scripts/bastion/scripts") +local function Load(dir) + local files = ListFiles(dir) -for i = 1, #files do - local file = files[i] - if file:sub(-4) == ".lua" or file:sub(-5) == '.luac' then - Tinkr:require("scripts/bastion/scripts/" .. file:sub(1, -5), Bastion) + for i = 1, #files do + local file = files[i] + if file:sub(-4) == ".lua" or file:sub(-5) == '.luac' then + require(dir .. file:sub(1, -5), Bastion) + end end end + +---@param library Library +function Bastion:RegisterLibrary(library) + LIBRARIES[library.name] = library +end + +function Bastion:CheckLibraryDependencies() + for k, v in pairs(LIBRARIES) do + if v.dependencies then + 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 + 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 + +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 + +Load("scripts/bastion/scripts/Libraries/") + +-- if not Bastion:CheckLibraryDependencies() then +-- return +-- end + +Load("scripts/bastion/scripts/Modules/") +Load("scripts/bastion/scripts/")