You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

426 lines
14 KiB

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