view PVPScan.lua @ 1:726745261b87

updates
author tercio
date Mon, 19 May 2014 05:50:51 -0300
parents ce416064d8a1
children f2456f1454af
line wrap: on
line source

PVPScan = LibStub ("AceAddon-3.0"):NewAddon ("PVPScan", "AceConsole-3.0", "AceEvent-3.0")

local LDB = LibStub ("LibDataBroker-1.1", true)
local LDBIcon = LDB and LibStub ("LibDBIcon-1.0", true)
local SharedMedia = LibStub:GetLibrary("LibSharedMedia-3.0")

local _bit_band = bit.band

local REACTION_HOSTILE = 0x00000040
local REACTION_NEUTRAL = 0x00000020

local OBJECT_TYPE_PLAYER = 0x00000400

PVPScan.IsInBattleground = false
PVPScan.IsInCity = false
PVPScan.IsInArena = false
PVPScan.IsInOutDoors = true
PVPScan.ScanEnabled = true

local default_db = {
	profile = {
		SpotBarHeight = 20,
		SpotBarAmount = 5,
		SpotBarWidth = 150,
		Locked = false,
		SoundPlay = false,
		SoundFile = "",
		Minimap = {hide = false, radius = 160, minimapPos = 220},
	},
}

function PVPScan:OnEnable()
end

function PVPScan:OnDisable()
end

local OptionsTable = {
	name = "PVPScan",
	type = "group",
	args = {
		SpotBarHeight = {
			type = "range",
			name = "Bar Height", 
			desc = "Change the height of spot bars.",
			min = 10,
			max = 40,
			step = 1,
			get = function() return PVPScan.db.profile.SpotBarHeight end,
			set = function (self, val) PVPScan.db.profile.SpotBarHeight = val; PVPScan:RefreshSpotBars() end,
			order = 1,
		},
		SpotBarWidth = {
			type = "range",
			name = "Bar Width", 
			desc = "Change the width of spot bars.",
			min = 50,
			max = 250,
			step = 1,
			get = function() return PVPScan.db.profile.SpotBarWidth end,
			set = function (self, val) PVPScan.db.profile.SpotBarWidth = val; PVPScan:RefreshSpotBars() end,
			order = 2,
		},
		SpotBarAmount = {
			type = "range",
			name = "Bar Amount", 
			desc = "Change the amount of spot bars.",
			min = 1,
			max = 40,
			step = 1,
			get = function() return PVPScan.db.profile.SpotBarAmount end,
			set = function (self, val) PVPScan.db.profile.SpotBarAmount = val; PVPScan:RefreshSpotBars() end,
			order = 3,
		},
		Locked = {
			type = "toggle",
			name = "Lock Scan Frame",
			desc = "Lock or unlock the SpotBars Frame.",
			order = 4,
			get = function() return PVPScan.db.profile.Locked end,
			set = function (self, val) PVPScan.db.profile.Locked = not PVPScan.db.profile.Locked; PVPScan:LockScanFrame (PVPScan.db.profile.Locked) end,
		},
		SoundPlay = {
			type = "toggle",
			name = "Play Sound",
			desc = "Play a sound when a enemy is found.",
			order = 5,
			get = function() return PVPScan.db.profile.SoundPlay end,
			set = function (self, val) PVPScan.db.profile.SoundPlay = not PVPScan.db.profile.SoundPlay end,
		},
		SoundFile = {
			type = "select",
			name = "Sound File",
			desc = "Choose the sound to play when a enemy is found.",
			values = function()
					local SoundTable = {}
					for name, _ in pairs (SharedMedia:HashTable ("sound")) do 
						SoundTable [name] = name
					end
					return SoundTable 
				end,
			get = function() return PVPScan.db.profile.SoundFile end,
			set = function (self, file) PVPScan.db.profile.SoundFile = file end,
			order = 6,
		},
		Minimap = {
			type = "toggle",
			name = "Hide Minimap Icon",
			desc = "Show or hide the minimap icon.",
			order = 7,
			get = function() return PVPScan.db.profile.Minimap.hide end,
			set = function (self, val) 
				PVPScan.db.profile.Minimap.hide = not PVPScan.db.profile.Minimap.hide
				LDBIcon:Refresh ("PVPScan", PVPScan.db.profile.Minimap)
				if (PVPScan.db.profile.Minimap.hide) then
					LDBIcon:Hide ("PVPScan")
				else
					LDBIcon:Show ("PVPScan")
				end
			end,
		},		
	},
}

