diff --git a/NamePlatesThreat.lua b/NamePlatesThreat.lua index 63ddcf0..2f9bf9f 100644 --- a/NamePlatesThreat.lua +++ b/NamePlatesThreat.lua @@ -9,7 +9,7 @@ local function initVariables(oldAcct) -- only the variables below are used by th newAcct["neutralsColor"] = {r= 0, g=112, b=222} -- blue neutral not in group fight newAcct["enablePlayers"] = true -- also color nameplates for player characters newAcct["pvPlayerColor"] = {r=245, g=140, b=186} -- pink player not in group fight - newAcct["gradientColor"] = true -- update nameplate color gradients (some CPU usage) + newAcct["gradientColor"] = false -- update nameplate color gradients (some CPU usage) newAcct["gradientPrSec"] = 5 -- update color gradients this many times per second newAcct["youTankCombat"] = true -- unique colors in combat instead of colors above newAcct["youTank7color"] = {r=255, g= 0, b= 0} -- red healers tanking by threat @@ -57,6 +57,7 @@ NPT.thisUpdate = 0 NPT.offTanks = {} NPT.nonTanks = {} NPT.offHeals = {} +NPT.nonHeals = {} NPT.threat = {} local NPTframe = CreateFrame("Frame", nil, NPT) -- options panel for tweaking the addon @@ -65,7 +66,11 @@ NPTframe.lastSwatch = nil local function resetFrame(plate) if plate.UnitFrame.unit and UnitCanAttack("player", plate.UnitFrame.unit) then if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then - plate.UnitFrame.healthBar.border:SetVertexColor(0, 0, 0, 1) + if UnitIsUnit(plate.UnitFrame.unit, "target") then + plate.UnitFrame.healthBar.border:SetVertexColor(1, 1, 1, 1) + else + plate.UnitFrame.healthBar.border:SetVertexColor(0, 0, 0, 1) + end end plate.UnitFrame.healthBar:SetStatusBarColor(plate.UnitFrame.healthBar.r, plate.UnitFrame.healthBar.g, plate.UnitFrame.healthBar.b, plate.UnitFrame.healthBar.a) end @@ -139,61 +144,77 @@ local function getGroupRoles() local collectedTanks = {} local collectedOther = {} local collectedHeals = {} - local collectedPlayer, unitPrefix, unit, i, unitRole = 0 - local isInRaid = IsInRaid() + local collectedPlayer, unitPrefix, unit, i, unitRole, raidRank = "NONE" - if GetNumGroupMembers() > 0 then - if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then - collectedPlayer = GetSpecializationRole(GetSpecialization()) - end --- mikfhan: WoW Classic has no unit spec but talent panel has a group role up top - if collectedPlayer ~= "TANK" then - collectedPlayer = UnitGroupRolesAssigned("player") - end - end - if collectedPlayer ~= "TANK" and collectedPlayer ~= "HEALER" then - collectedPlayer = "DAMAGER" - end - if UnitExists("pet") then - if NPTacct.showPetThreat or collectedPlayer == "TANK" then - table.insert(collectedTanks, "pet") - else - table.insert(collectedOther, "pet") - end - end - if isInRaid then + if IsInRaid() then unitPrefix = "raid" else unitPrefix = "party" end - - for i = 1, GetNumGroupMembers() do + for i = 1, MAX_RAID_MEMBERS do unit = unitPrefix .. i - if not UnitIsUnit(unit, "player") then + unitRole = "NONE" + if unitPrefix == "party" and i >= GetNumGroupMembers() then + break + elseif UnitExists(unit) then unitRole = UnitGroupRolesAssigned(unit) - if isInRaid and unitRole ~= "TANK" then - _, _, _, _, _, _, _, _, _, unitRole = GetRaidRosterInfo(i) - if unitRole == "MAINTANK" then + if unitRole ~= "TANK" and unitRole ~= "HEALER" then + if UnitIsGroupLeader(unit) then + raidRank = 3 + elseif unitPrefix == "raid" then + _, raidRank, _, _, _, _, _, _, _, unitRole = GetRaidRosterInfo(i) + else + raidRank = 0 + end + if unitRole == "MAINTANK" or unitRole == "MAINASSIST" or raidRank > 0 then unitRole = "TANK" end end - if unitRole == "TANK" then - table.insert(collectedTanks, unit) - elseif unitRole == "HEALER" then - table.insert(collectedHeals, unit) + if UnitIsUnit(unit, "player") then + collectedPlayer = unitRole else - table.insert(collectedOther, unit) - end - unit = unitPrefix .. "pet" .. i - if UnitExists(unit) then - if NPTacct.showPetThreat or unitRole == "TANK" then + if unitRole == "TANK" then table.insert(collectedTanks, unit) + elseif unitRole == "HEALER" then + table.insert(collectedHeals, unit) else table.insert(collectedOther, unit) end + unit = unitPrefix .. "pet" .. i + if UnitExists(unit) then + if NPTacct.showPetThreat or unitRole == "TANK" then + table.insert(collectedTanks, unit) + else + table.insert(collectedOther, unit) + end + end end end end +-- mikfhan: Outside raid groups the player is not counted amongst the party members + if GetNumGroupMembers() > 0 then + if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then +-- mikfhan: Retail will use player spec regardless of the group role chosen earlier + collectedPlayer = GetSpecializationRole(GetSpecialization()) + elseif unitPrefix == "party" then +-- mikfhan: Wrath Classic has no unit spec but talent panel has a party role up top + collectedPlayer = UnitGroupRolesAssigned("player") + if UnitIsGroupLeader("player") and collectedPlayer ~= "HEALER" then +-- mikfhan: Classic Era using party leader since roles did not even exist back then + collectedPlayer = "TANK" + end + end + end + if collectedPlayer ~= "TANK" and collectedPlayer ~= "HEALER" then + collectedPlayer = "DAMAGER" + end + if UnitExists("pet") then + if NPTacct.showPetThreat or collectedPlayer == "TANK" then + table.insert(collectedTanks, "pet") + else + table.insert(collectedOther, "pet") + end + end return collectedTanks, collectedPlayer, collectedOther, collectedHeals end @@ -627,6 +648,8 @@ if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then NPT:RegisterEvent("PLAYER_SOFT_INTERACT_CHANGED") NPT:RegisterEvent("PLAYER_SOFT_FRIEND_CHANGED") NPT:RegisterEvent("PLAYER_SOFT_ENEMY_CHANGED") +elseif WOW_PROJECT_ID == WOW_PROJECT_CLASSIC then + NPT:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") end NPT:RegisterEvent("NAME_PLATE_UNIT_ADDED") NPT:RegisterEvent("PLAYER_TARGET_CHANGED") @@ -650,6 +673,7 @@ NPT:SetScript("OnEvent", function(self, event, arg1) resetFrame(plate) end NPT.threat = {} + NPT.nonHeals = {} NPT.offTanks, NPT.playerRole, NPT.nonTanks, NPT.offHeals = getGroupRoles() C_Timer.NewTimer(0.1, callback) elseif event == "PLAYER_SOFT_INTERACT_CHANGED" or event == "PLAYER_SOFT_FRIEND_CHANGED" or @@ -668,6 +692,60 @@ NPT:SetScript("OnEvent", function(self, event, arg1) if plate and plate.UnitFrame then resetFrame(plate) end + elseif event == "COMBAT_LOG_EVENT_UNFILTERED" and GetNumGroupMembers() > 0 then + local timestamp, subevent, _, sourceGUID, _, sourceFlags, _, destGUID = CombatLogGetCurrentEventInfo() + local COMBATLOG_FILTER_GROUPHEAL = bit.bor( + COMBATLOG_OBJECT_AFFILIATION_MINE + , COMBATLOG_OBJECT_AFFILIATION_PARTY + , COMBATLOG_OBJECT_AFFILIATION_RAID + , COMBATLOG_OBJECT_REACTION_FRIENDLY + , COMBATLOG_OBJECT_CONTROL_PLAYER + , COMBATLOG_OBJECT_TYPE_PLAYER + ) + if CombatLog_Object_IsA(sourceFlags, COMBATLOG_FILTER_GROUPHEAL) then + --print(timestamp .. " " .. sourceGUID .. " " .. format("0x%X", sourceFlags)) + if subevent == "SPELL_HEAL" or subevent == "SPELL_PERIODIC_HEAL" then + if sourceGUID ~= destGUID and string.sub(destGUID, 1, 6) == "Player" then + NPT.nonHeals[sourceGUID] = timestamp + if sourceGUID == UnitGUID("player") then + if NPT.playerRole == "DAMAGER" then + --print("player is now HEALER") + NPT.playerRole = "HEALER" + end + else + local key, unit + for key, unit in pairs(NPT.nonTanks) do + if sourceGUID == UnitGUID(unit) then + --print(unit .. " is now HEALER") + table.insert(NPT.offHeals, unit) + table.remove(NPT.nonTanks, key) + break + end + end + end + end + elseif subevent == "SPELL_DAMAGE" or subevent == "SPELL_PERIODIC_DAMAGE" then + if NPT.nonHeals[sourceGUID] and NPT.nonHeals[sourceGUID] < timestamp - 60 then + NPT.nonHeals[sourceGUID] = nil + if sourceGUID == UnitGUID("player") then + if NPT.playerRole == "HEALER" then + --print("player is now DAMAGER") + NPT.playerRole = "DAMAGER" + end + else + local key, unit + for key, unit in pairs(NPT.offHeals) do + if sourceGUID == UnitGUID(unit) then + --print(unit .. " is now DAMAGER") + table.insert(NPT.nonTanks, unit) + table.remove(NPT.offHeals, key) + break + end + end + end + end + end + end end end) NPT:SetScript("OnUpdate", function(self, elapsed) diff --git a/NamePlatesThreat.toc b/NamePlatesThreat.toc index 478b634..c64a2d8 100644 --- a/NamePlatesThreat.toc +++ b/NamePlatesThreat.toc @@ -1,7 +1,7 @@ -## Interface: 100002 +## Interface: 100005 ## Title: NamePlatesThreat ## Notes: Colors the nameplate healthbar according to threat. -## Version: 3.4 +## Version: 3.5 ## Author: int3ro, exochron & mikfhan ## SavedVariables: NPTacct NamePlatesThreat.lua diff --git a/NamePlatesThreat_TBC.toc b/NamePlatesThreat_TBC.toc index 4c2811e..3c11c97 100644 --- a/NamePlatesThreat_TBC.toc +++ b/NamePlatesThreat_TBC.toc @@ -1,7 +1,7 @@ ## Interface: 20504 ## Title: NamePlatesThreat ## Notes: Colors the nameplate healthbar according to threat. -## Version: 3.4 +## Version: 3.5 ## Author: int3ro, exochron & mikfhan ## SavedVariables: NPTacct NamePlatesThreat.lua diff --git a/NamePlatesThreat_Vanilla.toc b/NamePlatesThreat_Vanilla.toc index 9e0b6e5..1b0718f 100644 --- a/NamePlatesThreat_Vanilla.toc +++ b/NamePlatesThreat_Vanilla.toc @@ -1,7 +1,7 @@ ## Interface: 11403 ## Title: NamePlatesThreat ## Notes: Colors the nameplate healthbar according to threat. -## Version: 3.4 +## Version: 3.5 ## Author: int3ro, exochron & mikfhan ## SavedVariables: NPTacct NamePlatesThreat.lua diff --git a/NamePlatesThreat_Wrath.toc b/NamePlatesThreat_Wrath.toc index 0da4910..d67d709 100644 --- a/NamePlatesThreat_Wrath.toc +++ b/NamePlatesThreat_Wrath.toc @@ -1,7 +1,7 @@ -## Interface: 30400 +## Interface: 30401 ## Title: NamePlatesThreat ## Notes: Colors the nameplate healthbar according to threat. -## Version: 3.4 +## Version: 3.5 ## Author: int3ro, exochron & mikfhan ## SavedVariables: NPTacct NamePlatesThreat.lua diff --git a/README.md b/README.md index 3c70001..c00d8fd 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,56 @@ # Blizzard Nameplates - Threat Extremely lightweight addon which colors the default blizzard nameplates according to threat. +See general usage in **bold** below. Settings are saved in your WoW \_retail\_ (or similar) subfolder: +WTF\Account\\\\SavedVariables\NamePlatesThreat.lua +You can tweak settings/colors below from Escape menu > Interface/Options > AddOns > NamePlatesThreat -General advice is everyone should attack red nameplates, then tanks should attack orange before yellow while others attack green before gray nameplates. +**Everyone should attack red, then tanks attack orange before yellow, others attack green before gray.** -You can tweak a few settings and colors below from Escape menu > Interface > AddOns > NamePlatesThreat: +"Color Non-Friendly Nameplates" addon option you can quickly disable if you want Blizzard colors always. +"Color Nameplate Border Only" (retail only) ensures healthbar inside still uses original Blizzard colors. -Colors Out of Combat (2.4-release): +The addon decides player roles via Set Role right-clicking their player portrait, with some exceptions: +Retail treats you purely by your talent spec, regardless of group role (you can still Set Role on others). +Wrath lets you Set Role default via the round icon top right of your talent panel (or Set Role on others). +Classic Era has no roles; leader or raid maintank/assist are tank, others healing within last 60 seconds. +"Color Group Pets as Tanks" is an addon option that treats all pets as a tank even if their player is not. -PINK: Player is Out of Combat (only if PvP colors enabled and no target) -VIOLET: Hostile Out of Combat (or gray if fighting totems/NPCs/others) -BLUE: Neutral Out of Combat (or gray if fighting totems/NPCs/others) +"Color out of Dungeons" and "Color Out of Combat" if disabled use Blizzard colors outside those situations. +Out of combat topmost three colors below indicate if enemy is a player, or hostile/neutral NPC reputation. +"Color Player Characters" for PvP enemies depending on role they are targeting (never based on NPC threat). -Playing as Tank spec (2.4-release): +**Colors Out of Combat (2.7-release and newer):** +VIOLET: Hostile Out of Combat (turns blue if fighting totems/NPCs/others) +BLUE: Neutral Out of Combat (or hostiles fighting totems/NPCs/others) +PINK: Player is Out of Combat (only if PvP colors enabled and no target) +**Playing as Tank role (2.7-release and newer):** RED: Healers have High Threat (emergency! get on it asap) ORANGE: Damage has High Threat (not good, defend your dps) YELLOW: Tanks have Low Threat (offtanks struggle, help them) -GRAY: You have the Low Threat (tanking, but not perfect) +GRAY: You have the Low Threat (or offtanks have high threat) GREEN: You have the High Threat (perfect tank, ignore these) -Damage or Heal spec (2.4-release): - +**Damage or Heal role (2.7-release and newer):** RED: Healers have High Threat (emergency! get on it asap) ORANGE: You have the High Threat (disengage! find a tank) YELLOW: You have the Low Threat (hold attacks, wait for tank) GRAY: Damage has High Threat (okay to attack, but not much) GREEN: Tanks have High Threat (fire at will, tanks are on it) -Settings are saved in your World of Warcraft _retail_ subfolder: -WTF\Account\\SavedVariables\NamePlatesThreat.lua - -Anyone from TidyPlates who prefer old colors before 1.8-release can find them in Issue #4 third comment, which has a SavedVariables file you can overwrite (remember to logout your characters while doing so). \ No newline at end of file +"Color Nameplates by Threat" you can disable if you only wish to color enemies by their target instead of threat, it still uses the colors below. +The role colors just below lets you customize colors when you have the tank role, you can disable checkbox above again after tweaking the colors. +Notice there is both a color for "you" and "tanks" even when you have a tank role, this is so you know if YOU have aggro or an offtank buddy does. +"Unique Colors In-Between" lets you pick custom colors when someone is using taunt skills, if disabled addon just reuses the colors from above. + +"Unique Colors as Non-Tank Role" lets you pick custom colors if you are a damager/healer role, otherwise addon reuses the color to the left of it. +Notice there is a color for "you" but also healers and damage, this is so you know if YOU have aggro or if another damage/healer buddy has aggro. +Note also how some role colors mention "you have the low threat" or "tanks have low threat" etc, this is when taunt skills are used to keep aggro. +Note also how healers have a different color from damage; healers are very important so ALL players should help tanks defend them. + +"Color Gradient Updates Per Second" is an advanced feature; x times per second it fades the color between high and low as threat percent changes. +Example if you are tank with high threat (green by default) then as threat is dropping toward only 100% it will fade toward the low color (gray). +World of Warcraft generally treats anyone with 100% threat or more as "having aggro" for that enemy, and only taunt skills can override this. +It may be crucial information as a tank to know if you are losing threat to one of the other players in the group, so they should cool off a bit. +This option is advanced because color fading makes it harder to see exactly who has aggro when close to the 100% low threat target switchover. +Having this information for hard-hitting bosses may still be preferred by some tanks. \ No newline at end of file