Quantcast
--[[
##############################################################################
_____/\\\\\\\\\\\____/\\\________/\\\__/\\\________/\\\__/\\\\\\\\\\\_       #
 ___/\\\/////////\\\_\/\\\_______\/\\\_\/\\\_______\/\\\_\/////\\\///__      #
  __\//\\\______\///__\//\\\______/\\\__\/\\\_______\/\\\_____\/\\\_____     #
   ___\////\\\__________\//\\\____/\\\___\/\\\_______\/\\\_____\/\\\_____    #
	______\////\\\________\//\\\__/\\\____\/\\\_______\/\\\_____\/\\\_____   #
	 _________\////\\\______\//\\\/\\\_____\/\\\_______\/\\\_____\/\\\_____  #
	  __/\\\______\//\\\______\//\\\\\______\//\\\______/\\\______\/\\\_____ #
	   _\///\\\\\\\\\\\/________\//\\\________\///\\\\\\\\\/____/\\\\\\\\\\\_#
		___\///////////___________\///___________\/////////_____\///////////_#
##############################################################################
S U P E R - V I L L A I N - U I   By: Munglunch                              #
##############################################################################
##########################################################
LOCALIZED LUA FUNCTIONS
##########################################################
]]--
--[[ GLOBALS ]]--
local _G = _G;
local unpack    = _G.unpack;
local select    = _G.select;
local pairs     = _G.pairs;
local ipairs    = _G.ipairs;
local type      = _G.type;
local error     = _G.error;
local pcall     = _G.pcall;
local tostring  = _G.tostring;
local tonumber  = _G.tonumber;
local tinsert   = _G.tinsert;
local string    = _G.string;
local math      = _G.math;
local bit       = _G.bit;
local table     = _G.table;
--[[ STRING METHODS ]]--
local lower, upper = string.lower, string.upper;
local find, format, split = string.find, string.format, string.split;
local match, gmatch, gsub = string.match, string.gmatch, string.gsub;
--[[ MATH METHODS ]]--
local floor = math.floor;  -- Basic
--[[ BINARY METHODS ]]--
local band, bor = bit.band, bit.bor;
--[[ TABLE METHODS ]]--
local tremove, tcopy, twipe, tsort, tconcat = table.remove, table.copy, table.wipe, table.sort, table.concat;
--[[
##########################################################
GET ADDON DATA
##########################################################
]]--
local SuperVillain, L = unpack(select(2, ...));
local MOD = SuperVillain.Registry:Expose('SVPlate');
--[[
##########################################################
LOCALS AND TRACKER FRAME
##########################################################
]]--
local NextUpdate = 0

local SpellIDTest = {
	[47540] = true, [88625] = true, [88684] = true, [88685] = true,
	[89485] = true, [10060] = true, [33206] = true, [62618] = true,
	[724] = true, [14751] = true, [34861] = true, [47788] = true,
	[18562] = true, [17116] = true, [48438] = true, [33891] = true,
	[974] = true, [17116] = true, [16190] = true, [61295] = true,
	[20473] = true, [31842] = true, [53563] = true, [31821] = true,
	[85222] = true, [115175] = true, [115294] = true, [115310] = true,
	[116670] = true, [116680] = true, [116849] = true, [116995] = true,
	[119611] = true, [132120] = true
}

local HealerDetection = {
	["SPELL_HEAL"] = true,
	["SPELL_AURA_APPLIED"] = true,
	["SPELL_CAST_START"] = true,
	["SPELL_CAST_SUCCESS"] = true,
	["SPELL_PERIODIC_HEAL"] = true,
	["Restoration"] = true,
	["Holy"] = true,
	["Discipline"] = true,
	["Mistweaver"] = true
}

local TrackingManager = CreateFrame("Frame")
local CPoints = {}
local TrackedPlatesCP = {}
local LastKnownTarget = false
local LastKnownPoints = 0
local Healers = {}
local Events = {}
--[[
##########################################################
PARSE FUNCTIONS
##########################################################
]]--
local function TrackViaScores()
	local curTime = GetTime()
	if curTime > NextUpdate then
		NextUpdate = curTime + 3
	else
		return
	end
	local scores = GetNumBattlefieldScores()
	if(scores > 0) then
		local filter
		for i = 1, scores do
			local name, _, _, _, _, faction, _, class, _, _, _, _, _, _, _, talentSpec = GetBattlefieldScore(i)
			if name and talentSpec then
				filter = HealerDetection[talentSpec]
				Healers[name] = filter
			end
		end
		if(filter) then
			MOD:RequestScanUpdate(false, false, name, "UpdateHealerIcon")
		end
	end
