/EnemyScanner2
-- mikma, 10/2014 |
-- debugprint works only if debug.EnemyScanner2 is set. |
-- The following function will require that debug.EnemyScanner2 is set to true. |
-- Setting it true will also result this addon to work everywhere. |
-- ChatFrame3 is used to print all the actions hostile players do. |
-- ChatFrame4 is used to print tooltipscan results and mouseover results. |
local function debugprint(chatframe,text,r,g,b) |
if debug.EnemyScanner2 then |
_G["ChatFrame"..chatframe]:AddMessage(text,r,g,b) |
local rows = {} |
local ES2temptable = {} |
local pvpmatch |
local HOSTILEUNITFLAG = 0x548 |
-- Stealth/Prowl/Invisibility watch. |
local spellwatch = { |
[66] = true, -- Mage, Invisibility |
[110959] = true, -- Mage, Greater Invisibility |
[1784] = true, -- Rogue, Stealth |
[5215] = true, -- Druid, Prowl |
} |
-- If SavedVariables database does not exist, create it and add some default values for anchor, expiration time and temporary PvP table. |
if not EnemyScanner2DB then EnemyScanner2DB = {["position"] = {point = "RIGHT", x = -70, y = 0}, ["expire"] = 10, ["PvP"] = {},} end |
if not EnemyScanner2DB then EnemyScanner2DB = {["position"] = {point = "RIGHT", x = -70, y = 0}, ["expire"] = 10, ["PvP"] = {}, ["enabled"] = true,} end |
-- bit.band the flag to check the following: |
-- Type: COMBATLOG_OBJECT_TYPE_PLAYER 0x00000400 |
-- Controller: COMBATLOG_OBJECT_CONTROL_PLAYER 0x00000100 |
-- Reaction: COMBATLOG_OBJECT_REACTION_HOSTILE 0x00000040 |
-- Controller affiliation: COMBATLOG_OBJECT_AFFILIATION_OUTSIDER 0X00000008 |
-- PLAYER controlled by PLAYER which is REACTION HOSTILE and is OUTSIDER (not in raid or party with you). |
local function isTargetHostile(flag) |
local HOSTILEUNITFLAG = 0x548 |
if bit.band(flag,HOSTILEUNITFLAG) == HOSTILEUNITFLAG then |
-- Yeap! |
return true |
end |
end |
-- Converts R,G,B into hexcolor. Example: RAID_CLASS_COLORS['SHAMAN'] (r,g,b) 0,0.44,0,87 turns into '|cff0070dd'. |
local function DecimalToHex(r,g,b) |
return string.format("|cff%02x%02x%02x", r*255, g*255, b*255) |
EnemyScanner2DB.expire = 10 |
EnemyScanner2:Clear() |
debugprint(3,"EnemyScanner2 PvP",0,0,1) |
EnemyScanner2DB.enabled = true |
elseif instancetype == "party" or instancetype == "raid" or instancetype == "arena" then |
EnemyScanner2:Disable() |
debugprint(3,"EnemyScanner2 Disabled",1,0,0) |
EnemyScanner2DB.enabled = false |
else |
-- Change temptable to realmName. |
temptable = EnemyScanner2DB[realmName] |
EnemyScanner2DB.expire = 30 |
EnemyScanner2:Enable() |
if pvpmatch then |
EnemyScanner2:Clear() |
pvpmatch = nil |
if not EnemyScanner2DB.enabled then |
-- Change temptable to realmName. |
temptable = EnemyScanner2DB[realmName] |
EnemyScanner2DB.expire = 30 |
EnemyScanner2:Enable() |
if pvpmatch then |
EnemyScanner2:Clear() |
pvpmatch = nil |
end |
debugprint(3,"EnemyScanner2 Enabled",0,1,0) |
EnemyScanner2DB.enabled = true |
end |
debugprint(3,"EnemyScanner2 Enabled",0,1,0) |
end |
end |
if not EnemyScanner2DB[realmName] then EnemyScanner2DB[realmName] = {} end |
db = EnemyScanner2DB[realmName] |
EnemyScanner2:ZONE_CHANGED_NEW_AREA() |
-- anchor SetPoint from SavedVariables is available after PLAYER_LOGIN, so initialize the anchor frame. |
EnemyScanner2:Initialize() |
end |
local function GetStats(unit) |
-- Unit exists, Unit is a player, and Unit is enemy to you. |
if UnitExists(unit) and UnitIsPlayer(unit) and UnitIsEnemy("player",unit) then |
if UnitExists(unit) and UnitIsPlayer(unit) and UnitIsEnemy("player",unit) and (not UnitIsPVPSanctuary("player") or debug.EnemyScanner2) then |
local guidsource = UnitGUID(unit) |
local level = UnitLevel(unit) |
local name = UnitName(unit) |
-- Level is shown as '-1' with UnitLevel if the target is ovet 10 levels over your level. |
if level == -1 then |
level = UnitLevel("player")+10 |
level = 0 |
end |
-- Level is shown as '-1' but we already know this player |
if level == -1 and db[guidsource] then |
level = db[guidsource] |
end |
-- Player doesn't exist in the database, create a spot for player in database. |
if not db[guidsource] then |
db[guidsource] = level |
tooltip:AddFontStrings(toolText3, tooltip:CreateFontString()) |
tooltip:SetOwner(UIParent, "ANCHOR_NONE") |
-- Working! |
local function tooltipScanner(guid) |
local tooltip = tooltip |
tooltip:ClearLines() |
-- debugprint required stuff, can be deleted later. |
local class, classFilename, race, raceFilename, sex, name, realm = GetPlayerInfoByGUID(guid) |
if lines > 0 then |
if string.match(toolText2:GetText(), "Level %d+") then |
if lines > 1 then |
if toolText2:GetText() and string.match(toolText2:GetText(), "Level %d+") then |
printline = string.match(toolText2:GetText(), "%d+") |
if not name then debugprint(4,"Tooltip: name not cached yet!",1,0,0); return; end |
debugprint(4,"Tooltip: scanning "..guid..": "..name..", "..printline) |
return tonumber(printline) |
elseif string.match(toolText3:GetText(), "Level %d+") then |
elseif toolText3:GetText() and string.match(toolText3:GetText(), "Level %d+") then |
printline = string.match(toolText3:GetText(), "%d+") |
if not name then debugprint(4,"Tooltip: name not cached yet!",1,0,0); return; end |
debugprint(4,"Tooltip: scanning "..guid..": "..name..", "..printline) |
return tonumber(printline) |
elseif string.match(toolText2:GetText(), "Level ??") then |
elseif toolText2:GetText() and string.match(toolText2:GetText(), "Level ??") then |
debugprint(4,"Tooltip: scanning "..guid..": "..name..", ??") |
if UnitLevel("player") <= MAX_PLAYER_LEVEL_TABLE[GetAccountExpansionLevel()] - 10 then |
return UnitLevel("player")+10 |
else |
return 0 |
end |
elseif string.match(toolText3:GetText(), "Level ??") then |
elseif toolText3:GetText() and string.match(toolText3:GetText(), "Level ??") then |
debugprint(4,"Tooltip: scanning "..guid..": "..name..", ??") |
if UnitLevel("player") <= MAX_PLAYER_LEVEL_TABLE[GetAccountExpansionLevel()] - 10 then |
return UnitLevel("player")+10 |
end |
end |
-- Working! |
-- function for SetScript("OnUpdate") |
local function onUpdate(self,elapsed) |
total = total + elapsed |
if total >= 1 then |
end |
end |
-- Working! |
-- This is where almost all of the magic is happening! CLEU <3 |
function EnemyScanner2:COMBAT_LOG_EVENT_UNFILTERED(_, _, minievent, _, guidsource, source, sourceflags, sourceflagsraid, guidtarget, target, targetflags, targetflagsraid, ...) |
if isTargetHostile(sourceflags) then --and not UnitIsPVPSanctuary("player") then |
-- bit.band the flag to check the following: |
-- Type: COMBATLOG_OBJECT_TYPE_PLAYER 0x00000400 |
-- Controller: COMBATLOG_OBJECT_CONTROL_PLAYER 0x00000100 |
-- Reaction: COMBATLOG_OBJECT_REACTION_HOSTILE 0x00000040 |
-- Controller affiliation: COMBATLOG_OBJECT_AFFILIATION_OUTSIDER 0X00000008 |
-- PLAYER controlled by PLAYER which is REACTION HOSTILE and is OUTSIDER (not in raid or party with you). |
if bit.band(sourceflags,HOSTILEUNITFLAG) == HOSTILEUNITFLAG and (not UnitIsPVPSanctuary("player") or debug.EnemyScanner2) then |
-- GUID is missing, exit. |
if guidsource == '' then |
debugprint(4,minievent..", "..guidsource and guidsource or "nil, "..source and source or "nil, "..sourceflags..", "..sourceflagsraid,...,1,0,0) |
return |
end |
local updating = ES2timer:GetScript("OnUpdate") |
-- Remove -Servername from player's name. |
source = source:match("[^-]+") |
local source = source:match("[^-]+") |
local spellID,spellName = ... |
local level |
-- Stealth/Prowl/Invisibility watch. |
local spellwatch = { |
[66] = true, -- Mage, Invisibility |
[110959] = true, -- Mage, Greater Invisibility |
[1784] = true, -- Rogue, Stealth |
[5215] = true, -- Druid, Prowl |
} |
-- GUID does not exist in database, add as level 0. |
if not db[guidsource] then |
db[guidsource] = 0 |
end |
-- Spell alert will show messages only once, after spell has been applied. |
-- Might need to find a better way of printing the alerts on screen. |
if minievent == "SPELL_AURA_APPLIED" then |
spellName = spellName:gsub("(%l)(%w*)", function(a,b) return string.upper(a)..b end) |
end |
-- In case the level ain't clear yet (Melee strike/miss?) |
if not level then level = db[guidsource] and db[guidsource] or 0 end |
-- Check if action is spell. |
if minievent:match("[^_]+") ~= "SWING" and tonumber(spellID) then |
level = GetSpellLevelLearned(spellID) |
spellName = GetSpellLink(spellID) |
end |
-- GUID does not exist in database, add as level 0. |
if not db[guidsource] then |
db[guidsource] = 0 |
end |
-- If spell is greater than the one stored in database, upgrade it in the database. |
if level and (db[guidsource] < level) then |
-- If spell level is greater than current max level in player's expansion, don't upgrade. |
end |
-- If we are not running onUpdate and there are messages in the queue, start it. |
local updating = ES2timer:GetScript("OnUpdate") |
if not updating and next(ES2messages) then |
ES2timer:SetScript("OnUpdate",onUpdate) |
end |
end |
end |
-- Working! |
-- Initialize the anchor where rows are SetPoint'd. |
function EnemyScanner2:Initialize() |
anchor:SetFrameStrata("MEDIUM") |
EnemyScanner2DB.position.point, EnemyScanner2DB.position.x, EnemyScanner2DB.position.y = "BOTTOMLEFT", self:GetLeft(), self:GetBottom() |
end) |
anchor:SetPoint(EnemyScanner2DB.position.point, EnemyScanner2DB.position.x, EnemyScanner2DB.position.y) |
anchor:Hide() |
end |
-- Working! |
-- Make sure nothing gets added if name is not found! |
-- Adds a message to the alert frame, returns a uid. |
function EnemyScanner2:AddMessage(name, level, spotted, class) |
if not name then debugprint(4,"AddMessage: Name not found!",1,0,0) return end |
end |
-- Working! |
-- Edits a message if it already exists and is being displayed in alert frame. |
function EnemyScanner2:EditMessage(uid,level,spotted) |
for i=1,#ES2messages do |
end |
end |
-- Working! |
-- Removes a message from the alert frame. |
function EnemyScanner2:DelMessage(uid) |
for i=1,#ES2messages do |
end |
end |
-- Working! |
-- Clears all messages from alert frame. |
function EnemyScanner2:Clear() |
table.wipe(ES2messages) |
EnemyScanner2:Update() |
end |
-- Working! |
-- Updates the frame to display. |
function EnemyScanner2:Update() |
-- Create enough frames, if necessary. |
row:SetWidth(250) |
row.text:SetFontObject("GameFontNormal") |
row:EnableMouse(false) |
if tonumber(entry.level) then |
local levelcolor = GetQuestDifficultyColor(entry.level) |
local levelcolorhex = DecimalToHex(levelcolor.r,levelcolor.g,levelcolor.b) |
row.text:SetText(entry.name.." "..levelcolorhex..entry.level) |
else |
local levelcolorhex = DecimalToHex(1,0,0) |
row.text:SetText(entry.name.." "..levelcolorhex..entry.level) |
end |
local raidclass = RAID_CLASS_COLORS[entry.class] |
if not raidclass then |
raidclass = {} |
raidclass.r, raidclass.g, raidclass.b = 0.5, 0.5, 0.5 |
end |
-- Color the level by Difficulty |
local levelcolor = GetQuestDifficultyColor(entry.level) |
local levelcolorhex = DecimalToHex(levelcolor.r,levelcolor.g,levelcolor.b) |
row.text:SetText(entry.name.." "..levelcolorhex..entry.level) |
-- if raidclass is known use classcolor, else use gray. |
local raidclass = RAID_CLASS_COLORS[entry.class] and RAID_CLASS_COLORS[entry.class] or { ["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.5,} |
row.text:SetTextColor(raidclass.r, raidclass.g, raidclass.b, 1) |
row:Show() |
end |
end |
end |
-- Initialize the anchor frame. |
EnemyScanner2:Initialize() |
-- Enable the addon by registering all the needed events. |
EnemyScanner2:Enable() |