diff --git a/Modules/CombatAlerter.lua b/Modules/CombatAlerter.lua index 303a9d3..85761e2 100644 --- a/Modules/CombatAlerter.lua +++ b/Modules/CombatAlerter.lua @@ -7,134 +7,135 @@ local ModuleName = "CombatAlerter" ---@field debug boolean ---@field channels string[] ----@diagnostic disable-next-line: missing-fields -shared.CombatAlerter = {} -function shared.CombatAlerter.Init() - local alerted = {} - local combatAlerterFrame = CreateFrame("Frame") - combatAlerterFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") - combatAlerterFrame:SetScript("OnEvent", function(self, event, ...) - if Heimdall_Data.config.combatAlerter.debug then - print(string.format("[%s] Combat log event received", ModuleName)) - end - if not Heimdall_Data.config.combatAlerter.enabled then +---@class CombatAlerter +shared.CombatAlerter = { + Init = function() + local alerted = {} + local combatAlerterFrame = CreateFrame("Frame") + combatAlerterFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") + combatAlerterFrame:SetScript("OnEvent", function(self, event, ...) if Heimdall_Data.config.combatAlerter.debug then - print(string.format("[%s] Module disabled, ignoring combat event", ModuleName)) + print(string.format("[%s] Combat log event received", ModuleName)) end - return - end - - ---@type string|nil, string, string - local err, source, destination - - destination, err = CLEUParser.GetDestName(...) - if err then - if Heimdall_Data.config.combatAlerter.debug then - print(string.format("[%s] Error getting destination: %s", ModuleName, err)) + if not Heimdall_Data.config.combatAlerter.enabled then + if Heimdall_Data.config.combatAlerter.debug then + print(string.format("[%s] Module disabled, ignoring combat event", ModuleName)) + end + return end - return - end - if Heimdall_Data.config.combatAlerter.debug then - print(string.format("[%s] Combat event destination: %s", ModuleName, destination)) - end + ---@type string|nil, string, string + local err, source, destination - if destination ~= UnitName("player") then - if Heimdall_Data.config.combatAlerter.debug then - print(string.format("[%s] Ignoring event - not targeted at player", ModuleName)) + destination, err = CLEUParser.GetDestName(...) + if err then + if Heimdall_Data.config.combatAlerter.debug then + print(string.format("[%s] Error getting destination: %s", ModuleName, err)) + end + return end - return - end - source, err = CLEUParser.GetSourceName(...) - if err then if Heimdall_Data.config.combatAlerter.debug then - print(string.format("[%s] Error getting source, using 'unknown': %s", ModuleName, err)) + print(string.format("[%s] Combat event destination: %s", ModuleName, destination)) end - source = "unknown" - end - if Heimdall_Data.config.combatAlerter.debug then - print(string.format("[%s] Combat event source: %s", ModuleName, source)) - end + if destination ~= UnitName("player") then + if Heimdall_Data.config.combatAlerter.debug then + print(string.format("[%s] Ignoring event - not targeted at player", ModuleName)) + end + return + end + + source, err = CLEUParser.GetSourceName(...) + if err then + if Heimdall_Data.config.combatAlerter.debug then + print(string.format("[%s] Error getting source, using 'unknown': %s", ModuleName, err)) + end + source = "unknown" + end - if shared.StinkyTracker.IsStinky(source) then if Heimdall_Data.config.combatAlerter.debug then - print( - string.format( - "[%s] Source is tracked stinky: %s (Already alerted: %s)", - ModuleName, - source, - tostring(alerted[source] or false) + print(string.format("[%s] Combat event source: %s", ModuleName, source)) + end + + if shared.StinkyTracker.IsStinky(source) then + if Heimdall_Data.config.combatAlerter.debug then + print( + string.format( + "[%s] Source is tracked stinky: %s (Already alerted: %s)", + ModuleName, + source, + tostring(alerted[source] or false) + ) ) - ) - end - if alerted[source] then return end + end + if alerted[source] then return end - alerted[source] = true - local x, y = GetPlayerMapPosition("player") - local zone, subZone = GetZoneText(), GetSubZoneText() + alerted[source] = true + local x, y = GetPlayerMapPosition("player") + local zone, subZone = GetZoneText(), GetSubZoneText() - if Heimdall_Data.config.combatAlerter.debug then - print( - string.format( - "[%s] Player location: %s/%s at %.2f,%.2f", - ModuleName, - zone, - subZone, + if Heimdall_Data.config.combatAlerter.debug then + print( + string.format( + "[%s] Player location: %s/%s at %.2f,%.2f", + ModuleName, + zone, + subZone, + x * 100, + y * 100 + ) + ) + end + + SetMapToCurrentZone() + SetMapByID(GetCurrentMapAreaID()) + local areaId = GetCurrentMapAreaID() + + for _, channel in pairs(Heimdall_Data.config.combatAlerter.channels) do + local locale = shared.GetLocaleForChannel(channel) + local text = string.format( + shared._L("combatAlerterInCombat", locale), + source, + shared._L("zone", locale), + shared._L("subZone", locale), + tostring(areaId), x * 100, y * 100 ) - ) - end - - SetMapToCurrentZone() - SetMapByID(GetCurrentMapAreaID()) - local areaId = GetCurrentMapAreaID() - - for _, channel in pairs(Heimdall_Data.config.combatAlerter.channels) do - local locale = shared.GetLocaleForChannel(channel) - local text = string.format( - shared._L("combatAlerterInCombat", locale), - source, - shared._L("zone", locale), - shared._L("subZone", locale), - tostring(areaId), - x * 100, - y * 100 - ) - ---@type Message - local msg = { - channel = "C", - data = channel, - message = text, - } - if Heimdall_Data.config.combatAlerter.debug then - print(string.format("[%s] Queuing alert message", ModuleName)) - shared.dumpTable(msg) + ---@type Message + local msg = { + channel = "C", + data = channel, + message = text, + } + if Heimdall_Data.config.combatAlerter.debug then + print(string.format("[%s] Queuing alert message", ModuleName)) + shared.dumpTable(msg) + end + table.insert(shared.messenger.queue, msg) end - table.insert(shared.messenger.queue, msg) + elseif Heimdall_Data.config.combatAlerter.debug then + print(string.format("[%s] Source not in stinky list, ignoring: %s", ModuleName, source)) end - elseif Heimdall_Data.config.combatAlerter.debug then - print(string.format("[%s] Source not in stinky list, ignoring: %s", ModuleName, source)) - end - end) + end) - local combatTriggerFrame = CreateFrame("Frame") - combatTriggerFrame:RegisterEvent("PLAYER_REGEN_DISABLED") - combatTriggerFrame:RegisterEvent("PLAYER_REGEN_ENABLED") - combatTriggerFrame:SetScript("OnEvent", function(self, event, ...) - if Heimdall_Data.config.combatAlerter.debug then - print(string.format("[%s] Combat state changed: %s", ModuleName, event)) - if event == "PLAYER_REGEN_DISABLED" then - print(string.format("[%s] Entered combat - Resetting alerts", ModuleName)) - else - print(string.format("[%s] Left combat - Resetting alerts", ModuleName)) + local combatTriggerFrame = CreateFrame("Frame") + combatTriggerFrame:RegisterEvent("PLAYER_REGEN_DISABLED") + combatTriggerFrame:RegisterEvent("PLAYER_REGEN_ENABLED") + combatTriggerFrame:SetScript("OnEvent", function(self, event, ...) + if Heimdall_Data.config.combatAlerter.debug then + print(string.format("[%s] Combat state changed: %s", ModuleName, event)) + if event == "PLAYER_REGEN_DISABLED" then + print(string.format("[%s] Entered combat - Resetting alerts", ModuleName)) + else + print(string.format("[%s] Left combat - Resetting alerts", ModuleName)) + end end - end - alerted = {} - end) + alerted = {} + end) - if Heimdall_Data.config.combatAlerter.debug then print(string.format("[%s] Module initialized", ModuleName)) end - print("[Heimdall] CombatAlerter loaded") -end + if Heimdall_Data.config.combatAlerter.debug then print(string.format("[%s] Module initialized", ModuleName)) end + print("[Heimdall] CombatAlerter loaded") + end, +} diff --git a/Modules/Commander.lua b/Modules/Commander.lua index 61e16b9..bc10425 100644 --- a/Modules/Commander.lua +++ b/Modules/Commander.lua @@ -39,344 +39,356 @@ local helpMessages = { }, } ----@diagnostic disable-next-line: missing-fields -shared.Commander = {} -function shared.Commander.Init() - ---@param text string - ---@param size number - ---@return string[] - local function Partition(text, size) - local words = {} - for word in text:gmatch("[^,]+") do - words[#words + 1] = word - end - - local ret = {} - local currentChunk = "" - - for _, word in ipairs(words) do - if #currentChunk + #word + 1 <= size then - currentChunk = currentChunk .. (currentChunk == "" and word or " " .. word) - else - if #currentChunk > 0 then ret[#ret + 1] = currentChunk end - currentChunk = word +---@class Commander +shared.Commander = { + Init = function() + ---@param text string + ---@param size number + ---@return string[] + local function Partition(text, size) + local words = {} + for word in text:gmatch("[^,]+") do + words[#words + 1] = word end - end - if #currentChunk > 0 then ret[#ret + 1] = currentChunk end + local ret = {} + local currentChunk = "" - return ret - end - ---@param arr table - ---@return string[] - local function Count(arr) - local ret = {} - for _, player in pairs(arr) do - if shared.Whoer.ShouldNotifyForZone(player.zone) then ret[player.zone] = (ret[player.zone] or 0) + 1 end - end - local text = {} - for zone, count in pairs(ret) do - text[#text + 1] = string.format("%s: %d", zone, count) - end - return text - end - ---@param arr table - ---@return string[] - local function CountPartitioned(arr) - local count = Count(arr) - local text = {} - ---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack - for _, line in pairs(Partition(strjoin(", ", unpack(count)), 200)) do - text[#text + 1] = line - end - return text - end - ---@param arr table - ---@return string[] - local function Who(arr) - local ret = {} - for _, player in pairs(arr) do - if shared.Whoer.ShouldNotifyForZone(player.zone) then - ret[#ret + 1] = string.format( - "%s/%s (%s) %s", - player.name, - player.class, - player.zone, - player.stinky and "(!!!!)" or "" - ) - end - end - if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Command result: %s", ModuleName, strjoin(", ", unpack(ret)))) - end - return ret - end - ---@param arr table - ---@return string[] - local function WhoPartitioned(arr) - local who = Who(arr) - local text = {} - ---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack - for _, line in pairs(Partition(strjoin(", ", unpack(who)), 200)) do - text[#text + 1] = "who: " .. line - end - return text - end - ---@param arr table - ---@return string[] - local function CountClass(arr) - local ret = {} - for _, player in pairs(arr) do - if shared.Whoer.ShouldNotifyForZone(player.zone) then ret[player.class] = (ret[player.class] or 0) + 1 end - end - local text = {} - for class, count in pairs(ret) do - text[#text + 1] = string.format("%s: %d", class, count) - end - if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Message text: %s", ModuleName, strjoin(", ", unpack(text)))) - end - return text - end - ---@param arr table - ---@return string[] - local function CountClassPartitioned(arr) - local countClass = CountClass(arr) - local text = {} - ---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack - for _, line in pairs(Partition(strjoin(", ", unpack(countClass)), 200)) do - text[#text + 1] = line - end - return text - end - local function CountClassPartitionedStinkies() - if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Executing: CountClassPartitionedStinkies", ModuleName)) - end - local res = CountClassPartitioned(HeimdallStinkies) - if #res == 0 then return { "No stinkies found" } end - return res - end - local function WhoPartitionedStinkies() - if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Executing: WhoPartitionedStinkies", ModuleName)) - shared.dumpTable(HeimdallStinkies) - end - local res = WhoPartitioned(HeimdallStinkies) - if #res == 0 then return { "No stinkies found" } end - return res - end - local function CountPartitionedStinkies() - if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Executing: CountPartitionedStinkies", ModuleName)) - end - local res = CountPartitioned(HeimdallStinkies) - if #res == 0 then return { "No stinkies found" } end - return res - end - local function HelpRu() - if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: HelpRu", ModuleName)) end - return helpMessages.ru - end - local function HelpEn() - if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: HelpEn", ModuleName)) end - return helpMessages.en - end - local groupInviteFrame = CreateFrame("Frame") - groupInviteFrame:SetScript("OnEvent", function(self, event, ...) - if Heimdall_Data.config.commander.debug then print(string.format("[%s] Event received", ModuleName)) end - AcceptGroup() - groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST") - C_Timer.NewTimer(0.1, function() - if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Click event triggered", ModuleName)) - end - _G["StaticPopup1Button1"]:Click() - end, 1) - end) - local function JoinGroup() - if Heimdall_Data.config.commander.debug then - print(string.format("[%s] JoinGroup command received", ModuleName)) - end - groupInviteFrame:RegisterEvent("PARTY_INVITE_REQUEST") - C_Timer.NewTimer(10, function() groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST") end, 1) - return { "+" } - end - local function LeaveGroup() - if Heimdall_Data.config.commander.debug then - print(string.format("[%s] LeaveGroup command received", ModuleName)) - end - LeaveParty() - return {} - end - ---@param target string - local function FollowTarget(target) - if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Following target: %s", ModuleName, target)) - end - if not target then return end - FollowUnit(target) - return {} - end - - ---@param args string[] - local function MacroTarget(args) - if Heimdall_Data.config.commander.debug then - ---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack - print(string.format("[%s] Macroing: %s", ModuleName, strjoin(" ", unpack(args)))) - end - if #args < 2 or #args % 2 ~= 0 then - if #args < 2 or #args % 2 ~= 0 then - if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Invalid number of arguments for MacroTarget", ModuleName)) + for _, word in ipairs(words) do + if #currentChunk + #word + 1 <= size then + currentChunk = currentChunk .. (currentChunk == "" and word or " " .. word) + else + if #currentChunk > 0 then ret[#ret + 1] = currentChunk end + currentChunk = word end - return {} end - end - table.remove(args, 1) - for i = 1, #args do - local stinky = strtrim(args[i]) - local name = stinky:match("([^/]+)") - local class = stinky:match("/([^ $]+)") - if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Adding stinky: %s/%s", ModuleName, name, tostring(class))) - end - shared.StinkyTracker.Track({ - name = name, - class = class or "unknown", - seenAt = GetTime(), - hostile = true, - }) - if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Added stinky: %s/%s", ModuleName, name, tostring(class))) - end - end - return {} - end + if #currentChunk > 0 then ret[#ret + 1] = currentChunk end - ---@param args string[] - local function IgnoreMacroTarget(args) - if Heimdall_Data.config.commander.debug then + return ret + end + ---@param arr table + ---@return string[] + local function Count(arr) + local ret = {} + for _, player in pairs(arr) do + if shared.Whoer.ShouldNotifyForZone(player.zone) then ret[player.zone] = (ret[player.zone] or 0) + 1 end + end + local text = {} + for zone, count in pairs(ret) do + text[#text + 1] = string.format("%s: %d", zone, count) + end + return text + end + ---@param arr table + ---@return string[] + local function CountPartitioned(arr) + local count = Count(arr) + local text = {} ---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack - print(string.format("[%s] Macroing: %s", ModuleName, strjoin(" ", unpack(args)))) + for _, line in pairs(Partition(strjoin(", ", unpack(count)), 200)) do + text[#text + 1] = line + end + return text end - if #args < 1 then + ---@param arr table + ---@return string[] + local function Who(arr) + local ret = {} + for _, player in pairs(arr) do + if shared.Whoer.ShouldNotifyForZone(player.zone) then + ret[#ret + 1] = string.format( + "%s/%s (%s) %s", + player.name, + player.class, + player.zone, + player.stinky and "(!!!!)" or "" + ) + end + end if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Invalid number of arguments for IgnoreMacroTarget", ModuleName)) + print(string.format("[%s] Command result: %s", ModuleName, strjoin(", ", unpack(ret)))) + end + return ret + end + ---@param arr table + ---@return string[] + local function WhoPartitioned(arr) + local who = Who(arr) + local text = {} + ---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack + for _, line in pairs(Partition(strjoin(", ", unpack(who)), 200)) do + text[#text + 1] = "who: " .. line + end + return text + end + ---@param arr table + ---@return string[] + local function CountClass(arr) + local ret = {} + for _, player in pairs(arr) do + if shared.Whoer.ShouldNotifyForZone(player.zone) then + ret[player.class] = (ret[player.class] or 0) + 1 + end + end + local text = {} + for class, count in pairs(ret) do + text[#text + 1] = string.format("%s: %d", class, count) + end + if Heimdall_Data.config.commander.debug then + print(string.format("[%s] Message text: %s", ModuleName, strjoin(", ", unpack(text)))) + end + return text + end + ---@param arr table + ---@return string[] + local function CountClassPartitioned(arr) + local countClass = CountClass(arr) + local text = {} + ---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack + for _, line in pairs(Partition(strjoin(", ", unpack(countClass)), 200)) do + text[#text + 1] = line + end + return text + end + local function CountClassPartitionedStinkies() + if Heimdall_Data.config.commander.debug then + print(string.format("[%s] Executing: CountClassPartitionedStinkies", ModuleName)) + end + local res = CountClassPartitioned(HeimdallStinkies) + if #res == 0 then return { "No stinkies found" } end + return res + end + local function WhoPartitionedStinkies() + if Heimdall_Data.config.commander.debug then + print(string.format("[%s] Executing: WhoPartitionedStinkies", ModuleName)) + shared.dumpTable(HeimdallStinkies) + end + local res = WhoPartitioned(HeimdallStinkies) + if #res == 0 then return { "No stinkies found" } end + return res + end + local function CountPartitionedStinkies() + if Heimdall_Data.config.commander.debug then + print(string.format("[%s] Executing: CountPartitionedStinkies", ModuleName)) + end + local res = CountPartitioned(HeimdallStinkies) + if #res == 0 then return { "No stinkies found" } end + return res + end + local function HelpRu() + if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: HelpRu", ModuleName)) end + return helpMessages.ru + end + local function HelpEn() + if Heimdall_Data.config.commander.debug then print(string.format("[%s] Executing: HelpEn", ModuleName)) end + return helpMessages.en + end + local groupInviteFrame = CreateFrame("Frame") + groupInviteFrame:SetScript("OnEvent", function(self, event, ...) + if Heimdall_Data.config.commander.debug then print(string.format("[%s] Event received", ModuleName)) end + AcceptGroup() + groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST") + C_Timer.NewTimer(0.1, function() + if Heimdall_Data.config.commander.debug then + print(string.format("[%s] Click event triggered", ModuleName)) + end + _G["StaticPopup1Button1"]:Click() + end, 1) + end) + local function JoinGroup() + if Heimdall_Data.config.commander.debug then + print(string.format("[%s] JoinGroup command received", ModuleName)) + end + groupInviteFrame:RegisterEvent("PARTY_INVITE_REQUEST") + C_Timer.NewTimer(10, function() groupInviteFrame:UnregisterEvent("PARTY_INVITE_REQUEST") end, 1) + return { "+" } + end + local function LeaveGroup() + if Heimdall_Data.config.commander.debug then + print(string.format("[%s] LeaveGroup command received", ModuleName)) + end + LeaveParty() + return {} + end + ---@param target string + local function FollowTarget(target) + if Heimdall_Data.config.commander.debug then + print(string.format("[%s] Following target: %s", ModuleName, target)) + end + if not target then return end + FollowUnit(target) + return {} + end + + ---@param args string[] + local function MacroTarget(args) + if Heimdall_Data.config.commander.debug then + ---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack + print(string.format("[%s] Macroing: %s", ModuleName, strjoin(" ", unpack(args)))) + end + if #args < 2 or #args % 2 ~= 0 then + if #args < 2 or #args % 2 ~= 0 then + if Heimdall_Data.config.commander.debug then + print(string.format("[%s] Invalid number of arguments for MacroTarget", ModuleName)) + end + return {} + end + end + table.remove(args, 1) + + for i = 1, #args do + local stinky = strtrim(args[i]) + local name = stinky:match("([^/]+)") + local class = stinky:match("/([^ $]+)") + if Heimdall_Data.config.commander.debug then + print(string.format("[%s] Adding stinky: %s/%s", ModuleName, name, tostring(class))) + end + shared.StinkyTracker.Track({ + name = name, + class = class or "unknown", + seenAt = GetTime(), + hostile = true, + }) + if Heimdall_Data.config.commander.debug then + print(string.format("[%s] Added stinky: %s/%s", ModuleName, name, tostring(class))) + end end return {} end - table.remove(args, 1) - for i = 1, #args do - local stinky = strtrim(args[i]) - local name = stinky:match("([^/]+)") + ---@param args string[] + local function IgnoreMacroTarget(args) if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Ignoring stinky: %s", ModuleName, name)) + ---@diagnostic disable-next-line: param-type-mismatch something wrong with luals, it's picking up the "wrong" unpack + print(string.format("[%s] Macroing: %s", ModuleName, strjoin(" ", unpack(args)))) end - shared.StinkyTracker.Ignore(name) + if #args < 1 then + if Heimdall_Data.config.commander.debug then + print(string.format("[%s] Invalid number of arguments for IgnoreMacroTarget", ModuleName)) + end + return {} + end + table.remove(args, 1) + + for i = 1, #args do + local stinky = strtrim(args[i]) + local name = stinky:match("([^/]+)") + if Heimdall_Data.config.commander.debug then + print(string.format("[%s] Ignoring stinky: %s", ModuleName, name)) + end + shared.StinkyTracker.Ignore(name) + end + return {} end - return {} - end - ---@class Command - ---@field keywordRe string - ---@field commanderOnly boolean - ---@field callback fun(...: any): string[] + ---@class Command + ---@field keywordRe string + ---@field commanderOnly boolean + ---@field callback fun(...: any): string[] - local commands = { - { keywordRe = "^who$", commanderOnly = false, callback = WhoPartitionedStinkies }, - { keywordRe = "^howmany$", commanderOnly = false, callback = CountPartitionedStinkies }, - { keywordRe = "^classes$", commanderOnly = false, callback = CountClassPartitionedStinkies }, - { keywordRe = "^help$", commanderOnly = false, callback = HelpRu }, - { keywordRe = "^helpen$", commanderOnly = false, callback = HelpEn }, - { keywordRe = "^joingroup$", commanderOnly = false, callback = JoinGroup }, - { keywordRe = "^leavegroup$", commanderOnly = false, callback = LeaveGroup }, - { keywordRe = "^follow$", commanderOnly = false, callback = FollowTarget }, - { keywordRe = "^macro", commanderOnly = false, callback = MacroTarget }, - { keywordRe = "^ignore", commanderOnly = false, callback = IgnoreMacroTarget }, - } + local commands = { + { keywordRe = "^who$", commanderOnly = false, callback = WhoPartitionedStinkies }, + { keywordRe = "^howmany$", commanderOnly = false, callback = CountPartitionedStinkies }, + { keywordRe = "^classes$", commanderOnly = false, callback = CountClassPartitionedStinkies }, + { keywordRe = "^help$", commanderOnly = false, callback = HelpRu }, + { keywordRe = "^helpen$", commanderOnly = false, callback = HelpEn }, + { keywordRe = "^joingroup$", commanderOnly = false, callback = JoinGroup }, + { keywordRe = "^leavegroup$", commanderOnly = false, callback = LeaveGroup }, + { keywordRe = "^follow$", commanderOnly = false, callback = FollowTarget }, + { keywordRe = "^macro", commanderOnly = false, callback = MacroTarget }, + { keywordRe = "^ignore", commanderOnly = false, callback = IgnoreMacroTarget }, + } - local commanderChannelFrame = CreateFrame("Frame") - commanderChannelFrame:RegisterEvent("CHAT_MSG_CHANNEL") - commanderChannelFrame:SetScript("OnEvent", function(self, event, msg, sender, ...) - --if Heimdall_Data.config.commander.debug then - -- print(string.format("[%s] Event received", ModuleName)) - -- shared.dumpTable(Heimdall_Data.config.commander) - --end - if not Heimdall_Data.config.commander.enabled then + local commanderChannelFrame = CreateFrame("Frame") + commanderChannelFrame:RegisterEvent("CHAT_MSG_CHANNEL") + commanderChannelFrame:SetScript("OnEvent", function(self, event, msg, sender, ...) --if Heimdall_Data.config.commander.debug then - -- print(string.format("[%s] Module disabled, ignoring event", ModuleName)) + -- print(string.format("[%s] Event received", ModuleName)) + -- shared.dumpTable(Heimdall_Data.config.commander) --end - return - end - local channelId = select(6, ...) - local _, channelname = GetChannelName(channelId) - local ok = false - for _, channel in pairs(Heimdall_Data.config.commander.channels) do - if channel == channelname then - ok = true - break + if not Heimdall_Data.config.commander.enabled then + --if Heimdall_Data.config.commander.debug then + -- print(string.format("[%s] Module disabled, ignoring event", ModuleName)) + --end + return end - end - if not ok then - if Heimdall_Data.config.commander.debug then - print( - string.format( - "[%s] Channel name '%s' does not match any of the channels '%s'", - ModuleName, - channelname, - table.concat(Heimdall_Data.config.commander.channels, ", ") + local channelId = select(6, ...) + local _, channelname = GetChannelName(channelId) + local ok = false + for _, channel in pairs(Heimdall_Data.config.commander.channels) do + if channel == channelname then + ok = true + break + end + end + if not ok then + if Heimdall_Data.config.commander.debug then + print( + string.format( + "[%s] Channel name '%s' does not match any of the channels '%s'", + ModuleName, + channelname, + table.concat(Heimdall_Data.config.commander.channels, ", ") + ) ) - ) + end + return end - return - end - sender = string.match(sender, "^[^-]+") - if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Message from: %s", ModuleName, sender)) - shared.dumpTable(Heimdall_Data.config.commander) - end - - for _, command in ipairs(commands) do - local enabled = Heimdall_Data.config.commander.commands[command.keywordRe] == true or false + sender = string.match(sender, "^[^-]+") if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Command match: %s = %s", ModuleName, command.keywordRe, tostring(enabled))) + print(string.format("[%s] Message from: %s", ModuleName, sender)) + shared.dumpTable(Heimdall_Data.config.commander) end - if - enabled - and ( - not command.commanderOnly - or (command.commanderOnly and sender == Heimdall_Data.config.commander.commander) - ) - then - if msg:match(command.keywordRe) then - ---@diagnostic disable-next-line: redundant-parameter Currently luals does not support variadic functions as a @field - local messages = command.callback({ strsplit(",", msg) }) - if Heimdall_Data.config.commander.debug then - ---@diagnostic disable-next-line: param-type-mismatch - print(string.format("[%s] Messages to send: %s", ModuleName, strjoin(", ", unpack(messages)))) - end - for _, message in ipairs(messages) do - ---@type Message - local returnmsg = { - channel = "C", - data = channelname, - message = message, - } + + for _, command in ipairs(commands) do + local enabled = Heimdall_Data.config.commander.commands[command.keywordRe] == true or false + if Heimdall_Data.config.commander.debug then + print( + string.format("[%s] Command match: %s = %s", ModuleName, command.keywordRe, tostring(enabled)) + ) + end + if + enabled + and ( + not command.commanderOnly + -- if Heimdall_Data.config.commander.debug then print(string.format("[%s] Ignoring command, sender %s not commander %s", ModuleName, sender, Heimdall_Data.config.commander.commander)) end + + + + + or (command.commanderOnly and sender == Heimdall_Data.config.commander.commander) + ) + then + if msg:match(command.keywordRe) then + ---@diagnostic disable-next-line: redundant-parameter Currently luals does not support variadic functions as a @field + local messages = command.callback({ strsplit(",", msg) }) if Heimdall_Data.config.commander.debug then - print(string.format("[%s] Queuing message", ModuleName)) - shared.dumpTable(msg) + ---@diagnostic disable-next-line: param-type-mismatch + print( + string.format("[%s] Messages to send: %s", ModuleName, strjoin(", ", unpack(messages))) + ) + end + for _, message in ipairs(messages) do + ---@type Message + local returnmsg = { + channel = "C", + data = channelname, + message = message, + } + if Heimdall_Data.config.commander.debug then + print(string.format("[%s] Queuing message", ModuleName)) + shared.dumpTable(msg) + end + --table.insert(shared.messenger.queue, msg) + table.insert(shared.networkMessenger.queue, returnmsg) end - --table.insert(shared.messenger.queue, msg) - table.insert(shared.networkMessenger.queue, returnmsg) end end end - end - end) + end) - print("[Heimdall] Commander module loaded") -end + print("[Heimdall] Commander module loaded") + end, +} diff --git a/Modules/Inviter.lua b/Modules/Inviter.lua index ba2a709..763c181 100644 --- a/Modules/Inviter.lua +++ b/Modules/Inviter.lua @@ -1,259 +1,276 @@ local _, shared = ... ---@cast shared HeimdallShared + +---@class HeimdallInviterConfig +---@field enabled boolean +---@field debug boolean +---@field channels string[] +---@field keyword string +---@field allAssist boolean +---@field agentsAssist boolean +---@field throttle number +---@field kickOffline boolean +---@field cleanupInterval number +---@field afkThreshold number +---@field listeningChannel table + local ModuleName = "Inviter" ----@diagnostic disable-next-line: missing-fields -shared.Inviter = {} -function shared.Inviter.Init() - -- Fallback for old config - if type(Heimdall_Data.config.inviter.listeningChannel) == "string" then - Heimdall_Data.config.inviter.listeningChannel = { - [Heimdall_Data.config.inviter.listeningChannel] = true, - } - end - ---@type Timer - local updateTimer = nil - - local function FixGroup() - if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] Checking and fixing group configuration", ModuleName)) +---@class Inviter +shared.Inviter = { + Init = function() + -- Fallback for old config + if type(Heimdall_Data.config.inviter.listeningChannel) == "string" then + Heimdall_Data.config.inviter.listeningChannel = { + [Heimdall_Data.config.inviter.listeningChannel] = true, + } end + ---@type Timer + local updateTimer = nil - if not IsInRaid() then + local function FixGroup() if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] Converting party to raid", ModuleName)) - end - ConvertToRaid() - end - - if Heimdall_Data.config.inviter.allAssist then - if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] Setting all members to assistant", ModuleName)) - end - SetEveryoneIsAssistant() - end - - if Heimdall_Data.config.inviter.agentsAssist then - if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] Processing agents for assistant promotion", ModuleName)) + print(string.format("[%s] Checking and fixing group configuration", ModuleName)) end - shared.AgentTracker.ForEach(function(agent) - if UnitInParty(agent) and not UnitIsGroupLeader(agent) and not UnitIsRaidOfficer(agent) then - if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] Promoting agent to assistant: %s", ModuleName, agent)) - end - PromoteToAssistant(agent, true) - elseif Heimdall_Data.config.inviter.debug then - if not UnitInParty(agent) then - print(string.format("[%s] Agent not in party: %s", ModuleName, agent)) - elseif UnitIsGroupLeader(agent) then - print(string.format("[%s] Agent is already leader: %s", ModuleName, agent)) - elseif UnitIsRaidOfficer(agent) then - print(string.format("[%s] Agent is already assistant: %s", ModuleName, agent)) - end - end - end) - end - - if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] Group configuration update complete", ModuleName)) - end - end - - ---@param name string - ---@return Frame? - local function FindPlayerRaidFrame(name) - for group = 1, 8 do - for player = 1, 5 do - local button = _G[string.format("ElvUF_RaidGroup%dUnitButton%d", group, player)] + if not IsInRaid() then if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] button = %s", ModuleName, tostring(button))) - end - - local unitName = button and button.unit and UnitName(button.unit) - if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] unitName = %s", ModuleName, tostring(unitName))) - end - if unitName == name then - if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] unitName == name", ModuleName)) - end - return button + print(string.format("[%s] Converting party to raid", ModuleName)) end + ConvertToRaid() end - end - return nil - end - local framePool = {} - local playerButtons = {} - setmetatable(playerButtons, { __mode = "kv" }) - ---@param players string[] - local function OverlayKickButtons(players) - for _, frame in pairs(framePool) do - frame:Hide() - end - for _, name in pairs(players) do - local frame = FindPlayerRaidFrame(name) - if frame then - playerButtons[name] = frame - -- All of these are ELVUI specific so they won't be in our meta... - ---@diagnostic disable-next-line: undefined-field - local button = framePool[frame.unit] - or CreateFrame( - "Button", - ---@diagnostic disable-next-line: undefined-field - string.format("HeimdallKickButton%s", frame.unit, frame, "SecureActionButtonTemplate") - ) - ---@diagnostic disable-next-line: undefined-field - framePool[frame.unit] = button + if Heimdall_Data.config.inviter.allAssist then + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] Setting all members to assistant", ModuleName)) + end + SetEveryoneIsAssistant() + end - ---@diagnostic disable-next-line: undefined-field - button:SetSize(frame.UNIT_WIDTH / 2, frame.UNIT_HEIGHT / 2) - button:SetPoint("CENTER", frame, "CENTER", 0, 0) - button:SetNormalTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon") - button:SetHighlightTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon") - button:SetPushedTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon") - button:SetDisabledTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon") - button:SetAlpha(0.5) - button:Show() - button:SetScript("OnClick", function() - UninviteUnit(name) - button:Hide() + if Heimdall_Data.config.inviter.agentsAssist then + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] Processing agents for assistant promotion", ModuleName)) + end + + shared.AgentTracker.ForEach(function(agent) + if UnitInParty(agent) and not UnitIsGroupLeader(agent) and not UnitIsRaidOfficer(agent) then + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] Promoting agent to assistant: %s", ModuleName, agent)) + end + PromoteToAssistant(agent, true) + elseif Heimdall_Data.config.inviter.debug then + if not UnitInParty(agent) then + print(string.format("[%s] Agent not in party: %s", ModuleName, agent)) + elseif UnitIsGroupLeader(agent) then + print(string.format("[%s] Agent is already leader: %s", ModuleName, agent)) + elseif UnitIsRaidOfficer(agent) then + print(string.format("[%s] Agent is already assistant: %s", ModuleName, agent)) + end + end end) - else - if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] Frame for player %s not found", ModuleName, name)) - end + end + + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] Group configuration update complete", ModuleName)) end end - end - ---@type table - local groupMembers = {} - local function CleanGroups() - if not Heimdall_Data.config.inviter.kickOffline then return end - print("Cleaning groups") - local now = GetTime() - for i = 1, 40 do - local unit = "raid" .. i - if UnitExists(unit) then - local name = UnitName(unit) - if name then - -- When we load (into game) we want to consider everyone "online" - -- In other words everyone we haven't seen before is "online" the first time we see them - -- This is to avoid kicking people who might not be offline which we don't know because we just logged in - if not groupMembers[name] then - groupMembers[name] = now - else - local online = UnitIsConnected(unit) - if online then groupMembers[name] = now end + ---@param name string + ---@return Frame? + local function FindPlayerRaidFrame(name) + for group = 1, 8 do + for player = 1, 5 do + local button = _G[string.format("ElvUF_RaidGroup%dUnitButton%d", group, player)] + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] button = %s", ModuleName, tostring(button))) + end + + local unitName = button and button.unit and UnitName(button.unit) + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] unitName = %s", ModuleName, tostring(unitName))) + end + if unitName == name then + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] unitName == name", ModuleName)) + end + return button + end + end + end + return nil + end + + local framePool = {} + local playerButtons = {} + setmetatable(playerButtons, { __mode = "kv" }) + ---@param players string[] + local function OverlayKickButtons(players) + for _, frame in pairs(framePool) do + frame:Hide() + end + for _, name in pairs(players) do + local frame = FindPlayerRaidFrame(name) + if frame then + playerButtons[name] = frame + -- All of these are ELVUI specific so they won't be in our meta... + ---@diagnostic disable-next-line: undefined-field + local button = framePool[frame.unit] + or CreateFrame( + "Button", + ---@diagnostic disable-next-line: undefined-field + string.format("HeimdallKickButton%s", frame.unit, frame, "SecureActionButtonTemplate") + ) + ---@diagnostic disable-next-line: undefined-field + framePool[frame.unit] = button + + ---@diagnostic disable-next-line: undefined-field + button:SetSize(frame.UNIT_WIDTH / 2, frame.UNIT_HEIGHT / 2) + button:SetPoint("CENTER", frame, "CENTER", 0, 0) + button:SetNormalTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon") + button:SetHighlightTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon") + button:SetPushedTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon") + button:SetDisabledTexture("Interface\\Buttons\\UI-GroupLoot-KickIcon") + button:SetAlpha(0.5) + button:Show() + button:SetScript("OnClick", function() + UninviteUnit(name) + button:Hide() + end) + else + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] Frame for player %s not found", ModuleName, name)) end end end end - local afkPlayers = {} - for name, time in pairs(groupMembers) do - if not UnitInParty(name) then - print(string.format("%s no longer in party", name)) - groupMembers[name] = nil - else - if time < now - Heimdall_Data.config.inviter.afkThreshold then - print(string.format("Kicking %s for being offline", name)) - afkPlayers[#afkPlayers + 1] = name - -- Blyat this is protected... - -- UninviteUnit(name) + + ---@type table + local groupMembers = {} + local function CleanGroups() + if not Heimdall_Data.config.inviter.kickOffline then return end + print("Cleaning groups") + local now = GetTime() + for i = 1, 40 do + local unit = "raid" .. i + if UnitExists(unit) then + local name = UnitName(unit) + if name then + -- When we load (into game) we want to consider everyone "online" + -- In other words everyone we haven't seen before is "online" the first time we see them + -- This is to avoid kicking people who might not be offline which we don't know because we just logged in + if not groupMembers[name] then + groupMembers[name] = now + else + local online = UnitIsConnected(unit) + if online then groupMembers[name] = now end + end + end end end - end - OverlayKickButtons(afkPlayers) - end - local function Tick() - CleanGroups() - C_Timer.NewTimer(Heimdall_Data.config.inviter.cleanupInterval, Tick, 1) - end - Tick() - - local groupRosterUpdateFrame = CreateFrame("Frame") - groupRosterUpdateFrame:RegisterEvent("GROUP_ROSTER_UPDATE") - groupRosterUpdateFrame:SetScript("OnEvent", function(self, event, ...) - if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] Event received: %s", ModuleName, event)) - end - - if not Heimdall_Data.config.inviter.enabled then - if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] Module disabled, ignoring event", ModuleName)) + local afkPlayers = {} + for name, time in pairs(groupMembers) do + if not UnitInParty(name) then + print(string.format("%s no longer in party", name)) + groupMembers[name] = nil + else + if time < now - Heimdall_Data.config.inviter.afkThreshold then + print(string.format("Kicking %s for being offline", name)) + afkPlayers[#afkPlayers + 1] = name + -- Blyat this is protected... + -- UninviteUnit(name) + end + end end - return + OverlayKickButtons(afkPlayers) end + local function Tick() + CleanGroups() + C_Timer.NewTimer(Heimdall_Data.config.inviter.cleanupInterval, Tick, 1) + end + Tick() + + local groupRosterUpdateFrame = CreateFrame("Frame") + groupRosterUpdateFrame:RegisterEvent("GROUP_ROSTER_UPDATE") + groupRosterUpdateFrame:SetScript("OnEvent", function(self, event, ...) + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] Event received: %s", ModuleName, event)) + end + + if not Heimdall_Data.config.inviter.enabled then + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] Module disabled, ignoring event", ModuleName)) + end + return + end + + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] Group roster changed - Checking configuration", ModuleName)) + end + if updateTimer then updateTimer:Cancel() end + updateTimer = C_Timer.NewTimer(Heimdall_Data.config.inviter.throttle, FixGroup) + end) + + local inviterChannelFrame = CreateFrame("Frame") + inviterChannelFrame:RegisterEvent("CHAT_MSG_CHANNEL") + inviterChannelFrame:SetScript("OnEvent", function(self, event, msg, sender, ...) + --if Heimdall_Data.config.inviter.debug then + -- print(string.format("[%s] Chat message received: %s", ModuleName, msg)) + -- shared.dumpTable(Heimdall_Data.config.inviter) + --end + if not Heimdall_Data.config.inviter.enabled then return end + local channelId = select(6, ...) + local _, channelname = GetChannelName(channelId) + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] Channel name: %s", ModuleName, channelname)) + end + + local ok = false + for _, channel in pairs(Heimdall_Data.config.inviter.channels) do + if channel == channelname then + ok = true + break + end + end + + if not ok then + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] Channel name does not match any of the channels", ModuleName)) + end + return + end + if msg == Heimdall_Data.config.inviter.keyword then + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] Inviting %s", ModuleName, sender)) + end + InviteUnit(sender) + else + if Heimdall_Data.config.inviter.debug then + print(string.format("[%s] Message does not match keyword", ModuleName)) + end + end + end) if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] Group roster changed - Checking configuration", ModuleName)) - end - if updateTimer then updateTimer:Cancel() end - updateTimer = C_Timer.NewTimer(Heimdall_Data.config.inviter.throttle, FixGroup) - end) - - local inviterChannelFrame = CreateFrame("Frame") - inviterChannelFrame:RegisterEvent("CHAT_MSG_CHANNEL") - inviterChannelFrame:SetScript("OnEvent", function(self, event, msg, sender, ...) - --if Heimdall_Data.config.inviter.debug then - -- print(string.format("[%s] Chat message received: %s", ModuleName, msg)) - -- shared.dumpTable(Heimdall_Data.config.inviter) - --end - if not Heimdall_Data.config.inviter.enabled then return end - local channelId = select(6, ...) - local _, channelname = GetChannelName(channelId) - if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] Channel name: %s", ModuleName, channelname)) - end - - local ok = false - for _, channel in pairs(Heimdall_Data.config.inviter.channels) do - if channel == channelname then - ok = true - break - end - end - - if not ok then - if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] Channel name does not match any of the channels", ModuleName)) - end - return - end - if msg == Heimdall_Data.config.inviter.keyword then - if Heimdall_Data.config.inviter.debug then print(string.format("[%s] Inviting %s", ModuleName, sender)) end - InviteUnit(sender) - else - if Heimdall_Data.config.inviter.debug then - print(string.format("[%s] Message does not match keyword", ModuleName)) - end - end - end) - - if Heimdall_Data.config.inviter.debug then - print( - string.format( - "[%s] Module initialized - All assist: %s, Agents assist: %s", - ModuleName, - tostring(Heimdall_Data.config.inviter.allAssist), - tostring(Heimdall_Data.config.inviter.agentsAssist) + print( + string.format( + "[%s] Module initialized - All assist: %s, Agents assist: %s", + ModuleName, + tostring(Heimdall_Data.config.inviter.allAssist), + tostring(Heimdall_Data.config.inviter.agentsAssist) + ) ) - ) - end + end - if Heimdall_Data.config.inviter.debug then - print( - string.format( - "[%s] Module initialized - All assist: %s, Agents assist: %s", - ModuleName, - tostring(Heimdall_Data.config.inviter.allAssist), - tostring(Heimdall_Data.config.inviter.agentsAssist) + if Heimdall_Data.config.inviter.debug then + print( + string.format( + "[%s] Module initialized - All assist: %s, Agents assist: %s", + ModuleName, + tostring(Heimdall_Data.config.inviter.allAssist), + tostring(Heimdall_Data.config.inviter.agentsAssist) + ) ) - ) - end - print("[Heimdall] Inviter loaded") -end + end + print("[Heimdall] Inviter loaded") + end, +} diff --git a/Modules/Macroer.lua b/Modules/Macroer.lua index 6d907d5..3347ca2 100644 --- a/Modules/Macroer.lua +++ b/Modules/Macroer.lua @@ -1,96 +1,102 @@ local _, shared = ... ---@cast shared HeimdallShared + +---@class HeimdallMacroerConfig +---@field enabled boolean +---@field debug boolean +---@field priority string[] + local ModuleName = "Macroer" ----@diagnostic disable-next-line: missing-fields -shared.Macroer = {} -function shared.Macroer.Init() - local function FindOrCreateMacro(macroName) - if Heimdall_Data.config.macroer.debug then - print(string.format("[%s] Finding or creating macro: %s", ModuleName, macroName)) - end - local idx = GetMacroIndexByName(macroName) - if idx == 0 then +---@class Macroer +shared.Macroer = { + Init = function() + local function FindOrCreateMacro(macroName) if Heimdall_Data.config.macroer.debug then - print(string.format("[%s] Creating new macro: %s", ModuleName, macroName)) + print(string.format("[%s] Finding or creating macro: %s", ModuleName, macroName)) end - CreateMacro(macroName, "INV_Misc_QuestionMark", "") - end - idx = GetMacroIndexByName(macroName) - if Heimdall_Data.config.macroer.debug then print(string.format("[%s] Macro index: %d", ModuleName, idx)) end - return idx - end - - ---@param stinkies table - local function FixMacro(stinkies) - if Heimdall_Data.config.macroer.debug then - print(string.format("[%s] Fixing macro with %d stinkies", ModuleName, #stinkies)) - end - if not Heimdall_Data.config.macroer.enabled then - if Heimdall_Data.config.macroer.debug then - print(string.format("[%s] Module disabled, skipping macro update", ModuleName)) - end - return - end - if InCombatLockdown() then - if Heimdall_Data.config.macroer.debug then - print(string.format("[%s] In combat, skipping macro update", ModuleName)) - end - return - end - - local priorityMap = {} - for priority, className in ipairs(Heimdall_Data.config.macroer.priority) do - priorityMap[className] = priority - end - local minPriority = #Heimdall_Data.config.macroer.priority + 1 - - local sortedStinkies = {} - for _, stinky in pairs(stinkies) do - if not shared.AgentTracker.IsAgent(stinky.name) then sortedStinkies[#sortedStinkies + 1] = stinky end - end - - if Heimdall_Data.config.macroer.debug then - print(string.format("[%s] Processing %d non-agent stinkies", ModuleName, #sortedStinkies)) - end - - table.sort(sortedStinkies, function(a, b) - local aPriority = priorityMap[a.class] or minPriority - local bPriority = priorityMap[b.class] or minPriority - return aPriority > bPriority - end) - - if Heimdall_Data.config.macroer.debug then - print(string.format("[%s] Sorted stinkies: %d", ModuleName, #sortedStinkies)) - shared.dumpTable(sortedStinkies) - end - local lines = { "/targetenemy" } - for _, stinky in pairs(sortedStinkies) do - if stinky.seenAt > GetTime() - 600 then + local idx = GetMacroIndexByName(macroName) + if idx == 0 then if Heimdall_Data.config.macroer.debug then - print(string.format("[%s] Adding target macro for: %s", ModuleName, stinky.name)) + print(string.format("[%s] Creating new macro: %s", ModuleName, macroName)) end - lines[#lines + 1] = string.format("/tar %s", stinky.name) + CreateMacro(macroName, "INV_Misc_QuestionMark", "") end + idx = GetMacroIndexByName(macroName) + if Heimdall_Data.config.macroer.debug then print(string.format("[%s] Macro index: %d", ModuleName, idx)) end + return idx end - local idx = FindOrCreateMacro("HeimdallTarget") - ---@diagnostic disable-next-line: param-type-mismatch - local body = strjoin("\n", unpack(lines)) - if Heimdall_Data.config.macroer.debug then - print(string.format("[%s] Updating macro with %d lines", ModuleName, #lines)) - end - EditMacro(idx, "HeimdallTarget", "INV_Misc_QuestionMark", body) - end + ---@param stinkies table + local function FixMacro(stinkies) + if Heimdall_Data.config.macroer.debug then + print(string.format("[%s] Fixing macro with %d stinkies", ModuleName, #stinkies)) + end + if not Heimdall_Data.config.macroer.enabled then + if Heimdall_Data.config.macroer.debug then + print(string.format("[%s] Module disabled, skipping macro update", ModuleName)) + end + return + end + if InCombatLockdown() then + if Heimdall_Data.config.macroer.debug then + print(string.format("[%s] In combat, skipping macro update", ModuleName)) + end + return + end - shared.StinkyTracker.OnChange(function(stinkies) - if Heimdall_Data.config.macroer.debug then - print(string.format("[%s] Stinkies changed, updating macro", ModuleName)) - shared.dumpTable(stinkies) - end - FixMacro(stinkies) - end) + local priorityMap = {} + for priority, className in ipairs(Heimdall_Data.config.macroer.priority) do + priorityMap[className] = priority + end + local minPriority = #Heimdall_Data.config.macroer.priority + 1 - if Heimdall_Data.config.macroer.debug then print(string.format("[%s] Module initialized", ModuleName)) end - print("[Heimdall] Macroer loaded") -end + local sortedStinkies = {} + for _, stinky in pairs(stinkies) do + if not shared.AgentTracker.IsAgent(stinky.name) then sortedStinkies[#sortedStinkies + 1] = stinky end + end + + if Heimdall_Data.config.macroer.debug then + print(string.format("[%s] Processing %d non-agent stinkies", ModuleName, #sortedStinkies)) + end + + table.sort(sortedStinkies, function(a, b) + local aPriority = priorityMap[a.class] or minPriority + local bPriority = priorityMap[b.class] or minPriority + return aPriority > bPriority + end) + + if Heimdall_Data.config.macroer.debug then + print(string.format("[%s] Sorted stinkies: %d", ModuleName, #sortedStinkies)) + shared.dumpTable(sortedStinkies) + end + local lines = { "/targetenemy" } + for _, stinky in pairs(sortedStinkies) do + if stinky.seenAt > GetTime() - 600 then + if Heimdall_Data.config.macroer.debug then + print(string.format("[%s] Adding target macro for: %s", ModuleName, stinky.name)) + end + lines[#lines + 1] = string.format("/tar %s", stinky.name) + end + end + + local idx = FindOrCreateMacro("HeimdallTarget") + ---@diagnostic disable-next-line: param-type-mismatch + local body = strjoin("\n", unpack(lines)) + if Heimdall_Data.config.macroer.debug then + print(string.format("[%s] Updating macro with %d lines", ModuleName, #lines)) + end + EditMacro(idx, "HeimdallTarget", "INV_Misc_QuestionMark", body) + end + + shared.StinkyTracker.OnChange(function(stinkies) + if Heimdall_Data.config.macroer.debug then + print(string.format("[%s] Stinkies changed, updating macro", ModuleName)) + shared.dumpTable(stinkies) + end + FixMacro(stinkies) + end) + if Heimdall_Data.config.macroer.debug then print(string.format("[%s] Module initialized", ModuleName)) end + print("[Heimdall] Macroer loaded") + end, +} diff --git a/Modules/Sniffer.lua b/Modules/Sniffer.lua index 5bff1eb..075148a 100644 --- a/Modules/Sniffer.lua +++ b/Modules/Sniffer.lua @@ -2,82 +2,91 @@ local _, shared = ... ---@cast shared HeimdallShared local ModuleName = "Sniffer" ----@diagnostic disable-next-line: missing-fields -shared.Sniffer = {} -function shared.Sniffer.Init() - if Heimdall_Data.config.sniffer.debug then print(string.format("[%s] Module initializing", ModuleName)) end - local smellThrottle = {} - local SmellStinky = function(stinky) - if Heimdall_Data.config.sniffer.debug then - print(string.format("%s: SmellStinky", ModuleName)) - shared.dumpTable(Heimdall_Data.config.sniffer) - end - if not Heimdall_Data.config.sniffer.enabled then return end - if Heimdall_Data.config.sniffer.stinky and not shared.IsStinky(stinky) then - if Heimdall_Data.config.sniffer.debug then - print(string.format("%s: Stinky not found in config", ModuleName)) - end - return - end - if smellThrottle[stinky] and GetTime() - smellThrottle[stinky] < Heimdall_Data.config.sniffer.throttleTime then - if Heimdall_Data.config.sniffer.debug then print(string.format("%s: Throttled", ModuleName)) end - return - end - smellThrottle[stinky] = GetTime() +---@class HeimdallSnifferConfig +---@field enabled boolean +---@field debug boolean +---@field channels string[] +---@field throttle number -- throttleTime in the original code, matching config name now +---@field zoneOverride string? +---@field stinky boolean - for _, channel in pairs(Heimdall_Data.config.sniffer.channels) do - local locale = shared.GetLocaleForChannel(channel) - local text = string.format(shared._L("snifferStinky", locale), stinky) - ---@type Message - local msg = { - channel = "C", - data = channel, - message = text, - } +---@class Sniffer +shared.Sniffer = { + Init = function() + if Heimdall_Data.config.sniffer.debug then print(string.format("[%s] Module initializing", ModuleName)) end + local smellThrottle = {} + local SmellStinky = function(stinky) if Heimdall_Data.config.sniffer.debug then - print(string.format("[%s] Queuing sniffer message", ModuleName)) - shared.dumpTable(msg) + print(string.format("%s: SmellStinky", ModuleName)) + shared.dumpTable(Heimdall_Data.config.sniffer) end - table.insert(shared.messenger.queue, msg) - end - end + if not Heimdall_Data.config.sniffer.enabled then return end + if Heimdall_Data.config.sniffer.stinky and not shared.IsStinky(stinky) then + if Heimdall_Data.config.sniffer.debug then + print(string.format("%s: Stinky not found in config", ModuleName)) + end + return + end + if smellThrottle[stinky] and GetTime() - smellThrottle[stinky] < Heimdall_Data.config.sniffer.throttle then + if Heimdall_Data.config.sniffer.debug then print(string.format("%s: Throttled", ModuleName)) end + return + end + smellThrottle[stinky] = GetTime() - local cleuFrame = CreateFrame("Frame") - cleuFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") - cleuFrame:SetScript("OnEvent", function(self, event, ...) - if Heimdall_Data.config.sniffer.debug then - print(string.format("[%s] Received event: %s", ModuleName, event)) - end - if not Heimdall_Data.config.sniffer.enabled then - if Heimdall_Data.config.sniffer.debug then - print(string.format("[%s] Module disabled, ignoring event", ModuleName)) + for _, channel in pairs(Heimdall_Data.config.sniffer.channels) do + local locale = shared.GetLocaleForChannel(channel) + local text = string.format(shared._L("snifferStinky", locale), stinky) + ---@type Message + local msg = { + channel = "C", + data = channel, + message = text, + } + if Heimdall_Data.config.sniffer.debug then + print(string.format("[%s] Queuing sniffer message", ModuleName)) + shared.dumpTable(msg) + end + table.insert(shared.messenger.queue, msg) end - return end - local source, destination, err - source, err = CLEUParser.GetSourceName(...) - if Heimdall_Data.config.sniffer.debug then - print(string.format("[%s] Processing source: %s", ModuleName, source)) - end - if err then + + local cleuFrame = CreateFrame("Frame") + cleuFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") + cleuFrame:SetScript("OnEvent", function(self, event, ...) if Heimdall_Data.config.sniffer.debug then - print(string.format("[%s] Error parsing source: %s", ModuleName, err)) + print(string.format("[%s] Received event: %s", ModuleName, event)) end - return - end - SmellStinky(source) - destination, err = CLEUParser.GetDestName(...) - if Heimdall_Data.config.sniffer.debug then - print(string.format("[%s] Processing destination: %s", ModuleName, destination)) - end - if err then + if not Heimdall_Data.config.sniffer.enabled then + if Heimdall_Data.config.sniffer.debug then + print(string.format("[%s] Module disabled, ignoring event", ModuleName)) + end + return + end + local source, destination, err + source, err = CLEUParser.GetSourceName(...) if Heimdall_Data.config.sniffer.debug then - print(string.format("[%s] Error parsing destination: %s", ModuleName, err)) + print(string.format("[%s] Processing source: %s", ModuleName, source)) end - return - end - SmellStinky(destination) - end) - if Heimdall_Data.config.sniffer.debug then print(string.format("[%s] Module initialized", ModuleName)) end - print("[Heimdall] Sniffer loaded") -end + if err then + if Heimdall_Data.config.sniffer.debug then + print(string.format("[%s] Error parsing source: %s", ModuleName, err)) + end + return + end + SmellStinky(source) + destination, err = CLEUParser.GetDestName(...) + if Heimdall_Data.config.sniffer.debug then + print(string.format("[%s] Processing destination: %s", ModuleName, destination)) + end + if err then + if Heimdall_Data.config.sniffer.debug then + print(string.format("[%s] Error parsing destination: %s", ModuleName, err)) + end + return + end + SmellStinky(destination) + end) + if Heimdall_Data.config.sniffer.debug then print(string.format("[%s] Module initialized", ModuleName)) end + print("[Heimdall] Sniffer loaded") + end, +}