end

local function PlateIsHealer(name)
	if name then
		if Healers[name] then
			return true
		else
			RequestBattlefieldScoreData()
		end
	end
end

local function PlateIsEnemy(flags)
	if (band(flags, COMBATLOG_OBJECT_REACTION_FRIENDLY) == 0) and (band(flags, COMBATLOG_OBJECT_CONTROL_PLAYER) > 0) then
		return true
	end
end

local function DetectHealer(event, id)
	if (HealerDetection[event] and SpellIDTest[id]) then
		return true
	else
		return false
	end
end

local function ClearTracking()
	twipe(CPoints)
	twipe(Healers)
end

local function ClearExpiredPoints()
	local saved
	for plate,_ in pairs(TrackedPlatesCP) do
		if(plate.guid ~= LastKnownTarget) then
			for i=1, MAX_COMBO_POINTS do
				plate.frame.combo[i]:Hide()
			end
		else
			saved = plate
		end
	end
	CPoints = {}
	TrackedPlatesCP = {}

	if(saved) then
		TrackedPlatesCP[saved] = true
	end

	if(LastKnownTarget) then
		CPoints[LastKnownTarget] = LastKnownPoints;
	end
end

local function TrackingEventHandler(self, event, ...)
	local handler = Events[event]
	if handler then handler(...) end
end
--[[
##########################################################
EVENTS
##########################################################
]]--
function Events.UNIT_COMBO_POINTS(unit)
	MOD:UpdateComboPointsByUnitID(unit)
end

function Events.PLAYER_ENTERING_WORLD()
	ClearTracking()
	return
end

function Events.PLAYER_TARGET_CHANGED()
	ClearExpiredPoints()
	return
end

function Events.UPDATE_BATTLEFIELD_SCORE()
	TrackViaScores()
	return
end

function Events.COMBAT_LOG_EVENT_UNFILTERED(...)
	local timestamp, combatevent, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlag, spellid  = ...
	if PlateIsEnemy(sourceFlags) and sourceGUID and sourceName then
		if DetectHealer(combatevent, spellid) then
			local rawName = split("-", sourceName)
			if not Healers[rawName] then
				Healers[rawName] = true
				MOD:RequestScanUpdate(destGUID, false, false, "UpdateHealerIcon")
			end
		end
	end
end
--[[
##########################################################
MODULE FUNCTIONS
##########################################################
]]--
function MOD:EnableTracking()
	TrackingManager:SetScript("OnEvent", TrackingEventHandler)
	TrackingManager:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
	TrackingManager:RegisterEvent("PLAYER_ENTERING_WORLD")
	TrackingManager:RegisterEvent("UPDATE_BATTLEFIELD_SCORE")
	if (MOD.UseCombo) then
		TrackingManager:RegisterEvent("UNIT_COMBO_POINTS")
		TrackingManager:RegisterEvent("PLAYER_TARGET_CHANGED")
	end
	ClearTracking()
end

function MOD:DisableTracking()
	TrackingManager:UnregisterAllEvents()
	TrackingManager:SetScript("OnEvent", nil)
	ClearTracking()
end

function MOD:UpdateHealerIcon(plate)
	local rawName = plate.ref.nametext
	if rawName then
		local healerIcon = plate.frame.health.icon
		if PlateIsHealer(rawName) then
			healerIcon:Show()
		else
			healerIcon:Hide()
		end
	end
end

function MOD:UpdateComboPoints(plate)
	local frame = plate.frame
	local numPoints = CPoints[plate.guid] or 0
	if(numPoints == 0) then
		TrackedPlatesCP[plate] = nil
	else
		TrackedPlatesCP[plate] = true
	end
	for i=1, MAX_COMBO_POINTS do
		if(i <= numPoints) then
			frame.combo[i]:Show()
		else
			frame.combo[i]:Hide()
		end
	end
end

function MOD:UpdateComboPointsByUnitID(unit)
	if(unit == "player" or unit == "vehicle") then
		local guid = UnitGUID("target")
		if (not guid) then return end
		local numPoints = GetComboPoints(UnitHasVehicleUI('player') and 'vehicle' or 'player', 'target')
		if(numPoints > 0) then
			if(LastKnownTarget ~= guid) then
				CPoints[LastKnownTarget] = nil
			end
		end
		LastKnownTarget = guid
		LastKnownPoints = numPoints
		CPoints[guid] = numPoints
		MOD:RequestScanUpdate(guid, false, false, "UpdateComboPoints")
	end
end