local addonname, data = ... ---@cast data HeimdallData ---@cast addonname string -- TODO: Maybe make a configuration weakaura, make use of weakaura options... -- TODO: Implement counting kills and display on whosniffer -- Take last N seconds of combatlog into account ie. count who does damage to who -- Maybe even make an alert when someone does too much damage to someone else... -- But that would not be trivial as of now, I can't think of a way to do it sensibly -- TODO: Implement auto grouping via agent, maybe find "+" or something -- TODO: Implement some sort of automatic grouping feature... -- Don't know how to elect leader yet... Who invites? -- Maybe we can just make it agent #6, have him always be the group leader? local function init() ---@class Heimdall_Data ---@field who { data: table } ---@field stinkies table if not Heimdall_Data then Heimdall_Data = {} end if not Heimdall_Data.config then Heimdall_Data.config = {} end -- We don't care about these persisting -- Actually we don't want some of them to persist -- For those we DO we use (global) Heimdall_Data ---@class HeimdallData ---@field config HeimdallConfig ---@field raceMap table ---@field classColors table ---@field messenger HeimdallMessengerData ---@field who HeimdallWhoData ---@field dumpTable fun(table: any, depth?: number): nil ---@field utf8len fun(input: string): number ---@field padString fun(input: string, targetLength: number, left?: boolean): string ---@field GetOrDefault fun(table: table, keys: string[], default: any): any ---@field Whoer { Init: fun() } ---@field Messenger { Init: fun() } ---@field Spotter { Init: fun() } ---@field DeathReporter { Init: fun() } ---@field Inviter { Init: fun() } --- Config --- ---@class HeimdallConfig ---@field spotter HeimdallSpotterConfig ---@field who HeimdallWhoConfig ---@field messenger HeimdallMessengerConfig ---@field deathReporter HeimdallDeathReporterConfig ---@field inviter HeimdallInviterConfig ---@field whisperNotify table ---@field stinkies table ---@class HeimdallSpotterConfig ---@field enabled boolean ---@field everyone boolean ---@field hostile boolean ---@field alliance boolean ---@field stinky boolean ---@field notifyChannel string ---@field zoneOverride string? ---@field throttleTime number ---@class HeimdallWhoConfig ---@field enabled boolean ---@field ignored table ---@field notifyChannel string ---@field ttl number ---@field doWhisper boolean ---@field zoneNotifyFor table ---@class HeimdallMessengerConfig ---@field enabled boolean ---@class HeimdallDeathReporterConfig ---@field enabled boolean ---@field throttle number ---@field doWhisper boolean ---@field notifyChannel string ---@field zoneOverride string? ---@field duelThrottle number ---@class HeimdallInviterConfig ---@field enabled boolean ---@field listeningChannel string ---@field keyword string ---@field updateInterval number --- Data --- ---@class HeimdallMessengerData ---@field queue table ---@field ticker number? ---@class HeimdallWhoData ---@field updateTicker number? ---@field whoTicker number? ---@field ignored table data.GetOrDefault = function(table, keys, default) local value = default if not table then return value end if not keys then return value end local traverse = table for i = 1, #keys do local key = keys[i] if traverse[key] ~= nil then traverse = traverse[key] else break end if i == #keys then value = traverse end end return value end data.messenger = { queue = {} } data.who = { ignored = {}, } --/run Heimdall_Data.config = {inviter={enabled=false},deathReporter={enabled=false},spotter={enabled=false,everyone=false}} --/run Heimdall_Data.config = {who={enabled=true},deathReporter={enabled=true},spotter={enabled=true}} --/run Heimdall_Data.config = {deathReporter={enabled=true}} --/run Heimdall_Data.config = {deathReporter={enabled=false},spotter={enabled=false}} --/run Heimdall_Data.config = {deathReporter={enabled=false},spotter={enabled=true,everyone=true}} --/run Heimdall_Data.config = {inviter={enabled=true},deathReporter={enabled=true},spotter={enabled=true,everyone=true}} --/run Heimdall_Data.config = {inviter={enabled=true,keyword="+++"},deathReporter={enabled=true},spotter={enabled=true,everyone=true}} --/run Heimdall_Data.config.inviter.enabled = true data.config = { spotter = { enabled = data.GetOrDefault(Heimdall_Data, { "config", "spotter", "enabled" }, true), everyone = data.GetOrDefault(Heimdall_Data, { "config", "spotter", "everyone" }, false), hostile = data.GetOrDefault(Heimdall_Data, { "config", "spotter", "hostile" }, true), alliance = data.GetOrDefault(Heimdall_Data, { "config", "spotter", "alliance" }, true), stinky = data.GetOrDefault(Heimdall_Data, { "config", "spotter", "stinky" }, true), notifyChannel = data.GetOrDefault(Heimdall_Data, { "config", "spotter", "notifyChannel" }, "Agent"), zoneOverride = data.GetOrDefault(Heimdall_Data, { "config", "spotter", "zoneOverride" }, nil), throttleTime = data.GetOrDefault(Heimdall_Data, { "config", "spotter", "throttleTime" }, 10) }, who = { enabled = data.GetOrDefault(Heimdall_Data, { "config", "who", "enabled" }, false), ignored = data.GetOrDefault(Heimdall_Data, { "config", "who", "ignored" }, {}), notifyChannel = data.GetOrDefault(Heimdall_Data, { "config", "who", "notifyChannel" }, "Agent"), ttl = data.GetOrDefault(Heimdall_Data, { "config", "who", "ttl" }, 20), doWhisper = data.GetOrDefault(Heimdall_Data, { "config", "who", "doWhisper" }, true), zoneNotifyFor = data.GetOrDefault(Heimdall_Data, { "config", "who", "zoneNotifyFor" }, { ["Orgrimmar"] = true, ["Thunder Bluff"] = true, ["Undercity"] = true, ["Durotar"] = true, ["Echo Isles"] = true, ["Valley of Trials"] = true, }), }, messenger = { enabled = data.GetOrDefault(Heimdall_Data, { "config", "messenger", "enabled" }, true), }, deathReporter = { enabled = data.GetOrDefault(Heimdall_Data, { "config", "deathReporter", "enabled" }, false), throttle = data.GetOrDefault(Heimdall_Data, { "config", "deathReporter", "throttle" }, 10), doWhisper = data.GetOrDefault(Heimdall_Data, { "config", "deathReporter", "doWhisper" }, true), notifyChannel = data.GetOrDefault(Heimdall_Data, { "config", "deathReporter", "notifyChannel" }, "Agent"), zoneOverride = data.GetOrDefault(Heimdall_Data, { "config", "deathReporter", "zoneOverride" }, nil), duelThrottle = data.GetOrDefault(Heimdall_Data, { "config", "deathReporter", "duelThrottle" }, 5), }, whisperNotify = data.GetOrDefault(Heimdall_Data, { "config", "whisperNotify" }, { "Extazyk", "Smokefire", "Smokemantra", "Хихихантер", "Муркот", "Растафаркрай", "Frosstmorn", "Pulsjkee", "Paskoo", "发酸的风景画", }), stinkies = data.GetOrDefault(Heimdall_Data, { "config", "stinkies" }, { ["Ahhahahh"] = true, ["Aye"] = true, ["Bbd"] = true, ["Blessly"] = true, ["Bunkkeer"] = true, ["Calmer"] = true, ["Chuvirloeban"] = true, ["Clairvoyant"] = true, ["Dewdew"] = true, ["Dwxrfshaman"] = true, ["Ebanirot"] = true, ["Heger"] = true, ["Hmor"] = true, ["Joule"] = true, ["Kaøs"] = true, ["Kromsaevmode"] = true, ["Kugisara"] = true, ["Lax"] = true, ["Negron"] = true, ["Oakskin"] = true, ["Pizdosorkam"] = true, ["Pussymism"] = true, ["Rattenfenger"] = true, ["Riener"] = true, ["Rollbot"] = true, ["Samuraqt"] = true, ["Sekiiro"] = true, ["Shadowmilf"] = true, ["Sonikblaster"] = true, ["Srakonyh"] = true, ["Stuffo"] = true, ["Subaruwrxsti"] = true, ["Sukunexd"] = true, ["Tomoki"] = true, ["Unwashed"] = true, ["Voitas"] = true, ["Wataru"] = true, ["Yooshima"] = true, ["Анджелос"] = true, ["Артейда"] = true, ["Асталабиста"] = true, ["Гебефрени"] = true, ["Курлык"] = true, ["Лжедмитресса"] = true, ["Ловилуну"] = true, ["Лопапа"] = true, ["Неонанируй"] = true, ["Паладийпал"] = true, ["Психопаточка"] = true, ["Сильверлейн"] = true, ["Сосканереалк"] = true, ["Счастьевам"] = true, ["Фоська"] = true, ["Фрил"] = true, ["Ххантуля"] = true, ["Чмодвенк"] = true, ["Шпек"] = true, }), inviter = { enabled = data.GetOrDefault(Heimdall_Data, { "config", "inviter", "enabled" }, false), listeningChannel = data.GetOrDefault(Heimdall_Data, { "config", "inviter", "listeningChannel" }, "Agent"), keyword = data.GetOrDefault(Heimdall_Data, { "config", "inviter", "keyword" }, "+"), updateInterval = data.GetOrDefault(Heimdall_Data, { "config", "inviter", "updateInterval" }, 1), } } data.raceMap = { ["Orc"] = "Horde", ["Undead"] = "Horde", ["Tauren"] = "Horde", ["Troll"] = "Horde", ["Blood Elf"] = "Horde", ["Goblin"] = "Horde", ["Human"] = "Alliance", ["Dwarf"] = "Alliance", ["Night Elf"] = "Alliance", ["Gnome"] = "Alliance", ["Draenei"] = "Alliance", ["Worgen"] = "Alliance", ["Vulpera"] = "Horde", ["Nightborne"] = "Horde", ["Zandalari Troll"] = "Horde", ["Kul Tiran"] = "Alliance", ["Dark Iron Dwarf"] = "Alliance", ["Void Elf"] = "Alliance", ["Lightforged Draenei"] = "Alliance", ["Mechagnome"] = "Alliance", ["Mag'har Orc"] = "Horde" } data.classColors = { ["Warrior"] = "C69B6D", ["Paladin"] = "F48CBA", ["Hunter"] = "AAD372", ["Rogue"] = "FFF468", ["Priest"] = "FFFFFF", ["Death Knight"] = "C41E3A", ["Shaman"] = "0070DD", ["Mage"] = "3FC7EB", ["Warlock"] = "8788EE", ["Monk"] = "00FF98", ["Druid"] = "FF7C0A", ["Demon Hunter"] = "A330C9" } ---@param input string ---@return number data.utf8len = function(input) if not input then return 0 end local len = 0 local i = 1 local n = #input while i <= n do local c = input:byte(i) if c >= 0 and c <= 127 then i = i + 1 elseif c >= 194 and c <= 223 then i = i + 2 elseif c >= 224 and c <= 239 then i = i + 3 elseif c >= 240 and c <= 244 then i = i + 4 else i = i + 1 end len = len + 1 end return len end ---@param input string ---@param targetLength number ---@param left boolean ---@return string data.padString = function(input, targetLength, left) left = left or false local len = data.utf8len(input) if len < targetLength then if left then input = input .. string.rep(" ", targetLength - len) else input = string.rep(" ", targetLength - len) .. input end end return input end data.Whoer.Init() data.Messenger.Init() data.Spotter.Init() data.DeathReporter.Init() data.Inviter.Init() print("Heimdall loaded!") end local loadedFrame = CreateFrame("Frame") loadedFrame:RegisterEvent("ADDON_LOADED") loadedFrame:SetScript("OnEvent", function(self, event, addonName) if addonName == addonname then init() end end) local logoutFrame = CreateFrame("Frame") logoutFrame:RegisterEvent("PLAYER_LOGOUT") logoutFrame:SetScript("OnEvent", function(self, event) Heimdall_Data.config.stinkies = data.config.stinkies end) SlashCmdList["HEIMDALL_TOGGLE_STINKY"] = function(input) print("Toggling stinky: " .. tostring(input)) if data.config.stinkies[input] then data.config.stinkies[input] = nil else data.config.stinkies[input] = true end print(data.config.stinkies[input]) end SLASH_HEIMDALL_TOGGLE_STINKY1 = "/has"