--[[ KLH Threatmeter KLHTM_RaidGui.lua Lukon Mod 2: Part of the replacement for Gui.lua and Tables.lua. Controls the GUI for the raid threat section of KLH ThreatMeter. See also KTM_Gui.xml, KTM_Gui.lua. --]] local mod = klhtm local me = { } mod.guiraid = me -- The number of rows defined in New_Frame.xml local Max_Rows = 20; KLHTM_MaxRaidRows = Max_Rows; -- If the top threat value is greater than 150% of aggro gain when no master target is set -- then the threat100 reference value is set to the top threat value. This prevents very -- large %threat values when mobs use secondary targetting abilities. local Max_Aggro_Ratio = 1.5 -- Local references to some Gui variables local options = KLHTM_GuiOptions; local gui = KLHTM_Gui; local sizes = KLHTM_GuiSizes; local state = KLHTM_GuiState; local heights = KLHTM_GuiHeights; ------------------------------------------------------------------------------ -- Sets up the instance variable "gui.raid". It contains data on the GUI -- components in the raid threat frame. ------------------------------------------------------------------------------ function KLHTM_CreateRaidTable() gui.raid = { ["frame"] = KLHTM_RaidFrame, ["line"] = KLHTM_RaidFrameLine, -- dividing line between title bar and frame ["head"] = { -- column headers ["name"] = { ["frame"] = KLHTM_RaidFrameHeaderName, ["text"] = KLHTM_RaidFrameHeaderNameText, ["width"] = 90, ["colour"] = {["r"] = 1.0, ["g"] = 1.0, ["b"] = 1.0}, ["vis"] = function() return (options.raid.columnVis.name) end, }, ["threat"] = { ["frame"] = KLHTM_RaidFrameHeaderThreat, ["text"] = KLHTM_RaidFrameHeaderThreatText, ["width"] = 45, ["colour"] = {["r"] = 1.0, ["g"] = 1.0, ["b"] = 1.0}, ["vis"] = function() return (options.raid.columnVis.threat) end, }, ["pc"] = { ["frame"] = KLHTM_RaidFrameHeaderPercentThreat, ["text"] = KLHTM_RaidFrameHeaderPercentThreatText, ["width"] = 40, ["colour"] = {["r"] = 1.0, ["g"] = 1.0, ["b"] = 1.0}, ["vis"] = function() return (options.raid.columnVis.pc) end, }, }, ["rows"] = {}, ["bottom"] = { -- bottom bar ["frame"] = KLHTM_RaidFrameBottom, ["line"] = KLHTM_RaidFrameBottomLine, -- dividing line between frame and bottom bar ["tdef"] = { ["frame"] = KLHTM_RaidFrameBottomThreatDefecit, ["text"] = KLHTM_RaidFrameBottomThreatDefecitText, ["width"] = 40, }, ["targ"] = { ["frame"] = KLHTM_RaidFrameBottomMasterTarget, ["text"] = KLHTM_RaidFrameBottomMasterTargetText, --["width"] = 50, -- should take up whatever remaining space there is }, }, }; for x = 1 , Max_Rows do gui.raid.rows[x] = { ["frame"] = getglobal("KLHTM_RaidFrameRow" .. x), ["name"] = { ["frame"] = getglobal("KLHTM_RaidFrameRow" .. x .. "Name"), ["text"] = getglobal("KLHTM_RaidFrameRow" .. x .. "NameText"), }, ["threat"] = { ["frame"] = getglobal("KLHTM_RaidFrameRow" .. x .. "Threat"), ["text"] = getglobal("KLHTM_RaidFrameRow" .. x .. "ThreatText"), }, ["pc"] = { ["frame"] = getglobal("KLHTM_RaidFrameRow" .. x .. "PercentThreat"), ["text"] = getglobal("KLHTM_RaidFrameRow" .. x .. "PercentThreatText"), }, ["bar"] = getglobal("KLHTM_RaidFrameRow" .. x .. "Bar"), }; end end ------------------------------------------------------------------------------ -- Applies Gui component properties that are not specified in the XML ------------------------------------------------------------------------------ function KLHTM_SetupRaidGui() -- headers for index, header in gui.raid.head do header.text:SetText(mod.string.get("gui", "raid", "head", index)); header.frame:SetHeight(heights.header); KLHTM_AddOutline(header.text); KLHTM_LocaliseStringWidth(header); for _, row in gui.raid.rows do row[index].text:SetTextColor(header.colour.r, header.colour.g, header.colour.b); row[index].frame:SetHeight(heights.data); KLHTM_AddOutline(row[index].text); end end -- rows for _, row in gui.raid.rows do row.frame:SetHeight(heights.data); end -- botton bar gui.raid.bottom.frame:SetHeight(heights.data); gui.raid.bottom.tdef.frame:SetHeight(heights.data); gui.raid.bottom.targ.frame:SetHeight(heights.data); end ------------------------------------------------------------------------------ -- Sets the default options for displaying the main window and title bar strings -- when the raid view is selected. ------------------------------------------------------------------------------ function KLHTM_SetDefaultRaidOptions() options.raid = { -- column visibility ["columnVis"] = { ["name"] = true, ["threat"] = true, ["pc"] = true, }, -- title bar string visibility ["stringVis"] = { ["rank"] = false, ["pc"] = false, ["tdef"] = false, }, -- max number of rows to show ["rows"] = 10, -- if true, rows with 0 threat are not shown ["hideZeroRows"] = true, -- if true, the raid window will shrink if there are fewer data rows -- than the specified in ["rows"]. Otherwise empty rows will be shown. ["resize"] = false, -- if true, numbers 10,000 or greater are abbreviated with "k" ["abbreviate"] = false, -- if true, a virtual player "aggro gain" is shown ["showAggroGain"] = true, -- if true, the bottom bar will not be shown ["hideBottomBar"] = false, }; end ------------------------------------------------------------------------------ -- Updates the visibility of columns the raid table and the bottom bar. The -- contents are not rendered here. The frame width is stored in sizes.self.x. -- Should be called: -- -- a) when the column visibility changes -- b) when the number of rows to be drawn changes ------------------------------------------------------------------------------ function KLHTM_UpdateRaidFrame() sizes.raid.x = 0; for column, header in gui.raid.head do -- header if (header.vis()) then header.frame:SetWidth(header.width); sizes.raid.x = sizes.raid.x + header.width; header.frame:Show(); else header.frame:Hide(); header.frame:SetWidth(0.1); end -- rows for index, row in gui.raid.rows do if (header.vis()) then row[column].frame:SetWidth(header.width); row[column].frame:Show(); else row[column].frame:Hide(); row[column].frame:SetWidth(0.1); end end end for _, row in gui.raid.rows do row.frame:SetWidth(sizes.raid.x); end -- bottom bar gui.raid.bottom.tdef.frame:SetWidth(gui.raid.bottom.tdef.width); -- do we need this now that we have dual anchors? gui.raid.bottom.targ.text:SetWidth(gui.raid.bottom.targ.frame:GetWidth()); if (options.raid.hideBottomBar) then gui.raid.bottom.frame:Hide(); else gui.raid.bottom.frame:Show(); end end ------------------------------------------------------------------------------ -- Draws the minimised title bar strings present in the raid view. ------------------------------------------------------------------------------ function KLHTM_DrawRaidStrings(raidData, playerCount, threat100) -- update title bar strings local userThreat = mod.table.raiddata[UnitName("player")]; if userThreat == nil then userThreat = 0 end -- threat defecit (todo: colours?) local defecit = threat100 - userThreat; if (options.raid.abbreviate) then defecit = KLHTM_Abbreviate(defecit); end -- threat rank local userRank = 1; for _, data in raidData do if (data.threat > userThreat) then userRank = userRank + 1; end end if (threat100 == 0) then gui.title.string.tdef.text:SetText("0"); gui.title.string.pc.text:SetText("0%"); gui.title.string.rank.text:SetText("-/" .. playerCount); else gui.title.string.tdef.text:SetText(defecit); gui.title.string.pc.text:SetText(math.floor(userThreat * 100 / threat100 + 0.5) .. "%"); gui.title.string.rank.text:SetText(userRank .. "/" .. playerCount); end end ------------------------------------------------------------------------------ -- Draws raid the bottom bar strings -- -- [data] - the sorted threat data -- [threat100] - ?? -- help i am broken. ------------------------------------------------------------------------------ function KLHTM_DrawRaidBottom(data, threat100, playerCount, userThreat) -- master target if (mod.boss.mastertarget ~= nil) then gui.raid.bottom.targ.text:SetText(mod.boss.mastertarget); else gui.raid.bottom.targ.text:SetText(""); end -- new threat defecit ... maybe... if (false) then if ((mod.boss.mastertarget ~= nil) and (mod.boss.mttruetarget ~= nil) and (mod.tables.raiddata[mod.boss.mttruetarget] ~= nil)) then -- there is an active, valid master target and targettarget if (mod.boss.mttruetarget == UnitName("player")) then -- we are the MT. either someone above us, or below us end end end -- threat defecit. Several options here. (a) we are MT, show distance to no2. -- (b) we are dps, show defecit from MT \ aggro gain. (c) all zero. -- How do we know what threat100 is referring to? local defecit = threat100 - userThreat; if (defecit == 0) then defecit = ""; elseif (options.raid.abbreviate) then defecit = KLHTM_Abbreviate(defecit); end gui.raid.bottom.tdef.text:SetText(defecit); end -- used by GetRaidData(). Defined at the class level to reduce memory use. local GetRaidData_data; ------------------------------------------------------------------------------ -- Makes a copy of the raid threat data from KLHTM_RaidData for use by -- KLHTM_DrawRaidFrame and performs some processing. -- -- returns: -- [data] - the sorted threat data (with zero-pruning only), -- [playerCount] - the number of preporting players (virtual and real), -- [threat100] - the reference value for %max threat calculations ------------------------------------------------------------------------------ function KLHTM_GetRaidData() local data = GetRaidData_data; if (data == nil) then data = {}; -- 50: 40 players + room for "virtual players" eg aggro gain for x = 1, 50 do data[x] = {["name"] = "", ["threat"] = 0, ["pc"] = 0,}; end GetRaidData_data = data end -- check for aggro gain if (options.raid.showAggroGain) then mod.boss.updateaggrogain() else mod.table.raiddata[mod.string.get("misc", "aggrogain")] = nil; end -- copy data over local rowCount = 0; -- the number of rows to be rendered local playerCount = 0; -- the number of players found for player, threat in mod.table.raiddata do playerCount = playerCount + 1; -- omit "zero rows" if necessary if (not(options.raid.hideZeroRows and (threat == 0))) then rowCount = rowCount + 1; data[rowCount].name = player; data[rowCount].threat = threat; end end table.setn(data, rowCount); table.sort(data, function(a,b) return a.threat > b.threat; end); -- determine the %threat reference value -- this part is highly suspect. Need the updated boss module, then a recode -- of the threat100 and related calculations. local threat100; local aggro; if (rowCount == 0) then -- there is no data availible threat100 = 0; else if (options.raid.showAggroGain == false) then -- ignore aggro gain. Wrong! threat100 = data[1].threat; else -- use MT if possible, or targettarget if (mod.boss.mastertarget == nil) then aggro = mod.table.raiddata[mod.string.get("misc", "aggrogain")]; else aggro = mod.table.raiddata[mod.boss.mttruetarget]; end -- ignore unreasonable threat100 values if ((aggro == nil) or (aggro * Max_Aggro_Ratio < data[1].threat)) then threat100 = data[1].threat; else threat100 = aggro; end end end return data, playerCount, threat100; end ------------------------------------------------------------------------------ -- Updates the raid threat window (if maximised) and title bar raid strings. -- Updates the raid threat data. A copy of KLHTM_RaidData is made, and processed. -- If minimised, KLHTM_DrawRaidStrings is called. Otherwise all the strings in -- the raid frame are redrawn. ------------------------------------------------------------------------------ function KLHTM_DrawRaidFrame() local data, playerCount, threat100 = KLHTM_GetRaidData(); if (state.min) then KLHTM_DrawRaidStrings(data, playerCount, threat100); return; end local userThreat = mod.table.raiddata[UnitName("player")]; if (userThreat == nil) then -- seems to happen at initialisation userThreat = 0; end -- make sure the user is visible (user may not show up with 0 threat) if (table.getn(data) > options.raid.rows) then if (userThreat < data[options.raid.rows].threat) then data[options.raid.rows].name = UnitName("player"); data[options.raid.rows].threat = userThreat; end -- ignore rows that won't be drawn from here on table.setn(data, options.raid.rows); end -- calculate % threat for x = 1, table.getn(data) do if (threat100 == 0) then data[x].pc = 0; else data[x].pc = math.floor(data[x].threat / threat100 * 100); end end -- bar reference width (max threat) local barRef; if ((data[1] ~= nil) and (data[1].threat ~= 0)) then barRef = sizes.raid.x / data[1].threat; end -- render the rows for row = 1, table.getn(data) do for index, value in data[row] do if (options.raid.abbreviate) then gui.raid.rows[row][index].text:SetText(KLHTM_Abbreviate(value)); else gui.raid.rows[row][index].text:SetText(value); end end -- bars if ((barRef == nil) or (data[row].threat == 0)) then gui.raid.rows[row].bar:Hide(); else local colours = KLHTM_GetClassColours(data[row].name); gui.raid.rows[row].bar:SetWidth(data[row].threat * barRef); gui.raid.rows[row].bar:SetVertexColor(colours.r, colours.g, colours.b); gui.raid.rows[row].bar:Show(); end gui.raid.rows[row].frame:Show(); end -- bottom bar if (options.raid.hideBottomBar ~= true) then KLHTM_DrawRaidBottom(data, threat100, playerCount, userThreat); end -- hide empty rows for row = table.getn(data) + 1, Max_Rows do gui.raid.rows[row].frame:Hide(); end -- resize frame if (options.raid.resize) then sizes.raid.y = heights.header + heights.data * table.getn(data); else sizes.raid.y = heights.header + heights.data * options.raid.rows; end if (options.raid.hideBottomBar ~= true) then sizes.raid.y = sizes.raid.y + heights.data + 2; end -- 14: (5 + 1) * 2 for the insets plus a gap. -- Then 2 each for the title-header, header-data and (optional) data-bottom gaps. sizes.frame.y = sizes.raid.y + sizes.title.y + 14; gui.frame:SetHeight(sizes.frame.y); end -- used to unlocalise class names local _classes = {"warrior", "druid", "priest", "shaman", "mage", "warlock", "rogue", "hunter", "paladin"} ------------------------------------------------------------------------------ -- Returns the class colours of the specified player -- -- [return]: A table with .r, .g, .b values from 0 to 1. ------------------------------------------------------------------------------ function KLHTM_GetClassColours(playerName) local className; -- apply pre-defined colours if (playerName == UnitName("player")) then return {["r"] = 1.0, ["g"] = 0, ["b"] = 0}; end if (playerName == mod.string.get("misc", "aggrogain")) then return {["r"] = 0, ["g"] = 0, ["b"] = 1.0}; end className = mod.table.raidclasses[playerName]; if (className == nil) then -- the player's class isnt stored in our table, rebuild it. if mod.out.checktrace("info", me, "raidcolours") then mod.out.printtrace(string.format("Updating class entry for %s.", playerName)); end mod.table.redoraidclasses(); className = mod.table.raidclasses[playerName]; end if (className == nil) then -- class name could not be found. Seems to be due to people who have left -- the raid group? if mod.out.checktrace("warning", me, "raidcolours") then mod.out.printtrace(string.format("Updating class entry for %s.", playerName)) end mod.table.raidclasses[playerName] = ""; className = ""; end className = string.upper(className) if (className == "") then return {["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.5}; else return RAID_CLASS_COLORS[className]; end end ------------------------------------------------------------------------------ -- Called when the user mouses over a raid string ------------------------------------------------------------------------------ function KLHTM_RaidString_OnEnter(name) if (name == "targ") then if (mod.boss.mastertarget ~= nil) then local text = string.format(mod.string.get("gui", "raid", "stringlong", name), mod.boss.mastertarget); text = string.format("|cffffc900%s\n|r%s", mod.string.get("gui", "raid", "stringshort", name), text); GameTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT", -100, 0); GameTooltip:SetText(text, 1.0, 1.0, 1.0, 1, 1); GameTooltip:Show(); gui.raid.bottom[name].text:SetTextColor(1.0, 0.82, 0); end end -- threat defecit text disabled for the moment end function KLHTM_RaidString_OnLeave(name) gui.raid.bottom[name].text:SetTextColor(1.0, 1.0, 1.0); GameTooltip:Hide(); end