From c41ca9b782e47756a140a220d51ac3127d5bb31f Mon Sep 17 00:00:00 2001 From: Adam Hellberg Date: Sat, 7 Sep 2019 02:19:47 +0200 Subject: [PATCH] Add option to disable tooltip data --- Command.lua | 354 +++++++++--------- KillTrack.lua | 976 +++++++++++++++++++++++++------------------------- Options.lua | 8 + 3 files changed, 678 insertions(+), 660 deletions(-) diff --git a/Command.lua b/Command.lua index 64366c8..a188d69 100644 --- a/Command.lua +++ b/Command.lua @@ -1,28 +1,28 @@ --[[ - * Copyright (c) 2011-2013 by Adam Hellberg. - * - * This file is part of KillTrack. - * - * KillTrack is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * KillTrack is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with KillTrack. If not, see . + * Copyright (c) 2011-2013 by Adam Hellberg. + * + * This file is part of KillTrack. + * + * KillTrack is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * KillTrack is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with KillTrack. If not, see . --]] KillTrack.Command = { - Slash = { - "killtrack", - "kt" - }, - Commands = {} + Slash = { + "killtrack", + "kt" + }, + Commands = {} } local KT = KillTrack @@ -33,223 +33,229 @@ local KTT = KillTrack_Tools -- Argument #1 (command) can be either string or a table. function C:Register(command, func) - if type(command) == "string" then - command = {command} - end - for _,v in pairs(command) do - if not self:HasCommand(v) then - if v ~= "__DEFAULT__" then v = v:lower() end - self.Commands[v] = func - end - end + if type(command) == "string" then + command = {command} + end + for _,v in pairs(command) do + if not self:HasCommand(v) then + if v ~= "__DEFAULT__" then v = v:lower() end + self.Commands[v] = func + end + end end function C:HasCommand(command) - for k,_ in pairs(self.Commands) do - if k == command then return true end - end - return false + for k,_ in pairs(self.Commands) do + if k == command then return true end + end + return false end function C:GetCommand(command) - local cmd = self.Commands[command] - if cmd then return cmd else return self.Commands["__DEFAULT__"] end + local cmd = self.Commands[command] + if cmd then return cmd else return self.Commands["__DEFAULT__"] end end function C:HandleCommand(command, args) - local cmd = self:GetCommand(command) - if cmd then - cmd(args) - else - KT:Msg(("%q is not a valid command."):format(command)) - end + local cmd = self:GetCommand(command) + if cmd then + cmd(args) + else + KT:Msg(("%q is not a valid command."):format(command)) + end end C:Register("__DEFAULT__", function(args) - KT:Msg("/kt target - Display number of kills on target mob.") - KT:Msg("/kt lookup - Display number of kills on , can also be NPC ID.") - KT:Msg("/kt print - Toggle printing kill updates to chat.") - KT:Msg("/kt list - Display a list of all mobs entries.") - KT:Msg("/kt delete - Delete entry with NPC id .") - KT:Msg("/kt purge [threshold] - Open dialog to purge entries, specifiying a threshold here is optional.") - KT:Msg("/kt reset - Clear the mob database.") - KT:Msg("/kt time - Track kills within specified time.") - KT:Msg("/kt immediate - Track kills made from this point on.") - KT:Msg("/kt threshold - Set threshold for kill record notices to show.") - KT:Msg("/kt countmode - Toggle between counting group killing blows or your killing blows only.") - KT:Msg("/kt minimap - Toggles the minimap icon") - KT:Msg("/kt - Displays this help message.") + KT:Msg("/kt target - Display number of kills on target mob.") + KT:Msg("/kt lookup - Display number of kills on , can also be NPC ID.") + KT:Msg("/kt print - Toggle printing kill updates to chat.") + KT:Msg("/kt list - Display a list of all mobs entries.") + KT:Msg("/kt delete - Delete entry with NPC id .") + KT:Msg("/kt purge [threshold] - Open dialog to purge entries, specifiying a threshold here is optional.") + KT:Msg("/kt reset - Clear the mob database.") + KT:Msg("/kt time - Track kills within specified time.") + KT:Msg("/kt immediate - Track kills made from this point on.") + KT:Msg("/kt threshold - Set threshold for kill record notices to show.") + KT:Msg("/kt countmode - Toggle between counting group killing blows or your killing blows only.") + KT:Msg("/kt minimap - Toggles the minimap icon") + KT:Msg("/kt tooltip - Toggles showing mob data in tooltip") + KT:Msg("/kt - Displays this help message.") end) C:Register({"target", "t", "tar"}, function(args) - if not UnitExists("target") or UnitIsPlayer("target") then return end - local id = KTT:GUIDToID(UnitGUID("target")) - KT:PrintKills(id) + if not UnitExists("target") or UnitIsPlayer("target") then return end + local id = KTT:GUIDToID(UnitGUID("target")) + KT:PrintKills(id) end) C:Register({"print", "p"}, function(args) - KT.Global.PRINTKILLS = not KT.Global.PRINTKILLS - if KT.Global.PRINTKILLS then - KT:Msg("Announcing kill updates.") - else - KT:Msg("No longer announcing kill updates.") - end + KT.Global.PRINTKILLS = not KT.Global.PRINTKILLS + if KT.Global.PRINTKILLS then + KT:Msg("Announcing kill updates.") + else + KT:Msg("No longer announcing kill updates.") + end end) C:Register({"printnew", "pn"}, function(args) - KT.Global.PRINTNEW = not KT.Global.PRINTNEW - if KT.Global.PRINTNEW then - KT:Msg("Announcing new mob entries") - else - KT:Msg("No longer announcing new mob entries") - end + KT.Global.PRINTNEW = not KT.Global.PRINTNEW + if KT.Global.PRINTNEW then + KT:Msg("Announcing new mob entries") + else + KT:Msg("No longer announcing new mob entries") + end end) C:Register({"delete", "del", "remove", "rem"}, function(args) - if #args <= 0 then - KT:Msg("Missing argument: id") - return - end - local id = tonumber(args[1]) - if not id then - KT:Msg("Id must be a number") - return - end - if not KT.Global.MOBS[id] then - KT:Msg(("Id %d does not exist in the database."):format(id)) - return - end - local name = KT.Global.MOBS[id].Name - KT:ShowDelete(id, name) + if #args <= 0 then + KT:Msg("Missing argument: id") + return + end + local id = tonumber(args[1]) + if not id then + KT:Msg("Id must be a number") + return + end + if not KT.Global.MOBS[id] then + KT:Msg(("Id %d does not exist in the database."):format(id)) + return + end + local name = KT.Global.MOBS[id].Name + KT:ShowDelete(id, name) end) C:Register({"purge"}, function(args) - local threshold - if #args >= 1 then threshold = tonumber(args[1]) end - KT:ShowPurge(threshold) + local threshold + if #args >= 1 then threshold = tonumber(args[1]) end + KT:ShowPurge(threshold) end) C:Register({"reset", "r"}, function(args) - KT:ShowReset() + KT:ShowReset() end) C:Register({"lookup", "lo", "check"}, function(args) - if #args <= 0 then - KT:Msg("Missing argument: name") - return - end - local name = table.concat(args, " ") - KT:PrintKills(name) + if #args <= 0 then + KT:Msg("Missing argument: name") + return + end + local name = table.concat(args, " ") + KT:PrintKills(name) end) C:Register({"list", "moblist", "mobs"}, function(args) - KT.MobList:Show() + KT.MobList:Show() end) C:Register({"time", "timer"}, function(args) - if #args <= 0 then - KT:Msg("Usage: time [minutes] [hours]") - KT:Msg("Usage: time [s][m][h]") - return - end - - local s, m, h - - if #args == 1 then - if not tonumber(args[1]) then - args[1] = args[1]:lower() - s = args[1]:match("(%d+)s") - m = args[1]:match("(%d+)m") - h = args[1]:match("(%d+)h") - if not s and not m and not h then - KT:Msg("Invalid number format.") - return - end - else - s = tonumber(args[1]) - end - else - s = tonumber(args[1]) - m = tonumber(args[2]) - h = tonumber(args[3]) - end - KT.TimerFrame:Start(s, m, h) + if #args <= 0 then + KT:Msg("Usage: time [minutes] [hours]") + KT:Msg("Usage: time [s][m][h]") + return + end + + local s, m, h + + if #args == 1 then + if not tonumber(args[1]) then + args[1] = args[1]:lower() + s = args[1]:match("(%d+)s") + m = args[1]:match("(%d+)m") + h = args[1]:match("(%d+)h") + if not s and not m and not h then + KT:Msg("Invalid number format.") + return + end + else + s = tonumber(args[1]) + end + else + s = tonumber(args[1]) + m = tonumber(args[2]) + h = tonumber(args[3]) + end + KT.TimerFrame:Start(s, m, h) end) C:Register({"immediate", "imm", "i"}, function(args) - if #args < 1 then - KT.Immediate:Show() - elseif args[1]:match("^t") then - local threshold = tonumber(args[2]) - if #args < 2 then - KT:Msg("Usage: immediate threshold ") - KT:Msg("E.g: /kt immediate threshold 50") - KT:Msg(" Notice will be shown on every 50th kill when immediate frame is active") - else - KT:SetImmediateThreshold(threshold) - end - elseif args[1]:match("^f") then - if #args < 2 then - local current = KT.Global.IMMEDIATE.FILTER - KT:Msg("The current immediate filter is set to: " .. (current and current or "")) - KT:Msg("Use /kt immediate filter to set a new filter") - KT:Msg("Use /kt immediate clearfilter to clear the filter") - else - KT:SetImmediateFilter(tostring(args[2])) - end - elseif args[1]:match("^c") then - KT:ClearImmediateFilter() - end + if #args < 1 then + KT.Immediate:Show() + elseif args[1]:match("^t") then + local threshold = tonumber(args[2]) + if #args < 2 then + KT:Msg("Usage: immediate threshold ") + KT:Msg("E.g: /kt immediate threshold 50") + KT:Msg(" Notice will be shown on every 50th kill when immediate frame is active") + else + KT:SetImmediateThreshold(threshold) + end + elseif args[1]:match("^f") then + if #args < 2 then + local current = KT.Global.IMMEDIATE.FILTER + KT:Msg("The current immediate filter is set to: " .. (current and current or "")) + KT:Msg("Use /kt immediate filter to set a new filter") + KT:Msg("Use /kt immediate clearfilter to clear the filter") + else + KT:SetImmediateFilter(tostring(args[2])) + end + elseif args[1]:match("^c") then + KT:ClearImmediateFilter() + end end) C:Register({"threshold"}, function(args) - if #args <= 0 then - KT:Msg("Usage: threshold ") - KT:Msg("E.g: /kt threshold 100") - KT:Msg(" Notice will be shown on every 100th kill.") - return - end - local t = tonumber(args[1]) - if t then - KT:SetThreshold(t) - else - KT:Msg("Argument must be a number.") - end + if #args <= 0 then + KT:Msg("Usage: threshold ") + KT:Msg("E.g: /kt threshold 100") + KT:Msg(" Notice will be shown on every 100th kill.") + return + end + local t = tonumber(args[1]) + if t then + KT:SetThreshold(t) + else + KT:Msg("Argument must be a number.") + end end) C:Register({"countmode", "cm", "count", "counttype", "changecount", "switchcount"}, function(args) - KT:ToggleCountMode() + KT:ToggleCountMode() end) C:Register({"debug", "toggledebug", "d", "td"}, function(args) - KT:ToggleDebug() + KT:ToggleDebug() end) C:Register({"exp", "xp", "experience", "shoexp", "showxp"}, function(args) - KT:ToggleExp() + KT:ToggleExp() end) C:Register({"options", "opt", "config", "conf"}, function(args) - KT.Options:Open() + KT.Options:Open() end) C:Register({"minimap", "mp"}, function(args) - KT.Broker:SetMinimap(not KT.Global.BROKER.MINIMAP.hide) + KT.Broker:SetMinimap(not KT.Global.BROKER.MINIMAP.hide) +end) + +C:Register({"tooltip", "tt"}, function(args) + KT.Global.TOOLTIP = not KT.Global.TOOLTIP + KT:Msg("Tooltip data " .. (KT.Global.TOOLTIP and "enabled" or "disabled")) end) for i,v in ipairs(C.Slash) do - _G["SLASH_" .. KT.Name:upper() .. i] = "/" .. v + _G["SLASH_" .. KT.Name:upper() .. i] = "/" .. v end SlashCmdList[KT.Name:upper()] = function(msg, editBox) - msg = KTT:Trim(msg) - local args = KTT:Split(msg) - local cmd = args[1] - local t = {} - if #args > 1 then - for i=2,#args do - table.insert(t, args[i]) - end - end - C:HandleCommand(cmd, t) + msg = KTT:Trim(msg) + local args = KTT:Split(msg) + local cmd = args[1] + local t = {} + if #args > 1 then + for i=2,#args do + table.insert(t, args[i]) + end + end + C:HandleCommand(cmd, t) end diff --git a/KillTrack.lua b/KillTrack.lua index bf3adc7..f91e97b 100644 --- a/KillTrack.lua +++ b/KillTrack.lua @@ -1,20 +1,20 @@ --[[ - * Copyright (c) 2011-2013 by Adam Hellberg. - * - * This file is part of KillTrack. - * - * KillTrack is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * KillTrack is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with KillTrack. If not, see . + * Copyright (c) 2011-2013 by Adam Hellberg. + * + * This file is part of KillTrack. + * + * KillTrack is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * KillTrack is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with KillTrack. If not, see . --]] -- Upvalue some functions used in CLEU @@ -23,29 +23,29 @@ local UnitIsTapDenied = UnitIsTapDenied local CombatLogGetCurrentEventInfo = CombatLogGetCurrentEventInfo KillTrack = { - Name = "KillTrack", - Version = GetAddOnMetadata("KillTrack", "Version"), - Events = {}, - Global = {}, - CharGlobal = {}, - Temp = {}, - Sort = { - Desc = 0, - Asc = 1, - CharDesc = 2, - CharAsc = 3, - AlphaD = 4, - AlphaA = 5, - IdDesc = 6, - IdAsc = 7 - }, - Session = { - Count = 0, - Kills = {} - }, - Messages = { - Announce = "[KillTrack] Session Length: %s. Session Kills: %d. Kills Per Minute: %.2f." - } + Name = "KillTrack", + Version = GetAddOnMetadata("KillTrack", "Version"), + Events = {}, + Global = {}, + CharGlobal = {}, + Temp = {}, + Sort = { + Desc = 0, + Asc = 1, + CharDesc = 2, + CharAsc = 3, + AlphaD = 4, + AlphaA = 5, + IdDesc = 6, + IdAsc = 7 + }, + Session = { + Count = 0, + Kills = {} + }, + Messages = { + Announce = "[KillTrack] Session Length: %s. Session Kills: %d. Kills Per Minute: %.2f." + } } local KT = KillTrack @@ -60,13 +60,13 @@ local LastDamage = {} -- Tracks whoever did the most recent damage to a mob local DamageValid = {} -- Determines if mob is tapped by player/group local Units = { - "target", - "targetpet", - "focus", - "focuspet", - "pet", - "mouseover", - "mouseoverpet", + "target", + "targetpet", + "focus", + "focuspet", + "pet", + "mouseover", + "mouseoverpet", } local combat_log_damage_events = {} @@ -81,574 +81,578 @@ do end for i = 1, 40 do - if i <= 4 then - Units[#Units + 1] = "party" .. i - Units[#Units + 1] = "partypet" .. i - end - Units[#Units + 1] = "raid" .. i - Units[#Units + 1] = "raidpet" .. i + if i <= 4 then + Units[#Units + 1] = "party" .. i + Units[#Units + 1] = "partypet" .. i + end + Units[#Units + 1] = "raid" .. i + Units[#Units + 1] = "raidpet" .. i end for i = 1, #Units * 2 do - Units[#Units + 1] = Units[i] .. "target" + Units[#Units + 1] = Units[i] .. "target" end if KT.Version == "@" .. "project-version" .. "@" then - KT.Version = "Development" - KT.Debug = true + KT.Version = "Development" + KT.Debug = true end local function FindUnitByGUID(guid) - for i = 1, #Units do - if UnitGUID(Units[i]) == guid then return Units[i] end - end - return nil + for i = 1, #Units do + if UnitGUID(Units[i]) == guid then return Units[i] end + end + return nil end function KT:OnEvent(_, event, ...) - if self.Events[event] then - self.Events[event](self, ...) - end + if self.Events[event] then + self.Events[event](self, ...) + end end function KT.Events.ADDON_LOADED(self, ...) - local name = (select(1, ...)) - if name ~= "KillTrack" then return end - ET = KT.ExpTracker - if type(_G["KILLTRACK"]) ~= "table" then - _G["KILLTRACK"] = {} - end - self.Global = _G["KILLTRACK"] - if type(self.Global.PRINTKILLS) ~= "boolean" then - self.Global.PRINTKILLS = false - end - if type(self.Global.PRINTNEW) ~= "boolean" then - self.Global.PRINTNEW = false - end - if type(self.Global.ACHIEV_THRESHOLD) ~= "number" then - self.Global.ACHIEV_THRESHOLD = 1000 - end - if type(self.Global.COUNT_GROUP) ~= "boolean" then - self.Global.COUNT_GROUP = false - end - if type(self.Global.SHOW_EXP) ~= "boolean" then - self.Global.SHOW_EXP = false - end - if type(self.Global.MOBS) ~= "table" then - self.Global.MOBS = {} - end - if type(self.Global.IMMEDIATE) ~= "table" then - self.Global.IMMEDIATE = {} - end - if type(self.Global.IMMEDIATE.POSITION) ~= "table" then - self.Global.IMMEDIATE.POSITION = {} - end - if type(self.Global.IMMEDIATE.THRESHOLD) ~= "number" then - self.Global.IMMEDIATE.THRESHOLD = 0 - end - if type(self.Global.BROKER) ~= "table" then - self.Global.BROKER = {} - end - if type(self.Global.BROKER.SHORT_TEXT) ~= "boolean" then - self.Global.BROKER.SHORT_TEXT = false - end - if type(self.Global.BROKER.MINIMAP) ~= "table" then - self.Global.BROKER.MINIMAP = {} - end - if type(self.Global.DISABLE_DUNGEONS) ~= "boolean" then - self.Global.DISABLE_DUNGEONS = false - end - if type(self.Global.DISABLE_RAIDS) ~= "boolean" then - self.Global.DISABLE_RAIDS = false - end - if type(_G["KILLTRACK_CHAR"]) ~= "table" then - _G["KILLTRACK_CHAR"] = {} - end - self.CharGlobal = _G["KILLTRACK_CHAR"] - if type(self.CharGlobal.MOBS) ~= "table" then - self.CharGlobal.MOBS = {} - end - self.PlayerName = UnitName("player") - self:Msg("AddOn Loaded!") - self.Session.Start = time() - self.Broker:OnLoad() + local name = (select(1, ...)) + if name ~= "KillTrack" then return end + ET = KT.ExpTracker + if type(_G["KILLTRACK"]) ~= "table" then + _G["KILLTRACK"] = {} + end + self.Global = _G["KILLTRACK"] + if type(self.Global.PRINTKILLS) ~= "boolean" then + self.Global.PRINTKILLS = false + end + if type(self.Global.PRINTNEW) ~= "boolean" then + self.Global.PRINTNEW = false + end + if type(self.Global.ACHIEV_THRESHOLD) ~= "number" then + self.Global.ACHIEV_THRESHOLD = 1000 + end + if type(self.Global.COUNT_GROUP) ~= "boolean" then + self.Global.COUNT_GROUP = false + end + if type(self.Global.SHOW_EXP) ~= "boolean" then + self.Global.SHOW_EXP = false + end + if type(self.Global.MOBS) ~= "table" then + self.Global.MOBS = {} + end + if type(self.Global.IMMEDIATE) ~= "table" then + self.Global.IMMEDIATE = {} + end + if type(self.Global.IMMEDIATE.POSITION) ~= "table" then + self.Global.IMMEDIATE.POSITION = {} + end + if type(self.Global.IMMEDIATE.THRESHOLD) ~= "number" then + self.Global.IMMEDIATE.THRESHOLD = 0 + end + if type(self.Global.BROKER) ~= "table" then + self.Global.BROKER = {} + end + if type(self.Global.BROKER.SHORT_TEXT) ~= "boolean" then + self.Global.BROKER.SHORT_TEXT = false + end + if type(self.Global.BROKER.MINIMAP) ~= "table" then + self.Global.BROKER.MINIMAP = {} + end + if type(self.Global.DISABLE_DUNGEONS) ~= "boolean" then + self.Global.DISABLE_DUNGEONS = false + end + if type(self.Global.DISABLE_RAIDS) ~= "boolean" then + self.Global.DISABLE_RAIDS = false + end + if type(self.Global.TOOLTIP) ~= "boolean" then + self.Global.TOOLTIP = true + end + if type(_G["KILLTRACK_CHAR"]) ~= "table" then + _G["KILLTRACK_CHAR"] = {} + end + self.CharGlobal = _G["KILLTRACK_CHAR"] + if type(self.CharGlobal.MOBS) ~= "table" then + self.CharGlobal.MOBS = {} + end + self.PlayerName = UnitName("player") + self:Msg("AddOn Loaded!") + self.Session.Start = time() + self.Broker:OnLoad() end function KT.Events.COMBAT_LOG_EVENT_UNFILTERED(self) - local timestamp, event, hideCaster, s_guid, s_name, s_flags, s_raidflags, d_guid, d_name, d_flags, d_raidflags = CombatLogGetCurrentEventInfo() - if combat_log_damage_events[event] then - if FirstDamage[d_guid] == nil then - -- s_name is (probably) the player who first damaged this mob and probably has the tag - FirstDamage[d_guid] = s_name - end - - LastDamage[d_guid] = s_name - - if not DamageValid[d_guid] then - -- if DamageValid returns true for a GUID, we can tell with 100% certainty that it's valid - -- But this relies on one of the valid unit names currently being the damaged mob - - local d_unit = FindUnitByGUID(d_guid) + local timestamp, event, hideCaster, s_guid, s_name, s_flags, s_raidflags, d_guid, d_name, d_flags, d_raidflags = CombatLogGetCurrentEventInfo() + if combat_log_damage_events[event] then + if FirstDamage[d_guid] == nil then + -- s_name is (probably) the player who first damaged this mob and probably has the tag + FirstDamage[d_guid] = s_name + end - if not d_unit then return end + LastDamage[d_guid] = s_name - DamageValid[d_guid] = not UnitIsTapDenied(d_unit) - end + if not DamageValid[d_guid] then + -- if DamageValid returns true for a GUID, we can tell with 100% certainty that it's valid + -- But this relies on one of the valid unit names currently being the damaged mob - return - end + local d_unit = FindUnitByGUID(d_guid) - if event ~= "UNIT_DIED" then return end + if not d_unit then return end - -- Perform solo/group checks - local d_id = KTT:GUIDToID(d_guid) - local firstDamage = FirstDamage[d_guid] or "" - local lastDamage = LastDamage[d_guid] or "" - local firstByPlayer = firstDamage == self.PlayerName or firstDamage == UnitName("pet") - local firstByGroup = self:IsInGroup(firstDamage) - local lastByPlayer = lastDamage == self.PlayerName or lastDamage == UnitName("pet") - local pass + DamageValid[d_guid] = not UnitIsTapDenied(d_unit) + end - -- All checks after DamageValid should be safe to remove - -- The checks after DamageValid are also not 100% failsafe - -- Scenario: You deal the killing blow to an already tapped mob <- Would count as kill with current code + return + end - -- if DamageValid[guid] is set, it can be used to decide if the kill was valid with 100% certainty - if DamageValid[d_guid] ~= nil then - pass = DamageValid[d_guid] - else -- The one who dealt the very first bit of damage was probably the one who got the tag on the mob - -- This should apply in most (if not all) situations and is probably a safe fallback when we couldn't retrieve tapped status from GUID->Unit - pass = firstByPlayer or firstByGroup - end + if event ~= "UNIT_DIED" then return end + + -- Perform solo/group checks + local d_id = KTT:GUIDToID(d_guid) + local firstDamage = FirstDamage[d_guid] or "" + local lastDamage = LastDamage[d_guid] or "" + local firstByPlayer = firstDamage == self.PlayerName or firstDamage == UnitName("pet") + local firstByGroup = self:IsInGroup(firstDamage) + local lastByPlayer = lastDamage == self.PlayerName or lastDamage == UnitName("pet") + local pass + + -- All checks after DamageValid should be safe to remove + -- The checks after DamageValid are also not 100% failsafe + -- Scenario: You deal the killing blow to an already tapped mob <- Would count as kill with current code + + -- if DamageValid[guid] is set, it can be used to decide if the kill was valid with 100% certainty + if DamageValid[d_guid] ~= nil then + pass = DamageValid[d_guid] + else -- The one who dealt the very first bit of damage was probably the one who got the tag on the mob + -- This should apply in most (if not all) situations and is probably a safe fallback when we couldn't retrieve tapped status from GUID->Unit + pass = firstByPlayer or firstByGroup + end - if not self.Global.COUNT_GROUP and pass and not lastByPlayer then - pass = false -- Player or player's pet did not deal the killing blow and addon only tracks player kills - end + if not self.Global.COUNT_GROUP and pass and not lastByPlayer then + pass = false -- Player or player's pet did not deal the killing blow and addon only tracks player kills + end - if not pass or d_id == nil or d_id == 0 then return end - FirstDamage[d_guid] = nil - DamageValid[d_guid] = nil - self:AddKill(d_id, d_name) - if self.Timer:IsRunning() then - self.Timer:SetData("Kills", self.Timer:GetData("Kills", true) + 1) - end + if not pass or d_id == nil or d_id == 0 then return end + FirstDamage[d_guid] = nil + DamageValid[d_guid] = nil + self:AddKill(d_id, d_name) + if self.Timer:IsRunning() then + self.Timer:SetData("Kills", self.Timer:GetData("Kills", true) + 1) + end end function KT.Events.UPDATE_MOUSEOVER_UNIT(self, ...) - if UnitIsPlayer("mouseover") then return end - local id = KTT:GUIDToID(UnitGUID("mouseover")) - if not id then return end - if UnitCanAttack("player", "mouseover") then - local mob, charMob = self:InitMob(id, UnitName("mouseover")) - local gKills, cKills = mob.Kills, charMob.Kills --self:GetKills(id) - local exp = mob.Exp - GameTooltip:AddLine(("Killed %d (%d) times."):format(cKills, gKills), 1, 1, 1) - if self.Global.SHOW_EXP and exp then - local toLevel = exp > 0 and math.ceil((UnitXPMax("player") - UnitXP("player")) / exp) or "N/A" - GameTooltip:AddLine(("EXP: %d (%s kills to level)"):format(exp, toLevel), 1, 1, 1) - end - end - if KT.Debug then - GameTooltip:AddLine(("ID = %d"):format(id)) - end - GameTooltip:Show() + if not self.Global.TOOLTIP then return end + if UnitIsPlayer("mouseover") then return end + local id = KTT:GUIDToID(UnitGUID("mouseover")) + if not id then return end + if UnitCanAttack("player", "mouseover") then + local mob, charMob = self:InitMob(id, UnitName("mouseover")) + local gKills, cKills = mob.Kills, charMob.Kills --self:GetKills(id) + local exp = mob.Exp + GameTooltip:AddLine(("Killed %d (%d) times."):format(cKills, gKills), 1, 1, 1) + if self.Global.SHOW_EXP and exp then + local toLevel = exp > 0 and math.ceil((UnitXPMax("player") - UnitXP("player")) / exp) or "N/A" + GameTooltip:AddLine(("EXP: %d (%s kills to level)"):format(exp, toLevel), 1, 1, 1) + end + end + if KT.Debug then + GameTooltip:AddLine(("ID = %d"):format(id)) + end + GameTooltip:Show() end function KT.Events.CHAT_MSG_COMBAT_XP_GAIN(self, message) - ET:CheckMessage(message) + ET:CheckMessage(message) end function KT.Events.ENCOUNTER_START(self, encounterID, name, difficulty, size) - if (self.Global.DISABLE_DUNGEONS and size == 5) or (self.Global.DISABLE_RAIDS and size > 5) then - self.Frame:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") - self.Frame:UnregisterEvent("UPDATE_MOUSEOVER_UNIT") - self.Frame:UnregisterEvent("CHAT_MSG_COMBAT_XP_GAIN") - end + if (self.Global.DISABLE_DUNGEONS and size == 5) or (self.Global.DISABLE_RAIDS and size > 5) then + self.Frame:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") + self.Frame:UnregisterEvent("UPDATE_MOUSEOVER_UNIT") + self.Frame:UnregisterEvent("CHAT_MSG_COMBAT_XP_GAIN") + end end function KT.Events.ENCOUNTER_END(self, encounterID, name, difficulty, size) - if (self.Global.DISABLE_DUNGEONS and size == 5) or (self.Global.DISABLE_RAIDS and size > 5) then - self.Frame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") - self.Frame:RegisterEvent("UPDATE_MOUSEOVER_UNIT") - self.Frame:RegisterEvent("CHAT_MSG_COMBAT_XP_GAIN") - end + if (self.Global.DISABLE_DUNGEONS and size == 5) or (self.Global.DISABLE_RAIDS and size > 5) then + self.Frame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") + self.Frame:RegisterEvent("UPDATE_MOUSEOVER_UNIT") + self.Frame:RegisterEvent("CHAT_MSG_COMBAT_XP_GAIN") + end end function KT:ToggleExp() - self.Global.SHOW_EXP = not self.Global.SHOW_EXP - if self.Global.SHOW_EXP then - KT:Msg("Now showing EXP on tooltips!") - else - KT:Msg("No longer showing EXP on tooltips.") - end + self.Global.SHOW_EXP = not self.Global.SHOW_EXP + if self.Global.SHOW_EXP then + KT:Msg("Now showing EXP on tooltips!") + else + KT:Msg("No longer showing EXP on tooltips.") + end end function KT:ToggleDebug() - self.Debug = not self.Debug - if self.Debug then - KT:Msg("Debug enabled!") - else - KT:Msg("Debug disabled!") - end + self.Debug = not self.Debug + if self.Debug then + KT:Msg("Debug enabled!") + else + KT:Msg("Debug disabled!") + end end function KT:IsInGroup(unit) - if unit == self.PlayerName then return true end - if UnitInParty(unit) then return true end - if UnitInRaid(unit) then return true end - return false + if unit == self.PlayerName then return true end + if UnitInParty(unit) then return true end + if UnitInRaid(unit) then return true end + return false end function KT:SetThreshold(threshold) - if type(threshold) ~= "number" then - error("KillTrack.SetThreshold: Argument #1 (threshold) must be of type 'number'") - end - self.Global.ACHIEV_THRESHOLD = threshold - if threshold > 0 then - self:ResetAchievCount() - KT:Msg(("New kill notice (achievement) threshold set to %d."):format(threshold)) - else - KT:Msg("Kill notices have been disabled (set threshold to a value greater than 0 to re-enable).") - end + if type(threshold) ~= "number" then + error("KillTrack.SetThreshold: Argument #1 (threshold) must be of type 'number'") + end + self.Global.ACHIEV_THRESHOLD = threshold + if threshold > 0 then + self:ResetAchievCount() + KT:Msg(("New kill notice (achievement) threshold set to %d."):format(threshold)) + else + KT:Msg("Kill notices have been disabled (set threshold to a value greater than 0 to re-enable).") + end end function KT:SetImmediateThreshold(threshold) - if type(threshold) ~= "number" then - error("KillTrack.SetImmediateThreshold: Argument #1 (threshold) must be of type 'number'") - end - self.Global.IMMEDIATE.THRESHOLD = threshold - if threshold > 0 then - KT:Msg(("New immediate threshold set to %d."):format(threshold)) - else - KT:Msg("Immediate threshold disabled.") - end + if type(threshold) ~= "number" then + error("KillTrack.SetImmediateThreshold: Argument #1 (threshold) must be of type 'number'") + end + self.Global.IMMEDIATE.THRESHOLD = threshold + if threshold > 0 then + KT:Msg(("New immediate threshold set to %d."):format(threshold)) + else + KT:Msg("Immediate threshold disabled.") + end end function KT:SetImmediateFilter(filter) - if type(filter) ~= "string" then - error("KillTrack.SetImmediateFilter: Argument #1 (filter) must be of type 'string'") - end - self.Global.IMMEDIATE.FILTER = filter - KT:Msg("New immediate filter set to: " .. filter) + if type(filter) ~= "string" then + error("KillTrack.SetImmediateFilter: Argument #1 (filter) must be of type 'string'") + end + self.Global.IMMEDIATE.FILTER = filter + KT:Msg("New immediate filter set to: " .. filter) end function KT:ClearImmediateFilter() - self.Global.IMMEDIATE.FILTER = nil - KT:Msg("Immediate filter cleared!") + self.Global.IMMEDIATE.FILTER = nil + KT:Msg("Immediate filter cleared!") end function KT:ToggleCountMode() - self.Global.COUNT_GROUP = not self.Global.COUNT_GROUP - if self.Global.COUNT_GROUP then - KT:Msg("Now counting kills for every player in the group (party/raid)!") - else - KT:Msg("Now counting your own killing blows ONLY.") - end + self.Global.COUNT_GROUP = not self.Global.COUNT_GROUP + if self.Global.COUNT_GROUP then + KT:Msg("Now counting kills for every player in the group (party/raid)!") + else + KT:Msg("Now counting your own killing blows ONLY.") + end end function KT:InitMob(id, name) - name = name or "" + name = name or "" - if type(self.Global.MOBS[id]) ~= "table" then - self.Global.MOBS[id] = { Name = name, Kills = 0, AchievCount = 0 } - if self.Global.PRINTNEW then - self:Msg(("Created new entry for %q"):format(name)) - end - elseif self.Global.MOBS[id].Name ~= name then - self.Global.MOBS[id].Name = name - end + if type(self.Global.MOBS[id]) ~= "table" then + self.Global.MOBS[id] = { Name = name, Kills = 0, AchievCount = 0 } + if self.Global.PRINTNEW then + self:Msg(("Created new entry for %q"):format(name)) + end + elseif self.Global.MOBS[id].Name ~= name then + self.Global.MOBS[id].Name = name + end - if type(self.CharGlobal.MOBS[id]) ~= "table" then - self.CharGlobal.MOBS[id] = { Name = name, Kills = 0 } - if self.Global.PRINTNEW then - self:Msg(("Created new entry for %q on this character."):format(name)) - end - elseif self.CharGlobal.MOBS[id].Name ~= name then - self.CharGlobal.MOBS[id].Name = name - end + if type(self.CharGlobal.MOBS[id]) ~= "table" then + self.CharGlobal.MOBS[id] = { Name = name, Kills = 0 } + if self.Global.PRINTNEW then + self:Msg(("Created new entry for %q on this character."):format(name)) + end + elseif self.CharGlobal.MOBS[id].Name ~= name then + self.CharGlobal.MOBS[id].Name = name + end - return self:GetMob(id) + return self:GetMob(id) end function KT:AddKill(id, name) - name = name or "" - self:InitMob(id, name) - self.Global.MOBS[id].Kills = self.Global.MOBS[id].Kills + 1 - self.CharGlobal.MOBS[id].Kills = self.CharGlobal.MOBS[id].Kills + 1 - if self.Global.PRINTKILLS then - self:Msg(("Updated %q, new kill count: %d. Kill count on this character: %d"):format(name, self.Global.MOBS[id].Kills, self.CharGlobal.MOBS[id].Kills)) - end - self:AddSessionKill(name) - if self.Immediate.Active then - local filter = self.Global.IMMEDIATE.FILTER - local filterPass = not filter or name:match(filter) - if filterPass then - self.Immediate:AddKill() - if self.Global.IMMEDIATE.THRESHOLD > 0 and self.Immediate.Kills % self.Global.IMMEDIATE.THRESHOLD == 0 then - PlaySound("RaidWarning") - PlaySound("PVPTHROUGHQUEUE") - RaidNotice_AddMessage(RaidWarningFrame, ("%d KILLS!"):format(self.Immediate.Kills), ChatTypeInfo["SYSTEM"]) - end - end - end - if self.Global.ACHIEV_THRESHOLD <= 0 then return end - if type(self.Global.MOBS[id].AchievCount) ~= "number" then - self.Global.MOBS[id].AchievCount = floor(self.Global.MOBS[id].Kills / self.Global.ACHIEV_THRESHOLD) - if self.Global.MOBS[id].AchievCount >= 1 then - self:KillAlert(self.Global.MOBS[id]) - end - else - local achievCount = self.Global.MOBS[id].AchievCount - self.Global.MOBS[id].AchievCount = floor(self.Global.MOBS[id].Kills / self.Global.ACHIEV_THRESHOLD) - if self.Global.MOBS[id].AchievCount > achievCount then - self:KillAlert(self.Global.MOBS[id]) - end - end + name = name or "" + self:InitMob(id, name) + self.Global.MOBS[id].Kills = self.Global.MOBS[id].Kills + 1 + self.CharGlobal.MOBS[id].Kills = self.CharGlobal.MOBS[id].Kills + 1 + if self.Global.PRINTKILLS then + self:Msg(("Updated %q, new kill count: %d. Kill count on this character: %d"):format(name, self.Global.MOBS[id].Kills, self.CharGlobal.MOBS[id].Kills)) + end + self:AddSessionKill(name) + if self.Immediate.Active then + local filter = self.Global.IMMEDIATE.FILTER + local filterPass = not filter or name:match(filter) + if filterPass then + self.Immediate:AddKill() + if self.Global.IMMEDIATE.THRESHOLD > 0 and self.Immediate.Kills % self.Global.IMMEDIATE.THRESHOLD == 0 then + PlaySound("RaidWarning") + PlaySound("PVPTHROUGHQUEUE") + RaidNotice_AddMessage(RaidWarningFrame, ("%d KILLS!"):format(self.Immediate.Kills), ChatTypeInfo["SYSTEM"]) + end + end + end + if self.Global.ACHIEV_THRESHOLD <= 0 then return end + if type(self.Global.MOBS[id].AchievCount) ~= "number" then + self.Global.MOBS[id].AchievCount = floor(self.Global.MOBS[id].Kills / self.Global.ACHIEV_THRESHOLD) + if self.Global.MOBS[id].AchievCount >= 1 then + self:KillAlert(self.Global.MOBS[id]) + end + else + local achievCount = self.Global.MOBS[id].AchievCount + self.Global.MOBS[id].AchievCount = floor(self.Global.MOBS[id].Kills / self.Global.ACHIEV_THRESHOLD) + if self.Global.MOBS[id].AchievCount > achievCount then + self:KillAlert(self.Global.MOBS[id]) + end + end end function KT:AddSessionKill(name) - if self.Session.Kills[name] then - self.Session.Kills[name] = self.Session.Kills[name] + 1 - else - self.Session.Kills[name] = 1 - end - self.Session.Count = self.Session.Count + 1 + if self.Session.Kills[name] then + self.Session.Kills[name] = self.Session.Kills[name] + 1 + else + self.Session.Kills[name] = 1 + end + self.Session.Count = self.Session.Count + 1 end function KT:SetExp(name, exp) - for id, mob in pairs(self.Global.MOBS) do - if mob.Name == name then mob.Exp = tonumber(exp) end - end + for id, mob in pairs(self.Global.MOBS) do + if mob.Name == name then mob.Exp = tonumber(exp) end + end end function KT:GetSortedSessionKills(max) - max = tonumber(max) or 3 - local t = {} - for k,v in pairs(self.Session.Kills) do - t[#t + 1] = {Name = k, Kills = v} - end - table.sort(t, function(a, b) return a.Kills > b.Kills end) - -- Trim table to only contain 3 entries - local trimmed = {} - local c = 0 - for i,v in ipairs(t) do - trimmed[i] = v - c = c + 1 - if c >= max then break end - end - return trimmed + max = tonumber(max) or 3 + local t = {} + for k,v in pairs(self.Session.Kills) do + t[#t + 1] = {Name = k, Kills = v} + end + table.sort(t, function(a, b) return a.Kills > b.Kills end) + -- Trim table to only contain 3 entries + local trimmed = {} + local c = 0 + for i,v in ipairs(t) do + trimmed[i] = v + c = c + 1 + if c >= max then break end + end + return trimmed end function KT:ResetSession() - wipe(self.Session.Kills) - self.Session.Count = 0 - self.Session.Start = time() + wipe(self.Session.Kills) + self.Session.Count = 0 + self.Session.Start = time() end function KT:GetKills(id) - local gKills, cKills = 0, 0 - local mob = self.Global.MOBS[id] - if type(mob) == "table" then - gKills = mob.Kills - local cMob = self.CharGlobal.MOBS[id] - if type(cMob) == "table" then - cKills = cMob.Kills - end - end - return gKills, cKills + local gKills, cKills = 0, 0 + local mob = self.Global.MOBS[id] + if type(mob) == "table" then + gKills = mob.Kills + local cMob = self.CharGlobal.MOBS[id] + if type(cMob) == "table" then + cKills = cMob.Kills + end + end + return gKills, cKills end function KT:GetTotalKills() - local count = 0 - for k,v in pairs(self.Global.MOBS) do - count = count + v.Kills - end - return count + local count = 0 + for k,v in pairs(self.Global.MOBS) do + count = count + v.Kills + end + return count end function KT:GetSessionStats() - if not self.Session.Start then return 0, 0, 0 end - local now = time() - local session = now - self.Session.Start - local kps = session == 0 and 0 or self.Session.Count / session - local kpm = kps * 60 - local kph = kpm * 60 - return kps, kpm, kph, session + if not self.Session.Start then return 0, 0, 0 end + local now = time() + local session = now - self.Session.Start + local kps = session == 0 and 0 or self.Session.Count / session + local kpm = kps * 60 + local kph = kpm * 60 + return kps, kpm, kph, session end function KT:PrintKills(identifier) - local found = false - local name = "" - local gKills = 0 - local cKills = 0 - if type(identifier) ~= "string" and type(identifier) ~= "number" then identifier = "" end - for k,v in pairs(self.Global.MOBS) do - if type(v) == "table" and (tostring(k) == tostring(identifier) or v.Name == identifier) then - name = v.Name - gKills = v.Kills - if self.CharGlobal.MOBS[k] then - cKills = self.CharGlobal.MOBS[k].Kills - end - found = true - end - end - if found then - self:Msg(("You have killed %q %d times in total, %d times on this character"):format(name, gKills, cKills)) - else - if UnitExists("target") and not UnitIsPlayer("target") then - identifier = UnitName("target") - end - self:Msg(("Unable to find %q in mob database."):format(tostring(identifier))) - end + local found = false + local name = "" + local gKills = 0 + local cKills = 0 + if type(identifier) ~= "string" and type(identifier) ~= "number" then identifier = "" end + for k,v in pairs(self.Global.MOBS) do + if type(v) == "table" and (tostring(k) == tostring(identifier) or v.Name == identifier) then + name = v.Name + gKills = v.Kills + if self.CharGlobal.MOBS[k] then + cKills = self.CharGlobal.MOBS[k].Kills + end + found = true + end + end + if found then + self:Msg(("You have killed %q %d times in total, %d times on this character"):format(name, gKills, cKills)) + else + if UnitExists("target") and not UnitIsPlayer("target") then + identifier = UnitName("target") + end + self:Msg(("Unable to find %q in mob database."):format(tostring(identifier))) + end end function KT:Announce(target) - if target == "GROUP" then - target = ((IsInRaid() and "RAID") or (IsInGroup() and "PARTY")) or "SAY" - end - local _, kpm, _, length = self:GetSessionStats() - local msg = self.Messages.Announce:format(KTT:FormatSeconds(length), self.Session.Count, kpm) - SendChatMessage(msg, target) + if target == "GROUP" then + target = ((IsInRaid() and "RAID") or (IsInGroup() and "PARTY")) or "SAY" + end + local _, kpm, _, length = self:GetSessionStats() + local msg = self.Messages.Announce:format(KTT:FormatSeconds(length), self.Session.Count, kpm) + SendChatMessage(msg, target) end function KT:Msg(msg) - DEFAULT_CHAT_FRAME:AddMessage("\124cff00FF00[KillTrack]\124r " .. msg) + DEFAULT_CHAT_FRAME:AddMessage("\124cff00FF00[KillTrack]\124r " .. msg) end function KT:KillAlert(mob) - local data = { - Text = ("%d kills on %s!"):format(mob.Kills, mob.Name), - Title = "Kill Record!", - bTitle = "Congratulations!", - Icon = "Interface\\Icons\\ABILITY_Deathwing_Bloodcorruption_Death", - FrameStyle = "GuildAchievement" - } - if IsAddOnLoaded("Glamour") then - if not GlamourShowAlert then - KT:Msg("ERROR: GlamourShowAlert == nil! Notify AddOn developer.") - return - end - GlamourShowAlert(500, data) - else - RaidNotice_AddMessage(RaidBossEmoteFrame, data.Text, ChatTypeInfo["SYSTEM"]) - RaidNotice_AddMessage(RaidBossEmoteFrame, data.Text, ChatTypeInfo["SYSTEM"]) - end - self:Msg(data.Text) + local data = { + Text = ("%d kills on %s!"):format(mob.Kills, mob.Name), + Title = "Kill Record!", + bTitle = "Congratulations!", + Icon = "Interface\\Icons\\ABILITY_Deathwing_Bloodcorruption_Death", + FrameStyle = "GuildAchievement" + } + if IsAddOnLoaded("Glamour") then + if not GlamourShowAlert then + KT:Msg("ERROR: GlamourShowAlert == nil! Notify AddOn developer.") + return + end + GlamourShowAlert(500, data) + else + RaidNotice_AddMessage(RaidBossEmoteFrame, data.Text, ChatTypeInfo["SYSTEM"]) + RaidNotice_AddMessage(RaidBossEmoteFrame, data.Text, ChatTypeInfo["SYSTEM"]) + end + self:Msg(data.Text) end function KT:GetMob(id) - for k,v in pairs(self.Global.MOBS) do - if type(v) == "table" and (tostring(k) == tostring(id) or v.Name == id) then - return v, self.CharGlobal.MOBS[k] - end - end - return false, nil + for k,v in pairs(self.Global.MOBS) do + if type(v) == "table" and (tostring(k) == tostring(id) or v.Name == id) then + return v, self.CharGlobal.MOBS[k] + end + end + return false, nil end function KT:GetSortedMobTable(mode, filter, caseSensitive) - if not tonumber(mode) then mode = self.Sort.Desc end - if mode < 0 or mode > 7 then mode = self.Sort.Desc end - if filter and filter == "" then filter = nil end - local t = {} - for k,v in pairs(self.Global.MOBS) do - assert(type(v) == "table", "Unexpected mob entry type in db: " .. type(v) .. ". Expected table") - local matches = nil - if filter then - local name = caseSensitive and v.Name or v.Name:lower() - filter = caseSensitive and filter or filter:lower() - local status, result = pcall(string.match, name, filter) - matches = status and result - end - if matches or not filter then - local cKills = 0 - if self.CharGlobal.MOBS[k] and type(self.CharGlobal.MOBS[k]) == "table" then - cKills = self.CharGlobal.MOBS[k].Kills - end - local entry = {Id = k, Name = v.Name, gKills = v.Kills, cKills = cKills} - table.insert(t, entry) - end - end - local function compare(a, b) - if mode == self.Sort.Asc then - return a.gKills < b.gKills - elseif mode == self.Sort.CharDesc then - return a.cKills > b.cKills - elseif mode == self.Sort.CharAsc then - return a.cKills < b.cKills - elseif mode == self.Sort.AlphaD then - return a.Name > b.Name - elseif mode == self.Sort.AlphaA then - return a.Name < b.Name - elseif mode == self.Sort.IdDesc then - return a.Id > b.Id - elseif mode == self.Sort.IdAsc then - return a.Id < b.Id - else - return a.gKills > b.gKills -- Descending - end - end - table.sort(t, compare) - return t + if not tonumber(mode) then mode = self.Sort.Desc end + if mode < 0 or mode > 7 then mode = self.Sort.Desc end + if filter and filter == "" then filter = nil end + local t = {} + for k,v in pairs(self.Global.MOBS) do + assert(type(v) == "table", "Unexpected mob entry type in db: " .. type(v) .. ". Expected table") + local matches = nil + if filter then + local name = caseSensitive and v.Name or v.Name:lower() + filter = caseSensitive and filter or filter:lower() + local status, result = pcall(string.match, name, filter) + matches = status and result + end + if matches or not filter then + local cKills = 0 + if self.CharGlobal.MOBS[k] and type(self.CharGlobal.MOBS[k]) == "table" then + cKills = self.CharGlobal.MOBS[k].Kills + end + local entry = {Id = k, Name = v.Name, gKills = v.Kills, cKills = cKills} + table.insert(t, entry) + end + end + local function compare(a, b) + if mode == self.Sort.Asc then + return a.gKills < b.gKills + elseif mode == self.Sort.CharDesc then + return a.cKills > b.cKills + elseif mode == self.Sort.CharAsc then + return a.cKills < b.cKills + elseif mode == self.Sort.AlphaD then + return a.Name > b.Name + elseif mode == self.Sort.AlphaA then + return a.Name < b.Name + elseif mode == self.Sort.IdDesc then + return a.Id > b.Id + elseif mode == self.Sort.IdAsc then + return a.Id < b.Id + else + return a.gKills > b.gKills -- Descending + end + end + table.sort(t, compare) + return t end function KT:Delete(id, charOnly) - id = tonumber(id) - if not id then error(("Expected 'id' param to be number, got %s."):format(type(id))) end - local found = false - local name - if self.Global.MOBS[id] then - name = self.Global.MOBS[id].Name - if not charOnly then self.Global.MOBS[id] = nil end - if self.CharGlobal.MOBS[id] then - self.CharGlobal.MOBS[id] = nil - end - found = true - end - if found then - self:Msg(("Deleted %q (%d) from database."):format(name, id)) - StaticPopup_Show("KILLTRACK_FINISH", 1) - else - self:Msg(("ID: %d was not found in the database."):format(id)) - end + id = tonumber(id) + if not id then error(("Expected 'id' param to be number, got %s."):format(type(id))) end + local found = false + local name + if self.Global.MOBS[id] then + name = self.Global.MOBS[id].Name + if not charOnly then self.Global.MOBS[id] = nil end + if self.CharGlobal.MOBS[id] then + self.CharGlobal.MOBS[id] = nil + end + found = true + end + if found then + self:Msg(("Deleted %q (%d) from database."):format(name, id)) + StaticPopup_Show("KILLTRACK_FINISH", 1) + else + self:Msg(("ID: %d was not found in the database."):format(id)) + end end function KT:Purge(threshold) - local count = 0 - for k,v in pairs(KT.Global.MOBS) do - if type(v) == "table" and v.Kills < threshold then - self.Global.MOBS[k] = nil - count = count + 1 - end - end - for k,v in pairs(KT.CharGlobal.MOBS) do - if type(v) == "table" and v.Kills < threshold then - self.CharGlobal.MOBS[k] = nil - count = count + 1 - end - end - self:Msg(("Purged %d entries with a kill count below %d"):format(count, threshold)) - self.Temp.Threshold = nil - StaticPopup_Show("KILLTRACK_FINISH", tostring(count)) + local count = 0 + for k,v in pairs(KT.Global.MOBS) do + if type(v) == "table" and v.Kills < threshold then + self.Global.MOBS[k] = nil + count = count + 1 + end + end + for k,v in pairs(KT.CharGlobal.MOBS) do + if type(v) == "table" and v.Kills < threshold then + self.CharGlobal.MOBS[k] = nil + count = count + 1 + end + end + self:Msg(("Purged %d entries with a kill count below %d"):format(count, threshold)) + self.Temp.Threshold = nil + StaticPopup_Show("KILLTRACK_FINISH", tostring(count)) end function KT:Reset() - local count = #KT.Global.MOBS + #KT.CharGlobal.MOBS - wipe(self.Global.MOBS) - wipe(self.CharGlobal.MOBS) - KT:Msg(("%d mob entries have been removed!"):format(count)) - StaticPopup_Show("KILLTRACK_FINISH", tostring(count)) + local count = #KT.Global.MOBS + #KT.CharGlobal.MOBS + wipe(self.Global.MOBS) + wipe(self.CharGlobal.MOBS) + KT:Msg(("%d mob entries have been removed!"):format(count)) + StaticPopup_Show("KILLTRACK_FINISH", tostring(count)) end function KT:ResetAchievCount() - for _,v in pairs(self.Global.MOBS) do - v.AchievCount = floor(v.Kills / self.Global.ACHIEV_THRESHOLD) - end + for _,v in pairs(self.Global.MOBS) do + v.AchievCount = floor(v.Kills / self.Global.ACHIEV_THRESHOLD) + end end KT.Frame = CreateFrame("Frame") for k,_ in pairs(KT.Events) do - KT.Frame:RegisterEvent(k) + KT.Frame:RegisterEvent(k) end KT.Frame:SetScript("OnEvent", function(_, event, ...) KT:OnEvent(_, event, ...) end) diff --git a/Options.lua b/Options.lua index 444658d..4cccdca 100644 --- a/Options.lua +++ b/Options.lua @@ -80,6 +80,13 @@ function Opt:Show() end) printKills:SetPoint("TOPLEFT", title, "BOTTOMLEFT", -2, -16) + local tooltipControl = checkbox("Show mob data in tooltip", + "With this enabled, KillTrack will print data about mobs in the tooltip", + function(check, checked) + KT.Global.TOOLTIP = checked + end) + tooltipControl:SetPoint("LEFT", printKills, "RIGHT", 180, 0) + local printNew = checkbox("Print new mob entries to chat", "With this enabled, new mobs added to the database will be announced locally in the chat", function(check, checked) @@ -179,6 +186,7 @@ function Opt:Show() local function init() printKills:SetChecked(KT.Global.PRINT) + tooltipControl:SetChecked(KT.Global.TOOLTIP) printNew:SetChecked(KT.Global.PRINTNEW) countGroup:SetChecked(KT.Global.COUNT_GROUP) threshold:SetText(KT.Global.ACHIEV_THRESHOLD)