Add Details_TargetCaller plugin

This commit is contained in:
andrew6180
2024-05-26 15:06:32 -07:00
parent a40b4d098e
commit ccffbc329f
14 changed files with 572 additions and 3 deletions
+3 -3
View File
@@ -3502,13 +3502,13 @@ do
{"DETAILS_PLUGIN_ENCOUNTER_DETAILS", "Details_EncounterDetails", "Encounter Breakdown", "Show detailed information about a boss encounter. Also provide damage per phase, graphic charts, easy weakauras creation.", ""},
{"DETAILS_PLUGIN_RAIDCHECK", "Details_RaidCheck", "Raid Check", "Show talents and item level for all members in your group, also shows food and flask state.", ""},
{"DETAILS_PLUGIN_STREAM_OVERLAY", "Details_Streamer", "Action Tracker", "Show which spells you are casting, viewers can see what are you doing and follow your steps.", ""},
}
}
local allExistentRaidPlugins = {
{"DETAILS_PLUGIN_COMPARETWO_WINDOW", "Details_Compare2", "Compare 2.0", "Replace the Compare tab in the player breakdown window.", ""},
{"DETAILS_PLUGIN_TARGET_CALLER", "Details_TargetCaller", "Target Caller", "Show raid damage done to an entity since you targetted it.", "https://www.curseforge.com/wow/addons/details-target-caller-plugin"},
{"DETAILS_PLUGIN_TARGET_CALLER", "Details_TargetCaller", "racks your current target and show in the window who is doing damage to it. The amount of damage shown is the amount dealt since you selected the target.", ""},
{"DETAILS_PLUGIN_TINY_THREAT", "Details_TinyThreat", "Tiny Threat", "Threat meter plugin, show threat for group members in the window. Select it from the Plugin menu in the Orange Cogwheel.", ""},
{"DETAILS_PLUGIN_VANGUARD", "Details_Vanguard", "Vanguard", "Show the health and debuffs for tanks in your group.", ""}
--{"DETAILS_PLUGIN_VANGUARD", "Details_Vanguard", "Vanguard", "Show the health and debuffs for tanks in your group.", ""}
}
local installedToolbarPlugins = {}
@@ -0,0 +1,426 @@
do
local L = LibStub ("AceLocale-3.0"):GetLocale ("DetailsTargetCaller")
local Details = Details
if (not Details) then
print (L["STRING_INSTALL_ERROR1"])
return
end
local _
--> minimal details version required to run this plugin
local MINIMAL_DETAILS_VERSION_REQUIRED = 75
local DETAILS_ATTRIBUTE_DAMAGE = DETAILS_ATTRIBUTE_DAMAGE
local TCALLER_VERSION = "v1.2.3"
--> keeps the information which details window the plugin is being shown
local attachedInstance
--> create a plugin object
local targetCaller = Details:NewPluginObject ("Details_TargetCaller")
--> just localizing here the plugin's main frame
local frame = targetCaller.Frame
--> set the description
targetCaller:SetPluginDescription (L ["STRING_PLUGIN_DESC"])
--> get the framework object
local framework = targetCaller:GetFramework()
local rosterTable = {} --> indexed table with players in the raid
local rosterHashTable = {} --> a hash table with [playername] = true, just to know we already added the player inside the indexed table
local barsTable = {} --> holds the bars we created
local currentTarget = "" --> who we are targeting now
local currentCombat = targetCaller:GetCurrentCombat() --> the reference of the current combat on Details!
local textformat = targetCaller:GetCurrentToKFunction() --> the current number format function used by Details!
targetCaller.Bars = barsTable --> adding this as a member, so we can call UpdatePluginBarsConfig()
--> simple sort function
local sort_by_total = function (actor1, actor2)
return actor1.total > actor2.total
end
local sort_by_overall = function (actor1, actor2)
return actor1.overall > actor2.overall
end
function targetCaller.UpdateWindowBars()
--> create more bars if needed
local totalbars = attachedInstance.rows_fit_in_window
if (totalbars > #barsTable) then
for i = #barsTable+1, totalbars, 1 do
barsTable [i] = framework:CreateBar (frame)
end
end
--> update SetPoint() and import row_info from the attached instance into our addon object
--> row_info holds all config used by the bars
targetCaller:UpdatePluginBarsConfig()
--> set our .Frame width and height to be the same as the instance
targetCaller:AttachToInstance()
--> with row_info copied, we update the bars here
local row_info = targetCaller.row_info
for _, bar in ipairs (barsTable) do
bar.height = row_info.height
bar.texture = row_info.texture
bar.fontsize = row_info.font_size
bar.fontface = row_info.font_face
bar.fontcolor = row_info.fixed_text_color
bar.shadow = row_info.textL_outline
end
--> and also update our ToK (text format number function)
textformat = targetCaller:GetCurrentToKFunction()
end
--> hide all bars
function targetCaller.ClearBars()
for _, bar in ipairs (barsTable) do
if (bar:IsShown()) then
bar:Hide()
end
end
end
--> update how much damage players dealt to our current target
function targetCaller.UpdateTotal (actor)
local damage_actor = currentCombat (DETAILS_ATTRIBUTE_DAMAGE, actor.name)
if (damage_actor) then
local total = damage_actor.targets [currentTarget]
actor.total = (total or 0) - actor.breakpoint
end
end
--> when we changed the target, iterate amoung all players and save which are the current damage dealt to the target
function targetCaller.SetBreakPoints (actor)
if (actor) then
--> this part runs when there is an update on the group roster
actor.total = 0
local damage_actor = currentCombat (DETAILS_ATTRIBUTE_DAMAGE, actor.name)
if (damage_actor) then
actor.breakpoint = damage_actor.targets [currentTarget] or 0
end
else
--> this runs when we change our target
for _, actor in ipairs (rosterTable) do
actor.overall = actor.overall + actor.total
actor.total = 0
local damage_actor = currentCombat (DETAILS_ATTRIBUTE_DAMAGE, actor.name)
if (damage_actor) then
--> gets the current damage by this player done to our main target
actor.breakpoint = damage_actor.targets [currentTarget] or 0
end
end
end
end
function targetCaller.UpdateRoster()
local unitType = IsInRaid() and "raid" or "party"
--> update the hash table (this is in case if we need to get a single actor, so we do rosterTable [rosterHashTable [name]])
for index, actor in ipairs (rosterTable) do
rosterHashTable [actor.name] = index
end
--> update raid members
for i = 1, GetNumGroupMembers() do
local unit = "" .. unitType .. i
local name = GetUnitName (unit, true)
if (not rosterHashTable [name] and not UnitIsUnit (unit, "player")) then
local actor = {}
actor.name = name
actor.displayName = targetCaller:GetOnlyName (name) or name or ""
actor.class = select (2, UnitClass (unit)) or "PRIEST"
actor.total = 0
actor.overall = 0
actor.breakpoint = 0
tinsert (rosterTable, actor)
rosterHashTable [name] = #rosterTable
targetCaller.SetBreakPoints (actor)
end
end
end
--> start loop with basic stuff, reset roster, register needed events, start ticker.
function targetCaller.StartLoop()
--> clear the delay var
targetCaller.StartDelay = nil
--> start a new combat
wipe (rosterTable)
wipe (rosterHashTable)
targetCaller.UpdateWindowBars()
currentTarget = GetUnitName ("target", true)
currentCombat = targetCaller:GetCurrentCombat()
targetCaller:RegisterEvent ("GROUP_ROSTER_UPDATE")
targetCaller:RegisterEvent ("PLAYER_TARGET_CHANGED")
targetCaller.UpdateRoster()
--targetCaller.ticker = C_Timer.NewTicker (0.2, targetCaller.LoopTicker)
--use details! update speed
targetCaller.ticker = C_Timer.NewTicker (Details.update_speed, targetCaller.LoopTicker)
end
--> target changed, time to save new breakpoints, also update the title on the instance
function targetCaller.TargetChanged()
currentTarget = GetUnitName ("target", true) or ""
targetCaller.ClearBars()
targetCaller.SetBreakPoints()
if (currentTarget ~= "") then
attachedInstance:SetTitleBarText (L ["STRING_PLUGIN_NAME"] .. ": " .. targetCaller:GetOnlyName (currentTarget))
else
attachedInstance:SetTitleBarText (L ["STRING_PLUGIN_NAME"] .. ": |cFFFFAA00" .. L["STRING_OVERALL"] .. "|r")
end
end
--> we are using member method .icon to set the icon and the texcoord, so we need to pass a table with the texture and the coords
--> here we have the texture, the coords table we just import from details
local iconTable = {[[Interface\AddOns\Details\images\classes_small]]}
function targetCaller.UpdateOverall()
local top = 0
for _, actor in ipairs (rosterTable) do
if (actor.overall > top) then
top = actor.overall
end
end
table.sort (rosterTable, sort_by_overall)
local classCoords = targetCaller.class_coords --> importing the coords table from Details!
for i = 1, min (#rosterTable, #barsTable) do
local bar, actor = barsTable [i], rosterTable [i]
if (actor.overall >= 1) then
bar.lefttext = actor.displayName
bar.righttext = textformat (_, actor.overall)
--> the framework handles color strings such as non-localized class names and HTML color names.
--> for example bar.color = "HUNTER" or bar.color = "purple" works perfectly fine
--bar.color = actor.class
bar.color = "silver"
iconTable [2] = classCoords [actor.class] --> placing the class coords into index [2]
bar.icon = iconTable
local percent = actor.overall / top * 100
bar.value = percent
bar:Show()
else
bar:Hide()
end
end
end
function targetCaller.LoopTicker()
--> when no target, show overall
if (currentTarget == "") then
return targetCaller.UpdateOverall()
end
--> update to our current target
local top = 0
for _, actor in ipairs (rosterTable) do
targetCaller.UpdateTotal (actor)
if (actor.total > top) then
top = actor.total
end
end
table.sort (rosterTable, sort_by_total)
local classCoords = targetCaller.class_coords --> importing the coords table from Details!
for i = 1, min (#rosterTable, #barsTable) do
local bar, actor = barsTable [i], rosterTable [i]
if (actor.total >= 1) then
bar.lefttext = actor.displayName
bar.righttext = textformat (_, actor.total)
--> the framework handles color strings such as non-localized class names and HTML color names.
--> for example bar.color = "HUNTER" or bar.color = "purple" works perfectly fine
bar.color = actor.class
iconTable [2] = classCoords [actor.class] --> placing the class coords into index [2]
bar.icon = iconTable
--no need to create a new local
--local percent = actor.total / top * 100
bar.value = actor.total / top * 100
bar:Show()
else
bar:Hide()
end
end
end
--> finish the ticker, unregister events, hide bars, wipe roster tables
function targetCaller.EndLoop (isFromDataReset)
if (targetCaller.ticker and not targetCaller.ticker._cancelled) then
targetCaller.ticker:Cancel()
end
if (targetCaller.StartDelay and not targetCaller.StartDelay._cancelled) then
targetCaller.StartDelay:Cancel()
end
targetCaller.ClearBars()
--> update the overall counter
if (currentTarget ~= "" and not isFromDataReset) then
targetCaller.SetBreakPoints()
end
currentTarget = ""
targetCaller:UnregisterEvent ("GROUP_ROSTER_UPDATE")
targetCaller:UnregisterEvent ("PLAYER_TARGET_CHANGED")
--> show the overall when the update is done
if (not isFromDataReset) then
targetCaller.UpdateOverall()
else
--> wipe all if details! got a wipe too
wipe (rosterTable)
wipe (rosterHashTable)
end
end
--> if we start checking the damage on the target
function targetCaller.CheckFor_CanStartRunning()
if (targetCaller:IsInCombat() and targetCaller:InGroup()) then
if (targetCaller.StartDelay) then
return
end
--> delay startloop, sometimes we get a roster event update after the enter combat event
local timer = C_Timer.NewTimer (5, targetCaller.StartLoop)
targetCaller.StartDelay = timer
end
end
--> when receiving an event from details, handle it here
local handle_details_event = function (event, ...)
if (event == "HIDE") then
--> the user closed the window or selected other plugin / mode
targetCaller.EndLoop()
elseif (event == "SHOW") then
--> the plugin beign shown on a window
targetCaller:AttachToInstance()
attachedInstance = targetCaller:GetPluginInstance()
currentCombat = targetCaller:GetCurrentCombat()
targetCaller.UpdateWindowBars()
targetCaller.CheckFor_CanStartRunning()
elseif (event == "COMBAT_PLAYER_ENTER") then
--> details create a new segment
currentCombat = targetCaller:GetCurrentCombat()
targetCaller.CheckFor_CanStartRunning()
elseif (event == "COMBAT_PLAYER_LEAVE") then
--> details finished a segment
targetCaller.EndLoop()
elseif (event == "DETAILS_INSTANCE_ENDRESIZE" or event == "DETAILS_INSTANCE_SIZECHANGED") then
--> size of the window has changed
targetCaller.UpdateWindowBars()
elseif (event == "DETAILS_INSTANCE_STARTSTRETCH" or event == "DETAILS_INSTANCE_ENDSTRETCH") then
--> the window started to be stretched
targetCaller.UpdateWindowBars()
elseif (event == "DETAILS_OPTIONS_MODIFIED") then
--> an option has changed at details options panel
targetCaller.UpdateWindowBars()
elseif (event == "PLUGIN_DISABLED") then
--> plugin has been disabled at the details options panel
targetCaller.EndLoop()
elseif (event == "PLUGIN_ENABLED") then
--> plugin has been enabled at the details options panel
attachedInstance = targetCaller:GetPluginInstance()
currentCombat = targetCaller:GetCurrentCombat()
targetCaller.CheckFor_CanStartRunning()
elseif (event == "GROUP_ONENTER") then
--> the player is now in a group
targetCaller.CheckFor_CanStartRunning()
elseif (event == "GROUP_ONLEAVE") then
--> the player left the group
if (targetCaller.ticker and not targetCaller.ticker._cancelled) then
targetCaller.EndLoop()
end
elseif (event == "DETAILS_DATA_SEGMENTREMOVED") then
--> old segment got deleted by the segment limit
if (targetCaller.ticker and not targetCaller.ticker._cancelled) then
--> there is an update going on, we need to stop
targetCaller.EndLoop (true)
end
elseif (event == "DETAILS_DATA_RESET") then
--> combat data got wiped
if (targetCaller.ticker and not targetCaller.ticker._cancelled) then
--> there is an update going on, we need to stop
targetCaller.EndLoop (true)
end
end
end
function targetCaller:OnEvent (_, event, ...)
if (event == "GROUP_ROSTER_UPDATE") then
targetCaller.UpdateRoster()
elseif (event == "PLAYER_TARGET_CHANGED") then
targetCaller.TargetChanged()
elseif (event == "ADDON_LOADED") then
local AddonName = select (1, ...)
if (AddonName == "Details_TargetCaller") then
--> every plugin must have a OnDetailsEvent function
function targetCaller:OnDetailsEvent (event, ...)
return handle_details_event (event, ...)
end
--> Install: install -> if successful installed; saveddata -> a table saved inside details db, used to save small amount of data like configs
local install, saveddata = Details:InstallPlugin ("RAID", L ["STRING_PLUGIN_NAME"], "Interface\\Icons\\Ability_Warrior_BattleShout", targetCaller, "DETAILS_PLUGIN_TARGET_CALLER", MINIMAL_DETAILS_VERSION_REQUIRED, "Details! Team", TCALLER_VERSION)
if (type (install) == "table" and install.error) then
print (install.error)
end
--> registering details events we need
Details:RegisterEvent (targetCaller, "COMBAT_PLAYER_ENTER") --when details creates a new segment, not necessary the player entering in combat.
Details:RegisterEvent (targetCaller, "COMBAT_PLAYER_LEAVE") --when details finishs a segment, not necessary the player leaving the combat.
Details:RegisterEvent (targetCaller, "DETAILS_INSTANCE_ENDRESIZE") --when the player releases the grab after resize.
Details:RegisterEvent (targetCaller, "DETAILS_INSTANCE_SIZECHANGED") --when a details window got its size changed.
Details:RegisterEvent (targetCaller, "DETAILS_INSTANCE_STARTSTRETCH") --when the player start to stretch a window.
Details:RegisterEvent (targetCaller, "DETAILS_INSTANCE_ENDSTRETCH") --stretch ends
Details:RegisterEvent (targetCaller, "DETAILS_OPTIONS_MODIFIED") --fired when any options at details options panel is changed by the user.
Details:RegisterEvent (targetCaller, "GROUP_ONENTER") --when the player enters in a group
Details:RegisterEvent (targetCaller, "GROUP_ONLEAVE") --player left a group endd
Details:RegisterEvent (targetCaller, "DETAILS_DATA_RESET") --details combat data has been wiped
end
end
end
end
@@ -0,0 +1,22 @@
## Interface: 30300
## Title: Details Target Caller
## DefaultState: disabled
## Notes: racks your current target and show in the window who is doing damage to it. The amount of damage shown is the amount dealt since you selected the target.
## RequiredDeps: Details
## X-Curse-Project-ID: 95101
## X-Wago-ID: 0mKOpYGx
locales\enUS.lua
locales\deDE.lua
locales\esES.lua
locales\esMX.lua
locales\frFR.lua
locales\itIT.lua
locales\koKR.lua
locales\ptBR.lua
locales\ruRU.lua
locales\zhCN.lua
locales\zhTW.lua
Details_TargetCaller.lua
@@ -0,0 +1,13 @@
local L = LibStub("AceLocale-3.0"):NewLocale("DetailsTargetCaller", "deDE")
if not L then return end
--[[Translation missing --]]
L["STRING_INSTALL_ERROR1"] = "Target Caller cannot be installed: Details! not found."
--[[Translation missing --]]
L["STRING_OVERALL"] = "Overall"
--[[Translation missing --]]
L["STRING_PLUGIN_DESC"] = [=[Plugin for Target Caller on PvP, can also be used by raid leader on PvE.
When you select a new target, tells how much damage each raid member inflicted since you changed the target.]=]
--[[Translation missing --]]
L["STRING_PLUGIN_NAME"] = "Target Caller"
@@ -0,0 +1,9 @@
local L = LibStub("AceLocale-3.0"):NewLocale("DetailsTargetCaller", "enUS", true)
if not L then return end
L["STRING_INSTALL_ERROR1"] = "Target Caller cannot be installed: Details! not found."
L["STRING_OVERALL"] = "Overall"
L["STRING_PLUGIN_DESC"] = [=[Plugin for Target Caller on PvP, can also be used by raid leader on PvE.
When you select a new target, tells how much damage each raid member inflicted since you changed the target.]=]
L["STRING_PLUGIN_NAME"] = "Target Caller"
@@ -0,0 +1,13 @@
local L = LibStub("AceLocale-3.0"):NewLocale("DetailsTargetCaller", "esES")
if not L then return end
--[[Translation missing --]]
L["STRING_INSTALL_ERROR1"] = "Target Caller cannot be installed: Details! not found."
--[[Translation missing --]]
L["STRING_OVERALL"] = "Overall"
--[[Translation missing --]]
L["STRING_PLUGIN_DESC"] = [=[Plugin for Target Caller on PvP, can also be used by raid leader on PvE.
When you select a new target, tells how much damage each raid member inflicted since you changed the target.]=]
--[[Translation missing --]]
L["STRING_PLUGIN_NAME"] = "Target Caller"
@@ -0,0 +1,7 @@
local L = LibStub("AceLocale-3.0"):NewLocale("DetailsTargetCaller", "esMX")
if not L then return end
L["STRING_INSTALL_ERROR1"] = "Llamador de objetivo no se puede instalar: Details! no se encuentra."
L["STRING_OVERALL"] = "General"
L["STRING_PLUGIN_DESC"] = "Plugin para Llamador de objetivo en JcJ, también puede ser utilizado por líder de banda en JcE. Cuando seleccionas un nuevo objetivo, indica cuánto daño infligió cada miembro de la banda desde que cambiaste el objetivo."
L["STRING_PLUGIN_NAME"] = "Llamador de objetivo"
@@ -0,0 +1,13 @@
local L = LibStub("AceLocale-3.0"):NewLocale("DetailsTargetCaller", "frFR")
if not L then return end
--[[Translation missing --]]
L["STRING_INSTALL_ERROR1"] = "Target Caller cannot be installed: Details! not found."
--[[Translation missing --]]
L["STRING_OVERALL"] = "Overall"
--[[Translation missing --]]
L["STRING_PLUGIN_DESC"] = [=[Plugin for Target Caller on PvP, can also be used by raid leader on PvE.
When you select a new target, tells how much damage each raid member inflicted since you changed the target.]=]
--[[Translation missing --]]
L["STRING_PLUGIN_NAME"] = "Target Caller"
@@ -0,0 +1,13 @@
local L = LibStub("AceLocale-3.0"):NewLocale("DetailsTargetCaller", "itIT")
if not L then return end
--[[Translation missing --]]
L["STRING_INSTALL_ERROR1"] = "Target Caller cannot be installed: Details! not found."
--[[Translation missing --]]
L["STRING_OVERALL"] = "Overall"
--[[Translation missing --]]
L["STRING_PLUGIN_DESC"] = [=[Plugin for Target Caller on PvP, can also be used by raid leader on PvE.
When you select a new target, tells how much damage each raid member inflicted since you changed the target.]=]
--[[Translation missing --]]
L["STRING_PLUGIN_NAME"] = "Target Caller"
@@ -0,0 +1,9 @@
local L = LibStub("AceLocale-3.0"):NewLocale("DetailsTargetCaller", "koKR")
if not L then return end
L["STRING_INSTALL_ERROR1"] = "일점사 대상 설치 불가: Details!를 찾을 수 없습니다."
L["STRING_OVERALL"] = "종합"
L["STRING_PLUGIN_DESC"] = [=[PvP 상황에서 일점사 대상 지정자 또는 PvE 상황에서 공격대장이 사용할 수 있는 플러그인입니다.
당신이 새로운 대상을 선택하면 당신이 대상을 변경했을 때부터 각 공격대원이 입힌 피해량을 알려줍니다.]=]
L["STRING_PLUGIN_NAME"] = "일점사 대상"
@@ -0,0 +1,14 @@
local L = LibStub("AceLocale-3.0"):NewLocale("DetailsTargetCaller", "ptBR")
if not L then return end
--[[Translation missing --]]
L["STRING_INSTALL_ERROR1"] = "Target Caller cannot be installed: Details! not found."
--[[Translation missing --]]
L["STRING_OVERALL"] = "Overall"
--[[Translation missing --]]
L["STRING_PLUGIN_DESC"] = [=[Plugin for Target Caller on PvP, can also be used by raid leader on PvE.
When you select a new target, tells how much damage each raid member inflicted since you changed the target.]=]
--[[Translation missing --]]
L["STRING_PLUGIN_NAME"] = "Target Caller"
@@ -0,0 +1,8 @@
local L = LibStub("AceLocale-3.0"):NewLocale("DetailsTargetCaller", "ruRU")
if not L then return end
L["STRING_INSTALL_ERROR1"] = "Target Caller не может быть установлен: Details! не найден."
L["STRING_OVERALL"] = "Общий"
L["STRING_PLUGIN_DESC"] = "Плагин для Target Caller в PvP также может использоваться лидером рейда в PvE. Когда Вы выбираете новую цель, сообщает, сколько урона нанес каждый участник рейда с тех пор, как вы изменили цель."
L["STRING_PLUGIN_NAME"] = "Target Caller"
@@ -0,0 +1,14 @@
local L = LibStub("AceLocale-3.0"):NewLocale("DetailsTargetCaller", "zhCN")
if not L then return end
--[[Translation missing --]]
L["STRING_INSTALL_ERROR1"] = "Target Caller cannot be installed: Details! not found."
--[[Translation missing --]]
L["STRING_OVERALL"] = "Overall"
--[[Translation missing --]]
L["STRING_PLUGIN_DESC"] = [=[Plugin for Target Caller on PvP, can also be used by raid leader on PvE.
When you select a new target, tells how much damage each raid member inflicted since you changed the target.]=]
--[[Translation missing --]]
L["STRING_PLUGIN_NAME"] = "Target Caller"
@@ -0,0 +1,8 @@
local L = LibStub("AceLocale-3.0"):NewLocale("DetailsTargetCaller", "zhTW")
if not L then return end
L["STRING_INSTALL_ERROR1"] = "目標調用無法安裝:未發現Details!。"
L["STRING_OVERALL"] = "整體"
L["STRING_PLUGIN_DESC"] = "PvP上的目標調用插件也可以由PvE上的團隊領隊使用。當您選擇一個新的目標時,告訴您自更改目標以來每個團隊成員造成的傷害。"
L["STRING_PLUGIN_NAME"] = "目標調用"