function PVPScan:OnInitialize()

	--declarar primeiro o db usando a global que é declarada no toc.
  	self.db = LibStub ("AceDB-3.0"):New ("PVPScanDB", default_db, true)
	
	--declara agora as opções da tab raiz
	LibStub("AceConfig-3.0"):RegisterOptionsTable ("PVPScan", OptionsTable)
	PVPScan.OptionsFrame1 = LibStub ("AceConfigDialog-3.0"):AddToBlizOptions ("PVPScan", "PVPScan")
	--sub tab
	LibStub ("AceConfig-3.0"):RegisterOptionsTable ("PVPScan-Profiles", LibStub ("AceDBOptions-3.0"):GetOptionsTable (self.db))
	PVPScan.OptionsFrame2 = LibStub ("AceConfigDialog-3.0"):AddToBlizOptions ("PVPScan-Profiles", "Profiles", "PVPScan")
	
	if LDB then
		local databroker = LDB:NewDataObject ("PVPScan", {
			type = "launcher",
			icon = [[Interface\PvPRankBadges\PvPRank15]],
			--HotCornerIgnore = true,
			OnClick = function (self, button)
				InterfaceOptionsFrame_OpenToCategory ("PVPScan")
				InterfaceOptionsFrame_OpenToCategory ("PVPScan")
			end
		})
		
		if (databroker and not LDBIcon:IsRegistered ("PVPScan")) then
			LDBIcon:Register ("PVPScan", databroker, PVPScan.db.profile.Minimap)
		end	
	end
	
	PVPScan:RefreshSpotBars()
	PVPScan:LockScanFrame (PVPScan.db.profile.Locked)
end

PVPScan:RegisterChatCommand ("pvpscan", function() 
	InterfaceOptionsFrame_OpenToCategory ("PVPScan")
	InterfaceOptionsFrame_OpenToCategory ("PVPScan")
end)


------------------------------------------------------------------------------------------------------------------------------------------------------------
--> general

function PVPScan:ChangeZones()

	local name, type, difficulty, difficultyName, maxPlayers, playerDifficulty, isDynamicInstance, mapID, instanceGroupSize = GetInstanceInfo()
	local pvpType, isFFA, faction = GetZonePVPInfo()
	
	PVPScan.IsInBattleground = false
	PVPScan.IsInCity = false
	PVPScan.IsInArena = false
	PVPScan.IsInOutDoors = false
	PVPScan.ScanEnabled = false
	
	if (pvpType == "contested" and (not type or type == "none")) then
		PVPScan.IsInOutDoors = true
		PVPScan.ScanEnabled = true
	
	elseif (type == "pvp") then
		PVPScan.IsInBattleground = true
	
	elseif (type == "arena") then
		PVPScan.IsInArena = true
	
	elseif (type and (type == "scenario" or type == "party" or type == "raid" or pvpType == "friendly" or pvpType == "sanctuary")) then
		PVPScan.ScanEnabled = false
	
	else
		PVPScan.IsInOutDoors = true
		PVPScan.ScanEnabled = true
	end

	if (PVPScan.ScanEnabled) then
		PVPScan:EnableScan()
	else
		PVPScan:DisableScan()
	end
	
end

PVPScan:RegisterEvent ("ZONE_CHANGED_NEW_AREA", "ChangeZones")
PVPScan:RegisterEvent ("PLAYER_ENTERING_WORLD", "ChangeZones")

function PVPScan:EnableScan()
	PVPScan.EventFrame:RegisterEvent ("COMBAT_LOG_EVENT_UNFILTERED")
	PVPScan:RefreshSpotBars()
end

function PVPScan:DisableScan()
	PVPScan.EventFrame:UnregisterEvent ("COMBAT_LOG_EVENT_UNFILTERED")
	PVPScan:RefreshSpotBars()
end

function PVPScan:LockScanFrame (IsLocked)
	if (IsLocked) then
		PVPScanFrame.text:SetText ("")
		PVPScanFrame:SetBackdrop (nil)
		PVPScanFrame:EnableMouse (false)
	else
		PVPScanFrame.text:SetText ("PVPScan Anchor")
		PVPScanFrame:SetBackdrop ({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tile = true, TileSize = 64})
		PVPScanFrame:SetBackdropColor (0, 0, 0, 1)
		PVPScanFrame:EnableMouse (true)
	end
