--[[ ########################################################## S V U I By: S.Jackson ########################################################## 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 assert = _G.assert; local tostring = _G.tostring; local tonumber = _G.tonumber; local collectgarbage = _G.collectgarbage; local tinsert = _G.tinsert; local string = _G.string; local math = _G.math; local table = _G.table; local bit = _G.bit; local time = _G.time; --[[ STRING METHODS ]]-- local format, sub = string.format, string.sub; --[[ MATH METHODS ]]-- local abs, ceil, floor, round, random = math.abs, math.ceil, math.floor, math.round, math.random; --[[ TABLE METHODS ]]-- local tremove, wipe = table.remove, table.wipe; --[[ BINARY METHODS ]]-- local band, bor = bit.band, bit.bor; --BLIZZARD API local CreateFrame = _G.CreateFrame; local InCombatLockdown = _G.InCombatLockdown; local GameTooltip = _G.GameTooltip; local hooksecurefunc = _G.hooksecurefunc; local IsSpellKnown = _G.IsSpellKnown; local GetSpellInfo = _G.GetSpellInfo; local IsAltKeyDown = _G.IsAltKeyDown; local IsShiftKeyDown = _G.IsShiftKeyDown; local IsControlKeyDown = _G.IsControlKeyDown; local IsModifiedClick = _G.IsModifiedClick; local PlaySound = _G.PlaySound; local PlaySoundFile = _G.PlaySoundFile; local UnitName = _G.UnitName; local UnitLevel = _G.UnitLevel; local UnitClass = _G.UnitClass; local UnitExists = _G.UnitExists; local UnitIsUnit = _G.UnitIsUnit; local UnitGUID = _G.UnitGUID; local UnitIsDead = _G.UnitIsDead; local UnitIsPlayer = _G.UnitIsPlayer; local UnitIsFriend = _G.UnitIsFriend; local UnitIsEnemy = _G.UnitIsEnemy; local DoEmote = _G.DoEmote; local SendChatMessage = _G.SendChatMessage; local GetZoneText = _G.GetZoneText; local GetZonePVPInfo = _G.GetZonePVPInfo; local GetRealZoneText = _G.GetRealZoneText; local CombatLog_Object_IsA = _G.CombatLog_Object_IsA; local ERR_NOT_IN_COMBAT = _G.ERR_NOT_IN_COMBAT; local RAID_CLASS_COLORS = _G.RAID_CLASS_COLORS; local CUSTOM_CLASS_COLORS = _G.CUSTOM_CLASS_COLORS; --[[ CONSTANTS ]]-- _G.BINDING_HEADER_SVUIFIGHT = "Supervillain UI: Fight-O-Matic"; _G.BINDING_NAME_SVUIFIGHT_RADIO = "Call Out Incoming"; --[[ ########################################################## GET ADDON DATA ########################################################## ]]-- local SV = _G["SVUI"]; local L = SV.L; local PLUGIN = select(2, ...) local CONFIGS = SV.defaults[PLUGIN.Schema]; local NewHook = hooksecurefunc; local RadioSound = SV.Sounds:Blend("Static", "Sparks"); --[[ ########################################################## GLOBAL SLASH FUNCTIONS ########################################################## ]]-- _G.SVUISayIncoming = function() local subzoneText = GetSubZoneText() local msg = ("{rt8} Incoming %s {rt8}"):format(subzoneText) SendChatMessage(msg, "INSTANCE_CHAT") return end --[[ ########################################################## MUNGLUNCH's FAVORITE EMOTE GENERATOR ########################################################## ]]-- local SpecialEmotes = { "ROFL", "CACKLE", "GIGGLE", "GRIN", "SMIRK", "MOON", "LICK", "YAWN", "FLEX", "TICKLE", "TAUNT", "SHOO", "PRAY", "SPIT", "MOCK", "GLOAT", "PITY", "VIOLIN", "BYE", } local LowHealthPlayerEmotes = { "ROFL", "CACKLE", "GIGGLE", "GRIN", "SMIRK", "MOON", "LICK", "YAWN", "BITE", "NOSEPICK" } local LowHealthTargetEmotes = { "ROFL", "CACKLE", "FLEX", "TICKLE", "TAUNT", "SHOO", "PRAY", "SPIT", "MOCK", "GLOAT", "PITY", "VIOLIN", "BYE", } local KOSEmotes = { "THREATEN", "CRACK", "POINT", "GRIN", "SMIRK", "TAUNT", "CHICKEN" } local StealthEmotes = { "CURIOUS", "EYE", "GASP", "GAZE", "MOCK", "NOSEPICK", "PEER", "POINT", "READY", "STARE", "TAP", } _G.SVUIEmote = function() local index = random(1,#SpecialEmotes) DoEmote(SpecialEmotes[index]) end local function LowHealth_PlayerEmote() local index = random(1,#LowHealthPlayerEmotes) DoEmote(LowHealthPlayerEmotes[index]) end local function LowHealth_TargetEmote() local index = random(1,#LowHealthTargetEmotes) DoEmote(LowHealthTargetEmotes[index]) end local function KOS_Emote() local index = random(1,#KOSEmotes) DoEmote(KOSEmotes[index]) end local function Stealth_Emote(name) local index = random(1,#StealthEmotes) DoEmote(StealthEmotes[index], name) end --[[ ########################################################## CORE FUNCTIONS ########################################################## ]]-- local EnemyCache, AlertedCache = {},{} local playerGUID = UnitGUID('player') local playerFaction = UnitFactionGroup("player") local classColor = RAID_CLASS_COLORS local classColors = CUSTOM_CLASS_COLORS[SV.class] local classR, classG, classB = classColors.r, classColors.g, classColors.b local classA = 0.35 local fallbackColor = {r=1,g=1,b=1} local ACTIVE_ZONE = "" --[[ ICONS ]]-- local INFO_ICON = [[Interface\AddOns\SVUI_FightOMatic\artwork\PVP-INFO]] local UTILITY_ICON = [[Interface\AddOns\SVUI_FightOMatic\artwork\PVP-UTILITIES]] local RADIO_ICON = [[Interface\AddOns\SVUI_FightOMatic\artwork\PVP-RADIO]] local SCANNER_ICON = [[Interface\AddOns\SVUI_FightOMatic\artwork\PVP-SCANNER]] local ICON_FILE = [[Interface\AddOns\SVUI_FightOMatic\artwork\DOCK-PVP]] local PVP_SAFE = [[Interface\AddOns\SVUI_FightOMatic\artwork\PVP-SAFE]] local PVP_HELP = [[Interface\AddOns\SVUI_FightOMatic\artwork\PVP-INCOMING]] local PVP_LOST = [[Interface\WorldMap\Skull_64Red]] local linkString = "|Hplayer:%s:1|h%s|h" --[[ BG MAP DATA ]]-- local PVP_NODES = { [461] = { --Arathi Basin (5) "Stables", "Lumber", "Blacksmith", "Mine", "Farm" }, [935] = { --Deepwind Gorge (3) "Center Mine", "North Mine", "South Mine" }, [482] = { --Eye of the Storm (4) "Fel Reaver", "Blood Elf", "Draenei", "Mage" }, [736] = { --The Battle for Gilneas (3) "LightHouse", "WaterWorks", "Mines" }, } -- local PVP_POI = { -- [401] = { --Alterac Valley (15) -- "Stormpike Aid Station", "Dun Baldar North Bunker", "Dun Baldar South Bunker", -- "Stormpike Graveyard", "Icewing Bunker", "Stonehearth Graveyard", -- "Stonehearth Bunker", "Snowfall Graveyard", "Iceblood Tower", -- "Iceblood Graveyard", "Tower Point", "Frostwolf Graveyard", -- "West Frostwolf Tower", "East Frostwolf Tower", "Frostwolf Relief Hut" -- }, -- [935] = { --Deepwind Gorge (2) -- "Horde Cart", "Alliance Cart" -- }, -- [482] = { --Eye of the Storm (1) -- "Flag" -- }, -- [860] = { --Silvershard Mines (1) -- "Cart" -- }, -- [512] = { --Strand of the Ancients (5) -- "Green Emerald", "Blue Sapphire", "Purple Amethyst", "Red Sun", "Yellow Moon" -- }, -- [540] = { --Isle of Conquest (5) -- "Quarry", "Hangar", "Workshop", "Docks", "Refinery" -- }, -- [856] = { --Temple of Kotmogu (4) -- "Red Orb", "Blue Orb", "Orange Orb", "Purple Orb" -- }, -- [626] = { --Twin Peaks (2) -- "Horde Flag", "Alliance Flag" -- }, -- [443] = { --Warsong Gulch (2) -- "Horde Flag", "Alliance Flag" -- }, -- } local Safe_OnEnter = function(self) if InCombatLockdown() then return end local zone = self.name if(zone and zone ~= "") then self:SetBackdropBorderColor(1,0.45,0) GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT", 0, 4) GameTooltip:ClearLines() GameTooltip:AddLine(("%s Is Safe!"):format(zone), 1, 1, 1) GameTooltip:Show() end end local Safe_OnLeave = function(self) if InCombatLockdown() then return end self:SetBackdropBorderColor(0,0,0) if(GameTooltip:IsShown()) then GameTooltip:Hide() end end local Safe_OnClick = function(self) local zone = self.name if(zone and zone ~= "") then SendChatMessage(("{rt4} %s Is Safe {rt4}"):format(zone), "INSTANCE_CHAT") end end local Help_OnEnter = function(self) if InCombatLockdown() then return end local zone = self.name if(zone and zone ~= "") then self:SetBackdropBorderColor(1,0.45,0) GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT", 0, 4) GameTooltip:ClearLines() GameTooltip:AddLine(("%s Needs Help!"):format(zone), 1, 1, 1) GameTooltip:Show() end end local Help_OnLeave = function(self) if InCombatLockdown() then return end self:SetBackdropBorderColor(0,0,0) if(GameTooltip:IsShown()) then GameTooltip:Hide() end end local Help_OnClick = function(self) if(self.name and self.name ~= "") then local msg = ("{rt8} Incoming %s {rt8}"):format(self.name) SendChatMessage(msg, "INSTANCE_CHAT") end end local function AddEnemyScan(guid, timestamp) if(EnemyCache[guid]) then return EnemyCache[guid] end local class, classToken, race, raceToken, sex, name, realm = GetPlayerInfoByGUID(guid) local colors = classColor[classToken] or fallbackColor EnemyCache[guid] = { ["name"] = name, ["realm"] = realm, ["class"] = class, ["race"] = race, ["sex"] = sex, ["colors"] = colors, ["time"] = timestamp } PLUGIN:ScannerLog(EnemyCache[guid]) return EnemyCache[guid]; end local function SaveEnemyScan(guid, timestamp) local enemy = EnemyCache[guid] if(not enemy) then enemy = AddEnemyScan(guid, timestamp) end PLUGIN.public[guid] = { ["name"] = enemy.name, ["realm"] = enemy.realm, ["class"] = enemy.class, ["race"] = enemy.race, ["sex"] = enemy.sex, ["colors"] = enemy.colors, ["time"] = enemy.timestamp } local msg = ("Killed By: %s"):format(enemy.name); SV:SCTMessage(msg, enemy.colors.r, enemy.colors.g, enemy.colors.b, "sticky"); PLUGIN:UpdateSummary() end local function KilledEnemyHandler(guid) local enemy = PLUGIN.public[guid] if(enemy and enemy.name) then SV:SCTMessage(("Killed Mortal Enemy: %s"):format(enemy.name), 0.2, 1, 0.1, "sticky"); end enemy = EnemyCache[guid] if(enemy) then SV:SCTMessage(("Killed Enemy: %s"):format(enemy.name), 0.1, 0.8, 0); end end local function ClearCacheScans() wipe(EnemyCache) wipe(AlertedCache) if(PLUGIN.LOG and PLUGIN.LOG.Output) then PLUGIN.LOG.Output:Clear() end end local function ClearSavedScans() wipe(PLUGIN.public) end local function EnemyAlarm(name, class, colors, kos) if not name then return end local inInstance, instanceType = IsInInstance() if(instanceType ~= "pvp" and not AlertedCache[name]) then local msg if(kos) then msg = ("Mortal Enemy Detected!: %s"):format(name); SV:SCTMessage(msg, 1, 0, 0) elseif(class and colors) then msg = ("%s Detected"):format(class); SV:SCTMessage(msg, colors.r, colors.g, colors.b) end AlertedCache[name] = true end end local function StealthAlarm(spell, name) local msg = ("%s Detected!"):format(spell); SV:SCTMessage(msg, 1, 0.5, 0); print(("%s has %sed nearby!"):format(name, spell)) if(CONFIGS.annoyingEmotes) then Stealth_Emote(name) end end function PLUGIN:UpdateSummary() self.Summary:Clear(); local stored = self.public; local amount = 0 for _,data in pairs(stored) do if type(data) == "table" and data.name and data.class then amount = amount + 1; end end self.Summary:AddMessage(("You Have |cffff5500%s|r Mortal Enemies"):format(amount), 0.8, 0.8, 0.8); end function PLUGIN:ResetLogs() wipe(EnemyCache) self.Title:Clear(); self.Summary:Clear(); self.LOG.Output:Clear(); self.Title:AddMessage(("Scanning %s"):format(ACTIVE_ZONE), 1, 1, 0); self.Switch:Show() local stored = self.public; local amount = 0 for _,data in pairs(stored) do if type(data) == "table" and data.name and data.class then amount = amount + 1; end end self.Summary:AddMessage(("You Have |cffff5500%s|r Mortal Enemies"):format(amount), 0.8, 0.8, 0.8) collectgarbage("collect") end function PLUGIN:PopulateKOS() self.Title:Clear(); self.Summary:Clear(); self.LOG.Output:Clear(); self.Title:AddMessage(("Scanning %s"):format(ACTIVE_ZONE), 1, 1, 0); self.Switch:Show() local stored = self.public; local amount = 0 for _,data in pairs(stored) do if type(data) == "table" and data.name and data.class and data.race then amount = amount + 1; local nameLink = linkString:format(data.name, data.name) local hex = ("%s - %s %s"):format(nameLink, data.race, data.class) self.LOG.Output:AddMessage(hex, data.colors.r, data.colors.g, data.colors.b); end end self.Summary:AddMessage(("You Have |cffff5500%s|r Mortal Enemies"):format(amount), 0.8, 0.8, 0.8) end function PLUGIN:PopulateScans() self.Title:Clear(); self.Summary:Clear(); self.LOG.Output:Clear(); self.Title:AddMessage(("Scanning %s"):format(ACTIVE_ZONE), 1, 1, 0); self.Switch:Show() local stored = self.public; local amount = 0 for _,data in pairs(stored) do if type(data) == "table" and data.name and data.class then amount = amount + 1; end end self.Summary:AddMessage(("You Have |cffff5500%s|r Mortal Enemies"):format(amount), 0.8, 0.8, 0.8); local hasScans = false; for _,data in pairs(EnemyCache) do if type(data) == "table" and data.name and data.class and data.race then local nameLink = linkString:format(data.name, data.name) local hex = ("%s - %s %s"):format(nameLink, data.race, data.class) self.LOG.Output:AddMessage(hex, data.colors.r, data.colors.g, data.colors.b); hasScans = true; end end end function PLUGIN:PauseScanner() if(not self.InPVP) then self.Title:Clear(); self.Summary:Clear(); self.LOG.Output:Clear(); self.Title:AddMessage("Scanning Paused", 1, 0.1, 0); self.Summary:AddMessage(ACTIVE_ZONE, 1, 0.75, 0); self.Switch:Hide() self.LOG.Output:AddMessage(" ", 1, 1, 1); self.LOG.Output:AddMessage(" ", 1, 1, 1); self.LOG.Output:AddMessage("The Enenmy Scanner Will Resume", 0.8, 0.8, 0.8); self.LOG.Output:AddMessage("When You Leave This BattleGround", 0.8, 0.8, 0.8); else self:PopulateScans() end end function PLUGIN:ScannerLog(enemy) if(not enemy.name or not enemy.race or not enemy.class) then return end local nameLink = linkString:format(enemy.name, enemy.name) local hex = ("%s - %s %s"):format(nameLink, enemy.race, enemy.class) self.LOG.Output:AddMessage(hex, enemy.colors.r, enemy.colors.g, enemy.colors.b); EnemyAlarm(enemy.name, enemy.class, enemy.colors) end function PLUGIN:UpdateCommunicator() self.COMM.Unavailable:Hide() if(self.InPVP) then self.COMM.Unavailable:Show() for i = 1, 5 do local nodeName = ("SVUI_PVPNode%d"):format(i) local node = _G[nodeName] local safe = node.Safe local help = node.Help safe.name = "" help.name = "" node.Text:SetText("") node:Hide() end self.InPVP = nil self:RegisterEvent("UPDATE_BATTLEFIELD_SCORE") self.Scanning = true self:PopulateScans() else local mapID = GetCurrentMapAreaID() if(mapID) then local points = PVP_NODES[mapID] if(points) then for i = 1, 5 do local nodeName = ("SVUI_PVPNode%d"):format(i) local node = _G[nodeName] local safe = node.Safe local help = node.Help if(i <= #points) then local name = points[i] safe.name = name help.name = name node.Text:SetText(name) node:Show() else safe.name = "" help.name = "" node.Text:SetText("") node:Hide() end end self.InPVP = true self:UnregisterEvent("UPDATE_BATTLEFIELD_SCORE") self.Scanning = false self:PauseScanner() end end end end function PLUGIN:UpdateZoneStatus() if PLUGIN.ZoneTimer then return end local zoneText = GetRealZoneText() or GetZoneText() if(not zoneText or zoneText == "") then PLUGIN.ZoneTimer = SV.Timers:ExecuteTimer(PLUGIN.UpdateZoneStatus, 5) return end if(zoneText ~= ACTIVE_ZONE) then ClearCacheScans() ACTIVE_ZONE = zoneText PLUGIN.Title:Clear(); PLUGIN.Title:AddMessage(("Scanning %s"):format(ACTIVE_ZONE), 1, 1, 0); end local zonePvP = GetZonePVPInfo() if(zonePvP == "sanctuary" or zoneText == "") then PLUGIN.Scanning = false else PLUGIN.Scanning = true local inInstance, instanceType = IsInInstance() if(inInstance and ((instanceType == "party") or (instanceType == "raid"))) then PLUGIN.Scanning = false elseif (not zonePvP or (zonePvP == "friendly") or (not UnitIsPVP("player"))) then PLUGIN.Scanning = false elseif(instanceType == "pvp") then PLUGIN:PauseScanner() PLUGIN.Scanning = false if(not PLUGIN.InPVP) then PLUGIN:UpdateCommunicator() end end end PLUGIN.ZoneTimer = nil end local function ParseIncomingLog(timestamp, event, eGuid, eName, pGuid) local cached; local kos, needsUpdate = false, false if(PLUGIN.public[eGuid]) then cached = PLUGIN.public[eGuid] kos = true else cached = EnemyCache[eGuid] end if(cached and cached.time) then needsUpdate = (cached.time + 60) < timestamp; else cached = AddEnemyScan(eGuid, timestamp) needsUpdate = true end if(cached) then if(needsUpdate) then EnemyAlarm(eName, cached.class, cached.colors, kos) cached.time = timestamp end if(pGuid == playerGUID and not AlertedCache[eName]) then AlertedCache[eName] = true local incoming = ("%s Attacking You!"):format(eName); SV:SCTMessage(incoming, 1, 0.05, 0, "crit") end end end local function CheckSourceType(guid, flags) if not guid then return end local isHostile = false; if(flags) then isHostile = CombatLog_Object_IsA(flags, COMBATLOG_FILTER_HOSTILE_PLAYERS) end local srcType = guid:sub(1,6) if((srcType == "Player") and (isHostile == true)) then return true end return false end function PLUGIN:COMBAT_LOG_EVENT_UNFILTERED(_, timestamp, event, _, srcGUID, srcName, srcFlags, sourceRaidFlags, dstGUID, dstName, dstFlags, destRaidFlags, _, spellName) if not srcFlags then return end local flagParse = band(srcFlags, COMBATLOG_OBJECT_REACTION_HOSTILE) local flagged = flagParse == COMBATLOG_OBJECT_REACTION_HOSTILE if(flagged) then if(srcGUID and srcName) then if(CheckSourceType(srcGUID, srcFlags)) then if(event == "SPELL_AURA_APPLIED" and (spellName == L["Stealth"] or spellName == L["Prowl"])) then StealthAlarm(spellName, srcName) end if(dstGUID == playerGUID) then PLUGIN.HitBy = srcGUID end if(not PLUGIN.Scanning) then return end ParseIncomingLog(timestamp, event, srcGUID, srcName, dstGUID) end end if(PLUGIN.Scanning and dstGUID and dstName) then if(CheckSourceType(dstGUID, dstFlags)) then ParseIncomingLog(timestamp, event, dstGUID, dstName, srcGUID) end end end if(PLUGIN.Scanning and event == "PARTY_KILL") then if(srcGUID == playerGUID and dstName) then KilledEnemyHandler(dstGUID) end end end function PLUGIN:EventDistributor(event, ...) local inInstance, instanceType = IsInInstance() if(event == "PLAYER_REGEN_ENABLED") then self.HitBy = false; if(instanceType == "pvp") then self.Scanning = false end else if(instanceType ~= "pvp") then if(event == "PLAYER_TARGET_CHANGED") then if(UnitIsPlayer("target") and UnitIsEnemy("target", "player")) then local guid = UnitGUID("target") if(not EnemyCache[guid]) then local timestamp = time() AddEnemyScan(guid, timestamp) elseif(self.public[guid] and self.public[guid].name) then --SV:SCTMessage("Kill On Sight!", 1, 0, 0, "crit") if(CONFIGS.annoyingEmotes) then KOS_Emote() end end end elseif(event == "PLAYER_DEAD") then local guid = self.HitBy if(guid and guid ~= "") then local stamp = time() SaveEnemyScan(guid, stamp) end end else self.Scanning = false end end end local onMouseWheel = function(self, delta) if (delta > 0) then self:ScrollUp() elseif (delta < 0) then self:ScrollDown() end end local function MakeLogWindow() local frame = CreateFrame("Frame", nil, UIParent) frame:SetFrameStrata("MEDIUM") frame:SetPoint("TOPLEFT", PLUGIN.Summary, "BOTTOMLEFT",0,0) frame:SetPoint("BOTTOMRIGHT", PLUGIN.Docklet, "BOTTOMRIGHT",0,0) frame:SetParent(PLUGIN.Docklet) local output = CreateFrame("ScrollingMessageFrame", nil, frame) output:SetSpacing(4) output:SetClampedToScreen(false) output:SetFrameStrata("MEDIUM") output:SetAllPoints(frame) output:SetFont(SV.media.font.dialog, 11, "OUTLINE") output:SetJustifyH("CENTER") output:SetJustifyV("MIDDLE") output:SetShadowColor(0, 0, 0, 0) output:SetMaxLines(120) output:EnableMouseWheel(true) output:SetHyperlinksEnabled(true) output:SetScript("OnMouseWheel", onMouseWheel) output:SetFading(false) output:SetInsertMode('TOP') output:SetScript("OnHyperlinkEnter", function(self, linkData, link, button) local t = link:explode(":") local name = t[2] or "" SVUI_TargetScanButton:SetAttribute("macrotext", ("/tar %s"):format(name)) SVUI_TargetScanButton:EnableMouse(true) end) frame.Output = output PLUGIN.LOG = frame return PLUGIN.LOG end local function MakeCommWindow() local frame = CreateFrame("Frame", nil, UIParent) frame:SetFrameStrata("MEDIUM") frame:SetPoint("TOPLEFT", PLUGIN.Summary, "BOTTOMLEFT",0,0) frame:SetPoint("BOTTOMRIGHT", PLUGIN.Docklet, "BOTTOMRIGHT",0,0) frame:SetParent(PLUGIN.Docklet) local fallback = CreateFrame("Frame", nil, frame) fallback:SetAllPoints(frame) local fbText = fallback:CreateFontString(nil, "OVERLAY") fbText:SetAllPoints(fallback) fbText:SetFont(SV.media.font.default, 12, "NONE") fbText:SetText("Nothing To Broadcast Right Now") frame.Unavailable = fallback local DOCK_WIDTH = frame:GetWidth() or PLUGIN.Docklet:GetWidth(); local DOCK_HEIGHT = frame:GetHeight() or PLUGIN.Docklet:GetHeight(); local BUTTON_SIZE = (DOCK_HEIGHT * 0.25) - 4; local sectionWidth = 28 local sectionHeight = 22 local iconSize = sectionHeight * 0.5 for i = 1, 5 do local yOffset = (sectionHeight * (i - 1)) + 2 local poiName = ("SVUI_PVPNode%d"):format(i) local poi = CreateFrame("Frame", poiName, frame) poi:SetPoint("TOPLEFT", frame, "TOPLEFT", 2, -yOffset) poi:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -2, -yOffset) poi:SetHeight(22) poi:SetStyle("Transparent") local safe = CreateFrame("Button", nil, poi) safe:SetSize(sectionWidth, sectionHeight) safe:SetPoint("RIGHT", poi, "RIGHT", -2, 0) safe:SetStyle() safe:SetPanelColor("green") local sicon = safe:CreateTexture(nil, "OVERLAY") sicon:SetPoint("CENTER", safe, "CENTER", 0, 0) sicon:SetSize(iconSize,iconSize) sicon:SetTexCoord(0.1, 0.9, 0.1, 0.9) sicon:SetTexture(PVP_SAFE) safe:SetScript("OnEnter", Safe_OnEnter) safe:SetScript("OnLeave", Safe_OnLeave) safe:SetScript("OnClick", Safe_OnClick) poi.Safe = safe local help = CreateFrame("Button", nil, poi) help:SetSize(sectionWidth, sectionHeight) help:SetPoint("RIGHT", safe, "LEFT", -2, 0) help:SetStyle() help:SetPanelColor("red") local hicon = help:CreateTexture(nil, "OVERLAY") hicon:SetPoint("CENTER", help, "CENTER", 0, 0) hicon:SetSize(iconSize,iconSize) hicon:SetTexCoord(0.1, 0.9, 0.1, 0.9) hicon:SetTexture(PVP_HELP) help:SetScript("OnEnter", Help_OnEnter) help:SetScript("OnLeave", Help_OnLeave) help:SetScript("OnClick", Help_OnClick) poi.Help = help poi.Text = poi:CreateFontString(nil,"OVERLAY") poi.Text:SetFont(SV.media.font.default, 12, "NONE") poi.Text:SetPoint("TOPLEFT", poi, "TOPLEFT", 2, 0) poi.Text:SetPoint("BOTTOMRIGHT", help, "BOTTOMLEFT", -2, 0) poi.Text:SetJustifyH("CENTER") poi.Text:SetText("") poi:Hide() end PLUGIN.COMM = frame PLUGIN.COMM:Hide() return PLUGIN.COMM end local function MakeUtilityWindow() local frame = CreateFrame("Frame", nil, UIParent) frame:SetFrameStrata("MEDIUM") frame:SetPoint("TOPLEFT", PLUGIN.Summary, "BOTTOMLEFT",0,0) frame:SetPoint("BOTTOMRIGHT", PLUGIN.Docklet, "BOTTOMRIGHT",0,0) frame:SetParent(PLUGIN.Docklet) local fbText = frame:CreateFontString(nil, "OVERLAY") fbText:SetAllPoints(frame) fbText:SetFont(SV.media.font.default, 12, "NONE") fbText:SetText("Utilities Coming Soon....") PLUGIN.TOOL = frame PLUGIN.TOOL:Hide() return PLUGIN.TOOL end local function MakeInfoWindow() local frame = CreateFrame("Frame", nil, UIParent) frame:SetFrameStrata("MEDIUM") frame:SetPoint("TOPLEFT", PLUGIN.Summary, "BOTTOMLEFT",0,0) frame:SetPoint("BOTTOMRIGHT", PLUGIN.Docklet, "BOTTOMRIGHT",0,0) frame:SetParent(PLUGIN.Docklet) local DATA_WIDTH = (frame:GetWidth() * 0.5) - 2; local DATA_HEIGHT = frame:GetHeight() - 2; local leftColumn = CreateFrame("Frame", "SVUI_FightOMaticInfoLeft", frame) leftColumn:SetSize(DATA_WIDTH, DATA_HEIGHT) leftColumn:SetPoint("LEFT", frame, "LEFT", 0, 0) leftColumn.lockedOpen = true SV.Reports:NewHolder(leftColumn, 3, "ANCHOR_CURSOR", 1, "Transparent") leftColumn:SetFrameLevel(0) local rightColumn = CreateFrame("Frame", "SVUI_FightOMaticInfoRight", frame) rightColumn:SetSize(DATA_WIDTH, DATA_HEIGHT) rightColumn:SetPoint("LEFT", leftColumn, "RIGHT", 2, 0) rightColumn.lockedOpen = true SV.Reports:NewHolder(rightColumn, 3, "ANCHOR_CURSOR", 2, "Transparent") rightColumn:SetFrameLevel(0) PLUGIN.INFO = frame SV.Reports:UpdateAllReports() PLUGIN.INFO:Hide() return PLUGIN.INFO end --[[ ########################################################## DOCK ELEMENT HANDLERS ########################################################## ]]-- local FightOMaticAlert_OnEnter = function(self) if InCombatLockdown() then return; end self:SetBackdropColor(0.9, 0.15, 0.1) GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT", 0, 4) GameTooltip:ClearLines() GameTooltip:AddLine(self.TText, 1, 1, 0) GameTooltip:Show() end local FightOMaticAlert_OnLeave = function(self) GameTooltip:Hide() if InCombatLockdown() then return end self:SetBackdropColor(0.25, 0.52, 0.1) end local FightOMaticAlert_OnHide = function() if InCombatLockdown() then SV:AddonMessage(ERR_NOT_IN_COMBAT); return; end SV.Dock.BottomRight.Alert:Deactivate() end local FightOMaticAlert_OnShow = function(self) if InCombatLockdown() then SV:AddonMessage(ERR_NOT_IN_COMBAT); self:Hide() return; end self:FadeIn(0.3, 0, 1) SV.Dock.BottomRight.Alert:Activate(self) end local FightOMaticAlert_OnMouseDown = function(self) -- DO STUFF self:FadeOut(0.5, 1, 0, true) end local FightOMaticTool_OnEnter = function(self) if InCombatLockdown() then return; end self.icon:SetGradient(unpack(SV.media.gradient.yellow)) GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT", 0, 4) GameTooltip:ClearLines() GameTooltip:AddLine(self.TText, 1, 1, 1) GameTooltip:Show() end local FightOMaticTool_OnLeave = function(self) if InCombatLockdown() then return; end self.icon:SetGradient("VERTICAL", 0.5, 0.53, 0.55, 0.8, 0.8, 1) GameTooltip:Hide() end local FightOMaticTool_OnMouseDown = function(self) RadioSound() PLUGIN.LOG:FadeOut(0.5, 1, 0, true) PLUGIN.COMM:FadeOut(0.5, 1, 0, true) PLUGIN.TOOL:FadeOut(0.5, 1, 0, true) PLUGIN.INFO:FadeOut(0.5, 1, 0, true) self.Window:FadeIn(0.3, 0, 1) PLUGIN.Title:Clear(); PLUGIN.Title:AddMessage(self.TTitle, 1, 1, 0); end local Scanner_OnMouseDown = function(self) RadioSound() PLUGIN.LOG:FadeOut(0.5, 1, 0, true) PLUGIN.COMM:FadeOut(0.5, 1, 0, true) PLUGIN.TOOL:FadeOut(0.5, 1, 0, true) PLUGIN.INFO:FadeOut(0.5, 1, 0, true) self.Window:FadeIn(0.3, 0, 1) PLUGIN:PopulateScans() end local Switch_OnEnter = function(self) GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT", 0, 4) GameTooltip:ClearLines() if(self.ShowingKOS) then GameTooltip:AddDoubleLine("Click", "Show Scan List", 0.1, 1, 0.2, 1, 1, 1) else GameTooltip:AddDoubleLine("Click", 'Show "Kill On Sight" List', 0.1, 1, 0.2, 1, 1, 1) end GameTooltip:AddDoubleLine("[SHIFT] Click", "Clear All Scans", 0.1, 1, 0.2, 1, 1, 1) GameTooltip:AddDoubleLine("[CTRL] Click", 'Clear All "Kill On Sight"', 0.1, 1, 0.2, 1, 1, 1) GameTooltip:Show() end local Switch_OnLeave = function(self) GameTooltip:Hide() end local Switch_OnClick = function(self, button) Switch_OnLeave(self) if(IsControlKeyDown()) then ClearSavedScans() PLUGIN:ResetLogs() elseif(IsShiftKeyDown()) then ClearCacheScans() else if(self.ShowingKOS) then PLUGIN:PopulateScans() self.ShowingKOS = false else PLUGIN:PopulateKOS() self.ShowingKOS = true end end Switch_OnEnter(self) end --[[ ########################################################## BUILD FUNCTION ########################################################## ]]-- function PLUGIN:Load() CONFIGS = SV.db[self.Schema]; self.public = self.public or {} local ALERT_HEIGHT = 60; local DOCK_WIDTH = SV.Dock.BottomRight.Window:GetWidth(); local DOCK_HEIGHT = SV.Dock.BottomRight.Window:GetHeight(); local BUTTON_SIZE = (DOCK_HEIGHT * 0.25) - 4; self.HitBy = false; self.Scanning = false; self.InPVP = false self.Docklet = SV.Dock:NewDocklet("BottomRight", "SVUI_FightOMaticDock", self.TitleID, ICON_FILE) local toolBar = CreateFrame("Frame", "SVUI_FightOMaticToolBar", self.Docklet) toolBar:SetWidth(BUTTON_SIZE + 4); toolBar:SetHeight((BUTTON_SIZE + 4) * 4); toolBar:SetPoint("BOTTOMLEFT", self.Docklet, "BOTTOMLEFT", 0, 0); local tbDivider = toolBar:CreateTexture(nil,"OVERLAY") tbDivider:SetTexture(0,0,0,0.5) tbDivider:SetPoint("TOPRIGHT") tbDivider:SetPoint("BOTTOMRIGHT") tbDivider:SetWidth(1) local title = CreateFrame("ScrollingMessageFrame", nil, self.Docklet) title:SetSpacing(4) title:SetClampedToScreen(false) title:SetFrameStrata("MEDIUM") title:SetPoint("TOPLEFT", toolBar, "TOPRIGHT",0,0) title:SetPoint("BOTTOMRIGHT", self.Docklet, "TOPRIGHT",0,-20) title:SetFontObject(SVUI_Font_Header) title:SetMaxLines(1) title:EnableMouseWheel(false) title:SetFading(false) title:SetInsertMode('TOP') local divider1 = title:CreateTexture(nil,"OVERLAY") divider1:SetTexture(0,0,0,0.5) divider1:SetPoint("BOTTOMLEFT") divider1:SetPoint("BOTTOMRIGHT") divider1:SetHeight(1) self.Title = title local listbutton = CreateFrame("Button", nil, self.Docklet) listbutton:SetPoint("TOPLEFT", title, "BOTTOMLEFT",0,0) listbutton:SetPoint("BOTTOMRIGHT", title, "BOTTOMRIGHT",0,-14) listbutton:SetStyle("Lite") listbutton.ShowingKOS = false listbutton:SetScript("OnEnter", Switch_OnEnter) listbutton:SetScript("OnLeave", Switch_OnLeave) listbutton:SetScript("OnClick", Switch_OnClick) self.Switch = listbutton local summary = CreateFrame("ScrollingMessageFrame", nil, self.Docklet) summary:SetSpacing(4) summary:SetClampedToScreen(false) summary:SetFrameStrata("MEDIUM") summary:SetPoint("TOPLEFT", title, "BOTTOMLEFT",0,0) summary:SetPoint("BOTTOMRIGHT", title, "BOTTOMRIGHT",0,-14) summary:SetFontObject(SVUI_Font_Default) summary:SetMaxLines(1) summary:EnableMouse(false) summary:SetFading(false) summary:SetInsertMode('TOP') self.Summary = summary local divider2 = summary:CreateTexture(nil,"OVERLAY") divider2:SetTexture(0,0,0,0.5) divider2:SetPoint("BOTTOMLEFT") divider2:SetPoint("BOTTOMRIGHT") divider2:SetHeight(1) local tool4 = CreateFrame("Frame", "SVUI_FightOMaticTool4", toolBar) tool4:SetPoint("BOTTOM",toolBar,"BOTTOM",0,0) tool4:SetSize(BUTTON_SIZE,BUTTON_SIZE) tool4.icon = tool4:CreateTexture(nil, 'OVERLAY') tool4.icon:SetTexture(INFO_ICON) tool4.icon:InsetPoints(tool4) tool4.icon:SetGradient("VERTICAL", 0.5, 0.53, 0.55, 0.8, 0.8, 1) tool4.TText = "Stats" tool4.TTitle = "Statistics and Information" tool4:SetScript('OnEnter', FightOMaticTool_OnEnter) tool4:SetScript('OnLeave', FightOMaticTool_OnLeave) tool4:SetScript('OnMouseDown', FightOMaticTool_OnMouseDown) tool4.Window = MakeInfoWindow() local tool3 = CreateFrame("Frame", "SVUI_FightOMaticTool3", toolBar) tool3:SetPoint("BOTTOM",tool4,"TOP",0,2) tool3:SetSize(BUTTON_SIZE,BUTTON_SIZE) tool3.icon = tool3:CreateTexture(nil, 'OVERLAY') tool3.icon:SetTexture(UTILITY_ICON) tool3.icon:InsetPoints(tool3) tool3.icon:SetGradient("VERTICAL", 0.5, 0.53, 0.55, 0.8, 0.8, 1) tool3.TText = "Tools" tool3.TTitle = "Tools and Utilities" tool3:SetScript('OnEnter', FightOMaticTool_OnEnter) tool3:SetScript('OnLeave', FightOMaticTool_OnLeave) tool3:SetScript('OnMouseDown', FightOMaticTool_OnMouseDown) tool3.Window = MakeUtilityWindow() local tool2 = CreateFrame("Frame", "SVUI_FightOMaticTool2", toolBar) tool2:SetPoint("BOTTOM",tool3,"TOP",0,2) tool2:SetSize(BUTTON_SIZE,BUTTON_SIZE) tool2.icon = tool2:CreateTexture(nil, 'OVERLAY') tool2.icon:SetTexture(RADIO_ICON) tool2.icon:InsetPoints(tool2) tool2.icon:SetGradient("VERTICAL", 0.5, 0.53, 0.55, 0.8, 0.8, 1) tool2.TText = "Radio" tool2.TTitle = "Radio Communicator" tool2:SetScript('OnEnter', FightOMaticTool_OnEnter) tool2:SetScript('OnLeave', FightOMaticTool_OnLeave) tool2:SetScript('OnMouseDown', FightOMaticTool_OnMouseDown) tool2.Window = MakeCommWindow() local tool1 = CreateFrame("Frame", "SVUI_FightOMaticTool1", toolBar) tool1:SetPoint("BOTTOM",tool2,"TOP",0,2) tool1:SetSize(BUTTON_SIZE,BUTTON_SIZE) tool1.icon = tool1:CreateTexture(nil, 'OVERLAY') tool1.icon:SetTexture(SCANNER_ICON) tool1.icon:InsetPoints(tool1) tool1.icon:SetGradient("VERTICAL", 0.5, 0.53, 0.55, 0.8, 0.8, 1) tool1.TText = "Scanner" tool1.TTitle = "Enemy Scanner" tool1:SetScript('OnEnter', FightOMaticTool_OnEnter) tool1:SetScript('OnLeave', FightOMaticTool_OnLeave) tool1:SetScript('OnMouseDown', Scanner_OnMouseDown) tool1.Window = MakeLogWindow() --self.Docklet:Hide() self:ResetLogs() local targetButton = CreateFrame("Button", "SVUI_TargetScanButton", UIParent, "SecureActionButtonTemplate") targetButton:SetAllPoints(self.LOG) targetButton:SetFrameLevel(99) targetButton:RegisterForClicks("AnyUp") targetButton:SetAttribute("type1", "macro") targetButton:SetAttribute("macrotext", "/tar") targetButton:EnableMouse(false) targetButton:HookScript("OnClick", function(this) this:EnableMouse(false) end) self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") self:RegisterEvent("PLAYER_TARGET_CHANGED", "EventDistributor") self:RegisterEvent("PLAYER_REGEN_ENABLED", "EventDistributor") self:RegisterEvent("PLAYER_DEAD", "EventDistributor") self:RegisterEvent("ZONE_CHANGED", "UpdateZoneStatus") self:RegisterEvent("ZONE_CHANGED_NEW_AREA", "UpdateZoneStatus") self:RegisterEvent("UNIT_FACTION", "UpdateZoneStatus") self:RegisterEvent("PLAYER_ENTERING_WORLD", "UpdateCommunicator") self:RegisterEvent("UPDATE_BATTLEFIELD_SCORE", "UpdateCommunicator") if(CONFIGS.annoyingEmotes) then SVUI_Player.Health.LowAlertFunc = LowHealth_PlayerEmote SVUI_Target.Health.LowAlertFunc = LowHealth_TargetEmote end end