forked from Bastion/Bastion
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
321 lines
9.6 KiB
321 lines
9.6 KiB
---@type Tinkr
|
|
local Tinkr = ...
|
|
|
|
---@class Bastion.Globals.SpellName : { [spellId]: string }
|
|
|
|
---@class Bastion
|
|
local Bastion = {
|
|
Enabled = false,
|
|
Globals = {
|
|
---@type Bastion.Globals.SpellName
|
|
SpellName = {}
|
|
},
|
|
Tick = GetGameTick()
|
|
}
|
|
|
|
local BastionBase = string.format("%s/%s", "scripts", "bastion")
|
|
local BastionScriptsBase = string.format("%s/%s", BastionBase, "scripts")
|
|
local ThirdPartyModulesBase = string.format("%s/%s", "scripts", "BastionScripts")
|
|
|
|
Bastion.__index = Bastion
|
|
|
|
---@class Bastion.LoadedFiles.Table
|
|
---@field [number] { originalPath: string, loadedPath: string, reloadable: boolean, order: number, newPath: string }
|
|
Bastion.LoadedFiles = {}
|
|
|
|
---@param filePath string
|
|
function Bastion:CheckIfLoaded(filePath)
|
|
for i, file in ipairs(Bastion.LoadedFiles) do
|
|
if file.loadedPath == filePath or file.originalPath == filePath or file.newPath == filePath then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
---@param path string
|
|
---@param extension string
|
|
---@return string
|
|
local function AppendExtension(path, extension)
|
|
return string.format("%s.%s", path, extension)
|
|
end
|
|
|
|
---@param path string
|
|
---@param extensions string|string[]
|
|
local function CheckFileExtensions(path, extensions)
|
|
local exts = {}
|
|
if type(extensions) == "string" then
|
|
exts = { extensions }
|
|
else
|
|
exts = extensions
|
|
end
|
|
|
|
for i, extension in ipairs(exts) do
|
|
local newPath = path
|
|
if newPath:sub(extension:len() * -1) ~= extension then
|
|
newPath = AppendExtension(newPath, extension)
|
|
end
|
|
if FileExists(newPath) then
|
|
return newPath:sub(1, (extension:len() + 2) * -1), true
|
|
end
|
|
end
|
|
return path, false
|
|
end
|
|
|
|
--- 0 = Failed, 1 = Success, 2 = Already Loaded
|
|
---@param filePath string | { filePath: string, reloadable: boolean }
|
|
---@param ... any
|
|
---@return 0|1|2, table
|
|
function Bastion:Require(filePath, ...)
|
|
local loadedFile = {
|
|
originalPath = type(filePath) == "table" and filePath.filePath or tostring(filePath),
|
|
newPath = type(filePath) == "table" and filePath.filePath or tostring(filePath),
|
|
loadedPath = type(filePath) == "table" and filePath.filePath or tostring(filePath),
|
|
reloadable = type(filePath) == "table" and filePath.reloadable or false,
|
|
order = #Bastion.LoadedFiles + 1,
|
|
}
|
|
|
|
local filePathModifier = loadedFile.originalPath:sub(1, 1)
|
|
local base = filePathModifier == "@" and BastionScriptsBase or filePathModifier == "~" and BastionBase
|
|
if base then
|
|
loadedFile.newPath = string.format("%s%s", base, loadedFile.originalPath:sub(2))
|
|
loadedFile.loadedPath = loadedFile.newPath
|
|
end
|
|
|
|
local found = false
|
|
-- Check if file path has a .lua or .luac extension. If not, try to add one and check if the file exists
|
|
loadedFile.loadedPath, found = CheckFileExtensions(loadedFile.newPath, { "lua", "luac" })
|
|
|
|
if not found then
|
|
Log(string.format("Bastion:Require - Not Found: %s (%s)", loadedFile.newPath, loadedFile.originalPath))
|
|
return 0, SafePack(nil)
|
|
end
|
|
|
|
if not loadedFile.reloadable then
|
|
if Bastion:CheckIfLoaded(loadedFile.loadedPath) then
|
|
--Log(string.format("Bastion:Require - Already loaded: %s (%s)", loadedFile.newPath, loadedFile.originalPath))
|
|
return 2, SafePack(nil)
|
|
end
|
|
end
|
|
|
|
table.insert(Bastion.LoadedFiles, loadedFile)
|
|
return 1, SafePack(require(loadedFile.loadedPath, Bastion, ...))
|
|
end
|
|
|
|
local loadExamples = false
|
|
local exampleNames = {
|
|
"ExampleDependency.lua",
|
|
"ExampleDependencyError.lua",
|
|
"ExampleLibrary.lua",
|
|
"ExampleModule.lua",
|
|
}
|
|
|
|
---@param dir string
|
|
local function Load(dir)
|
|
if dir:sub(1, 1) == "@" then
|
|
dir = dir:sub(2)
|
|
dir = string.format("%s/%s", BastionScriptsBase, dir)
|
|
end
|
|
|
|
if dir:sub(1, 1) == "~" then
|
|
dir = dir:sub(2)
|
|
dir = string.format("%s/%s", BastionBase, dir)
|
|
end
|
|
|
|
local files = ListFiles(dir)
|
|
for i = 1, #files do
|
|
local file = files[i]
|
|
local loadFile = true
|
|
if not loadExamples then
|
|
for j = 1, #exampleNames do
|
|
if file:find(exampleNames[j]) then
|
|
loadFile = false
|
|
break
|
|
end
|
|
end
|
|
end
|
|
if loadFile and (file:sub(-4) == ".lua" or file:sub(-5) == ".luac") then
|
|
Bastion:Require(dir .. file:sub(1, -5))
|
|
end
|
|
end
|
|
end
|
|
|
|
local function LoadThird()
|
|
local thirdPartyModulesFolders = ListFolders(ThirdPartyModulesBase)
|
|
for i = 1, #thirdPartyModulesFolders do
|
|
local currentFolderDir = string.format("%s/%s", ThirdPartyModulesBase, thirdPartyModulesFolders[i])
|
|
local loaderFilePath = string.format("%s/%s", currentFolderDir, "loader")
|
|
if FileExists(loaderFilePath .. ".lua") or FileExists(loaderFilePath .. ".luac") then
|
|
Bastion:Require(loaderFilePath, currentFolderDir)
|
|
end
|
|
end
|
|
end
|
|
|
|
local bastionFiles = {
|
|
"~/src/ClassMagic/ClassMagic",
|
|
"~/src/List/List",
|
|
"~/src/Command/Command",
|
|
"~/src/Util/Util",
|
|
"~/src/Library/Library",
|
|
"~/src/Notification/Notification",
|
|
"~/src/NotificationList/NotificationList",
|
|
"~/src/Vector3/Vector3",
|
|
"~/src/Sequencer/Sequencer",
|
|
"~/src/Cache/Cache",
|
|
"~/src/Cacheable/Cacheable",
|
|
"~/src/Refreshable/Refreshable",
|
|
"~/src/Unit/Unit",
|
|
"~/src/Aura/Aura",
|
|
"~/src/APLTrait/APLTrait",
|
|
"~/src/APLActor/APLActor",
|
|
"~/src/APL/APL",
|
|
"~/src/Module/Module",
|
|
"~/src/UnitManager/UnitManager",
|
|
"~/src/ObjectManager/ObjectManager",
|
|
"~/src/EventManager/EventManager",
|
|
"~/src/Spell/Spell",
|
|
"~/src/SpellBook/SpellBook",
|
|
"~/src/Item/Item",
|
|
"~/src/ItemBook/ItemBook",
|
|
"~/src/AuraTable/AuraTable",
|
|
"~/src/Class/Class",
|
|
"~/src/Timer/Timer",
|
|
"~/src/MythicPlusUtils/MythicPlusUtils",
|
|
"~/src/Config/Config",
|
|
"~/src/TimeToDie/TimeToDie",
|
|
}
|
|
|
|
for i = 1, #bastionFiles do
|
|
Bastion:Require(bastionFiles[i])
|
|
end
|
|
|
|
Bastion.Globals.CombatTimer = Bastion.Timer:New("combat", function()
|
|
return UnitAffectingCombat("player")
|
|
end)
|
|
|
|
---@param unitTarget UnitId
|
|
Bastion.Globals.EventManager:RegisterWoWEvent("UNIT_HEALTH", function(unitTarget)
|
|
--Bastion.UnitManager:Get(unitTarget):UpdateHealth()
|
|
end)
|
|
|
|
---@param unit UnitToken
|
|
---@param auras UnitAuraUpdateInfo
|
|
Bastion.Globals.EventManager:RegisterWoWEvent("UNIT_AURA", function(unit, auras)
|
|
---@type Bastion.Unit | nil
|
|
local u = Bastion.UnitManager:Get(unit)
|
|
|
|
if u then
|
|
u:GetAuras():OnUpdate(auras)
|
|
end
|
|
end)
|
|
|
|
Bastion.Globals.EventManager:RegisterWoWEvent("UNIT_SPELLCAST_SUCCEEDED", function(...)
|
|
---@type UnitIds, string, spellId
|
|
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)
|
|
|
|
local playerGuid = UnitGUID("player")
|
|
local missed = {}
|
|
|
|
Bastion.Globals.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function()
|
|
local args = { CombatLogGetCurrentEventInfo() }
|
|
|
|
---@type string
|
|
local subEvent = args[2]
|
|
---@type string
|
|
local sourceGUID = args[4]
|
|
---@type string
|
|
local destGUID = args[8]
|
|
---@type number
|
|
local spellID = args[12]
|
|
---@type string
|
|
local spellName = args[13]
|
|
|
|
if subEvent == "SPELL_CAST_SUCCESS" then
|
|
if (not Bastion.Globals.SpellName[spellID] or Bastion.Globals.SpellName[spellID] ~= spellName) then
|
|
Bastion.Globals.SpellName[spellID] = spellName
|
|
end
|
|
end
|
|
|
|
---@type Bastion.Unit?
|
|
local u = Bastion.UnitManager[sourceGUID]
|
|
---@type Bastion.Unit
|
|
local u2 = Bastion.UnitManager[destGUID]
|
|
|
|
local t = GetTime()
|
|
|
|
if type(u) ~= "nil" then
|
|
u:SetLastCombatTime(t)
|
|
end
|
|
|
|
if type(u2) ~= "nil" then
|
|
u2:SetLastCombatTime(t)
|
|
if subEvent == "SPELL_MISSED" and sourceGUID == playerGuid and spellID == 408 then
|
|
local missType = args[15]
|
|
|
|
if type(u) ~= "nil" and missType == "IMMUNE" then
|
|
local castingSpell = u:GetCastingOrChannelingSpell()
|
|
|
|
if castingSpell and type(castingSpell) == "table" then
|
|
if not missed[castingSpell:GetID()] then
|
|
missed[castingSpell:GetID()] = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
Bastion.Ticker = C_Timer.NewTicker(0.1, function()
|
|
Bastion.Tick = GetGameTick()
|
|
Bastion.Globals.CombatTimer:Check()
|
|
|
|
if Bastion.Enabled then
|
|
Bastion.ObjectManager:Refresh()
|
|
Bastion.TimeToDie:Refresh()
|
|
Bastion:TickModules()
|
|
end
|
|
end)
|
|
|
|
Bastion.Globals.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
|
|
|
|
-- use spellName and spellSubName here
|
|
local spellID = select(7, GetSpellInfo(spellName))
|
|
|
|
if spellID then
|
|
spellName = spellName:gsub("[%W%s]", "")
|
|
WriteFile("bastion-" .. UnitClass("player") .. "-" .. rand .. ".lua",
|
|
"local " .. spellName .. " = Bastion.Globals.SpellBook:GetSpell(" .. spellID .. ")\n", true)
|
|
end
|
|
i = i + 1
|
|
end
|
|
end)
|
|
|
|
Bastion.Globals.Command:Register("missed", "Dump the list of immune kidney shot spells", function()
|
|
for k, v in pairs(missed) do
|
|
Bastion.Util:Print(k)
|
|
end
|
|
end)
|
|
|
|
Load("@Libraries/")
|
|
Load("@Modules/")
|
|
Load("@")
|
|
LoadThird()
|
|
|