end
------------------------------------------------------------------------------------------------------------------------------------------------------------
--> outside world scan

	--> parser

	PVPScan.SpotBars = {}
	PVPScan.NeedClass = {}
	PVPScan.NextSpotBar = 1
	
	local CurrentShownIndex = {}
	local CurrentShownHash = {}
	local CurrentShownTime = {}
	local NeutralCandidate = {}
	
	local find_neutral_players = false

	PVPScan.EventFrame = CreateFrame ("frame", "PVPScanCombatLobReader", UIParent)
	PVPScan.EventFrame:RegisterEvent ("COMBAT_LOG_EVENT_UNFILTERED")

	function PVPScan:OnParserEvent (event, time, token, hidding, who_serial, who_name, who_flags, who_flags2, target_serial, target_name, target_flags, target_flags2, ...)

		if (PVPScan.NeedClass [who_name]) then
			local class = PVPScan:GuessClass (...)
			if (class) then
				PVPScan:UpdateBar (PVPScan.NeedClass [who_name], class, who_name)
				PVPScan.NeedClass [who_name] = nil
			end
			return
		end
		
		if (PVPScan.NeedClass [target_name]) then
			local class = PVPScan:GuessClass (...)
			if (class) then
				PVPScan:UpdateBar (PVPScan.NeedClass [target_name], class, target_name)
				PVPScan.NeedClass [target_name] = nil
			end
			return
		end
		
		if (not CurrentShownHash [target_name] and _bit_band (target_flags, OBJECT_TYPE_PLAYER) ~= 0) then --> is player
			if (_bit_band (target_flags, REACTION_HOSTILE) ~= 0) then --> is hostile
				local class = PVPScan:GuessClass (...)
				PVPScan:EnemySpoted (target_name, target_serial, target_flags, class)
				
			elseif (find_neutral_players and _bit_band (target_flags, REACTION_NEUTRAL) ~= 0) then
				if (NeutralCandidate [target_name]) then
					NeutralCandidate [target_name] = NeutralCandidate [target_name] + 1
					if (NeutralCandidate [target_name] == 5) then
						--print ("neutral", target_name)
						local class = PVPScan:GuessClass (...)
						PVPScan:EnemySpoted (target_name, target_serial, target_flags, class)
					end
				else
					NeutralCandidate [target_name] = 1
				end
				
			elseif (NeutralCandidate [target_name]) then
				NeutralCandidate [target_name] = nil
			end
		end
		
		if (not CurrentShownHash [who_name] and _bit_band (who_flags, OBJECT_TYPE_PLAYER) ~= 0) then --> is player
			if (_bit_band (who_flags, REACTION_HOSTILE) ~= 0) then --> is hostile
				local class = PVPScan:GuessClass (...)
				PVPScan:EnemySpoted (who_name, who_serial, who_flags, class)
			
			elseif (find_neutral_players and _bit_band (who_flags, REACTION_NEUTRAL) ~= 0) then
				if (NeutralCandidate [who_name]) then
					NeutralCandidate [who_name] = NeutralCandidate [who_name] + 1
					if (NeutralCandidate [who_name] == 5) then
						--print ("neutral", who_name)
						local class = PVPScan:GuessClass (...)
						PVPScan:EnemySpoted (who_name, who_serial, who_flags, class)
					end
				else
					NeutralCandidate [who_name] = 1
				end
				
			elseif (NeutralCandidate [who_name]) then
				NeutralCandidate [who_name] = nil
			end
		end
	end

	PVPScan.EventFrame:SetScript ("OnEvent", PVPScan.OnParserEvent)
	
	function PVPScan:LeftCombatLockdown()
		if (PVPScan.schedule_frame_update) then
			PVPScan.schedule_frame_update = false
			PVPScan:RefreshSpotBars()
		end
	end
	function PVPScan:GotCombatLockdown()
	end
	
	PVPScan:RegisterEvent ("PLAYER_REGEN_DISABLED", "GotCombatLockdown")
	PVPScan:RegisterEvent ("PLAYER_REGEN_ENABLED", "LeftCombatLockdown")

	-- found a enemy on the scan
	
	function PVPScan:EnemySpoted (name, serial, flags, class)

		if (not name) then
			return
		end

		--> check for overwrite
		local current_player_shown = CurrentShownIndex [PVPScan.NextSpotBar]
		if (current_player_shown) then
			PVPScan.NeedClass [current_player_shown] = nil
		end
	
		local SpotBar = PVPScan.SpotBars [PVPScan.NextSpotBar]

		if (class) then
			PVPScan:UpdateBar (PVPScan.NextSpotBar, class, name)
		else
			PVPScan:UpdateBar (PVPScan.NextSpotBar, nil, name)
			PVPScan.NeedClass [name] = PVPScan.NextSpotBar
		end
		
		CurrentShownIndex [PVPScan.NextSpotBar] = name
		CurrentShownHash [name] = PVPScan.NextSpotBar
		CurrentShownTime [name] = GetTime()
		
		if (not UnitAffectingCombat ("player") and not InCombatLockdown()) then
			SpotBar:SetAttribute ("macrotext", "/cleartarget\n/targetexact " .. name)
		end
		
		SpotBar:Show()
		
		PVPScan.NextSpotBar = PVPScan.NextSpotBar + 1
		if (PVPScan.NextSpotBar > PVPScan.db.profile.SpotBarAmount) then
			PVPScan.NextSpotBar = 1
		end

	end
	
	-- frames

	function PVPScanOnFrameMouseDown (self, button)
		if (button == "LeftButton") then
			if (not self.IsMoving) then
				self:StartMoving()
				self.IsMoving = true
			end
		end
	end

	function PVPScanOnFrameMouseUp (self, button)
		if (button == "LeftButton") then
			if (self.IsMoving) then
				self:StopMovingOrSizing()
				self.IsMoving = false
			end
			
		elseif (button == "RightButton") then
			InterfaceOptionsFrame_OpenToCategory ("PVPScan")
			InterfaceOptionsFrame_OpenToCategory ("PVPScan")
		end
	end

	function PVPScan:UpdateBar (index, class, name)
	
		if (UnitAffectingCombat ("player") or InCombatLockdown()) then
			--return
		end
	
		local SpotBar = PVPScan.SpotBars [index]
		
		if (class) then
			local color = RAID_CLASS_COLORS [class]
			SpotBar.classtexture:SetVertexColor (color.r, color.g, color.b)

			local texcoord = CLASS_ICON_TCOORDS [class]
			SpotBar.classicon:SetTexture ([[Interface\Glues\CHARACTERCREATE\UI-CHARACTERCREATE-CLASSES]])
			SpotBar.classicon:SetTexCoord (unpack (texcoord))
		else
			SpotBar.classtexture:SetVertexColor (.7, .7, .7)
			SpotBar.classicon:SetTexture ([[Interface\InventoryItems\WoWUnknownItem01]])
			SpotBar.classicon:SetTexCoord (0, 1, 0, 1)
		end
		
		SpotBar.name:SetText (name)
		
	end
	
	function PVPScan:RefreshSpotBars()
	
		if (UnitAffectingCombat ("player") or InCombatLockdown()) then
			PVPScan.schedule_frame_update = true
			PVPScan:Print ("When the combat finishes, the frame will be updated.")
			return
		end
		
		if (not PVPScan.ScanEnabled) then
			PVPScanFrame:Hide()
		else
			PVPScanFrame:Show()
		end
		
		local amount_bars = PVPScan.db.profile.SpotBarAmount
		PVPScanFrame:SetSize (PVPScan.db.profile.SpotBarWidth, 20)

		--> we need extra bars?
		if (amount_bars > #PVPScan.SpotBars) then
			for i = #PVPScan.SpotBars+1, amount_bars do 
			
				local new_bar = CreateFrame ("Button", "PVPScanSpotBar" .. i, PVPScanFrame, "PVPScanSpotBarTemplate")
				
				local y = (i-1) * PVPScan.db.profile.SpotBarHeight * -1
				
				new_bar:SetPoint ("topleft", PVPScanFrame, "topleft", 0, y)
				new_bar:SetSize (PVPScan.db.profile.SpotBarWidth, PVPScan.db.profile.SpotBarHeight)
				
				tinsert (PVPScan.SpotBars, new_bar)
			end
		end
		
		if (#PVPScan.SpotBars > amount_bars) then
			for i = #PVPScan.SpotBars, amount_bars+1, -1 do
				PVPScan.SpotBars [i]:Hide()
				local name = CurrentShownIndex [i]
				if (name) then
					tremove (CurrentShownIndex, i)
					CurrentShownHash [name] = nil
					CurrentShownTime [name] = nil
					PVPScan.NeedClass [name] = nil
				end
			end
		end

		--> refresh existing
		for index, bar in ipairs (PVPScan.SpotBars) do
			local y = (index-1) * PVPScan.db.profile.SpotBarHeight * -1
			bar:SetPoint ("topleft", PVPScanFrame, "bottomleft", 0, y)
			bar:SetSize (PVPScan.db.profile.SpotBarWidth, PVPScan.db.profile.SpotBarHeight)
			bar.classtexture:SetSize (PVPScan.db.profile.SpotBarWidth, PVPScan.db.profile.SpotBarHeight)
			bar.classicon:SetSize (PVPScan.db.profile.SpotBarHeight, PVPScan.db.profile.SpotBarHeight)
		end
		
	end

	--> misc

	function PVPScan:GuessClass (...)
		local arg1, arg2, arg3, arg4 = select (1, ...)
		
		if (type (arg1) == "number") then
			if (PVPScan.ClassSpellList [arg1]) then
				return PVPScan.ClassSpellList [arg1]
			end
		end
		
		if (type (arg3) == "number") then
			if (PVPScan.ClassSpellList [arg3]) then
				return PVPScan.ClassSpellList [arg3]
			end
		end
		
		if (type (arg2) == "number") then
			if (PVPScan.ClassSpellList [arg3]) then
				return PVPScan.ClassSpellList [arg3]
			end
		end

		if (type (arg4) == "number") then
			if (PVPScan.ClassSpellList [arg4]) then
				return PVPScan.ClassSpellList [arg4]
			end
		end
		
		return nil
	end


------------------------------------------------------------------------------------------------------------------------------------------------------------
--> battlegrounds