Skip to content

Instantly share code, notes, and snippets.

@addohm
Created May 8, 2020 01:04
Show Gist options
  • Save addohm/8be9821d4aeb93ee533399fa881f5883 to your computer and use it in GitHub Desktop.
Save addohm/8be9821d4aeb93ee533399fa881f5883 to your computer and use it in GitHub Desktop.
Updated NWB so that when a head drop happens, a sound plays.
--------------------
--Nova World Buffs--
--Classic WoW world buff timers and pre warnings.
--Novaspark-Arugal OCE (classic).
--https://www.curseforge.com/members/venomisto/projects
--Note: Server restarts will cause the timers to be inaccurate because the NPC's reset.
NWB = LibStub("AceAddon-3.0"):NewAddon("NovaWorldBuffs", "AceComm-3.0");
NWB.dragonLib = LibStub("HereBeDragons-2.0");
NWB.dragonLibPins = LibStub("HereBeDragons-Pins-2.0");
NWB.commPrefix = "NWB";
NWB.hasAddon = {};
NWB.realm = GetRealmName();
NWB.faction = UnitFactionGroup("player");
NWB.loadTime = 0;
--Can limit new layers created here, Blizzard have stated only 2 layers per realm.
--I can set this to 2 so only the first 2 layers after restart show up as a last ditch fix if needed.
--It's not a good solution though because the old layers still exist in database after restarts until the timers expire.
NWB.limitLayerCount = 99;
local L = LibStub("AceLocale-3.0"):GetLocale("NovaWorldBuffs");
local Serializer = LibStub:GetLibrary("AceSerializer-3.0");
local version = GetAddOnMetadata("NovaWorldBuffs", "Version") or 9999;
NWB.latestRemoteVersion = version;
function NWB:OnInitialize()
self:setLayered();
self:setLayerLimit();
self:loadSpecificOptions();
self.db = LibStub("AceDB-3.0"):New("NWBdatabase", NWB.optionDefaults, "Default");
LibStub("AceConfig-3.0"):RegisterOptionsTable("NovaWorldBuffs", NWB.options);
self.NWBOptions = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("NovaWorldBuffs", "NovaWorldBuffs");
self.chatColor = "|cff" .. self:RGBToHex(self.db.global.chatColorR, self.db.global.chatColorG, self.db.global.chatColorB);
self:RegisterComm(self.commPrefix);
self.loadTime = GetServerTime();
self:registerOtherAddons();
self:buildRealmFactionData();
self:setRegionFont();
self:timerCleanup();
self:setSongFlowers();
self:createSongflowerMarkers();
self:createTuberMarkers();
self:createDragonMarkers();
self:refreshFelwoodMarkers();
self:createWorldbuffMarkersTable();
self:createWorldbuffMarkers();
self:getDmfData();
self:createDmfMarkers();
self:resetSongFlowers();
self:resetLayerData();
self:removeOldLayers();
self:ticker();
self:yellTicker();
end
--Set font used in fontstrings on frames.
NWB.regionFont = "Fonts\\ARIALN.ttf";
function NWB:setRegionFont()
if (LOCALE_koKR) then
NWB.regionFont = "Fonts\\2002.TTF";
elseif (LOCALE_zhCN) then
NWB.regionFont = "Fonts\\ARKai_T.ttf";
elseif (LOCALE_zhTW) then
NWB.regionFont = "Fonts\\blei00d.TTF";
elseif (LOCALE_ruRU) then
--ARIALN seems to work in RU.
--NWB.regionFont = "Fonts\\FRIZQT___CYR.TTF";
end
end
local foundPartner; --Debug testing.
function NWB:OnCommReceived(commPrefix, string, distribution, sender)
if (distribution == "GUILD" and commPrefix == NWB.commPrefix) then
--Temp bug test.
local tempSender = sender;
if (not string.match(tempSender, "-")) then
tempSender = tempSender .. "-" .. GetNormalizedRealmName();
end
NWB.hasAddon[tempSender] = "0";
end
if (UnitInBattleground("player") and distribution ~= "GUILD") then
return;
end
--AceComm doesn't supply realm name if it's on the same realm as player.
--Not sure if it provives GetRealmName() or GetNormalizedRealmName() for crossrealm.
--For now we'll check all 3 name types just to be sure until tested.
local me = UnitName("player") .. "-" .. GetRealmName();
local meNormalized = UnitName("player") .. "-" .. GetNormalizedRealmName();
if (sender == UnitName("player") or sender == me or sender == meNormalized) then
NWB.hasAddon[meNormalized] = version;
return;
end
local _, realm = strsplit("-", sender, 2);
--If realm found then it's not my realm, but just incase acecomm changes and starts supplying realm also check if realm exists.
if (realm ~= nil or (realm and realm ~= GetRealmName() and realm ~= GetNormalizedRealmName())) then
--Ignore data from other realms (in bgs).
return;
end
if (commPrefix == "D4C") then
--Parse DBM.
NWB:parseDBM(commPrefix, string, distribution, sender);
return;
end
--If no realm in name it must be our realm so add it.
if (not string.match(sender, "-")) then
--Add normalized realm since roster checks use this.
sender = sender .. "-" .. GetNormalizedRealmName();
end
--Keep a list of addon users for use in NWB:sendGuildMsg().
if (distribution == "GUILD") then
foundPartner = true;
end
local deserializeResult, deserialized = Serializer:Deserialize(string);
if (not deserializeResult) then
NWB:debug("Error deserializing:", string);
return;
end
local args = NWB:explode(" ", deserialized, 2);
local cmd = args[1]; --Cmd (first arg) so we know where to send the data.
local remoteVersion = args[2]; --Version number.
local data = args[3]; --Data (everything after version arg).
if (data == nil) then
--Temp fix for people with old version data structure sending incompatable data.
--Only effects a few of the early testers.
data = args[2]; --Data (everything after version arg).
remoteVersion = 0;
end
NWB.hasAddon[sender] = remoteVersion or "0";
--if (commPrefix == "NWB") then
--NWB:debug("received", commPrefix, distribution, sender, cmd);
--end
if (not tonumber(remoteVersion)) then
--Trying to catch a lua error and find out why.
NWB:debug("version missing", sender, cmd, data);
return;
end
--Some updates requite ignoring old versions.
if (tonumber(remoteVersion) < 1.49) then
if (cmd == "requestData" and distribution == "GUILD") then
NWB:sendData("GUILD");
end
return;
end
if (cmd == "data" or cmd == "settings") then
NWB:receivedData(data, sender, distribution);
elseif (cmd == "requestData") then
--Other addon users request data when they log on.
NWB:receivedData(data, sender, distribution);
NWB:sendData("GUILD");
elseif (cmd == "requestSettings") then
--Only used once per logon.
NWB:receivedData(data, sender, distribution);
NWB:sendSettings("GUILD");
elseif (cmd == "yell" and not (NWB.db.global.receiveGuildDataOnly and distribution ~= "GUILD")) then
NWB:debug("yell inc", sender, data);
--Yell msg seen by someone in org.
NWB:doFirstYell(data);
elseif (cmd == "drop" and not (NWB.db.global.receiveGuildDataOnly and distribution ~= "GUILD")) then
NWB:debug("drop inc", sender, data);
--Buff drop seen by someone in org.
NWB:doBuffDropMsg(data);
elseif (cmd == "npcKilled" and not (NWB.db.global.receiveGuildDataOnly and distribution ~= "GUILD")) then
NWB:debug("npc killed inc", sender, data);
--Npc killed seen by someone in org.
NWB:doNpcKilledMsg(data);
elseif (cmd == "flower" and not (NWB.db.global.receiveGuildDataOnly and distribution ~= "GUILD")) then
NWB:debug("flower inc", sender, data);
--Flower picked.
NWB:doFlowerMsg(data);
end
NWB:versionCheck(remoteVersion);
end
--Send to specified addon channel.
function NWB:sendComm(distribution, string, target)
--if (NWB.isDebug and (UnitName("player") == "Exoblast" or UnitName("player") == "Novaspark")) then
-- return;
--end
if (target == UnitName("player")) then
return;
end
if (distribution == "GUILD" and not IsInGuild()) then
return;
end
if (distribution == "CHANNEL") then
--Get channel ID number.
local addonChannelId = GetChannelName(target);
--Not sure why this only accepts a string and not an int.
--Addon channels are disabled in classic but I'll leave this here anyway.
target = tostring(addonChannelId);
elseif (distribution ~= "WHISPER") then
target = nil;
end
--if (NWB.isDebug) then
-- local cmd = string:match("(%w+)(.+)");
-- NWB:debug("send", distribution, target, cmd);
--end
local serialized = Serializer:Serialize(string);
NWB:SendCommMessage(NWB.commPrefix, serialized, distribution, target);
end
--Send full data.
function NWB:sendData(distribution, target, prio)
if (not prio) then
prio = "NORMAL";
end
local data;
if (NWB.isLayered) then
data = NWB:createDataLayered(distribution);
else
data = NWB:createData(distribution);
end
if (next(data) ~= nil) then
if (distribution == "YELL") then
--We only send 1 yell msg every few minutes but it can still give the error msg in chat if many people are close.
--Not sure why it does this when we only send 1 single msg (possibly just loops through all players on blizz end?).
C_Timer.After(15, function()
NWB.doFilterAddonChatMsg = false;
end)
NWB.doFilterAddonChatMsg = true;
end
data = Serializer:Serialize(data);
NWB:sendComm(distribution, "data " .. version .. " " .. data, target, prio);
end
end
--Send settings only.
function NWB:sendSettings(distribution, target, prio)
if (UnitInBattleground("player") and distribution ~= "GUILD") then
return data;
end
if (not prio) then
prio = "NORMAL";
end
local data = NWB:createSettings(distribution);
if (next(data) ~= nil) then
data = Serializer:Serialize(data);
NWB:sendComm(distribution, "settings " .. version .. " " .. data, target, prio);
end
end
--Send first yell msg.
function NWB:sendYell(distribution, type, target)
NWB:sendComm(distribution, "yell " .. version .. " " .. type, target);
end
--Send npc killed msg.
function NWB:sendNpcKilled(distribution, type, target)
NWB:sendComm(distribution, "npcKilled " .. version .. " " .. type, target);
end
--Send flower msg.
function NWB:sendFlower(distribution, type, target)
NWB:debug("sending flower");
NWB:sendComm(distribution, "flower " .. version .. " " .. type, target);
end
--Send first yell msg.
function NWB:sendBuffDropped(distribution, type, target, layer)
if (tonumber(layer)) then
NWB:sendComm(distribution, "drop " .. version .. " " .. type .. " " .. layer, target);
else
NWB:sendComm(distribution, "drop " .. version .. " " .. type, target);
end
end
--Send full data and also request other users data back, used at logon time.
function NWB:requestData(distribution, target, prio)
if (not prio) then
prio = "NORMAL";
end
local data;
if (NWB.isLayered) then
data = NWB:createDataLayered(distribution);
else
data = NWB:createData(distribution);
end
data = Serializer:Serialize(data);
NWB:sendComm(distribution, "requestData " .. version .. " " .. data, target, prio);
end
--Send full data and also request other users data back, used at logon time.
function NWB:requestSettings(distribution, target, prio)
if (not prio) then
prio = "NORMAL";
end
local data = NWB:createSettings(distribution);
data = Serializer:Serialize(data);
NWB:sendComm(distribution, "requestSettings " .. version .. " " .. data, target, prio);
end
--Create data table for sending.
function NWB:createData(distribution)
local data = {};
if (UnitInBattleground("player") and distribution ~= "GUILD") then
return data;
end
if (NWB.data.rendTimer > (GetServerTime() - NWB.db.global.rendRespawnTime)) then
data['rendTimer'] = NWB.data.rendTimer;
data['rendTimerWho'] = NWB.data.rendTimerWho;
data['rendYell'] = NWB.data.rendYell or 0;
data['rendYell2'] = NWB.data.rendYell2 or 0;
data['rendSource'] = NWB.data.rendSource;
end
if (NWB.data.onyTimer > (GetServerTime() - NWB.db.global.onyRespawnTime)) then
data['onyTimer'] = NWB.data.onyTimer;
data['onyTimerWho'] = NWB.data.onyTimerWho;
data['onyYell'] = NWB.data.onyYell or 0;
data['onyYell2'] = NWB.data.onyYell2 or 0;
data['onySource'] = NWB.data.onySource;
end
if (NWB.data.nefTimer > (GetServerTime() - NWB.db.global.nefRespawnTime)) then
data['nefTimer'] = NWB.data.nefTimer;
data['nefTimerWho'] = NWB.data.nefTimerWho;
data['nefYell'] = NWB.data.nefYell or 0;
data['nefYell2'] = NWB.data.nefYell2 or 0;
data['nefSource'] = NWB.data.nefSource;
end
--[[if (NWB.data.zanTimer > (GetServerTime() - NWB.db.global.zanRespawnTime)) then
data['zanTimer'] = NWB.data.zanTimer;
data['zanTimerWho'] = NWB.data.zanTimerWho;
data['zanYell'] = NWB.data.zanYell or 0;
data['zanYell2'] = NWB.data.zanYell2 or 0;
data['zanSource'] = NWB.data.zanSource;
end]]
if ((NWB.data.onyNpcDied > NWB.data.onyTimer) and
(NWB.data.onyNpcDied > (GetServerTime() - NWB.db.global.onyRespawnTime))) then
data['onyNpcDied'] = NWB.data.onyNpcDied;
end
if ((NWB.data.nefNpcDied > NWB.data.nefTimer) and
(NWB.data.nefNpcDied > (GetServerTime() - NWB.db.global.nefRespawnTime))) then
data['nefNpcDied'] = NWB.data.nefNpcDied;
end
for k, v in pairs(NWB.songFlowers) do
--Add currently active songflower timers.
if (NWB.data[k] > GetServerTime() - 1500) then
data[k] = NWB.data[k];
end
end
for k, v in pairs(NWB.tubers) do
--Add currently active songflower timers.
if (NWB.data[k] > GetServerTime() - 1500) then
data[k] = NWB.data[k];
end
end
for k, v in pairs(NWB.dragons) do
--Add currently active songflower timers.
if (NWB.data[k] > GetServerTime() - 1500) then
data[k] = NWB.data[k];
end
end
for k, v in pairs(NWB.dragons) do
--Add currently active songflower timers.
if (NWB.data[k] > GetServerTime() - 1500) then
data[k] = NWB.data[k];
end
end
if (distribution == "GUILD") then
--Include settings with timer data for guild.
local settings = NWB:createSettings(distribution);
local me = UnitName("player") .. "-" .. GetNormalizedRealmName();
data[me] = settings[me];
end
--data['faction'] = NWB.faction;
return data;
end
local lastSendLayerMap = {};
function NWB:createDataLayered(distribution)
local data = {};
if (UnitInBattleground("player") and distribution ~= "GUILD") then
return data;
end
if (not lastSendLayerMap[distribution]) then
lastSendLayerMap[distribution] = 0;
end
local sendLayerMap;
if ((GetServerTime() - lastSendLayerMap[distribution]) > 540 or NWB.isDebug or distribution == "GUILD") then
--Only send layermap info once per 10mins, this data won't change much except right after a server restart.
--So there's no need to use the addon bandwidth every time we send, 540 seconds should be every 2rd yell.
sendLayerMap = true;
end
for layer, v in NWB:pairsByKeys(NWB.data.layers) do
if (NWB.data.layers[layer].rendTimer > (GetServerTime() - NWB.db.global.rendRespawnTime)) then
--Only create layers table if we have valid timers so we don't waste addon bandwidth with useless data.
--This was always done on non-layered realms but wasn't working right on layered realms, now it is.
--The data table is checked for empty when sending comms.
if (not data.layers) then
data.layers = {};
end
if (not data.layers[layer]) then
data.layers[layer] = {};
end
data.layers[layer]['rendTimer'] = NWB.data.layers[layer].rendTimer;
data.layers[layer]['rendTimerWho'] = NWB.data.layers[layer].rendTimerWho;
data.layers[layer]['rendYell'] = NWB.data.layers[layer].rendYell;
data.layers[layer]['rendYell2'] = NWB.data.layers[layer].rendYell2;
data.layers[layer]['rendSource'] = NWB.data.layers[layer].rendSource;
if (NWB.data.layers[layer].GUID) then
data.layers[layer]['GUID'] = NWB.data.layers[layer].GUID;
end
end
if (NWB.data.layers[layer].onyTimer > (GetServerTime() - NWB.db.global.onyRespawnTime)) then
if (not data.layers) then
data.layers = {};
end
if (not data.layers[layer]) then
data.layers[layer] = {};
end
data.layers[layer]['onyTimer'] = NWB.data.layers[layer].onyTimer;
data.layers[layer]['onyTimerWho'] = NWB.data.layers[layer].onyTimerWho;
data.layers[layer]['onyYell'] = NWB.data.layers[layer].onyYell;
data.layers[layer]['onyYell2'] = NWB.data.layers[layer].onyYell2;
data.layers[layer]['onySource'] = NWB.data.layers[layer].onySource;
if (NWB.data.layers[layer].GUID) then
data.layers[layer]['GUID'] = NWB.data.layers[layer].GUID;
end
end
if (NWB.data.layers[layer].nefTimer > (GetServerTime() - NWB.db.global.nefRespawnTime)) then
if (not data.layers) then
data.layers = {};
end
if (not data.layers[layer]) then
data.layers[layer] = {};
end
data.layers[layer]['nefTimer'] = NWB.data.layers[layer].nefTimer;
data.layers[layer]['nefTimerWho'] = NWB.data.layers[layer].nefTimerWho;
data.layers[layer]['nefYell'] = NWB.data.layers[layer].nefYell;
data.layers[layer]['nefYell2'] = NWB.data.layers[layer].nefYell2;
data.layers[layer]['nefSource'] = NWB.data.layers[layer].nefSource;
if (NWB.data.layers[layer].GUID) then
data.layers[layer]['GUID'] = NWB.data.layers[layer].GUID;
end
end
if ((NWB.data.layers[layer].onyNpcDied > NWB.data.layers[layer].onyTimer) and
(NWB.data.layers[layer].onyNpcDied > (GetServerTime() - NWB.db.global.onyRespawnTime))) then
if (not data.layers) then
data.layers = {};
end
if (not data.layers[layer]) then
data.layers[layer] = {};
end
data.layers[layer]['onyNpcDied'] = NWB.data.layers[layer].onyNpcDied;
if (NWB.data.layers[layer].GUID) then
data.layers[layer]['GUID'] = NWB.data.layers[layer].GUID;
end
end
if ((NWB.data.layers[layer].nefNpcDied > NWB.data.layers[layer].nefTimer) and
(NWB.data.layers[layer].nefNpcDied > (GetServerTime() - NWB.db.global.nefRespawnTime))) then
if (not data.layers) then
data.layers = {};
end
if (not data.layers[layer]) then
data.layers[layer] = {};
end
data.layers[layer]['nefNpcDied'] = NWB.data.layers[layer].nefNpcDied;
if (NWB.data.layers[layer].GUID) then
data.layers[layer]['GUID'] = NWB.data.layers[layer].GUID;
end
end
if (sendLayerMap) then
if (NWB.data.layers[layer].layerMap and next(NWB.data.layers[layer].layerMap)) then
lastSendLayerMap[distribution] = GetServerTime();
if (not data.layers) then
data.layers = {};
end
if (not data.layers[layer]) then
data.layers[layer] = {};
end
--NWB:debug("sending layer map data", distribution);
data.layers[layer].layerMap = NWB.data.layers[layer].layerMap;
--Don't share created time for now.
data.layers[layer].layerMap.created = nil;
end
end
end
for k, v in pairs(NWB.songFlowers) do
--Add currently active songflower timers.
if (NWB.data[k] > GetServerTime() - 1500) then
data[k] = NWB.data[k];
end
end
for k, v in pairs(NWB.tubers) do
--Add currently active songflower timers.
if (NWB.data[k] > GetServerTime() - 1500) then
data[k] = NWB.data[k];
end
end
for k, v in pairs(NWB.dragons) do
--Add currently active songflower timers.
if (NWB.data[k] > GetServerTime() - 1500) then
data[k] = NWB.data[k];
end
end
for k, v in pairs(NWB.dragons) do
--Add currently active songflower timers.
if (NWB.data[k] > GetServerTime() - 1500) then
data[k] = NWB.data[k];
end
end
if (distribution == "GUILD") then
--Include settings with timer data for guild.
local settings = NWB:createSettings(distribution);
local me = UnitName("player") .. "-" .. GetNormalizedRealmName();
data[me] = settings[me];
end
--data['faction'] = NWB.faction;
return data;
end
--Create settings for sending.
function NWB:createSettings(distribution)
local data = {};
if (UnitInBattleground("player") and distribution ~= "GUILD") then
return data;
end
if (distribution == "GUILD") then
local me = UnitName("player") .. "-" .. GetNormalizedRealmName();
data[me] = {
["lastUpdate"] = GetServerTime(),
["disableAllGuildMsgs"] = NWB.db.global.disableAllGuildMsgs,
["guildBuffDropped"] = NWB.db.global.guildBuffDropped,
["guildNpcDialogue"] = NWB.db.global.guildNpcDialogue,
["guildZanDialogue"] = NWB.db.global.guildZanDialogue,
["guildNpcKilled"] = NWB.db.global.guildNpcKilled,
["guildSongflower"] = NWB.db.global.guildSongflower,
["guildCommand"] = NWB.db.global.guildCommand,
["guild30"] = NWB.db.global.guild30,
["guild15"] = NWB.db.global.guild15,
["guild10"] = NWB.db.global.guild10,
["guild5"] = NWB.db.global.guild5,
["guild1"] = NWB.db.global.guild1,
["guild0"] = NWB.db.global.guild0,
};
end
data['faction'] = NWB.faction;
return data;
end
local validKeys = {
["rendTimer"] = true,
["rendTimerWho"] = true,
["rendYell"] = true,
["rendYell2"] = true,
["rendSource"] = true,
["onyTimer"] = true,
["onyTimerWho"] = true,
["onyYell"] = true,
["onyYell2"] = true,
["onySource"] = true,
["onyNpcDied"] = true,
["nefTimer"] = true,
["nefTimerWho"] = true,
["nefYell"] = true,
["nefYell2"] = true,
["nefSource"] = true,
["nefNpcDied"] = true,
["zanTimer"] = true,
["zanTimerWho"] = true,
["zanYell"] = true,
["zanYell2"] = true,
["zanSource"] = true,
["flower1"] = true,
["flower2"] = true,
["flower3"] = true,
["flower4"] = true,
["flower5"] = true,
["flower6"] = true,
["flower7"] = true,
["flower8"] = true,
["flower9"] = true,
["flower10"] = true,
["tuber1"] = true,
["tuber2"] = true,
["tuber3"] = true,
["tuber4"] = true,
["tuber5"] = true,
["tuber6"] = true,
["dragon1"] = true,
["dragon2"] = true,
["dragon3"] = true,
["dragon4"] = true,
["faction"] = true,
["GUID"] = true,
};
--Add received data to our database.
--This is super ugly for layered stuff, but it's meant to work with all diff versions at once, will be cleaned up later.
function NWB:receivedData(data, sender, distribution)
local deserializeResult, data = Serializer:Deserialize(data);
if (not deserializeResult) then
NWB:debug("Failed to deserialize data.");
return;
end
--A faction check should not be needed but who knows what funky stuff can happen with the new yell channel and mind control etc.
--if (not data['faction'] or data['faction'] ~= faction) then
-- NWB:debug("data from opposite faction received", sender, distribution);
-- return;
--end
if (not NWB:validateData(data)) then
NWB:debug("invalid data received.");
--NWB:debug(data);
return;
end
if (data["rendTimer"] and (data["rendTimer"] < NWB.data["rendTimer"] or
(data["rendYell"] < (data["rendTimer"] - 120) and data["rendYell2"] < (data["rendTimer"] - 120)))) then
--Don't overwrite any data for this timer type if it's an old timer.
if (data["rendYell"] < (data["rendTimer"] - 120) and data["rendYell2"] < (data["rendTimer"] - 120)) then
--NWB:debug("invalid rend timer from", sender, "npcyell:", data["rendYell"], "buffdropped:", data["rendTimer"]);
end
data['rendTimer'] = nil;
data['rendTimerWho'] = nil;
data['rendYell'] = nil;
data['rendYell2'] = nil;
data['rendSource'] = nil;
end
if (data["onyTimer"] and (data["onyTimer"] < NWB.data["onyTimer"] or
(data["onyYell"] < (data["onyTimer"] - 120) and data["onyYell2"] < (data["onyTimer"] - 120)))) then
if (data["onyYell"] < (data["onyTimer"] - 120) and data["onyYell2"] < (data["onyTimer"] - 120)) then
--NWB:debug("invalid ony timer from", sender, "npcyell:", data["onyYell"], "buffdropped:", data["onyTimer"]);
end
data['onyTimer'] = nil;
data['onyTimerWho'] = nil;
data['onyYell'] = nil;
data['onyYell2'] = nil;
data['onySource'] = nil;
end
if (data["nefTimer"] and (data["nefTimer"] < NWB.data["nefTimer"] or
(data["nefYell"] < (data["nefTimer"] - 120) and data["nefYell2"] < (data["nefTimer"] - 120)))) then
if (data["nefYell"] < (data["nefTimer"] - 120) and data["nefYell2"] < (data["nefTimer"] - 120)) then
--NWB:debug("invalid nef timer from", sender, "npcyell:", data["nefYell"], "buffdropped:", data["nefTimer"]);
end
data['nefTimer'] = nil;
data['nefTimerWho'] = nil;
data['nefYell'] = nil;
data['nefYell2'] = nil;
data['nefSource'] = nil;
end
local hasNewData, newFlowerData;
--Insert our layered data here.
if (NWB.isLayered and data.layers) then
--There's a lot of ugly shit in this function trying to quick fix timer bugs for this layered stuff...
for layer, vv in NWB:pairsByKeys(data.layers) do
if (type(vv) == "table" and next(vv)) then
for localLayer, localV in pairs(NWB.data.layers) do
--Quick fix for timestamps sometimes syncing between layers.
--I think this may happen when someone is mid layer changing when the boss drops.
--They get the buff in new layer but get old layers NPC GUID? Has to be tested.
if (vv["rendTimer"] and localV["rendTimer"] and vv["rendTimer"] == localV["rendTimer"]
and layer ~= localLayer) then
--NWB:debug("ignoring duplicate rend timstamp", layer, vv["rendTimer"], localLayer, localV["rendTimer"]);
vv['rendTimer'] = nil;
vv['rendTimerWho'] = nil;
vv['rendYell'] = nil;
vv['rendYell2'] = nil;
vv['rendSource'] = nil;
end
if (vv["onyTimer"] and localV["onyTimer"] and vv["onyTimer"] == localV["onyTimer"]
and layer ~= localLayer) then
--NWB:debug("ignoring duplicate ony timstamp", layer, vv["onyTimer"], localLayer, localV["onyTimer"]);
vv['onyTimer'] = nil;
vv['onyTimerWho'] = nil;
vv['onyYell'] = nil;
vv['onyYell2'] = nil;
vv['onySource'] = nil;
vv['onyNpcDied'] = nil;
end
if (vv["nefTimer"] and localV["nefTimer"] and vv["nefTimer"] == localV["nefTimer"]
and layer ~= localLayer) then
--NWB:debug("ignoring duplicate nef timstamp", layer, vv["nefTimer"], localLayer, localV["nefTimer"]);
vv['nefTimer'] = nil;
vv['nefTimerWho'] = nil;
vv['nefYell'] = nil;
vv['nefYell2'] = nil;
vv['nefSource'] = nil;
vv['nefNpcDied'] = nil;
end
end
if (NWB:validateLayer(layer)) then
if (not NWB.data.layers[layer]) then
if (vv['GUID']) then
NWB:createNewLayer(layer, vv['GUID']);
else
NWB:createNewLayer(layer, "other");
end
--NWB:debug(data.layers);
end
if (NWB.data.layers[layer]) then
NWB:fixLayer(layer);
--NWB:debug(data);
if (vv["rendTimer"] and (vv["rendTimer"] < (GetServerTime() - NWB.db.global.rendRespawnTime)
or not vv["rendYell"] or not vv["rendYell2"]
or (vv["rendYell"] < (vv["rendTimer"] - 120) and vv["rendYell2"] < (vv["rendTimer"] - 120)))) then
--Don't overwrite any data for this timer type if it's an old timer.
--if (vv["rendYell"] < (vv["rendTimer"] - 120) and vv["rendYell2"] < (vv["rendTimer"] - 120)) then
NWB:debug("invalid rend timer from", sender, "npcyell:", vv["rendYell"], "npcyell2:", vv["rendYell2"], "buffdropped:", vv["rendTimer"]);
--end
vv['rendTimer'] = nil;
vv['rendTimerWho'] = nil;
vv['rendYell'] = nil;
vv['rendYell2'] = nil;
vv['rendSource'] = nil;
end
if (vv["onyTimer"] and (vv["onyTimer"] < (GetServerTime() - NWB.db.global.onyRespawnTime)
or not vv["onyYell"] or not vv["onyYell2"]
or (vv["onyYell"] < (vv["onyTimer"] - 120) and vv["onyYell2"] < (vv["onyTimer"] - 120)))) then
--if (vv["onyYell"] < (vv["onyTimer"] - 120) and vv["onyYell2"] < (vv["onyTimer"] - 120)) then
NWB:debug("invalid ony timer from", sender, "npcyell:", vv["onyYell"], "npcyell2:", vv["onyYell2"], "buffdropped:", vv["onyTimer"]);
--end
vv['onyTimer'] = nil;
vv['onyTimerWho'] = nil;
vv['onyYell'] = nil;
vv['onyYell2'] = nil;
vv['onySource'] = nil;
vv['onyNpcDied'] = nil;
end
if (vv["nefTimer"] and (vv["nefTimer"] < (GetServerTime() - NWB.db.global.nefRespawnTime)
or not vv["nefYell"] or not vv["nefYell2"]
or (vv["nefYell"] < (vv["nefTimer"] - 120) and vv["nefYell2"] < (vv["nefTimer"] - 120)))) then
--if (vv["nefYell"] < (vv["nefTimer"] - 120) and vv["nefYell2"] < (vv["nefTimer"] - 120)) then
NWB:debug("invalid nef timer from", sender, "npcyell:", vv["nefYell"], "npcyell2:", vv["nefYell2"], "buffdropped:", vv["nefTimer"]);
--end
vv['nefTimer'] = nil;
vv['nefTimerWho'] = nil;
vv['nefYell'] = nil;
vv['nefYell2'] = nil;
vv['nefSource'] = nil;
vv['nefNpcDied'] = nil;
end
for k, v in pairs(vv) do
if ((string.match(k, "flower") and NWB.db.global.syncFlowersAll)
or (not NWB.db.global.receiveGuildDataOnly)
or (NWB.db.global.receiveGuildDataOnly and distribution == "GUILD")) then
if (validKeys[k] and tonumber(v)) then
--If data is numeric (a timestamp) then check it's newer than our current timer.
if (v ~= nil) then
if (not NWB.data.layers[layer][k] or not tonumber(NWB.data.layers[layer][k])) then
--Rare bug someone has corrupt data (not sure how and it's never happened to me, but been reported).
--This will correct it by resetting thier timestamp to 0.
NWB:debug("Local data error:", k, NWB.data[k])
NWB.data.layers[layer][k] = 0;
end
--Make sure the key exists, stop a lua error in old versions if we add a new timer type.
if (NWB.data.layers[layer][k] and v ~= 0 and v > NWB.data.layers[layer][k] and NWB:validateTimestamp(v)) then
--NWB:debug("new data", sender, distribution, k, v, "old:", NWB.data.layers[layer][k]);
if (string.match(k, "flower") and not (distribution == "GUILD" and (GetServerTime() - NWB.data.layers[layer][k]) > 15)) then
newFlowerData = true;
end
NWB.data.layers[layer][k] = v;
hasNewData = true;
end
end
elseif (k == "layerMap") then
if (not NWB.data.layers[layer].layerMap) then
NWB.data.layers[layer].layerMap = {};
end
for zoneID, mapID in pairs(v) do
if (not NWB.data.layers[layer].layerMap[zoneID]) then
NWB.data.layers[layer].layerMap[zoneID] = mapID;
end
end
elseif (v ~= nil and k ~= "layers") then
if (not validKeys[k]) then
--NWB:debug(data)
NWB:debug("Invalid key received:", k, v);
end
--if (not validKeys[k] and not next(v)) then
if (not validKeys[k] and type(v) ~= "table") then
NWB:debug("Invalid key received2:", k, v);
else
NWB.data.layers[layer][k] = v;
end
end
end
end
end
end
end
end
end
for k, v in pairs(data) do
if ((string.match(k, "flower") and NWB.db.global.syncFlowersAll)
or (not NWB.db.global.receiveGuildDataOnly)
or (NWB.db.global.receiveGuildDataOnly and distribution == "GUILD")) then
if (validKeys[k] and tonumber(v)) then
--If data is numeric (a timestamp) then check it's newer than our current timer.
if (v ~= nil) then
if (not NWB.data[k] or not tonumber(NWB.data[k])) then
--Rare bug someone has corrupt data (not sure how and it's never happened to me, but been reported).
--This will correct it by resetting thier timestamp to 0.
NWB:debug("Local data error:", k, NWB.data[k])
NWB.data[k] = 0;
end
--Make sure the key exists, stop a lua error in old versions if we add a new timer type.
if (NWB.data[k] and v ~= 0 and v > NWB.data[k] and NWB:validateTimestamp(v)) then
--NWB:debug("new data", sender, distribution, k, v, "old:", NWB.data[k]);
if (string.match(k, "flower") and not (distribution == "GUILD" and (GetServerTime() - NWB.data[k]) > 15)) then
newFlowerData = true;
end
NWB.data[k] = v;
hasNewData = true;
end
end
elseif (v ~= nil and k ~= "layers") then
if (not validKeys[k] and not next(v)) then
NWB:debug("Invalid key received:", k, v);
else
NWB.data[k] = v;
end
end
end
end
NWB:timerCleanup();
--If we get newer data from someone outside the guild then share it with the guild.
if (hasNewData) then
NWB.data.lastSyncBy = sender;
--NWB:debug("new data done", sender, distribution, NWB:isPlayerInGuild(sender));
if (distribution ~= "GUILD" and not NWB:isPlayerInGuild(sender)) then
NWB:sendData("GUILD");
end
end
--If new flower data received and not freshly picked by guild member (that sends a msg to guild chat already)
if (newFlowerData and NWB.db.global.showNewFlower) then
--local string = "New songflower timer received:";
local string = L["newSongflowerReceived"] .. ":";
local found;
for k, v in pairs(NWB.songFlowers) do
local time = (NWB.data[k] + 1500) - GetServerTime();
if (time > 60) then
local minutes = string.format("%02.f", math.floor(time / 60));
local seconds = string.format("%02.f", math.floor(time - minutes * 60));
string = string .. " (" .. v.subZone .. " " .. minutes .. L["minuteShort"] .. seconds .. L["secondShort"] .. ")";
found = true;
end
end
if (not found) then
string = string .. " " .. L["noActiveTimers"] .. ".";
end
NWB:print(string);
end
--NWB:debug(NWB.data);
end
function NWB:validateData(data)
--For some reason on rare occasions a timer is received without the yell msg timetsamps (not even a default 0);
if (tonumber(data["rendTimer"])
and (not tonumber(data["rendYell"]) or not tonumber(data["rendYell2"]))) then
return;
end
if (tonumber(data["onyTimer"])
and (not tonumber(data["onyYell"]) or not tonumber(data["onyYell2"]))) then
return;
end
if (tonumber(data["nefTimer"])
and (not tonumber(data["nefYell"]) or not tonumber(data["nefYell2"]))) then
return;
end
return true;
end
function NWB:versionCheck(remoteVersion)
local lastVersionMsg = NWB.db.global.lastVersionMsg;
if (tonumber(remoteVersion) > tonumber(version) and (GetServerTime() - lastVersionMsg) > 14400) then
print("|cffFF5100" .. L["versionOutOfDate"]);
NWB.db.global.lastVersionMsg = GetServerTime();
end
if (tonumber(remoteVersion) > tonumber(version)) then
NWB.latestRemoteVersion = remoteVersion;
end
end
--Print current buff timers to chat window.
function NWB:printBuffTimers(isLogon)
local msg;
if (NWB.faction == "Horde" or NWB.db.global.allianceEnableRend) then
if (NWB.data.rendTimer > (GetServerTime() - NWB.db.global.rendRespawnTime)) then
msg = L["rend"] .. ": " .. NWB:getTimeString(NWB.db.global.rendRespawnTime - (GetServerTime() - NWB.data.rendTimer), true) .. ".";
if (NWB.db.global.showTimeStamp) then
local timeStamp = NWB:getTimeFormat(NWB.data.rendTimer + NWB.db.global.rendRespawnTime);
msg = msg .. " (" .. timeStamp .. ")";
end
else
msg = L["rend"] .. ": " .. L["noCurrentTimer"] .. ".";
end
if ((not isLogon or NWB.db.global.logonRend) and not NWB.isLayered) then
NWB:print(msg);
end
end
if ((NWB.data.onyNpcDied > NWB.data.onyTimer) and
(NWB.data.onyNpcDied > (GetServerTime() - NWB.db.global.onyRespawnTime))) then
if (NWB.faction == "Horde") then
msg = string.format(L["onyxiaNpcKilledHordeWithTimer"], NWB:getTimeString(GetServerTime() - NWB.data.onyNpcDied, true));
else
msg = string.format(L["onyxiaNpcKilledAllianceWithTimer"], NWB:getTimeString(GetServerTime() - NWB.data.onyNpcDied, true));
end
elseif (NWB.data.onyTimer > (GetServerTime() - NWB.db.global.onyRespawnTime)) then
msg = L["onyxia"] .. ": " .. NWB:getTimeString(NWB.db.global.onyRespawnTime - (GetServerTime() - NWB.data.onyTimer), true) .. ".";
if (NWB.db.global.showTimeStamp) then
local timeStamp = NWB:getTimeFormat(NWB.data.onyTimer + NWB.db.global.onyRespawnTime);
msg = msg .. " (" .. timeStamp .. ")";
end
else
msg = L["onyxia"] .. ": " .. L["noCurrentTimer"] .. ".";
end
if ((not isLogon or NWB.db.global.logonOny) and not NWB.isLayered) then
NWB:print(msg);
end
if ((NWB.data.nefNpcDied > NWB.data.nefTimer) and
(NWB.data.nefNpcDied > (GetServerTime() - NWB.db.global.nefRespawnTime))) then
if (NWB.faction == "Horde") then
msg = string.format(L["nefarianNpcKilledHordeWithTimer"], NWB:getTimeString(GetServerTime() - NWB.data.nefNpcDied, true));
else
msg = string.format(L["nefarianNpcKilledAllianceWithTimer"], NWB:getTimeString(GetServerTime() - NWB.data.nefNpcDied, true));
end
elseif (NWB.data.nefTimer > (GetServerTime() - NWB.db.global.nefRespawnTime)) then
msg = L["nefarian"] .. ": " .. NWB:getTimeString(NWB.db.global.nefRespawnTime - (GetServerTime() - NWB.data.nefTimer), true) .. ".";
if (NWB.db.global.showTimeStamp) then
local timeStamp = NWB:getTimeFormat(NWB.data.nefTimer + NWB.db.global.nefRespawnTime);
msg = msg .. " (" .. timeStamp .. ")";
end
else
msg = L["nefarian"] .. ": " .. L["noCurrentTimer"] .. ".";
end
if ((not isLogon or NWB.db.global.logonNef) and not NWB.isLayered) then
NWB:print(msg);
end
--Disabled, is no zand timer, will remove later.
--[[if (NWB.data.zanTimer > (GetServerTime() - NWB.db.global.zanRespawnTime)) then
msg = L["zan"] .. ": " .. NWB:getTimeString(NWB.db.global.zanRespawnTime - (GetServerTime() - NWB.data.zanTimer), true) .. ".";
if (NWB.db.global.showTimeStamp) then
local timeStamp = NWB:getTimeFormat(NWB.data.zanTimer + NWB.db.global.zanRespawnTime);
msg = msg .. " (" .. timeStamp .. ")";
end
else
msg = L["zan"] .. ": " .. L["noCurrentTimer"] .. ".";
end
if (not isLogon or NWB.db.global.logonZan and NWB.zand) then
--NWB:print(msg);
end]]
if (NWB.isLayered) then
NWB:print("|HNWBCustomLink:timers|hYou are on a layered realm.|h");
NWB:print("|HNWBCustomLink:timers|hClick here to view current timers.|h");
end
local timestamp, timeLeft, type = NWB:getDmfData();
--if ((NWB.db.global.showDmfLogon and isLogon) or NWB.db.global.showDmfWb
-- or (NWB.db.global.showDmfWhenClose and (timeLeft > 0 and timeLeft < 43200))) then
if ((isLogon and NWB.db.global.logonDmfSpawn and (timeLeft > 0 and timeLeft < 21600)) or
(not isLogon and NWB.db.global.showDmfWb)) then
local zone;
if (NWB.dmfZone == "Mulgore") then
zone = L["mulgore"];
else
zone = L["elwynnForest"];
end
msg = NWB:getDmfTimeString() .. " (" .. zone .. ")";
NWB:print(msg, nil, "[DMF]");
end
if (NWB.isDmfUp and NWB.data.myChars[UnitName("player")].buffs) then
for k, v in pairs(NWB.data.myChars[UnitName("player")].buffs) do
if (v.type == "dmf" and (v.timeLeft + 7200) > 0) then
msg = string.format(L["dmfBuffCooldownMsg"], NWB:getTimeString(v.timeLeft + 7200, true));
if ((not isLogon and NWB.db.global.showDmfBuffWb) or NWB.db.global.logonDmfBuffCooldown) then
NWB:print(msg, nil, "[DMF]");
end
break;
end
end
end
end
--Single line buff timers.
function NWB:getShortBuffTimers(channel, layerID)
local msg = "";
local dataPrefix, layer;
local count = 0;
if (NWB.isLayered) then
table.sort(NWB.data.layers);
for k, v in NWB:pairsByKeys(NWB.data.layers) do
count = count + 1;
if (not layerID and count == 1) then
--Get first layer if no layer specified.
layer = k;
elseif (count == tonumber(layerID)) then
layer = k;
end
end
if (layerID and not layer) then
return "That layer wasn't found or has no valid timers.";
end
dataPrefix = NWB.data.layers[layer];
if (not dataPrefix and not layeriD) then
msg = "(" .. L["rend"] .. ": " .. L["noTimer"] .. ") ";
msg = msg .. "(" .. L["onyxia"] .. ": " .. L["noTimer"] .. ") ";
msg = msg .. "(" .. L["nefarian"] .. ": " .. L["noTimer"] .. ") ";
msg = msg .. "(No layers found)";
return msg;
end
else
dataPrefix = NWB.data;
end
if (NWB.faction == "Horde" or NWB.db.global.allianceEnableRend) then
if (dataPrefix.rendTimer > (GetServerTime() - NWB.db.global.rendRespawnTime)) then
msg = "(" .. L["rend"] .. ": " .. NWB:getTimeString(NWB.db.global.rendRespawnTime - (GetServerTime() - dataPrefix.rendTimer), true) .. ") ";
else
msg = "(" .. L["rend"] .. ": " .. L["noTimer"] .. ") ";
end
end
if ((dataPrefix.onyNpcDied > dataPrefix.onyTimer) and
(dataPrefix.onyNpcDied > (GetServerTime() - NWB.db.global.onyRespawnTime))) then
if (NWB.faction == "Horde") then
msg = msg .. "(Onyxia: NPC (Runthak) was killed " .. NWB:getTimeString(GetServerTime() - dataPrefix.onyNpcDied, true)
.. " ago no buff recorded since) ";
else
msg = msg .. "(Onyxia: NPC (Mattingly) was killed " .. NWB:getTimeString(GetServerTime() - dataPrefix.onyNpcDied, true)
.. " ago no buff recorded since) ";
end
elseif (dataPrefix.onyTimer > (GetServerTime() - NWB.db.global.onyRespawnTime)) then
msg = msg .. "(" .. L["onyxia"] .. ": " .. NWB:getTimeString(NWB.db.global.onyRespawnTime - (GetServerTime() - dataPrefix.onyTimer), true) .. ") ";
else
msg = msg .. "(" .. L["onyxia"] .. ": " .. L["noTimer"] .. ") ";
end
if ((dataPrefix.nefNpcDied > dataPrefix.nefTimer) and
(dataPrefix.nefNpcDied > (GetServerTime() - NWB.db.global.nefRespawnTime))) then
if (NWB.faction == "Horde") then
msg = msg .. "(Nefarian: NPC (Saurfang) was killed " .. NWB:getTimeString(GetServerTime() - dataPrefix.nefNpcDied, true)
.. " ago no buff recorded since)";
else
msg = msg .. "(Nefarian: NPC (Afrasiabi) was killed " .. NWB:getTimeString(GetServerTime() - dataPrefix.nefNpcDied, true)
.. " ago no buff recorded since)";
end
elseif (dataPrefix.nefTimer > (GetServerTime() - NWB.db.global.nefRespawnTime)) then
msg = msg .. "(" .. L["nefarian"] .. ": " .. NWB:getTimeString(NWB.db.global.nefRespawnTime - (GetServerTime() - dataPrefix.nefTimer), true) .. ")";
else
msg = msg .. "(" .. L["nefarian"] .. ": " .. L["noTimer"] .. ")";
end
--[[if (NWB.zand and dataPrefix.zanTimer > (GetServerTime() - NWB.db.global.zanRespawnTime)) then
msg = msg .. " (" .. L["zan"] .. ": " .. NWB:getTimeString(NWB.db.global.zanRespawnTime - (GetServerTime() - dataPrefix.zanTimer), true) .. ")";
elseif (NWB.zand) then
msg = msg .. " (" .. L["zan"] .. ": " .. L["noTimer"] .. ")";
end]]
if (layerID) then
return msg .. " (Layer " .. layerID .. " of " .. count .. ")";
elseif (NWB.isLayered) then
return msg .. " (Layer 1 of " .. count .. ")";
end
return msg;
end
--Prefixes are clickable in chat to open buffs frame.
function NWB.addClickLinks(self, event, msg, author, ...)
local types;
if (NWB.db.global.colorizePrefixLinks) then
types = {
["%[WorldBuffs%]"] = "|cFFFF5100|HNWBCustomLink:buffs|h[WorldBuffs]|h|r",
["%[NovaWorldBuffs%]"] = "|cFFFF5100|HNWBCustomLink:buffs|h[NovaWorldBuffs]|h|r",
["%[DMF%]"] = "|cFFFF5100|HNWBCustomLink:buffs|h[DMF]|h|r",
}
else
types = {
["%[WorldBuffs%]"] = "|HNWBCustomLink:buffs|h[WorldBuffs]|h",
["%[NovaWorldBuffs%]"] = "|HNWBCustomLink:buffs|h[NovaWorldBuffs]|h",
["%[DMF%]"] = "|HNWBCustomLink:buffs|h[DMF]|h",
}
end
for k, v in pairs(types) do
local match = string.match(msg, k);
if (NWB.isLayered) then
if (match) then
--If layered make the whole msg clickable to open buffs frame.
msg = string.gsub(msg, k .. " (.+)", v .. " |HNWBCustomLink:timers|h%1|h");
return false, msg, author, ...;
end
else
if (match) then
msg = string.gsub(msg, k, v);
return false, msg, author, ...;
end
end
end
return false, msg, author, ...;
--if (NWB.isLayered and channel == "guild") then
-- msg = "|HNWBCustomLink:timers|h" .. msg .. "|h";
--end
end
function NWB.guildChatFilter(self, event, msg, author, ...)
local types = {
--NPC dialogue started msgs.
["zanFirstYellMsg"] = "filterYells",
["rendFirstYellMsg"] = "filterYells",
["onyxiaFirstYellMsg"] = "filterYells",
["nefarianFirstYellMsg"] = "filterYells",
--Buff has dropped msgs.
["rendBuffDropped"] = "filterDrops",
["onyxiaBuffDropped"] = "filterDrops",
["nefarianBuffDropped"] = "filterDrops",
["zanBuffDropped"] = "filterDrops",
--Timer msgs.
["newBuffCanBeDropped"] = "filterTimers", --"A new %s buff can be dropped now"
["buffResetsIn"] = "filterTimers",--"%s resets in %s";
--Songflower msgs.
["songflowerPicked"] = "filterSongflowers",
--Npc killed
["onyxiaNpcKilledHorde"] = "filterNpcKilled",
["onyxiaNpcKilledAlliance"] = "filterNpcKilled",
["nefarianNpcKilledHorde"] = "filterNpcKilled",
["nefarianNpcKilledAlliance"] = "filterNpcKilled",
};
for k, v in pairs(types) do
local match = string.gsub(L[k], "%(", "%%(");
match = string.gsub(match, "%)", "%%)");
match = string.gsub(match, "%%s", "(.+)");
if (NWB.db.global[v] and string.match(msg, "%[WorldBuffs%]") and string.match(msg, match)) then
NWB:debug("filtering", k);
return true;
end
end
if (NWB.db.global.filterCommand and (string.match(msg, "^!wb") or string.match(msg, "^!dmf"))) then
NWB:debug("filtering command");
return true;
end
if (NWB.db.global.filterCommandResponse and string.match(msg, "%[WorldBuffs%]") and
string.match(msg, L["onyxia"] .. ":(.+)" .. L["nefarian"] .. ":")) then
NWB:debug("filtering command response");
return true;
end
return false, msg, author, ...;
end
ChatFrame_AddMessageEventFilter("CHAT_MSG_CHANNEL", NWB.addClickLinks);
ChatFrame_AddMessageEventFilter("CHAT_MSG_SAY", NWB.addClickLinks);
ChatFrame_AddMessageEventFilter("CHAT_MSG_YELL", NWB.addClickLinks);
ChatFrame_AddMessageEventFilter("CHAT_MSG_WHISPER", NWB.addClickLinks);
ChatFrame_AddMessageEventFilter("CHAT_MSG_BATTLEGROUND", NWB.addClickLinks);
ChatFrame_AddMessageEventFilter("CHAT_MSG_BATTLEGROUND_LEADER", NWB.addClickLinks);
ChatFrame_AddMessageEventFilter("CHAT_MSG_BN_WHISPER", NWB.addClickLinks);
ChatFrame_AddMessageEventFilter("CHAT_MSG_GUILD", NWB.addClickLinks);
ChatFrame_AddMessageEventFilter("CHAT_MSG_GUILD", NWB.guildChatFilter);
ChatFrame_AddMessageEventFilter("CHAT_MSG_OFFICER", NWB.addClickLinks);
ChatFrame_AddMessageEventFilter("CHAT_MSG_PARTY", NWB.addClickLinks);
ChatFrame_AddMessageEventFilter("CHAT_MSG_PARTY_LEADER", NWB.addClickLinks);
ChatFrame_AddMessageEventFilter("CHAT_MSG_RAID", NWB.addClickLinks);
ChatFrame_AddMessageEventFilter("CHAT_MSG_RAID_LEADER", NWB.addClickLinks);
ChatFrame_AddMessageEventFilter("CHAT_MSG_RAID_WARNING", NWB.addClickLinks);
--Hook the chat link click func.
hooksecurefunc("ChatFrame_OnHyperlinkShow", function(...)
local chatFrame, link, text, button = ...;
if (link == "NWBCustomLink:buffs") then
NWB:openBuffListFrame();
end
if (link == "NWBCustomLink:timers" and NWB.isLayered) then
NWB:openLayerFrame();
end
end)
--Insert our custom link type into blizzards SetHyperlink() func.
local OriginalSetHyperlink = ItemRefTooltip.SetHyperlink
function ItemRefTooltip:SetHyperlink(link, ...)
if (link and link:sub(0, 13) == "NWBCustomLink") then
return;
end
return OriginalSetHyperlink(self, link, ...);
end
--Add prefix and colors from db then print.
local printPrefix;
function NWB:print(msg, channel, prefix)
if (prefix) then
printPrefix = "|cFFFF5100" .. prefix .. "|r";
end
if (channel) then
channel = string.lower(channel);
end
if (channel == "group" or channel == "team") then
channel = "party";
end
if (channel == "gchat" or channel == "gmsg") then
channel = "guild";
end
local channelWhisper, name;
if (channel) then
channelWhisper, name = strsplit(" ", channel, 2);
end
if (channelWhisper == "tell" or channelWhisper == "whisper" or channelWhisper == "msg") then
if (not prefix) then
printPrefix = "[NovaWorldBuffs]";
end
if (name and name ~= "") then
SendChatMessage(printPrefix .. " " .. msg, "WHISPER", nil, name);
else
print(NWB.chatColor .. "No whisper target found.");
end
elseif (channel == "r" or channel == "reply") then
if (not prefix) then
printPrefix = "[NovaWorldBuffs]";
end
if (NWB.lastWhisper and NWB.lastWhisper ~= "") then
if (NWB.lastWhisperType == "bnet") then
BNSendWhisper(NWB.lastWhisper, printPrefix .. " " .. msg);
else
SendChatMessage(printPrefix .. " " .. msg, "WHISPER", nil, NWB.lastWhisper);
end
else
print(NWB.chatColor .. "No last whisper target found.");
end
elseif (channel == "say" or channel == "yell" or channel == "party" or channel == "guild" or channel == "officer" or channel == "raid") then
--If posting to a specifed channel then advertise addon name in prefix, more people that have the addon then more accurate the data is.
if (not prefix) then
printPrefix = "[NovaWorldBuffs]";
if (channel == "guild") then
printPrefix = "[WorldBuffs]";
end
end
SendChatMessage(printPrefix .. " " .. msg, channel);
elseif (tonumber(channel)) then
--Send to numbered channel by number.
local id, name = GetChannelName(channel);
if (id == 0) then
print("|cFFFFFF00No channel with id |cFFFF5100" .. channel .. " |cFFFFFF00exists.");
print("|cFFFFFF00Type \"/wb\" to print world buff timers to yourself.");
print("|cFFFFFF00Type \"/wb config\" to open options.");
print("|cFFFFFF00Type \"/wb guild\" to post buff timers to the specified chat channel (accepts channel names and numbers).");
print("|cFFFFFF00Use \"/sf\" in the same way for songflowers.");
print("|cFFFFFF00Type \"/dmf\" for your Darkmoon Faire buff cooldown.");
print("|cFFFFFF00Type \"/buffs\" to view all your alts world buffs.");
return;
end
if (not prefix) then
printPrefix = "[NovaWorldBuffs]";
end
SendChatMessage(printPrefix .. " " .. NWB:stripColors(msg), "CHANNEL", nil, id);
elseif (channel ~= nil) then
--Send to numbered channel by name.
local id, name = GetChannelName(channel);
if (id == 0) then
print("|cFFFFFF00No channel with name |cFFFF5100" .. channel .. " |cFFFFFF00exists.");
print("|cFFFFFF00Type \"/wb\" to print world buff timers to yourself.");
print("|cFFFFFF00Type \"/wb config\" to open options.");
print("|cFFFFFF00Type \"/wb guild\" to post buff timers to the specified chat channel (accepts channel names and numbers).");
print("|cFFFFFF00Use \"/sf\" in the same way for songflowers.");
print("|cFFFFFF00Type \"/dmf\" for your Darkmoon Faire buff cooldown.");
print("|cFFFFFF00Type \"/buffs\" to view all your alts world buffs.");
return;
end
if (not prefix) then
printPrefix = "[NovaWorldBuffs]";
end
SendChatMessage(printPrefix .. " " .. NWB:stripColors(msg), "CHANNEL", nil, id);
else
if (not prefix) then
printPrefix = "|cFFFF5100|HNWBCustomLink:buffs|h[WorldBuffs]|h|r";
end
if (prefix == "[DMF]") then
printPrefix = "|cFFFF5100|HNWBCustomLink:buffs|h[DMF]|h|r";
end
if (NWB.isLayered) then
msg = "|HNWBCustomLink:timers|h" .. msg .. "|h";
end
print(printPrefix .. " " .. NWB.chatColor .. msg);
end
end
NWB.types = {
[1] = "rend",
[2] = "ony",
[3] = "nef",
--[4] = "zan"
};
--1 second looping function for timer warning msgs.
NWB.played = 0;
local lastDmfTick = 0;
function NWB:ticker()
for k, v in pairs(NWB.types) do
local offset = 0;
if (v == "rend") then
offset = NWB.db.global.rendRespawnTime;
elseif (v == "ony") then
offset = NWB.db.global.onyRespawnTime;
elseif (v == "nef") then
offset = NWB.db.global.nefRespawnTime;
--elseif (v == "zan") then
-- offset = NWB.db.global.zanRespawnTime;
end
if (NWB.isLayered) then
for layer, value in NWB:pairsByKeys(NWB.data.layers) do
local secondsLeft = (NWB.data.layers[layer][v .. "Timer"] + offset) - GetServerTime();
--This looks messy but when checking (secondsLeft == 0) it would sometimes skip, not sure why.
--This gives it a 2 second window instead of 1.
if (NWB.data.layers[layer][v .. "0"] and secondsLeft <= 0 and secondsLeft >= -1) then
NWB.data.layers[layer][v .. "0"] = nil;
NWB:doWarning(v, 0, secondsLeft, layer);
elseif (NWB.data.layers[layer][v .. "1"] and secondsLeft <= 60 and secondsLeft >= 59) then
NWB.data.layers[layer][v .. "1"] = nil;
NWB:doWarning(v, 1, secondsLeft, layer);
elseif (NWB.data.layers[layer][v .. "5"] and secondsLeft <= 300 and secondsLeft >= 299) then
NWB.data.layers[layer][v .. "5"] = nil;
NWB:doWarning(v, 5, secondsLeft, layer);
elseif (NWB.data.layers[layer][v .. "10"] and secondsLeft <= 600 and secondsLeft >= 599) then
NWB.data.layers[layer][v .. "10"] = nil;
NWB:doWarning(v, 10, secondsLeft, layer);
elseif (NWB.data.layers[layer][v .. "15"] and secondsLeft <= 900 and secondsLeft >= 899) then
NWB.data.layers[layer][v .. "15"] = nil;
NWB:doWarning(v, 15, secondsLeft, layer);
elseif (NWB.data.layers[layer][v .. "30"] and secondsLeft <= 1800 and secondsLeft >= 1799) then
NWB.data.layers[layer][v .. "30"] = nil;
NWB:doWarning(v, 30, secondsLeft, layer);
end
end
else
local secondsLeft = (NWB.data[v .. "Timer"] + offset) - GetServerTime();
--This looks messy but when checking (secondsLeft == 0) it would sometimes skip, not sure why.
--This gives it a 2 second window instead of 1.
if (NWB.data[v .. "0"] and secondsLeft <= 0 and secondsLeft >= -1) then
NWB.data[v .. "0"] = nil;
NWB:doWarning(v, 0, secondsLeft);
elseif (NWB.data[v .. "1"] and secondsLeft <= 60 and secondsLeft >= 59) then
NWB.data[v .. "1"] = nil;
NWB:doWarning(v, 1, secondsLeft);
elseif (NWB.data[v .. "5"] and secondsLeft <= 300 and secondsLeft >= 299) then
NWB.data[v .. "5"] = nil;
NWB:doWarning(v, 5, secondsLeft);
elseif (NWB.data[v .. "10"] and secondsLeft <= 600 and secondsLeft >= 599) then
NWB.data[v .. "10"] = nil;
NWB:doWarning(v, 10, secondsLeft);
elseif (NWB.data[v .. "15"] and secondsLeft <= 900 and secondsLeft >= 899) then
NWB.data[v .. "15"] = nil;
NWB:doWarning(v, 15, secondsLeft);
elseif (NWB.data[v .. "30"] and secondsLeft <= 1800 and secondsLeft >= 1799) then
NWB.data[v .. "30"] = nil;
NWB:doWarning(v, 30, secondsLeft);
end
end
end
if (NWB.played > 0) then
NWB.played = NWB.played + 1;
end
if (NWB.data.myChars[UnitName("player")].buffs) then
for k, v in pairs(NWB.data.myChars[UnitName("player")].buffs) do
--Correct a rare bug.
if (not v.timeLeft) then
NWB.data.myChars[UnitName("player")].buffs[k] = nil;
else
v.timeLeft = v.timeLeft - 1;
if (v.type == "dmf") then
if ((lastDmfTick + 7200) >= 1 and (v.timeLeft + 7200) <= 0) then
NWB:print(L["dmfBuffReset"]);
lastDmfTick = -99999;
NWB.data.myChars[UnitName("player")].buffs[k] = nil;
else
lastDmfTick = v.timeLeft;
end
end
end
end
end
C_Timer.After(1, function()
NWB:ticker();
end)
end
function NWB:yellTicker()
--One msg every 3 mins.
local yellDelay = 180;
if (NWB.isLayered) then
--Longer yell delay on high pop servers, no need for as many.
--One msg every 5 mins.
yellDelay = 300;
end
C_Timer.After(yellDelay, function()
--Msg inside the timer so it doesn't send first tick at logon, player entering world does that.
NWB:removeOldLayers();
local inInstance, instanceType = IsInInstance();
if (not UnitInBattleground("player") and inInstance ~= "raid") then
NWB:sendData("YELL");
end
NWB:yellTicker();
end)
end
--Filter addon comm warnings from yell for 5 seconds after sending a yell.
--Even though we only send 1 msg every few minutes I think it can still trigger this msg if a large amount of people are in 1 spot.
--Even if it triggers this msg the data still got out there to most people, it will spread just fine over time.
--"yell" msgs possibly don't just send 1 msg to the server but instead loop through every player close and send 1 by 1?
NWB.doFilterAddonChatMsg = false;
local function filterAddonChatMsg(self, event, msg, author, ...)
if (NWB.doFilterAddonChatMsg) then
--The number of messages that can be sent is limited, please wait to send another message.
if (string.find(msg, ERR_CHAT_THROTTLED) or string.find(msg, "The number of messages that can be sent is limited")) then
return true;
end
end
end
ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", filterAddonChatMsg);
--Send warnings to channels selected in options
local warningThroddle = {
["rend"] = 0,
["ony"] = 0,
["nef"] = 0,
["zan"] = 0,
};
function NWB:doWarning(type, num, secondsLeft, layer)
--Temporary bug fix.
if (warningThroddle[type] and (GetServerTime() - warningThroddle[type]) < 3) then
return;
end
warningThroddle[type] = GetServerTime();
local layerMsg = "";
if (layer) then
local count = 0;
for k, v in NWB:pairsByKeys(NWB.data.layers) do
count = count + 1;
if (k == tonumber(layer)) then
layerMsg = " (Layer " .. count .. ")";
end
end
end
local send = true;
local buff;
if (type == "rend") then
buff = L["rend"];
if (NWB.faction ~= "Horde" and not NWB.db.global.allianceEnableRend) then
--We only send rend timer warnings to alliance if they have enabled it.
send = nil;
end
elseif (type == "ony") then
buff = L["onyxia"];
elseif (type == "nef") then
buff = L["nefarian"];
elseif (type == "zan") then
buff = L["zan"];
end
local msg;
if (num == 0) then
msg = string.format(L["newBuffCanBeDropped"], buff);
else
msg = string.format(L["buffResetsIn"], buff, NWB:getTimeString(secondsLeft, true));
end
if ((type == "ony" and NWB.data.onyNpcDied > NWB.data.onyTimer)
or (type == "nef" and (NWB.data.nefNpcDied > NWB.data.nefTimer))) then
--If npc killed timestamp is newer than last set time then don't send any warnings.
return;
end
local period = ".";
if (LOCALE_zhCN or LOCALE_zhTW) then
period = "。";
end
msg = msg .. layerMsg .. period;
--Chat.
if (NWB.db.global.chat30 and num == 30 and send) then
NWB:print(msg);
elseif (NWB.db.global.chat15 and num == 15 and send) then
NWB:print(msg);
elseif (NWB.db.global.chat10 and num == 10 and send) then
NWB:print(msg);
elseif (NWB.db.global.chat5 and num == 5 and send) then
NWB:print(msg);
elseif (NWB.db.global.chat1 and num == 1 and send) then
NWB:print(msg);
elseif (NWB.db.global.chat0 and num == 0 and send) then
NWB:print(msg);
end
--Middle of the screen.
local colorTable = {r = self.db.global.middleColorR, g = self.db.global.middleColorG,
b = self.db.global.middleColorB, id = 41, sticky = 0};
if (NWB.db.global.middle30 and num == 30 and send) then
RaidNotice_AddMessage(RaidWarningFrame, NWB:stripColors(msg), colorTable, 5);
elseif (NWB.db.global.middle15 and num == 15 and send) then
RaidNotice_AddMessage(RaidWarningFrame, NWB:stripColors(msg), colorTable, 5);
elseif (NWB.db.global.middle10 and num == 10 and send) then
RaidNotice_AddMessage(RaidWarningFrame, NWB:stripColors(msg), colorTable, 5);
elseif (NWB.db.global.middle5 and num == 5 and send) then
RaidNotice_AddMessage(RaidWarningFrame, NWB:stripColors(msg), colorTable, 5);
elseif (NWB.db.global.middle1 and num == 1 and send) then
RaidNotice_AddMessage(RaidWarningFrame, NWB:stripColors(msg), colorTable, 5);
elseif (NWB.db.global.middle0 and num == 0 and send) then
RaidNotice_AddMessage(RaidWarningFrame, NWB:stripColors(msg), colorTable, 5);
end
--Guild.
local loadWait = GetServerTime() - NWB.loadTime;
if (loadWait > 5 and NWB.db.global.guild30 and num == 30 and send) then
NWB:sendGuildMsg(msg, "guild30");
elseif (loadWait > 5 and NWB.db.global.guild15 and num == 15 and send) then
NWB:sendGuildMsg(msg, "guild15");
elseif (loadWait > 5 and NWB.db.global.guild10 and num == 10 and send) then
NWB:sendGuildMsg(msg, "guild10");
elseif (loadWait > 5 and NWB.db.global.guild5 and num == 5 and send) then
NWB:sendGuildMsg(msg, "guild5");
elseif (loadWait > 5 and NWB.db.global.guild1 and num == 1 and send) then
NWB:sendGuildMsg(msg, "guild1");
elseif (loadWait > 5 and NWB.db.global.guild0 and num == 0 and send) then
NWB:sendGuildMsg(msg, "guild0");
end
if (num == 1) then
NWB:startFlash();
end
end
--Only one person online at a time sends guild msgs so there's no spam, chosen by alphabetical order.
--Can also specify zone so only 1 person from that zone will send the msg (like orgrimmar when npc yell goes out).
--BUG: sometimes a user doesn't register as having addon, checked table they don't exist when this happens.
--Must be some reason they don't send a guild addon msg at logon.
function NWB:sendGuildMsg(msg, type, zoneName)
if (NWB.db.global.disableAllGuildMsgs) then
return;
end
if (not IsInGuild()) then
return;
end
GuildRoster();
local numTotalMembers = GetNumGuildMembers();
local onlineMembers = {};
local me = UnitName("player") .. "-" .. GetNormalizedRealmName();
for i = 1, numTotalMembers do
local name, _, _, _, _, zone, _, _, online, _, _, _, _, isMobile = GetGuildRosterInfo(i);
if (zoneName) then
if (name and zone == zoneName and online and NWB.hasAddon[name] and not isMobile) then
--If guild member is in zone specified and online and has addon installed add to temp table.
--Not currently used anywhere, was removed.
onlineMembers[name] = true;
end
elseif (type) then
--If type then check our db for other peoples settings to ignore them in online list if they have this type disabled.
if (name and online and NWB.hasAddon[name] and not isMobile) then
if (NWB.data[name]) then
--If another guild member check thier settings.
if (NWB.data[name][type] == true and NWB.data[name].disableAllGuildMsgs ~= true) then
--Has addon and has this type of msg type option enabled.
onlineMembers[name] = true;
end
elseif (name == me) then
--If myself check my settings.
if (NWB.db.global[type] == true and NWB.db.global.disableAllGuildMsgs ~= true) then
onlineMembers[name] = true;
end
end
end
else
if (name and online and NWB.hasAddon[name] and not isMobile) then
--If guild member is online and has addon installed add to temp table.
onlineMembers[name] = true;
end
end
end
--Check temp table to see if we're first in alphabetical order.
for k, v in NWB:pairsByKeys(onlineMembers) do
if (k == me) then
SendChatMessage("[WorldBuffs] " .. NWB:stripColors(msg), "guild");
end
return;
end
end
--Guild chat msg event.
local guildWbCmdCooldown, guildDmfCmdCooldown = 0, 0;
function NWB:chatMsgGuild(...)
local msg = ...;
msg = string.lower(msg);
local cmd, arg = strsplit(" ", msg, 2);
if (string.match(msg, "^!wb") and NWB.db.global.guildCommand and (GetServerTime() - guildWbCmdCooldown) > 5) then
guildWbCmdCooldown = GetServerTime();
NWB:sendGuildMsg(NWB:getShortBuffTimers(nil, arg), "guildCommand");
end
if (string.match(msg, "^!dmf") and NWB.db.global.guildCommand and (GetServerTime() - guildDmfCmdCooldown) > 5) then
guildDmfCmdCooldown = GetServerTime();
local output = NWB:getDmfTimeString();
if (output) then
NWB:sendGuildMsg(output, "guildCommand");
end
end
end
--Play an audio queue
local last_played
function NWB:play_sound()
if not last_played or GetTime() - last_played > 8 then
PlaySoundFile([[Interface\AddOns\DBM-Core\sounds\AirHorn.ogg]], 'Master')
last_played = GetTime()
end
end
function NWB:monsterYell(...)
--Skip strict string matching yell msgs for regions we haven't localized yet.
--This could result in less accurate timers but better than no timers at all.
local locale = GetLocale();
local skipStringCheck;
if (NWB.faction == "Horde") then
if (locale == "frFR" or locale == "ptBR" or locale == "esES" or locale == "esMX" or locale == "itIT") then
skipStringCheck = true;
end
end
if (NWB.faction == "Alliance") then
if (locale == "frFR" or locale == "ptBR" or locale == "esES" or locale == "esMX" or locale == "itIT"
or locale == "ruRU" or locale == "deDE" or locale == "zhCN") then
skipStringCheck = true;
end
end
NWB:debugKR(0);
local msg, name = ...;
if ((name == L["Thrall"] or (name == L["Herald of Thrall"] and (not NWB.isLayered or NWB.faction == "Alliance")))
and (string.match(msg, L["Rend Blackhand, has fallen"]) or skipStringCheck)) then
--6 seconds between first rend yell and buff applied.
NWB.data.rendYell = GetServerTime();
NWB:play_sound()
NWB:doFirstYell("rend");
--Send first yell msg to guild so people in org see it, needed because 1 person online only will send msg.
NWB:sendYell("GUILD", "rend");
if (name == L["Herald of Thrall"] and not NWB.isLayered) then
--If it was herald we may we in the barrens but not in crossraods to receive buff, set buff timer.
if (not NWB.isLayered) then
C_Timer.After(5, function()
NWB:setRendBuff("self", UnitName("player"));
end)
end
end
NWB:debugKR(1);
elseif ((name == L["Thrall"] or (name == L["Herald of Thrall"] and (not NWB.isLayered or NWB.faction == "Alliance")))
and string.match(msg, "Be bathed in my power")) then
--Second yell right before drops "Be bathed in my power! Drink in my might! Battle for the glory of the Horde!".
NWB.data.rendYell2 = GetServerTime();
NWB:debugKR(2);
elseif ((name == L["Overlord Runthak"] and (string.match(msg, L["Onyxia, has been slain"]) or skipStringCheck))
or (name == L["Major Mattingly"] and (string.match(msg, L["history has been made"]) or skipStringCheck))) then
--14 seconds between first ony yell and buff applied.
NWB.data.onyYell = GetServerTime();
NWB:play_sound()
NWB:doFirstYell("ony");
--Send first yell msg to guild so people in org see it, needed because 1 person online only will send msg.
NWB:sendYell("GUILD", "ony");
NWB:debugKR(1);
elseif ((name == L["Overlord Runthak"] and string.match(msg, L["Be lifted by the rallying cry"]))
or (name == L["Major Mattingly"] and string.match(msg, L["Onyxia, hangs from the arches"]))) then
--Second yell right before drops "Be lifted by the rallying cry of your dragon slayers".
NWB.data.onyYell2 = GetServerTime();
NWB:debugKR(2);
elseif ((name == L["High Overlord Saurfang"] and (string.match(msg, L["NEFARIAN IS SLAIN"]) or skipStringCheck))
or (name == L["Field Marshal Afrasiabi"] and (string.match(msg, L["the Lord of Blackrock is slain"]) or skipStringCheck))) then
--15 seconds between first nef yell and buff applied.
NWB.data.nefYell = GetServerTime();
NWB:play_sound()
NWB:doFirstYell("nef");
--Send first yell msg to guild so people in org see it, needed because 1 person online only will send msg.
NWB:sendYell("GUILD", "nef");
NWB:debugKR(1);
elseif ((name == L["High Overlord Saurfang"] and string.match(msg, L["Revel in his rallying cry"]))
or (name == L["Field Marshal Afrasiabi"] and string.match(msg, L["Revel in the rallying cry"]))) then
--Second yell right before drops "Be lifted by PlayerName's accomplishment! Revel in his rallying cry!".
NWB.data.nefYell2 = GetServerTime();
NWB:debugKR(2);
elseif ((name == L["Molthor"] or name == L["Zandalarian Emissary"])
and (string.match(msg, L["Begin the ritual"]) or string.match(msg, L["The Blood God"]) or skipStringCheck)) then
--27ish seconds between first zan yell and buff applied if on island.
--45ish seconds between first zan yell and buff applied if in booty bay.
--Booty Bay yell (Zandalarian Emissary yells: The Blood God, the Soulflayer, has been defeated! We are imperiled no longer!)
NWB.data.zanYell = GetServerTime();
NWB:play_sound()
NWB:doFirstYell("zan");
NWB:sendYell("GUILD", "zan");
NWB:debugKR(1);
elseif ((name == L["Molthor"] or name == L["Zandalarian Emissary"]) and string.match(msg, L["slayer of Hakkar"])) then
--Second yell right before drops "All Hail <name>, slayer of Hakkar, and hero of Azeroth!".
--Booty Bay yell (Zandalarian Emissary yells: All Hail <name>, slayer of Hakkar, and hero of Azeroth!)
NWB.data.zanYell2 = GetServerTime();
NWB:debugKR(2);
end
end
--Post first yell warning to guild chat, shared by all different addon comms so no overlap.
local rendFirstYell, onyFirstYell, nefFirstYell, zanFirstYell = 0, 0, 0, 0;
function NWB:doFirstYell(type)
local colorTable = {r = self.db.global.middleColorR, g = self.db.global.middleColorG,
b = self.db.global.middleColorB, id = 41, sticky = 0};
if (type == "rend") then
if ((GetServerTime() - rendFirstYell) > 40) then
--6 seconds from rend first yell to buff drop.
NWB.data.rendYell = GetServerTime();
if (NWB.db.global.guildNpcDialogue and (NWB.faction == "Horde" or NWB.db.global.allianceEnableRend)) then
NWB:sendGuildMsg(L["rendFirstYellMsg"], "guildNpcDialogue");
end
rendFirstYell = GetServerTime();
NWB:startFlash();
if (NWB.db.global.middleBuffWarning) then
RaidNotice_AddMessage(RaidWarningFrame, L["rendFirstYellMsg"], colorTable, 5);
end
NWB:debugKR("rend3");
end
elseif (type == "ony") then
if ((GetServerTime() - onyFirstYell) > 40) then
--14 seconds from ony first yell to buff drop.
NWB.data.onyYell = GetServerTime();
if (NWB.db.global.guildNpcDialogue) then
NWB:sendGuildMsg(L["onyxiaFirstYellMsg"], "guildNpcDialogue");
end
onyFirstYell = GetServerTime();
NWB:startFlash();
if (NWB.db.global.middleBuffWarning) then
RaidNotice_AddMessage(RaidWarningFrame, L["onyxiaFirstYellMsg"], colorTable, 5);
end
NWB:debugKR("ony3");
end
elseif (type == "nef") then
if ((GetServerTime() - nefFirstYell) > 40) then
--15 seconds from nef first yell to buff drop.
NWB.data.nefYell = GetServerTime();
if (NWB.db.global.guildNpcDialogue) then
NWB:sendGuildMsg(L["nefarianFirstYellMsg"], "guildNpcDialogue");
end
nefFirstYell = GetServerTime();
NWB:startFlash();
if (NWB.db.global.middleBuffWarning) then
RaidNotice_AddMessage(RaidWarningFrame, L["nefarianFirstYellMsg"], colorTable, 5);
end
NWB:debugKR("nef3");
end
elseif (type == "zan") then
if ((GetServerTime() - zanFirstYell) > 120) then
--27ish seconds between first zan yell and buff applied if on island.
--45ish seconds between first zan yell and buff applied if in booty bay.
NWB.data.zanYell = GetServerTime();
if (NWB.db.global.chatZan) then
NWB:print(L["zanFirstYellMsg"]);
end
if (NWB.db.global.guildZanDialogue) then
NWB:sendGuildMsg(L["zanFirstYellMsg"], "guildZanDialogue");
end
NWB:debug(L["zanFirstYellMsg"]);
zanFirstYell = GetServerTime();
NWB:startFlash();
if (NWB.db.global.middleBuffWarning) then
RaidNotice_AddMessage(RaidWarningFrame, L["zanFirstYellMsg"], colorTable, 5);
end
NWB:debugKR("zan3");
end
end
end
--Post drop msg to guild chat, shared by all different addon comms so no overlap.
local rendDropMsg, onyDropMsg, nefDropMsg = 0, 0, 0;
function NWB:doBuffDropMsg(data)
local type, layer = strsplit(" ", data, 2);
if (type == "rend") then
if ((GetServerTime() - rendDropMsg) > 40) then
local layerMsg = "";
if (tonumber(layer)) then
layerMsg = " (Layer " .. layer .. ")";
end
if (NWB.db.global.guildBuffDropped) then
NWB:sendGuildMsg(L["rendBuffDropped"] .. layerMsg, "guildBuffDropped");
end
rendDropMsg = GetServerTime();
end
elseif (type == "ony") then
if ((GetServerTime() - onyDropMsg) > 40) then
local layerMsg = "";
if (tonumber(layer)) then
layerMsg = " (Layer " .. layer .. ")";
end
if (NWB.db.global.guildBuffDropped) then
NWB:sendGuildMsg(L["onyxiaBuffDropped"] .. layerMsg, "guildBuffDropped");
end
onyDropMsg = GetServerTime();
end
elseif (type == "nef") then
if ((GetServerTime() - nefDropMsg) > 40) then
local layerMsg = "";
if (tonumber(layer)) then
layerMsg = " (Layer " .. layer .. ")";
end
if (NWB.db.global.guildBuffDropped) then
NWB:sendGuildMsg(L["nefarianBuffDropped"] .. layerMsg, "guildBuffDropped");
end
nefDropMsg = GetServerTime();
end
end
end
local onyNpcKill, nefNpcKill = 0, 0;
function NWB:doNpcKilledMsg(type)
if (type == "ony") then
if ((GetServerTime() - onyNpcKill) > 40) then
if (NWB.db.global.guildNpcKilled) then
if (NWB.faction == "Horde") then
NWB:sendGuildMsg(L["onyxiaNpcKilledHorde"], "guildNpcKilled");
else
NWB:sendGuildMsg(L["onyxiaNpcKilledAlliance"], "guildNpcKilled");
end
end
onyNpcKill = GetServerTime();
end
elseif (type == "nef") then
if ((GetServerTime() - nefNpcKill) > 40) then
if (NWB.db.global.guildNpcKilled) then
if (NWB.faction == "Horde") then
NWB:sendGuildMsg(L["nefarianNpcKilledHorde"], "guildNpcKilled");
else
NWB:sendGuildMsg(L["nefarianNpcKilledAlliance"], "guildNpcKilled");
end
end
nefNpcKill = GetServerTime();
end
end
end
local lastZanBuffGained = 0;
function NWB:combatLogEventUnfiltered(...)
local timestamp, subEvent, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID,
destName, destFlags, destRaidFlags, _, spellName = CombatLogGetCurrentEventInfo();
if (subEvent == "UNIT_DIED") then
local _, _, zone = NWB.dragonLib:GetPlayerZonePosition();
local _, _, _, _, zoneID, npcID = strsplit("-", sourceGUID);
zoneID = tonumber(zoneID);
if ((zone == 1454 or zone == 1411) and destName == L["Overlord Runthak"]) then
if (NWB.faction ~= "Horde") then
return;
end
if (NWB.isLayered and zoneID and NWB.data.layers[zoneID]) then
NWB.data.layers[zoneID].onyNpcDied = GetServerTime();
end
NWB.data.onyNpcDied = GetServerTime();
--if (NWB.db.global.guildNpcKilled) then
-- SendChatMessage("[WorldBuffs] " .. L["onyxiaNpcKilledHorde"], "guild");
--end
NWB:doNpcKilledMsg("ony");
NWB:sendNpcKilled("GUILD", "ony");
NWB:print(L["onyxiaNpcKilledHorde"]);
NWB:timerCleanup();
NWB:sendData("GUILD");
NWB:sendData("YELL"); --Yell is further than npc view range.
elseif ((zone == 1454 or zone == 1411) and destName == L["High Overlord Saurfang"]) then
if (NWB.faction ~= "Horde") then
return;
end
if (NWB.isLayered and zoneID and NWB.data.layers[zoneID]) then
NWB.data.layers[zoneID].nefNpcDied = GetServerTime();
end
NWB.data.nefNpcDied = GetServerTime();
--if (NWB.db.global.guildNpcKilled) then
-- SendChatMessage("[WorldBuffs] " .. L["nefarianNpcKilledHorde"], "guild");
--end
NWB:doNpcKilledMsg("nef");
NWB:sendNpcKilled("GUILD", "nef");
NWB:print(L["nefarianNpcKilledHorde"]);
NWB:timerCleanup();
NWB:sendData("GUILD");
NWB:sendData("YELL"); --Yell is further than npc view range.
elseif ((zone == 1453 or zone == 1429) and destName == L["Major Mattingly"]) then
if (NWB.faction ~= "Alliance") then
return;
end
if (NWB.isLayered and zoneID and NWB.data.layers[zoneID]) then
NWB.data.layers[zoneID].onyNpcDied = GetServerTime();
end
NWB.data.onyNpcDied = GetServerTime();
--if (NWB.db.global.guildNpcKilled) then
-- SendChatMessage("[WorldBuffs] " .. L["onyxiaNpcKilledAlliance"], "guild");
--end
NWB:doNpcKilledMsg("ony");
NWB:sendNpcKilled("GUILD", "ony");
NWB:print(L["onyxiaNpcKilledAlliance"]);
NWB:timerCleanup();
NWB:sendData("GUILD");
NWB:sendData("YELL"); --Yell is further than npc view range.
elseif ((zone == 1453 or zone == 1429) and destName == L["Field Marshal Afrasiabi"]) then
if (NWB.faction ~= "Alliance") then
return;
end
if (NWB.isLayered and zoneID and NWB.data.layers[zoneID]) then
NWB.data.layers[zoneID].nefNpcDied = GetServerTime();
end
NWB.data.nefNpcDied = GetServerTime();
--if (NWB.db.global.guildNpcKilled) then
-- SendChatMessage("[WorldBuffs] " .. L["nefarianNpcKilledAlliance"], "guild");
--end
NWB:doNpcKilledMsg("nef");
NWB:sendNpcKilled("GUILD", "nef");
NWB:print(L["nefarianNpcKilledAlliance"]);
NWB:timerCleanup();
NWB:sendData("GUILD");
NWB:sendData("YELL"); --Yell is further than npc view range.
end
elseif (subEvent == "SPELL_AURA_APPLIED" or subEvent == "SPELL_AURA_REFRESH") then
local unitType, _, _, _, zoneID, npcID = strsplit("-", sourceGUID);
zoneID = tonumber(zoneID);
if (destName == UnitName("player") and spellName == L["Warchief's Blessing"]) then
local expirationTime = NWB:getBuffDuration(L["Warchief's Blessing"], 1);
local _, _, zone = NWB.dragonLib:GetPlayerZonePosition();
--If layered then you must be in org to set the right layer id, the barrens is disabled.
NWB:trackNewBuff(spellName, "rend");
if (NWB.isLayered and (not npcID or npcID ~= "4949")) then
--Some parts on the edges of orgrimmar seem to give the buff from Herald instead of Thrall, even while on map 1454.
--This creates a false 3rd layer with the barrens zoneid, took way too long to figure this out...
NWB:debug("bad rend buff source on layered realm", sourceGUID);
return;
end
if (expirationTime >= 3599.5 and (zone == 1454 or not NWB.isLayered) and unitType == "Creature") then
NWB:setRendBuff("self", UnitName("player"), zoneID, sourceGUID);
end
elseif (destName == UnitName("player") and spellName == L["Spirit of Zandalar"] and (GetServerTime() - lastZanBuffGained) > 1) then
--Zan buff has no sourceName or sourceGUID, not sure why.
local expirationTime = NWB:getBuffDuration(L["Spirit of Zandalar"], 4);
if (expirationTime >= 7199.5) then
NWB:setZanBuff("self", UnitName("player"), zoneID, sourceGUID);
NWB:trackNewBuff(spellName, "zan");
--Not sure why this triggers 4 times on PTR, needs more testing once it's on live server but for now we do a 1 second cooldown.
lastZanBuffGained = GetServerTime();
end
elseif ((npcID == "14720" or npcID == "14721") and destName == UnitName("player") and spellName == L["Rallying Cry of the Dragonslayer"]
and ((GetServerTime() - NWB.data.nefYell2) < 60 or (GetServerTime() - NWB.data.nefYell) < 60)
and unitType == "Creature") then
--To tell the difference between nef and ony we check if there a nef npc yell recently, if not then fall back to ony.
--1 minute is the buff window after 2nd yell to allow for mass lag.
--Doubt any server would drop both heads within 1min of each other.
local expirationTime = NWB:getBuffDuration(L["Rallying Cry of the Dragonslayer"], 2);
local _, _, zone = NWB.dragonLib:GetPlayerZonePosition();
if (expirationTime >= 7199.5) then
if ((zone == 1453 or zone == 1454) or not NWB.isLayered) then
NWB:setNefBuff("self", UnitName("player"), zoneID, sourceGUID);
end
end
elseif ((npcID == "14392" or npcID == "14394")and destName == UnitName("player") and spellName == L["Rallying Cry of the Dragonslayer"]
and ((GetServerTime() - NWB.data.onyYell2) < 60 or (GetServerTime() - NWB.data.onyYell) < 60)
and ((GetServerTime() - NWB.data.nefYell2) > 60)
and unitType == "Creature") then
local expirationTime = NWB:getBuffDuration(L["Rallying Cry of the Dragonslayer"], 2);
local _, _, zone = NWB.dragonLib:GetPlayerZonePosition();
if (expirationTime >= 7199.5) then
if ((zone == 1453 or zone == 1454) or not NWB.isLayered) then
NWB:setOnyBuff("self", UnitName("player"), zoneID, sourceGUID);
end
end
elseif (destName == UnitName("player") and (spellName == L["Sayge's Dark Fortune of Agility"]
or spellName == L["Sayge's Dark Fortune of Spirit"] or spellName == L["Sayge's Dark Fortune of Stamina"]
or spellName == L["Sayge's Dark Fortune of Strength"] or spellName == L["Sayge's Dark Fortune of Armor"]
or spellName == L["Sayge's Dark Fortune of Resistance"] or spellName == L["Sayge's Dark Fortune of Damage"]
or spellName == L["Sayge's Dark Fortune of Intelligence"])) then
local expirationTime = NWB:getBuffDuration(spellName, 0);
if (expirationTime >= 7199) then
NWB:trackNewBuff(spellName, "dmf");
end
elseif (destName == UnitName("player") and npcID == "14822") then
--Backup checking Sayge NPC ID until all localizations are done properly.
--Maybe this is a better way of doing it overall but I have to test when DMF is actually up first.
local expirationTime = NWB:getBuffDuration(spellName, 0);
if (expirationTime >= 7199) then
NWB:trackNewBuff(spellName, "dmf");
end
end
--Check new nef/ony buffs for tracking durations seperately than the buff timer checks with validation above.
if ((npcID == "14720" or npcID == "14721") and destName == UnitName("player")
and spellName == L["Rallying Cry of the Dragonslayer"]) then
local expirationTime = NWB:getBuffDuration(L["Rallying Cry of the Dragonslayer"], 2);
if (expirationTime >= 7199) then
NWB:trackNewBuff(spellName, "nef");
end
elseif ((npcID == "14392" or npcID == "14394") and destName == UnitName("player")
and spellName == L["Rallying Cry of the Dragonslayer"]) then
local expirationTime = NWB:getBuffDuration(L["Rallying Cry of the Dragonslayer"], 2);
if (expirationTime >= 7199) then
NWB:trackNewBuff(spellName, "ony");
end
elseif (destName == UnitName("player") and spellName == L["Songflower Serenade"]) then
local expirationTime = NWB:getBuffDuration(L["Songflower Serenade"], 3);
if (expirationTime >= 3599) then
NWB:trackNewBuff(spellName, "songflower");
end
elseif (npcID == "14326" and destName == UnitName("player")) then
--Mol'dar's Moxie.
local expirationTime = NWB:getBuffDuration(spellName, 0);
if (expirationTime >= 7199) then
NWB:trackNewBuff(spellName, "moxie");
end
elseif (npcID == "14321" and destName == UnitName("player")) then
--Fengus' Ferocity.
local expirationTime = NWB:getBuffDuration(spellName, 0);
if (expirationTime >= 7199) then
NWB:trackNewBuff(spellName, "ferocity");
end
elseif (npcID == "14323" and destName == UnitName("player")) then
--Slip'kik's Savvy.
local expirationTime = NWB:getBuffDuration(spellName, 0);
if (expirationTime >= 7199) then
NWB:trackNewBuff(spellName, "savvy");
end
elseif (NWB.isDebugg and destName == UnitName("player") and spellName == "Ice Armor") then
local expirationTime = NWB:getBuffDuration("Ice Armor", 0);
if (expirationTime >= 1799) then
NWB:trackNewBuff(spellName, "ice");
end
elseif (destName == UnitName("player")
and (spellName == L["Flask of Supreme Power"] or spellName == L["Supreme Power"])) then
local expirationTime = NWB:getBuffDuration(spellName, 0);
if (expirationTime >= 7199) then
NWB:trackNewBuff(spellName, "flaskPower");
end
elseif (destName == UnitName("player") and spellName == L["Flask of the Titans"]) then
--This is the only flask spell with "Flask" in the name it seems.
local expirationTime = NWB:getBuffDuration(spellName, 0);
if (expirationTime >= 7199) then
NWB:trackNewBuff(spellName, "flaskTitans");
end
elseif (destName == UnitName("player")
and (spellName == L["Flask of Distilled Wisdom"] or spellName == L["Distilled Wisdom"])) then
local expirationTime = NWB:getBuffDuration(spellName, 0);
if (expirationTime >= 7199) then
NWB:trackNewBuff(spellName, "flaskWisdom");
end
elseif (destName == UnitName("player")
and (spellName == L["Flask of Chromatic Resistance"] or spellName == L["Chromatic Resistance"])) then
local expirationTime = NWB:getBuffDuration(spellName, 0);
if (expirationTime >= 7199) then
NWB:trackNewBuff(spellName, "flaskResistance");
end
elseif (destName == UnitName("player") and spellName == L["Resist Fire"]) then
local expirationTime = NWB:getBuffDuration(spellName, 0);
if (expirationTime >= 3599) then
NWB:trackNewBuff(spellName, "resistFire");
end
elseif (destName == UnitName("player") and spellName == L["Blessing of Blackfathom"]) then
local expirationTime = NWB:getBuffDuration(spellName, 0);
if (expirationTime >= 3599) then
NWB:trackNewBuff(spellName, "blackfathom");
end
end
elseif (subEvent == "SPELL_AURA_REMOVED" and destName == UnitName("player")) then
NWB:untrackBuff(spellName);
end
end
local rendLastSet, onyLastSet, nefLastSet, zanLastSet = 0, 0, 0, 0;
function NWB:setRendBuff(source, sender, zoneID, GUID)
--Check if this addon has already set a timer a few seconds before another addon's comm.
if (source ~= "self" and (GetServerTime() - NWB.data.rendTimer) < 10) then
return;
end
if (not NWB:validateNewTimer("rend", source)) then
NWB:debug("failed rend timer validation", source);
return;
end
NWB:debugKR("rend4");
if (NWB.isLayered and tonumber(zoneID)) then
NWB:debugKR("rend5");
local count = 0;
for k, v in pairs(NWB.data.layers) do
count = count + 1;
end
if (count <= NWB.limitLayerCount) then
if (not NWB.data.layers[zoneID]) then
NWB:createNewLayer(zoneID, GUID);
end
if (NWB.data.layers[zoneID]) then
NWB:debugKR("rend6");
NWB.data.layers[zoneID].rendTimer = GetServerTime();
NWB.data.layers[zoneID].rendTimerWho = sender;
NWB.data.layers[zoneID].rendSource = source;
NWB.data.layers[zoneID].rendYell = NWB.data.rendYell;
NWB.data.layers[zoneID].rendYell2 = NWB.data.rendYell2;
end
end
end
--Keep recording older non layered data for now.
NWB.data.rendTimer = GetServerTime();
NWB.data.rendTimerWho = sender;
NWB.data.rendSource = source;
NWB:resetWarningTimers("rend", zoneID);
NWB:sendData("GUILD");
local count = 0;
--Once per drop one guild member will say in chat it dropped.
--Throddle the drop msg for when we get multiple sources at the same drop time.
if ((GetServerTime() - rendLastSet) > 60) then
if (NWB.db.global.guildBuffDropped and (NWB.faction == "Horde" or NWB.db.global.allianceEnableRend)) then
if (zoneID) then
for k, v in NWB:pairsByKeys(NWB.data.layers) do
count = count + 1;
if (k == zoneID) then
break;
end
end
end
--NWB:sendGuildMsg(L["rendBuffDropped"] .. layerMsg, "guildBuffDropped");
end
if (NWB.isLayered and count > 0) then
NWB:sendBuffDropped("GUILD", "rend", nil, count);
NWB:doBuffDropMsg("rend " .. count);
else
NWB:sendBuffDropped("GUILD", "rend");
NWB:doBuffDropMsg("rend");
end
end
rendLastSet = GetServerTime();
NWB:debug("set rend buff", source);
NWB.data.myChars[UnitName("player")].rendCount = NWB.data.myChars[UnitName("player")].rendCount + 1;
NWB:debug("zoneid drop", zoneID, count);
end
function NWB:setZanBuff(source, sender, zoneID, GUID)
--Disabled, there is no cooldown, will remove all the zand timer code at a later point.
--[[if (not NWB.zand) then
return;
end
NWB:debug("6");
if (source ~= "self" and (GetServerTime() - NWB.data.zanTimer) < 10) then
return;
end
if (not NWB:validateNewTimer("zan", source)) then
NWB:debug("failed zan timer validation", source);
return;
end
NWB:debug("7");
NWB.data.zanTimer = GetServerTime();
NWB.data.zanTimerWho = sender;
NWB.data.zanSource = source;
NWB:resetWarningTimers("zan", zoneID);
NWB:sendData("GUILD");
--Once per drop one guild member will say in chat it dropped.
--Throddle the drop msg for when we get multiple sources at the same drop time.
if ((GetServerTime() - zanLastSet) > 120) then
if (NWB.db.global.guildBuffDropped) then
NWB:sendGuildMsg(L["zanBuffDropped"], "guildBuffDropped");
end
end
zanLastSet = GetServerTime();
NWB:debug("set zan buff", source);]]
NWB.data.myChars[UnitName("player")].zanCount = NWB.data.myChars[UnitName("player")].zanCount + 1;
NWB:debug("zoneid drop", zoneID);
end
function NWB:setOnyBuff(source, sender, zoneID, GUID)
--Ony and nef share a last set cooldown to prevent any bugs with both being set at once.
if ((GetServerTime() - nefLastSet) < 20) then
return;
end
if (source ~= "self" and (GetServerTime() - NWB.data.onyTimer) < 10) then
return;
end
if (not NWB:validateNewTimer("ony", source)) then
NWB:debug("failed ony timer validation", source);
return;
end
NWB:debugKR("ony4");
if (NWB.isLayered and tonumber(zoneID)) then
NWB:debugKR("ony5");
local count = 0;
for k, v in pairs(NWB.data.layers) do
count = count + 1;
end
if (count <= NWB.limitLayerCount) then
if (not NWB.data.layers[zoneID]) then
NWB:createNewLayer(zoneID, GUID);
end
if (NWB.data.layers[zoneID]) then
NWB:debugKR("ony6");
NWB.data.layers[zoneID].onyTimer = GetServerTime();
NWB.data.layers[zoneID].onyTimerWho = sender;
NWB.data.layers[zoneID].onyNpcDied = 0;
NWB.data.layers[zoneID].onySource = source;
NWB.data.layers[zoneID].onyYell = NWB.data.onyYell;
NWB.data.layers[zoneID].onyYell2 = NWB.data.onyYell2;
end
end
end
NWB.data.onyTimer = GetServerTime();
NWB.data.onyTimerWho = sender;
NWB.data.onyNpcDied = 0;
NWB.data.onySource = source;
NWB:resetWarningTimers("ony", zoneID);
NWB:sendData("GUILD");
local count = 0;
if ((GetServerTime() - onyLastSet) > 60) then
local count = 0;
if (NWB.db.global.guildBuffDropped) then
if (zoneID) then
for k, v in NWB:pairsByKeys(NWB.data.layers) do
count = count + 1;
if (k == zoneID) then
break;
end
end
end
--NWB:sendGuildMsg(L["onyxiaBuffDropped"] .. layerMsg, "guildBuffDropped");
end
if (NWB.isLayered and count > 0) then
NWB:sendBuffDropped("GUILD", "ony", nil, count);
NWB:doBuffDropMsg("ony " .. count);
else
NWB:sendBuffDropped("GUILD", "ony");
NWB:doBuffDropMsg("ony");
end
end
onyLastSet = GetServerTime();
NWB:debug("set ony buff", source);
NWB.data.myChars[UnitName("player")].onyCount = NWB.data.myChars[UnitName("player")].onyCount + 1;
NWB:debug("zoneid drop", zoneID, count);
end
function NWB:setNefBuff(source, sender, zoneID, GUID)
--Ony and nef share a last set cooldown to prevent any bugs with both being set at once.
if ((GetServerTime() - onyLastSet) < 20) then
return;
end
if (source ~= "self" and (GetServerTime() - NWB.data.nefTimer) < 10) then
return;
end
if (not NWB:validateNewTimer("nef", source)) then
NWB:debug("failed nef timer validation", source);
return;
end
NWB:debugKR("nef4");
if (NWB.isLayered and tonumber(zoneID)) then
NWB:debugKR("nef5");
local count = 0;
for k, v in pairs(NWB.data.layers) do
count = count + 1;
end
NWB:debugKR("nef6");
if (count <= NWB.limitLayerCount) then
if (not NWB.data.layers[zoneID]) then
NWB:createNewLayer(zoneID, GUID);
end
if (NWB.data.layers[zoneID]) then
NWB.data.layers[zoneID].nefTimer = GetServerTime();
NWB.data.layers[zoneID].nefTimerWho = sender;
NWB.data.layers[zoneID].nefNpcDied = 0;
NWB.data.layers[zoneID].nefSource = source;
NWB.data.layers[zoneID].nefYell = NWB.data.nefYell;
NWB.data.layers[zoneID].nefYell2 = NWB.data.nefYell2;
end
end
end
NWB.data.nefTimer = GetServerTime();
NWB.data.nefTimerWho = sender;
NWB.data.nefNpcDied = 0;
NWB.data.nefSource = source;
NWB:resetWarningTimers("nef", zoneID);
NWB:sendData("GUILD");
local count = 0;
if ((GetServerTime() - nefLastSet) > 60) then
local count = 0;
if (NWB.db.global.guildBuffDropped) then
if (zoneID) then
for k, v in NWB:pairsByKeys(NWB.data.layers) do
count = count + 1;
if (k == zoneID) then
break;
end
end
end
--NWB:sendGuildMsg(L["nefarianBuffDropped"] .. layerMsg, "guildBuffDropped");
end
if (NWB.isLayered and count > 0) then
NWB:sendBuffDropped("GUILD", "nef", nil, count);
NWB:doBuffDropMsg("nef " .. count);
else
NWB:sendBuffDropped("GUILD", "nef");
NWB:doBuffDropMsg("nef");
end
end
nefLastSet = GetServerTime();
NWB:debug("set nef buff", source);
NWB.data.myChars[UnitName("player")].nefCount = NWB.data.myChars[UnitName("player")].nefCount + 1;
NWB:debug("zoneid drop", zoneID, count);
end
--Validate new timer, mostly used for testing blanket fixes for timers.
function NWB:validateNewTimer(type, source, timestamp)
if (type == "rend") then
return true;
elseif (type == "ony") then
if (source == "dbm") then
local timer = NWB.data.onyTimer;
local respawnTime = NWB.db.global.onyRespawnTime;
if ((timer - 30) > (GetServerTime() - respawnTime) and not (NWB.data.onyNpcDied > timer)) then
--Don't set dbm timers if valid timer already exists (current bug).
NWB:debug("trying to set timer from dbm when timer already exists");
return;
end
end
if (NWB.data.nefTimer == timestamp or NWB.data.nefTimer == GetServerTime()) then
NWB:debug("ony trying to set exact same timer as nef", source);
--Make sure ony never syncs with nef time stamp (current bug).
return;
end
elseif (type == "nef") then
if (NWB.data.onyTimer == timestamp or NWB.data.onyTimer == GetServerTime()) then
NWB:debug("nef trying to set exact same timer as ony", source);
--Make sure nef never syncs with ony time stamp (current bug).
return;
end
end
--If this is a realm with layering still (TW/CN) then don't overwrite timers ever, atleast 1 layer will be correct then.
--Really not sure why Blizzard still have layering in these asian regions.
--if (NWB.isLayered and NWB.data[type .. "Timer"]
--Disabled for now for new layer tracking method.
-- and (NWB.data[type .. "Timer"] > (GetServerTime() - NWB.db.global[type .. "RespawnTime"]))) then
-- return;
--end
return true;
end
function NWB:validateTimestamp(timestamp)
local currentTime = GetServerTime();
if (timestamp > 2585912598) then
return;
end
if (timestamp > (currentTime + 86400)) then
return;
end
return true;
end
--Track our current buff durations across all chars.
local gotPlayedData;
function NWB:trackNewBuff(spellName, type)
if (not NWB.data.myChars[UnitName("player")].buffs[spellName]) then
NWB.data.myChars[UnitName("player")].buffs[spellName] = {};
end
if (not NWB.data.myChars[UnitName("player")].buffs[spellName].setTime) then
NWB.data.myChars[UnitName("player")].buffs[spellName].setTime = 0;
end
if (not NWB.data.myChars[UnitName("player")].buffs[spellName].timeLeft) then
NWB.data.myChars[UnitName("player")].buffs[spellName].timeLeft = 0;
end
NWB.data.myChars[UnitName("player")].buffs[spellName].type = type;
--Set timestamp as a backup to calc from when dmf buff is got.
NWB.data.myChars[UnitName("player")].buffs[spellName].setTime = GetServerTime();
NWB.data.myChars[UnitName("player")].buffs[spellName].track = true;
--Request played data when getting new buff drops to calc from as primary.
--Use local cache if we have a valid number from RequestTimePlayed() at logon, otherwise request new data.
if (NWB.played > 600) then
NWB.data.myChars[UnitName("player")].buffs[spellName].playedCacheSetAt = NWB.played;
NWB:syncBuffsWithCurrentDuration();
NWB:recalcBuffTimers();
else
NWB.currentTrackBuff = NWB.data.myChars[UnitName("player")].buffs[spellName];
--Hide the msg from chat.
if (not gotPlayedData) then
DEFAULT_CHAT_FRAME:UnregisterEvent("TIME_PLAYED_MSG");
gotPlayedData = true;
RequestTimePlayed();
end
end
if (type == "dmf") then
NWB:print(string.format(L["dmfBuffDropped"], spellName));
end
NWB:debug("Tracking new buff", type, spellName);
end
function NWB:untrackBuff(spellName)
if (NWB.data.myChars[UnitName("player")].buffs and NWB.data.myChars[UnitName("player")].buffs[spellName]) then
--local hasBuff;
--for i = 1, 32 do
-- local spellName = UnitBuff("player", i);
-- if (NWB.data.myChars[UnitName("player")].buffs and NWB.data.myChars[UnitName("player")].buffs[spellName]) then
-- hasBuff = true;
-- end
--end
--if (not hasBuff) then
NWB.data.myChars[UnitName("player")].buffs[spellName].track = false;
--end
end
end
--Recalc time left on buffs we track.
--We recalc it from current total played time vs total played we recorded at time of buff drop.
function NWB:recalcBuffTimers()
if (NWB.data.myChars[UnitName("player")].buffs) then
for k, v in pairs(NWB.data.myChars[UnitName("player")].buffs) do
if (not v.timeLeft or not v.setTime) then
NWB.data.myChars[UnitName("player")].buffs[k] = nil;
else
if (not gotPlayedData) then
NWB:debug("no played data found");
return
end
if (not v.playedCacheSetAt) then
v.playedCacheSetAt = 0;
end
--Calc the difference between current total played time and the played time we record when buff was gotten.
v.timeLeft = NWB.db.global[v.type .. "BuffTime"] - (NWB.played - v.playedCacheSetAt);
--NWB.data.myChars[UnitName("player")].buffs[k].timeLeft = NWB.db.global[v.type .. "BuffTime"] - (NWB.played - v.playedCacheSetAt);
end
end
end
end
--/played can sometimes drift a bit with buff durations, probably due to loads times and such.
--Here we resync the buff tracking with current buff durations.
function NWB:syncBuffsWithCurrentDuration()
for i = 1, 32 do
local spellName, _, _, _, _, expirationTime, _, _, _, spellID = UnitBuff("player", i);
if (NWB.data.myChars[UnitName("player")].buffs and NWB.data.myChars[UnitName("player")].buffs[spellName]) then
if (NWB.played > 600) then
local type = NWB.data.myChars[UnitName("player")].buffs[spellName].type;
local timeLeft = expirationTime - GetTime();
local maxDuration = NWB.db.global[type .. "BuffTime"] or 0;
local elapsedDuration = maxDuration - timeLeft;
local newPlayedCache = NWB.played - elapsedDuration;
--Change the played seconds this was buff was set at to match the current time elapsed on our current buff.
NWB.data.myChars[UnitName("player")].buffs[spellName].playedCacheSetAt = math.floor(newPlayedCache);
--NWB:debug("resyncing tracked buff", spellName);
end
elseif (spellID == 16609 or spellID == 22888 or spellID == 24425 or spellID == 23768 or spellID == 23769
or spellID == 23767 or spellID == 23766 or spellID == 23738 or spellID == 23737 or spellID == 23735
or spellID == 23736 or spellID == 22818 or spellID == 22817 or spellID == 22820 or spellID == 17626
or spellID == 17628 or spellID == 17627 or spellID == 17629 or spellID == 15366 or spellID == 15123) then
--Temorary adding of buffs that aren't fresh while this new feature is out, usually we record them on drop.
local spellTypes = {
[16609] = "rend",
[22888] = "ony",
--[22888] = "nef",
[24425] = "zan",
[23768] = "dmf", --Sayge's Dark Fortune of Damage
[23769] = "dmf", --Sayge's Dark Fortune of Resistance
[23767] = "dmf", --Sayge's Dark Fortune of Armor
[23766] = "dmf", --Sayge's Dark Fortune of Intelligence
[23738] = "dmf", --Sayge's Dark Fortune of Spirit
[23737] = "dmf", --Sayge's Dark Fortune of Stamina
[23735] = "dmf", --Sayge's Dark Fortune of Strength
[23736] = "dmf", --Sayge's Dark Fortune of Agility
[22818] = "moxie",
[22817] = "ferocity",
[22820] = "savvy",
[17628] = "flaskPower", --Supreme Power.
[17626] = "flaskTitans", --Flask of the Titans (only flask spell with Flask in the name, dunno why).
[17627] = "flaskWisdom", --Distilled Wisdom.
[17629] = "flaskResistance", --Chromatic Resistance.
[15366] = "songflower",
[15123] = "resistFire", --LBRS fire resist buff.
[8733] = "blackfathom", --Blessing of Blackfathom
};
if (NWB.played > 600 and spellTypes[spellID]) then
local type = spellTypes[spellID];
NWB.data.myChars[UnitName("player")].buffs[spellName] = {};
NWB.data.myChars[UnitName("player")].buffs[spellName].type = type;
local timeLeft = expirationTime - GetTime();
local maxDuration = NWB.db.global[type .. "BuffTime"] or 0;
local elapsedDuration = maxDuration - timeLeft;
local newPlayedCache = NWB.played - elapsedDuration;
NWB.data.myChars[UnitName("player")].buffs[spellName].setTime = GetServerTime();
NWB.data.myChars[UnitName("player")].buffs[spellName].track = true;
--Change the played seconds this was buff was set at to match the current time elapsed on our current buff.
NWB.data.myChars[UnitName("player")].buffs[spellName].playedCacheSetAt = math.floor(newPlayedCache);
NWB:debug("resyncing2 tracked buff", spellName);
end
end
end
NWB:recalcBuffTimers();
end
--Played time data received, update local cache.
function NWB:timePlayedMsg(...)
local totalPlayed = ...;
--Update played cache for ticker when /played data received.
if (totalPlayed > 0) then
NWB.played = totalPlayed;
end
--Only set the total played seconds at time of a new buff drop we track.
if (totalPlayed > 0 and NWB.currentTrackBuff ~= nil) then
NWB.currentTrackBuff.playedCacheSetAt = totalPlayed;
--NWB:recalcBuffTimers();
NWB.currentTrackBuff = nil;
end
--Reregister the chat frame event after we're done.
--C_Timer.After(5, function()
DEFAULT_CHAT_FRAME:RegisterEvent("TIME_PLAYED_MSG");
--end)
NWB:syncBuffsWithCurrentDuration();
NWB:recalcBuffTimers();
end
--This only runs once at load time.
function NWB:setLayered()
--This needs to be changed to a table later.
--TW realms.
if (NWB.realm == "伊弗斯" or NWB.realm == "瑪拉頓"
--CN realms (so many realms and all have layering apparently, wtf?).
or NWB.realm == "匕首岭" or NWB.realm == "乌洛克" or NWB.realm == "厄运之槌" or NWB.realm == "巴罗夫"
or NWB.realm == "无尽风暴" or NWB.realm == "无畏" or NWB.realm == "木喉要塞" or NWB.realm == "比格沃斯"
or NWB.realm == "比斯巨兽" or NWB.realm == "水晶之牙" or NWB.realm == "火锤" or NWB.realm == "加丁"
or NWB.realm == "巨人追猎者" or NWB.realm == "巨龙沼泽" or NWB.realm == "巨龙追猎者" or NWB.realm == "布劳缪克丝"
or NWB.realm == "布鲁" or NWB.realm == "弗莱拉斯" or NWB.realm == "末日之刃" or NWB.realm == "龙之召唤"
or NWB.realm == "龙牙" or NWB.realm == "伊森迪奥斯" or NWB.realm == "伦鲁迪洛尔" or NWB.realm == "光芒"
or NWB.realm == "吉兹洛克" or NWB.realm == "安娜丝塔丽" or NWB.realm == "灰烬使者" or NWB.realm == "艾隆纳亚"
or NWB.realm == "克罗米" or NWB.realm == "希尔盖" or NWB.realm == "怀特迈恩" or NWB.realm == "沙尔图拉"
or NWB.realm == "沙顶" or NWB.realm == "灵风" or NWB.realm == "狂野之刃" or NWB.realm == "辛洛斯"
or NWB.realm == "辛迪加" or NWB.realm == "迈克斯纳" or NWB.realm == "卓越" or NWB.realm == "审判"
or NWB.realm == "帕奇维克" or NWB.realm == "拉姆斯登" or NWB.realm == "法尔班克斯" or NWB.realm == "法拉克斯"
or NWB.realm == "法琳娜" or NWB.realm == "觅心者" or NWB.realm == "阿什坎迪" or NWB.realm == "阿拉希盆地"
or NWB.realm == "阿鲁高" or NWB.realm == "哈霍兰" or NWB.realm == "奎尔塞拉" or NWB.realm == "娅尔罗"
or NWB.realm == "怒炉" or NWB.realm == "狮心" or NWB.realm == "祈福" or NWB.realm == "范克瑞斯"
or NWB.realm == "范克瑞斯" or NWB.realm == "范沃森" or NWB.realm == "埃提耶什" or NWB.realm == "席瓦莱恩"
or NWB.realm == "神谕林地" or NWB.realm == "秩序之源" or NWB.realm == "诺克赛恩" or NWB.realm == "诺格弗格"
or NWB.realm == "骨火" or NWB.realm == "曼多基尔" or NWB.realm == "维克尼拉斯" or NWB.realm == "维克托"
or NWB.realm == "维克洛尔" or NWB.realm == "维希度斯" or NWB.realm == "莫格莱尼" or NWB.realm == "奥罗"
or NWB.realm == "奥金斧" or NWB.realm == "寒冰之王" or NWB.realm == "寒脊山小径" or NWB.realm == "湖畔镇"
or NWB.realm == "黑曜石之锋" or NWB.realm == "塞卡尔" or NWB.realm == "塞雷布拉斯" or NWB.realm == "毁灭之刃"
or NWB.realm == "萨弗拉斯" or NWB.realm == "萨弗隆" or NWB.realm == "雷德" or NWB.realm == "雷霆之击"
or NWB.realm == "碧玉矿洞" or NWB.realm == "碧空之歌" or NWB.realm == "赫洛德" or NWB.realm == "德姆塞卡尔"
or NWB.realm == "震地者" or NWB.realm == "霜语"
--US/OCE layered realms.
or NWB.realm == "Arugal" or NWB.realm == "Benediction" or NWB.realm == "Earthfury" or NWB.realm == "Faerlina"
or NWB.realm == "Fairbanks" or NWB.realm == "Herod" or NWB.realm == "Pagle" or NWB.realm == "Sulfuras"
or NWB.realm == "Whitemane"
--EU layered realms.
or NWB.realm == "Auberdine" or NWB.realm == "Ashbringer" or NWB.realm == "Firemaw" or NWB.realm == "Flamegor"
or NWB.realm == "Gehennas" or NWB.realm == "Golemagg" or NWB.realm == "Mograine" or NWB.realm == "Sulfuron"
or NWB.realm == "Venoxis" or NWB.realm == "Пламегор"
--KR layered realms.
or NWB.realm == "로크홀라" or NWB.realm == "얼음피" or NWB.realm == "힐스브레드" or NWB.realm == "라그나로스"
or NWB.realm == "소금 평원") then
NWB.isLayered = true;
end
end
function NWB:setLayerLimit()
if (fsdfsfs) then
NWB.limitLayerCount = 2;
end
end
--Make sure warning msg values are correct for the current time left on each timer.
function NWB:timerCleanup()
local types = {
[1] = "rend",
[2] = "ony",
[3] = "nef",
--[4] = "zan"
};
for k, v in pairs(types) do
local offset = 0;
if (NWB.isLayered) then
for layer, value in NWB:pairsByKeys(NWB.data.layers) do
if (v == "rend") then
offset = NWB.db.global.rendRespawnTime;
NWB:resetWarningTimers("rend", layer);
elseif (v == "ony") then
offset = NWB.db.global.onyRespawnTime;
NWB:resetWarningTimers("ony", layer);
elseif (v == "nef") then
offset = NWB.db.global.nefRespawnTime;
NWB:resetWarningTimers("nef", layer);
--elseif (v == "zan") then
-- offset = NWB.db.global.zanRespawnTime;
-- NWB:resetWarningTimers("zan", layer);
end
--Clear warning timers that ended while we were offline or if NPC was killed since last buff.
if (NWB.data.layers[layer][v .. "NpcDied"]
and NWB.data.layers[layer][v .. "NpcDied"] > (GetServerTime() - NWB.db.global[v .. "RespawnTime"])) then
NWB.data.layers[layer][v .. "30"] = nil;
NWB.data.layers[layer][v .. "15"] = nil;
NWB.data.layers[layer][v .. "10"] = nil;
NWB.data.layers[layer][v .. "5"] = nil;
NWB.data.layers[layer][v .. "1"] = nil;
NWB.data.layers[layer][v .. "0"] = nil;
elseif (NWB.data.layers[layer][v .. "Timer"]
and ((NWB.data.layers[layer][v .. "Timer"] + offset) - GetServerTime()) < 0) then
NWB.data.layers[layer][v .. "30"] = nil;
NWB.data.layers[layer][v .. "15"] = nil;
NWB.data.layers[layer][v .. "10"] = nil;
NWB.data.layers[layer][v .. "5"] = nil;
NWB.data.layers[layer][v .. "1"] = nil;
NWB.data.layers[layer][v .. "0"] = nil;
elseif (NWB.data.layers[layer][v .. "Timer"]
and ((NWB.data.layers[layer][v .. "Timer"] + offset) - GetServerTime()) < 60) then
NWB.data.layers[layer][v .. "30"] = nil;
NWB.data.layers[layer][v .. "15"] = nil;
NWB.data.layers[layer][v .. "10"] = nil;
NWB.data.layers[layer][v .. "5"] = nil;
NWB.data.layers[layer][v .. "1"] = nil;
elseif (NWB.data.layers[layer][v .. "Timer"]
and ((NWB.data.layers[layer][v .. "Timer"] + offset) - GetServerTime()) < 300) then
NWB.data.layers[layer][v .. "30"] = nil;
NWB.data.layers[layer][v .. "15"] = nil;
NWB.data.layers[layer][v .. "10"] = nil;
NWB.data.layers[layer][v .. "5"] = nil;
elseif (NWB.data.layers[layer][v .. "Timer"]
and ((NWB.data.layers[layer][v .. "Timer"] + offset) - GetServerTime()) < 600) then
NWB.data.layers[layer][v .. "30"] = nil;
NWB.data.layers[layer][v .. "15"] = nil;
NWB.data.layers[layer][v .. "10"] = nil;
elseif (NWB.data.layers[layer][v .. "Timer"]
and ((NWB.data.layers[layer][v .. "Timer"] + offset) - GetServerTime()) < 900) then
NWB.data.layers[layer][v .. "30"] = nil;
NWB.data.layers[layer][v .. "15"] = nil;
elseif (NWB.data.layers[layer][v .. "Timer"]
and ((NWB.data.layers[layer][v .. "Timer"] + offset) - GetServerTime()) < 1800) then
NWB.data.layers[layer][v .. "30"] = nil;
end
end
else
if (v == "rend") then
offset = NWB.db.global.rendRespawnTime;
NWB:resetWarningTimers("rend");
elseif (v == "ony") then
offset = NWB.db.global.onyRespawnTime;
NWB:resetWarningTimers("ony");
elseif (v == "nef") then
offset = NWB.db.global.nefRespawnTime;
NWB:resetWarningTimers("nef");
--elseif (v == "zan") then
-- offset = NWB.db.global.zanRespawnTime;
-- NWB:resetWarningTimers("zan");
end
--Clear warning timers that ended while we were offline or if NPC was killed since last buff.
if (NWB.data[v .. "NpcDied"] and NWB.data[v .. "NpcDied"] > (GetServerTime() - NWB.db.global[v .. "RespawnTime"])) then
NWB.data[v .. "30"] = nil;
NWB.data[v .. "15"] = nil;
NWB.data[v .. "10"] = nil;
NWB.data[v .. "5"] = nil;
NWB.data[v .. "1"] = nil;
NWB.data[v .. "0"] = nil;
elseif (((NWB.data[v .. "Timer"] + offset) - GetServerTime()) < 0) then
NWB.data[v .. "30"] = nil;
NWB.data[v .. "15"] = nil;
NWB.data[v .. "10"] = nil;
NWB.data[v .. "5"] = nil;
NWB.data[v .. "1"] = nil;
NWB.data[v .. "0"] = nil;
elseif (((NWB.data[v .. "Timer"] + offset) - GetServerTime()) < 60) then
NWB.data[v .. "30"] = nil;
NWB.data[v .. "15"] = nil;
NWB.data[v .. "10"] = nil;
NWB.data[v .. "5"] = nil;
NWB.data[v .. "1"] = nil;
elseif (((NWB.data[v .. "Timer"] + offset) - GetServerTime()) < 300) then
NWB.data[v .. "30"] = nil;
NWB.data[v .. "15"] = nil;
NWB.data[v .. "10"] = nil;
NWB.data[v .. "5"] = nil;
elseif (((NWB.data[v .. "Timer"] + offset) - GetServerTime()) < 600) then
NWB.data[v .. "30"] = nil;
NWB.data[v .. "15"] = nil;
NWB.data[v .. "10"] = nil;
elseif (((NWB.data[v .. "Timer"] + offset) - GetServerTime()) < 900) then
NWB.data[v .. "30"] = nil;
NWB.data[v .. "15"] = nil;
elseif (((NWB.data[v .. "Timer"] + offset) - GetServerTime()) < 1800) then
NWB.data[v .. "30"] = nil;
end
end
end
end
--Reset and enable all warning msgs for specified timer.
function NWB:resetWarningTimers(type, layer)
if (NWB.isLayered and layer) then
NWB.data.layers[layer][type .. "30"] = true;
NWB.data.layers[layer][type .. "15"] = true;
NWB.data.layers[layer][type .. "10"] = true;
NWB.data.layers[layer][type .. "5"] = true;
NWB.data.layers[layer][type .. "1"] = true;
NWB.data.layers[layer][type .. "0"] = true;
else
NWB.data[type .. "30"] = true;
NWB.data[type .. "15"] = true;
NWB.data[type .. "10"] = true;
NWB.data[type .. "5"] = true;
NWB.data[type .. "1"] = true;
NWB.data[type .. "0"] = true;
end
end
local f = CreateFrame("Frame");
f:RegisterEvent("PLAYER_ENTERING_WORLD");
f:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
f:RegisterEvent("CHAT_MSG_MONSTER_YELL");
f:RegisterEvent("GROUP_JOINED");
f:RegisterEvent("TIME_PLAYED_MSG");
f:RegisterEvent("PLAYER_LOGIN");
f:RegisterEvent("CHAT_MSG_WHISPER");
f:RegisterEvent("CHAT_MSG_BN_WHISPER");
local doLogon = true;
f:SetScript("OnEvent", function(self, event, ...)
if (event == "PLAYER_LOGIN") then
--Testing this here instead of PLAYER_ENTERING_WORLD, maybe it fires slightly faster enough to stop duplicate msgs.
NWB.loadTime = GetServerTime();
NWB:requestData("GUILD", nil, "ALERT");
self:RegisterEvent("CHAT_MSG_GUILD");
C_Timer.After(10, function()
--If for some reason we get no replys to first msg, send again in 10 seconds (trying to fix a bug).
--Could be that first msg trys to send before chat connects on rare occasions?
if (not foundPartner) then
NWB:requestData("GUILD", nil, "ALERT");
end
end)
C_Timer.After(30, function()
--Send a ping with settings after 30 seconds to make sure we are registered as having the addon to others.
--There's a rare bug that makes 2 clients send a timer msg at once due to not registering each others clients.
--Not sure of the reason yet but it could be logging on at exact same time or something? This could fix that.
NWB:requestSettings("GUILD");
NWB:syncBuffsWithCurrentDuration();
end)
C_Timer.After(45, function()
--Can't work out why sometimes 2 users send same msg in guild chat, someitmes they don't register other as having the addon.
--Another temp bug fix just to see if it's an issue with the serialized table data being sent..
--NWB:sendComm("GUILD", "ping");
C_ChatInfo.SendAddonMessage(NWB.commPrefix, "ping", "GUILD");
end)
elseif (event == "PLAYER_ENTERING_WORLD") then
if (doLogon) then
GuildRoster();
if (NWB.db.global.logonPrint) then
C_Timer.After(10, function()
GuildRoster(); --Attempting to fix slow guild roster update at logon.
NWB:printBuffTimers(true);
end);
end
--If WorldBuffTimers isn't installed then send it's data request to guild.
--if (not WorldBuffTracker_HandleSync and IsInGuild()) then
-- C_ChatInfo.SendAddonMessage("WBT-0", 11326, "GUILD");
--end
--First request after logon is high prio so gets sent right away, need to register addon users asap so no duplicate guild msgs.
--NWB:requestData("GUILD", nil, "ALERT");
C_Timer.After(5, function()
--Only request played data at logon if we didn't get it already for some reason.
if (not gotPlayedData) then
gotPlayedData = true;
DEFAULT_CHAT_FRAME:UnregisterEvent("TIME_PLAYED_MSG");
RequestTimePlayed();
end
end)
--Temp debug.
if (NWB.isDebug) then
NWB:refreshWorldbuffMarkers();
end
doLogon = nil;
end
NWB:sendData("YELL");
elseif (event == "COMBAT_LOG_EVENT_UNFILTERED") then
NWB:combatLogEventUnfiltered(...);
elseif (event == "CHAT_MSG_MONSTER_YELL") then
NWB:monsterYell(...);
elseif (event == "GROUP_JOINED") then
C_Timer.After(5, function()
if (UnitInBattleground("player")) then
return;
end
if (IsInRaid()) then
NWB:sendData("RAID");
elseif (IsInGroup()) then
NWB:sendData("PARTY");
end
end)
elseif (event == "CHAT_MSG_GUILD") then
NWB:chatMsgGuild(...);
elseif (event == "TIME_PLAYED_MSG") then
gotPlayedData = true;
NWB:timePlayedMsg(...);
elseif (event == "CHAT_MSG_WHISPER") then
local _, name = ...;
NWB.lastWhisper = name;
NWB.lastWhisperType = "whisper";
elseif (event == "CHAT_MSG_BN_WHISPER") then
local _, name, _, _, _, _, _, _, _, _, _, _, presenceID = ...;
NWB.lastWhisper = presenceID;
NWB.lastWhisperType = "bnet";
end
end)
--Flight paths.
local doCheckLeaveFlghtPath = false;
hooksecurefunc("TakeTaxiNode", function(...)
doCheckLeaveFlghtPath = true;
--Give it a few seconds to get on the taxi.
C_Timer.After(5, function()
NWB.checkLeaveFlghtPath();
--Wipe felwood songflower detected players when leaving.
NWB.detectedPlayers = {};
end)
NWB:sendData("YELL");
end)
--Loop this func till flight path is left.
function NWB.checkLeaveFlghtPath()
local isOnFlightPath = UnitOnTaxi("player");
if (not isOnFlightPath) then
doCheckLeaveFlghtPath = false;
--Send data to people close when dismounting a flightpath.
NWB:sendData("YELL");
end
if (doCheckLeaveFlghtPath) then
C_Timer.After(2, function()
NWB.checkLeaveFlghtPath();
end)
end
end
--Convert seconds to a readable format.
function NWB:getTimeString(seconds, countOnly, short)
local timecalc = 0;
if (countOnly) then
timecalc = seconds;
else
timecalc = seconds - time();
end
local d = math.floor((timecalc % (86400*365)) / 86400);
local h = math.floor((timecalc % 86400) / 3600);
local m = math.floor((timecalc % 3600) / 60);
local s = math.floor((timecalc % 60));
local space = "";
if (LOCALE_koKR or LOCALE_zhCN or LOCALE_zhTW) then
space = " ";
end
if (short) then
if (d == 1 and h == 0) then
return d .. L["dayShort"];
elseif (d == 1) then
return d .. L["dayShort"] .. space .. h .. L["hourShort"];
end
if (d > 1 and h == 0) then
return d .. L["dayShort"];
elseif (d > 1) then
return d .. L["dayShort"] .. space .. h .. L["hourShort"];
end
if (h == 1 and m == 0) then
return h .. L["hourShort"];
elseif (h == 1) then
return h .. L["hourShort"] .. space .. m .. L["minuteShort"];
end
if (h > 1 and m == 0) then
return h .. L["hourShort"];
elseif (h > 1) then
return h .. L["hourShort"] .. space .. m .. L["minuteShort"];
end
if (m == 1 and s == 0) then
return m .. L["minuteShort"];
elseif (m == 1) then
return m .. L["minuteShort"] .. space .. s .. L["secondShort"];
end
if (m > 1 and s == 0) then
return m .. L["minuteShort"];
elseif (m > 1) then
return m .. L["minuteShort"] .. space .. s .. L["secondShort"];
end
--If no matches it must be seconds only.
return s .. L["secondShort"];
else
if (d == 1 and h == 0) then
return d .. " " .. L["day"];
elseif (d == 1) then
return d .. " " .. L["day"] .. " " .. h .. " " .. L["hours"];
end
if (d > 1 and h == 0) then
return d .. " " .. L["days"];
elseif (d > 1) then
return d .. " " .. L["days"] .. " " .. h .. " " .. L["hours"];
end
if (h == 1 and m == 0) then
return h .. " " .. L["hour"];
elseif (h == 1) then
return h .. " " .. L["hour"] .. " " .. m .. " " .. L["minutes"];
end
if (h > 1 and m == 0) then
return h .. " " .. L["hours"];
elseif (h > 1) then
return h .. " " .. L["hours"] .. " " .. m .. " " .. L["minutes"];
end
if (m == 1 and s == 0) then
return m .. " " .. L["minute"];
elseif (m == 1) then
return m .. " " .. L["minute"] .. " " .. s .. " " .. L["seconds"];
end
if (m > 1 and s == 0) then
return m .. " " .. L["minutes"];
elseif (m > 1) then
return m .. " " .. L["minutes"] .. " " .. s .. " " .. L["seconds"];
end
--If no matches it must be seconds only.
return s .. " " .. L["seconds"];
end
end
--Returns am/pm and lt/st format.
function NWB:getTimeFormat(timeStamp, fullDate)
if (NWB.db.global.timeStampZone == "server") then
--This is ugly and shouldn't work, and probably doesn't work on some time difference.
--Need a better solution but all I can get from the wow client in server time is hour:mins, not date or full timestamp.
local data = date("*t", GetServerTime());
local localHour, localMin = data.hour, data.min;
local serverHour, serverMin = GetGameTime();
local localSecs = (localMin*60) + ((localHour*60)*60);
local serverSecs = (serverMin*60) + ((serverHour*60)*60);
local diff = localSecs - serverSecs;
--local diff = difftime(localSecs - serverSecs);
local serverTime = 0;
--if (localHour < serverHour) then
-- timeStamp = timeStamp - (diff + 86400);
--else
timeStamp = timeStamp - diff;
--end
end
if (NWB.db.global.timeStampFormat == 12) then
--Strip leading zero and convert to lowercase am/pm.
if (fullDate) then
return date("%a %b %d", timeStamp) .. " " .. gsub(string.lower(date("%I:%M%p", timeStamp)), "^0", "");
else
return gsub(string.lower(date("%I:%M%p", timeStamp)), "^0", "");
end
else
if (fullDate) then
local dateFormat = NWB:getRegionTimeFormat();
return date(dateFormat .. " %H:%M:%S", timeStamp);
else
return date("%H:%M:%S", timeStamp);
end
end
end
--Date 24h string format based on region, won't be 100% accurate but better than %x returning US format for every region like it does now.
function NWB:getRegionTimeFormat()
local dateFormat = "%x";
local region = GetCurrentRegion();
if (NWB.realm == "Arugal" or NWB.realm == "Felstriker" or NWB.realm == "Remulos" or NWB.realm == "Yojamba") then
--OCE
dateFormat = "%d/%m/%y";
elseif (NWB.realm == "Sulthraze" or NWB.realm == "Loatheb") then
--Brazil/Latin America.
dateFormat = "%d/%m/%y";
elseif (region == 1) then
--US.
dateFormat = "%m/%d/%y";
elseif (region == 2 or region == 4 or region == 5) then
--Korea, Taiwan, Chinda all same format.
dateFormat = "%y/%m/%d";
elseif (region == 3) then
--EU.
dateFormat = "%d/%m/%y";
end
return dateFormat;
end
local lastFlash = 0;
function NWB:startFlash()
if (NWB.db.global.flashMinimized) then
if (lastFlash < (GetServerTime() - 4)) then
FlashClientIcon();
lastFlash = GetServerTime();
end
end
end
--Accepts both types of RGB.
function NWB:RGBToHex(r, g, b)
r = tonumber(r);
g = tonumber(g);
b = tonumber(b);
--Check if whole numbers.
if (r == math.floor(r) and g == math.floor(g) and b == math.floor(b)) then
r = r <= 255 and r >= 0 and r or 0;
g = g <= 255 and g >= 0 and g or 0;
b = b <= 255 and b >= 0 and b or 0;
return string.format("%02x%02x%02x", r, g, b);
else
return string.format("%02x%02x%02x", r*255, g*255, b*255);
end
end
--English buff names, we check both english and locale names for buff durations just to be sure in untested locales.
local englishBuffs = {
[0] = "NoNe",
[1] = "Warchief's Blessing",
[2] = "Rallying Cry of the Dragonslayer",
[3] = "Songflower Serenade",
[4] = "Spirit of Zandalar"
}
--Get seconds left on a buff by name.
function NWB:getBuffDuration(buff, englishID)
for i = 1, 32 do
local name, _, _, _, _, expirationTime = UnitBuff("player", i);
if ((name and name == buff) or (englishID and name == englishBuffs[englishID])) then
return expirationTime - GetTime();
end
end
return 0;
end
--Check if player is in guild, accepts full realm name and normalized.
function NWB:isPlayerInGuild(who, onlineOnly)
if (not IsInGuild()) then
return;
end
GuildRoster();
local numTotalMembers = GetNumGuildMembers();
local normalizedWho = string.gsub(who, " ", "");
normalizedWho = string.gsub(normalizedWho, "'", "");
local me = UnitName("player") .. "-" .. GetRealmName();
local normalizedMe = UnitName("player") .. "-" .. GetNormalizedRealmName();
if (who == me or who == normalizedMe) then
return true;
end
for i = 1, numTotalMembers do
local name, _, _, _, _, _, _, _, online, _, _, _, _, isMobile = GetGuildRosterInfo(i);
if (onlineOnly) then
if (name and (name == who or name == normalizedWho) and online and not isMobile) then
return true;
end
else
if (name and (name == who or name == normalizedWho)) then
return true;
end
end
end
end
--PHP explode type function.
function NWB:explode(div, str, count)
if (div == '') then
return false;
end
local pos,arr = 0,{};
local index = 0;
for st, sp in function() return string.find(str, div, pos, true) end do
index = index + 1;
table.insert(arr, string.sub(str, pos, st-1));
pos = sp + 1;
if (count and index == count) then
table.insert(arr, string.sub(str, pos));
return arr;
end
end
table.insert(arr, string.sub(str, pos));
return arr;
end
--Iterate table keys in alphabetical order.
function NWB:pairsByKeys(t, f)
local a = {};
for n in pairs(t) do
table.insert(a, n);
end
table.sort(a, f);
local i = 0;
local iter = function()
i = i + 1;
if (a[i] == nil) then
return nil;
else
return a[i], t[a[i]];
end
end
return iter;
end
--Strip escape strings from chat msgs.
function NWB:stripColors(str)
local escapes = {
["|c%x%x%x%x%x%x%x%x"] = "", --Color start.
["|r"] = "", --Color end.
--["|H.-|h(.-)|h"] = "%1", --Links.
["|T.-|t"] = "", --Textures.
["{.-}"] = "", --Raid target icons.
};
if (str) then
for k, v in pairs(escapes) do
str = gsub(str, k, v);
end
end
return str;
end
function NWB:debug(...)
if (NWB.isDebug) then
if (type(...) == "table") then
UIParentLoadAddOn('Blizzard_DebugTools');
--DevTools_Dump(...);
DisplayTableInspectorWindow(...);
else
print("NWBDebug:", ...);
end
end
end
--Temp debug for a korean realm problem.
function NWB:debugKR(...)
if (NWB.isDebugKR) then
--if (type(...) == "table") then
--UIParentLoadAddOn('Blizzard_DebugTools');
--DevTools_Dump(...);
--DisplayTableInspectorWindow(...);
--else
print("KRDebug:", ...);
--end
end
end
SLASH_NWBCMD1, SLASH_NWBCMD2, SLASH_NWBCMD3, SLASH_NWBCMD4, SLASH_NWBCMD5, SLASH_NWBCMD6
= '/nwb', '/novaworldbuff', '/novaworldbuffs', '/wb', '/worldbuff', '/worldbuffs';
function SlashCmdList.NWBCMD(msg, editBox)
local cmd, arg;
if (msg) then
msg = string.lower(msg);
cmd, arg = strsplit(" ", msg, 2);
if (arg) then
msg = cmd;
end
end
if (msg == "reset") then
NWB:resetTimerData();
return;
end
if (msg == "layermap") then
NWB:openLayerMapFrame();
return;
end
if (msg == "version" or msg == "versions") then
NWB:openVersionFrame();
return;
end
if (msg == "show" or msg == "buff" or msg == "buffs") then
NWB:openBuffListFrame();
return;
end
if (msg == "group" or msg == "team") then
msg = "party";
end
if (msg == "map") then
WorldMapFrame:Show();
if (NWB.faction == "Alliance") then
WorldMapFrame:SetMapID(1453);
else
WorldMapFrame:SetMapID(1454);
end
return;
end
if (msg == "options" or msg == "option" or msg == "config" or msg == "menu") then
--Opening the frame needs to be run twice to avoid a bug.
InterfaceOptionsFrame_OpenToCategory("NovaWorldBuffs");
--Hack to fix the issue of interface options not opening to menus below the current scroll range.
--This addon name starts with N and will always be closer to the middle so just scroll to the middle when opening.
local min, max = InterfaceOptionsFrameAddOnsListScrollBar:GetMinMaxValues();
if (min < max) then
InterfaceOptionsFrameAddOnsListScrollBar:SetValue(math.floor(max/2));
end
InterfaceOptionsFrame_OpenToCategory("NovaWorldBuffs");
elseif (msg ~= nil and msg ~= "") then
NWB:print(NWB:getShortBuffTimers(nil, arg), msg);
else
NWB:printBuffTimers();
if (NWB.isLayered) then
NWB:openLayerFrame();
end
end
end
function NWB:resetTimerData()
NWB:resetBuffData();
for k, v in pairs(NWB.songFlowers) do
NWB.data[k] = 0;
end
for k, v in pairs(NWB.tubers) do
NWB.data[k] = 0;
end
for k, v in pairs(NWB.dragons) do
NWB.data[k] = 0;
end
NWB.data.layers = {};
NWB.data.rendTimer = 0;
NWB.data.rendYell = 0;
NWB.data.rendYell2 = 0;
NWB.data.onyTimer = 0;
NWB.data.onyYell = 0;
NWB.data.onyYell2 = 0;
NWB.data.onyNpcDied = 0;
NWB.data.nefTimer = 0;
NWB.data.nefYell = 0;
NWB.data.nefYell2 = 0;
NWB.data.nefNpcDied = 0;
--zanTimer = 0;
NWB.data.zanYell = 0;
NWB.data.zanYell2 = 0;
NWB:print("All timer data has been reset.");
end
---===== Most of these are now disabled, only DBM is left =====---
---Parse other world buff addons for increased accuracy and to spread more data around.
---Thanks to all authors for their work.
---If any of these authors ask me to stop parsing their comms I'll remove it.
function NWB:registerOtherAddons()
self:RegisterComm("D4C");
end
--DBM.
local dbmLastRend, dbmLastOny, dbmLastNef, dbmLastZan = 0, 0, 0, 0;
function NWB:parseDBM(prefix, msg, channel, sender)
if (NWB.isLayered) then
--We need the NPC GUIDs for buff setting on layered realms so exclude DBM from those realms.
return;
end
--Strings.
--D4C WBA rendBlackhand Horde Warchief's Blessing 59 GUILD
--D4C WBA Onyxia Horde Rallying Cry of the Dragonslayer 15 GUILD
--D4C WBA Nefarian Horde Rallying Cry of the Dragonslayer 17 GUILD
--Same exact string comes from DBM for both yell msgs so disabled timer delay for now. SendWorldSync(self, "WBA", "Zandalar\tBoth\t"..spellName.."\t12")
if (string.match(msg, "rendBlackhand")
and (string.match(msg, "Warchief's Blessing") or string.match(msg, L["Warchief's Blessing"]))) then
NWB:doFirstYell("rend");
--6 seconds between DBM comm (first npc yell) and rend buff drop.
if (GetServerTime() - dbmLastRend > 30) then
C_Timer.After(7, function()
NWB:setRendBuff("dbm", sender);
end)
dbmLastRend = GetServerTime();
end
end
--I think maybe DBM is sending ony buff msg sometimes for nef, needs more testing.
if (string.match(msg, "Onyxia")
and (string.match(msg, "Rallying Cry of the Dragonslayer") or string.match(msg, L["Rallying Cry of the Dragonslayer"]))) then
NWB:doFirstYell("ony");
--14 seconds between DBM comm (first npc yell) and buff drop.
if (GetServerTime() - dbmLastOny > 30) then
C_Timer.After(15, function()
NWB:setOnyBuff("dbm", sender);
end)
dbmLastOny = GetServerTime();
end
end
if (string.match(msg, "Nefarian")
and (string.match(msg, "Rallying Cry of the Dragonslayer") or string.match(msg, L["Rallying Cry of the Dragonslayer"]))) then
NWB:doFirstYell("nef");
--15 seconds between DBM comm (first npc yell) and buff drop.
if (GetServerTime() - dbmLastNef > 30) then
C_Timer.After(16, function()
NWB:setNefBuff("dbm", sender);
end)
dbmLastNef = GetServerTime();
end
end
if (string.match(msg, "Zandalar")
and (string.match(msg, "Spirit of Zandalar") or string.match(msg, L["Spirit of Zandalar"]))) then
NWB:doFirstYell("zan");
NWB:debug("dbm doing zand");
--27ish seconds between first zan yell and buff applied if on island.
--45ish seconds between first zan yell and buff applied if in booty bay.
--Call it 30.
if (GetServerTime() - dbmLastRend > 50) then
C_Timer.After(30, function()
NWB:setZanBuff("dbm", sender);
end)
dbmLastZan = GetServerTime();
end
end
end
---TODO
--Add some sounds.
---=======---
---Felwood---
---=======---
function NWB:setSongFlowers()
NWB.songFlowers = {
--Songflowers in order from north to south. --Coords taken from NWB.dragonLib:GetPlayerZonePosition().
["flower1"] = {x = 63.9, y = 6.1, subZone = L["North Felpaw Village"]}, --x 63.907248382611, y 6.0921582958694
["flower2"] = {x = 55.8, y = 10.4, subZone = L["West Felpaw Village"]}, --x 55.80811845313, y 10.438248169009
["flower3"] = {x = 50.6, y = 13.9, subZone = L["North of Irontree Woods"]}, --x 50.575074328086, y 13.918245916971
["flower4"] = {x = 63.3, y = 22.6, subZone = L["Talonbranch Glade"]}, -- x 63.336814849559, y 22.610425663249
["flower5"] = {x = 40.1, y = 44.4, subZone = L["Shatter Scar Vale"]}, --x 40.142029982253, y 44.353905770542
["flower6"] = {x = 34.3, y = 52.2, subZone = L["Bloodvenom Post"]}, --x 34.345508209303, y 52.179993391643
["flower7"] = {x = 40.1, y = 56.5, subZone = L["East of Jaedenar"]}, --x 40.142029982253, y 56.523472021355
["flower8"] = {x = 48.3, y = 75.7, subZone = L["North of Emerald Sanctuary"]}, -- x 48.260292045699, y 75.650435262435
["flower9"] = {x = 45.9, y = 85.2, subZone = L["West of Emerald Sanctuary"]}, --x 45.942030228517, y 85.219126632059
["flower10"] = {x = 52.9, y = 87.8, subZone = L["South of Emerald Sanctuary"]}, --x 52.893336145267, y 87.825217631218
}
if (NWB.faction == "Horde") then
NWB.songFlowers.flower6.subZone = L["Bloodvenom Post"] .. " FP";
end
end
NWB.tubers = {
--Whipper root in order from north to south.
--Taken from wowhead, could be some missing.
["tuber1"] = {x = 49.5, y = 12.2, subZone = L["North of Irontree Woods"]},
["tuber2"] = {x = 50.6, y = 18.2, subZone = L["Irontree Woods"]},
["tuber3"] = {x = 40.7, y = 19.2, subZone = L["West of Irontree Woods"]},
["tuber4"] = {x = 43.0, y = 46.9, subZone = L["Bloodvenom Falls"]},
["tuber5"] = {x = 34.1, y = 60.3, subZone = L["Jaedenar"]},
["tuber6"] = {x = 40.2, y = 85.2, subZone = L["West of Emerald Sanctuary"]},
};
NWB.dragons = {
--Night dragon in order from north to south.
--Taken from wowhead, could be some missing.
["dragon1"] = {x = 42.5, y = 13.9, subZone = L["North-West of Irontree Woods"]},
["dragon2"] = {x = 50.6, y = 30.5, subZone = L["South of Irontree Woods"]},
["dragon3"] = {x = 35.1, y = 59.0, subZone = L["Jaedenar"]},
["dragon4"] = {x = 40.7, y = 78.3, subZone = L["West of Emerald Sanctuary"]},
};
--Debug.
function NWB:resetSongFlowers()
if (NWB.db.global.resetSongflowers) then
for k, v in pairs(NWB.songFlowers) do
NWB.data[k] = 0;
end
NWB.db.global.resetSongflowers = false;
end
end
SLASH_NWBSFCMD1, SLASH_NWBSFCMD2, SLASH_NWBSFCMD3, SLASH_NWBSFCMD4 = '/sf', '/sfs', '/songflower', '/songflowers';
function SlashCmdList.NWBSFCMD(msg, editBox)
if (msg) then
msg = string.lower(msg);
end
if (msg == "map") then
WorldMapFrame:Show();
WorldMapFrame:SetMapID(1448);
return;
end
if (msg == "options" or msg == "option" or msg == "config" or msg == "menu") then
--Opening the frame needs to be run twice to avoid a bug.
InterfaceOptionsFrame_OpenToCategory("NovaWorldBuffs");
--Hack to fix the issue of interface options not opening to menus below the current scroll range.
--This addon name starts with N and will always be closer to the middle so just scroll to the middle when opening.
local min, max = InterfaceOptionsFrameAddOnsListScrollBar:GetMinMaxValues();
if (min < max) then
InterfaceOptionsFrameAddOnsListScrollBar:SetValue(math.floor(max/2));
end
InterfaceOptionsFrame_OpenToCategory("NovaWorldBuffs");
return;
end
local string = L["Songflower"] .. ":";
local found;
for k, v in pairs(NWB.songFlowers) do
local time = (NWB.data[k] + 1500) - GetServerTime();
if (time > 0) then
local minutes = string.format("%02.f", math.floor(time / 60));
local seconds = string.format("%02.f", math.floor(time - minutes * 60));
string = string .. " (" .. v.subZone .. " " .. minutes .. "m" .. seconds .. "s)";
found = true;
end
end
if (not found) then
string = string .. " " .. L["noActiveTimers"] .. ".";
end
if (msg ~= nil and msg ~= "") then
NWB:print(string, msg);
else
NWB:print(string);
end
end
NWB.detectedPlayers = {};
local f = CreateFrame("Frame");
f:RegisterEvent("PLAYER_TARGET_CHANGED");
f:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
f:RegisterEvent("PLAYER_ENTERING_WORLD");
f:RegisterEvent("CHAT_MSG_LOOT");
f:SetScript('OnEvent', function(self, event, ...)
if (event == "COMBAT_LOG_EVENT_UNFILTERED") then
local _, _, zone = NWB.dragonLib:GetPlayerZonePosition();
local timestamp, subEvent, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID,
destName, destFlags, destRaidFlags, _, spellName = CombatLogGetCurrentEventInfo();
if ((subEvent == "SPELL_AURA_APPLIED" or subEvent == "SPELL_AURA_REFRESH") and spellName == L["Songflower Serenade"]) then
if (destName == UnitName("player")) then
--If buff is ours we'll validate it's a new buff incase we logon beside a songflower with the buff.
local expirationTime = NWB:getBuffDuration(L["Songflower Serenade"], 3)
if (expirationTime >= 3599) then
local closestFlower = NWB:getClosestSongflower();
if (NWB.data[closestFlower]) then
NWB:songflowerPicked(closestFlower);
end
end
elseif (not NWB.db.global.mySongflowerOnly) then
--If buff is not ours then we'll hope they didn't logon beside us at a songflower and set it.
--There's an option to make it only set if it's our buff in /wb config.
--I'll look for a way to tell if a player just entered our view or logged on later and check if buff is new that way.
local closestFlower = NWB:getClosestSongflower();
if (NWB.data[closestFlower]) then
NWB:songflowerPicked(closestFlower, destName);
end
end
end
if (zone == 1448) then
if (sourceName) then
NWB.detectedPlayers[sourceName] = GetServerTime();
elseif (destName) then
NWB.detectedPlayers[destName] = GetServerTime();
end
end
elseif (event == "PLAYER_TARGET_CHANGED") then
local _, _, zone = NWB.dragonLib:GetPlayerZonePosition();
if (zone == 1448) then
local name = UnitName("target");
if (name) then
NWB.detectedPlayers[UnitName("target")] = GetServerTime();
end
end
elseif (event == "PLAYER_ENTERING_WORLD") then
--Wipe felwood songflower detected players when leaving, it costs very little to just wipe this on every zone.
NWB.detectedPlayers = {};
elseif (event == "CHAT_MSG_LOOT") then
local msg = ...;
local name, otherPlayer;
--Self receive multiple loot "You receive loot: [Item]x2"
local itemLink, amount = string.match(msg, string.gsub(string.gsub(LOOT_ITEM_SELF_MULTIPLE, "%%s", "(.+)"), "%%d", "(%%d+)"));
if (not itemLink) then
--Self receive single loot "You receive loot: [Item]"
itemLink = msg:match(LOOT_ITEM_SELF:gsub("%%s", "(.+)"));
if (not itemLink) then
--Self receive multiple item "You receive item: [Item]x2"
itemLink, amount = string.match(msg, string.gsub(string.gsub(LOOT_ITEM_PUSHED_SELF_MULTIPLE, "%%s", "(.+)"), "%%d", "(%%d+)"));
--itemLink = msg:match(LOOT_ITEM_SELF:gsub("%%s", "(.+)"));
if (not itemLink) then
--Self receive single item "You receive item: [Item]"
itemLink = msg:match(LOOT_ITEM_PUSHED_SELF:gsub("%%s", "(.+)"));
end
end
end
--If no matches for self loot then check other player loot msgs.
if (not itemLink) then
--Other player receive multiple loot "Otherplayer receives loot: [Item]x2"
otherPlayer, itemLink, amount = string.match(msg, string.gsub(string.gsub(LOOT_ITEM_MULTIPLE, "%%s", "(.+)"), "%%d", "(%%d+)"));
if (not itemLink) then
--Other player receive single loot "Otherplayer receives loot: [Item]"
otherPlayer, itemLink = msg:match("^" .. LOOT_ITEM:gsub("%%s", "(.+)"));
if (not itemLink) then
--Other player loot multiple item "Otherplayer receives item: [Item]x2"
otherPlayer, itemLink, amount = string.match(msg, string.gsub(string.gsub(LOOT_ITEM_PUSHED_MULTIPLE, "%%s", "(.+)"), "%%d", "(%%d+)"));
if (not itemLink) then
--Other player receive single item "Otherplayer receives item: [Item]"
otherPlayer, itemLink = msg:match("^" .. LOOT_ITEM_PUSHED:gsub("%%s", "(.+)"));
end
end
end
end
--otherPlayer is basically a waste of time here, since it's a pushed item not a looted item the team doesn't see it be looted.
--But I'll keep my looted item function in tact anyway, maybe I'll track some other item here in the future.
if (itemLink) then
local item = Item:CreateFromItemLink(itemLink);
if (item) then
local itemID = item:GetItemID();
if (itemID and itemID == 11951) then
local closestTuber = NWB:getClosestTuber();
if (NWB.data[closestTuber]) then
NWB:tuberPicked(closestTuber, otherPlayer);
end
elseif (itemID and itemID == 11952) then
local closestDragon = NWB:getClosestDragon();
if (NWB.data[closestDragon]) then
NWB:dragonPicked(closestDragon, otherPlayer);
end
end
end
end
end
end)
--Check tooltips for players while waiting at the songflower, doesn't really matter if it adds non-player stuff, it gets wiped when leaving.
--This shouldn't be done OnUpdate but it will do for now and only happens in felwood.
--Not sure how to detect tooltip changed, OnShow doesn't work when tooltip changes before fading out.
--This whole thing is pretty ugly right now.
GameTooltip:HookScript("OnUpdate", function()
--This may need some more work to handle custom tooltip addons like elvui etc.
local _, _, zone = NWB.dragonLib:GetPlayerZonePosition();
if (zone == 1448) then
for i = 1, GameTooltip:NumLines() do
local line =_G["GameTooltipTextLeft"..i];
local text = line:GetText();
if (text and text ~= nil and text ~= "") then
local name;
if (string.match(text, " ")) then
name = NWB:stripColors(string.match(text, "%s(%S+)$"));
else
name = NWB:stripColors(text);
end
if (name) then
NWB.detectedPlayers[name] = GetServerTime();
end
end
--Iterate first line only.
return;
end
end
end)
--I record some data to try and make sure if another player picked flower infront of us it's valid and not an old buff.
--Check if player has been seen before (avoid logon buff aura gained events).
--Check if there is already a valid timer for the songflower (they should never be reset except server restart?)
local pickedTime = 0;
function NWB:songflowerPicked(type, otherPlayer)
local _, _, zone = NWB.dragonLib:GetPlayerZonePosition();
if (zone ~= 1448) then
--We're not in felwood.
return;
end
--If other player has not been seen before it may be someone logging in with the buff.
if (otherPlayer and not NWB.detectedPlayers[otherPlayer]) then
NWB:debug("Previously unseen player with buff:", otherPlayer);
return;
end
if (otherPlayer and (GetServerTime() - NWB.detectedPlayers[otherPlayer] > 1500)) then
NWB:debug("Player seen too long ago:", otherPlayer);
return;
end
if ((GetServerTime() - pickedTime) > 5) then
--Validate only if another player, we already check ours is valid by duration check.
if (otherPlayer and NWB.data[type] > (GetServerTime() - 1500)) then
NWB:debug("Trying to overwrite a valid songflower timer.");
return;
end
local timestamp = GetServerTime();
if (NWB:validateTimestamp(timestamp)) then
NWB.data[type] = timestamp;
--if (IsInGuild() and NWB.db.global.guildSongflower and not NWB.db.global.disableAllGuildMsgs) then
-- SendChatMessage(string.format(L["songflowerPicked"], NWB.songFlowers[type].subZone), "guild");
--end
NWB:doFlowerMsg(type);
NWB:sendFlower("GUILD", type);
NWB:sendData("GUILD");
NWB:sendData("YELL");
end
pickedTime = timestamp;
end
end
local flowerMsg = 0;
function NWB:doFlowerMsg(type)
if (type and (GetServerTime() - flowerMsg) > 10) then
if (NWB.db.global.guildSongflower) then
NWB:sendGuildMsg(string.format(L["songflowerPicked"], NWB.songFlowers[type].subZone), "guildSongflower");
end
flowerMsg = GetServerTime();
end
end
local tuberPickedTime = 0;
function NWB:tuberPicked(type, otherPlayer)
local _, _, zone = NWB.dragonLib:GetPlayerZonePosition();
if (zone ~= 1448) then
--We're not in felwood.
return;
end
if ((GetServerTime() - tuberPickedTime) > 5) then
if (NWB.data[type] > (GetServerTime() - 1500)) then
NWB:debug("Trying to overwrite a valid tuber timer.");
return;
end
local timestamp = GetServerTime();
if (NWB:validateTimestamp(timestamp)) then
NWB.data[type] = timestamp;
NWB:sendData("GUILD");
NWB:sendData("YELL");
end
tuberPickedTime = timestamp;
end
end
local dragonPickedTime = 0;
function NWB:dragonPicked(type, otherPlayer)
local _, _, zone = NWB.dragonLib:GetPlayerZonePosition();
if (zone ~= 1448) then
--We're not in felwood.
return;
end
if ((GetServerTime() - dragonPickedTime) > 5) then
if (NWB.data[type] > (GetServerTime() - 1500)) then
NWB:debug("Trying to overwrite a valid dragon timer.");
return;
end
local timestamp = GetServerTime();
if (NWB:validateTimestamp(timestamp)) then
NWB.data[type] = timestamp;
NWB:sendData("GUILD");
NWB:sendData("YELL");
end
dragonPickedTime = timestamp;
end
end
--Gets which songflower we are closest to, if we are actually beside one.
function NWB:getClosestSongflower()
local x, y, zone = NWB.dragonLib:GetPlayerZonePosition();
if (zone ~= 1448) then
--We're not in felwood.
return;
end
for k, v in pairs(NWB.songFlowers) do
--The distance returned by this is actually much further than yards like is specifed on the addon page.
--It returns 2 yards when I'm more like 50 yards away, it's good enough for this check anyway, songflowers aren't close together.
--Seems it returns the distance in coords you are away not the distance in yards? 1 yard is smaller than x = 1.0 coord?
local distance = NWB.dragonLib:GetWorldDistance(zone, x*100, y*100, v.x, v.y);
if (distance <= 2) then
return k;
end
end
end
function NWB:getClosestTuber()
local x, y, zone = NWB.dragonLib:GetPlayerZonePosition();
if (zone ~= 1448) then
return;
end
for k, v in pairs(NWB.tubers) do
local distance = NWB.dragonLib:GetWorldDistance(zone, x*100, y*100, v.x, v.y);
if (distance <= 2) then
return k;
end
end
end
function NWB:getClosestDragon()
local x, y, zone = NWB.dragonLib:GetPlayerZonePosition();
if (zone ~= 1448) then
return;
end
for k, v in pairs(NWB.dragons) do
local distance = NWB.dragonLib:GetWorldDistance(zone, x*100, y*100, v.x, v.y);
if (distance <= 2) then
return k;
end
end
end
--Update timers for Felwood worldmap when the map is open.
function NWB:updateFelwoodWorldmapMarker(type)
--Seconds left.
local time = (NWB.data[type] + 1500) - GetServerTime();
if (time > 0) then
--If timer is less than 25 minutes old then return time left.
local minutes = string.format("%02.f", math.floor(time / 60));
local seconds = string.format("%02.f", math.floor(time - minutes * 60));
_G[type .. "NWB"].timerFrame:Show();
local tooltipText = "|CffDEDE42" .. _G[type .. "NWB"].name .. "|r\n" .. _G[type .. "NWB"].subZone .. "\n"
.. NWB:getTimeFormat(NWB.data[type] + 1500) .. " " .. L["spawn"];
_G[type .. "NWB"].tooltip.fs:SetText(tooltipText);
_G[type .. "NWB"].tooltip:SetWidth(_G[type .. "NWB"].tooltip.fs:GetStringWidth() + 18);
_G[type .. "NWB"].tooltip:SetHeight(_G[type .. "NWB"].tooltip.fs:GetStringHeight() + 12);
return minutes .. ":" .. seconds;
end
_G[type .. "NWB"].tooltip.fs:SetText("|CffDEDE42" .. _G[type .. "NWB"].name .. "|r\n" .. _G[type .. "NWB"].subZone);
_G[type .. "NWB"].tooltip:SetWidth(_G[type .. "NWB"].tooltip.fs:GetStringWidth() + 18);
_G[type .. "NWB"].tooltip:SetHeight(_G[type .. "NWB"].tooltip.fs:GetStringHeight() + 12);
_G[type .. "NWB"].timerFrame:Hide();
return "";
end
--Update timer for minimap.
function NWB:updateFelwoodMinimapMarker(type)
--Seconds left.
local time = (NWB.data[type] + 1500) - GetServerTime();
if (time > 0) then
--If timer is less than 25 minutes old then return time left.
local minutes = string.format("%02.f", math.floor(time / 60));
local seconds = string.format("%02.f", math.floor(time - minutes * 60));
_G[type .. "NWBMini"].timerFrame:Show();
local tooltipText = "|CffDEDE42" .. _G[type .. "NWB"].name .. "|r\n" .. _G[type .. "NWB"].subZone .. "\n"
.. NWB:getTimeFormat(NWB.data[type] + 1500) .. " " .. L["spawn"];
_G[type .. "NWBMini"].tooltip.fs:SetText(tooltipText);
_G[type .. "NWBMini"].tooltip:SetWidth(_G[type .. "NWBMini"].tooltip.fs:GetStringWidth() + 9);
_G[type .. "NWBMini"].tooltip:SetHeight(_G[type .. "NWBMini"].tooltip.fs:GetStringHeight() + 9);
return minutes .. ":" .. seconds;
end
_G[type .. "NWBMini"].tooltip.fs:SetText("|CffDEDE42" .. _G[type .. "NWB"].name .. "|r\n" .. _G[type .. "NWB"].subZone);
_G[type .. "NWBMini"].tooltip:SetWidth(_G[type .. "NWBMini"].tooltip.fs:GetStringWidth() + 9);
_G[type .. "NWBMini"].tooltip:SetHeight(_G[type .. "NWBMini"].tooltip.fs:GetStringHeight() + 9);
_G[type .. "NWBMini"].timerFrame:Hide();
return L["noTimer"];
end
function NWB:createSongflowerMarkers()
local iconLocation = "Interface\\Icons\\spell_holy_mindvision";
for k, v in pairs(NWB.songFlowers) do
--Worldmap marker.
local obj = CreateFrame("Frame", k .. "NWB", WorldMapFrame);
obj.type = k;
obj.name = L["Songflower"];
obj.subZone = v.subZone;
local bg = obj:CreateTexture(nil, "MEDIUM");
bg:SetTexture(iconLocation);
bg:SetAllPoints(obj);
obj.texture = bg;
obj:SetSize(15, 15);
--World map tooltip.
obj.tooltip = CreateFrame("Frame", k.. "Tooltip", WorldMapFrame, "TooltipBorderedFrameTemplate");
obj.tooltip:SetPoint("CENTER", obj, "CENTER", 0, -36);
obj.tooltip:SetFrameStrata("TOOLTIP");
obj.tooltip:SetFrameLevel(9);
obj.tooltip.fs = obj.tooltip:CreateFontString(k .. "NWBTooltipFS", "ARTWORK");
obj.tooltip.fs:SetPoint("CENTER", 0, 0);
obj.tooltip.fs:SetFont(NWB.regionFont, 12);
obj.tooltip.fs:SetText("|CffDEDE42" .. L["Songflower"] .. "|r\n" .. v.subZone);
obj.tooltip:SetWidth(obj.tooltip.fs:GetStringWidth() + 18);
obj.tooltip:SetHeight(obj.tooltip.fs:GetStringHeight() + 12);
obj:SetScript("OnEnter", function(self)
obj.tooltip:Show();
end)
obj:SetScript("OnLeave", function(self)
obj.tooltip:Hide();
end)
obj.tooltip:Hide();
--Timer frame that sits above the icon when an active timer is found.
obj.timerFrame = CreateFrame("Frame", k.. "TimerFrame", WorldMapFrame, "TooltipBorderedFrameTemplate");
obj.timerFrame:SetPoint("CENTER", obj, "CENTER", 0, 20);
obj.timerFrame:SetFrameStrata("FULLSCREEN");
obj.timerFrame:SetFrameLevel(9);
obj.timerFrame.fs = obj.timerFrame:CreateFontString(k .. "NWBTimerFrameFS", "ARTWORK");
obj.timerFrame.fs:SetPoint("CENTER", 0, 0);
obj.timerFrame.fs:SetFont(NWB.regionFont, 13);
obj.timerFrame:SetWidth(42);
obj.timerFrame:SetHeight(24);
obj:SetScript("OnUpdate", function(self)
--Update timer when map is open.
obj.timerFrame.fs:SetText(NWB:updateFelwoodWorldmapMarker(obj.type));
--obj.timerFrame:SetWidth(obj.timerFrame.fs:GetStringWidth() + 15);
--obj.timerFrame:SetHeight(obj.timerFrame.fs:GetStringHeight() + 9);
end)
--Make it act like pin is the parent and not WorldMapFrame.
obj:SetScript("OnHide", function(self)
obj.timerFrame:Hide();
end)
obj:SetScript("OnShow", function(self)
obj.timerFrame:Show();
end)
obj:SetScript("OnMouseDown", function(self)
if (IsShiftKeyDown()) then
local time = (NWB.data[obj.type] + 1500) - GetServerTime();
if (time > 0) then
local msg = string.format(L["singleSongflowerMsg"], NWB.songFlowers[obj.type].subZone, NWB:getTimeString(time, true));
SendChatMessage("[WorldBuffs] " .. msg .. " (" .. NWB.songFlowers[obj.type].x .. ", " .. NWB.songFlowers[obj.type].y .. ")", "guild");
else
NWB:print(L["noTimer"] .. " (" .. NWB.songFlowers[obj.type].subZone .. ").");
end
else
NWB:openBuffListFrame();
end
end)
--Minimap marker.
local obj = CreateFrame("FRAME", k .. "NWBMini");
obj.type = k;
obj.name = L["Songflower"];
obj.subZone = v.subZone;
local bg = obj:CreateTexture(nil, "MEDIUM");
bg:SetTexture(iconLocation);
bg:SetAllPoints(obj);
obj.texture = bg;
obj:SetSize(12, 12);
--Minimap tooltip.
obj.tooltip = CreateFrame("Frame", k.. "Tooltip", MinimMapFrame, "TooltipBorderedFrameTemplate");
obj.tooltip:SetPoint("CENTER", obj, "CENTER", 0, 18);
obj.tooltip:SetFrameStrata("TOOLTIP");
obj.tooltip:SetFrameLevel(9);
obj.tooltip.fs = obj.tooltip:CreateFontString(k .. "NWBTooltipFS", "ARTWORK");
obj.tooltip.fs:SetPoint("CENTER", 0, 0);
obj.tooltip.fs:SetFont(NWB.regionFont, 8.5);
obj.tooltip.fs:SetText("00:00");
obj.tooltip:SetWidth(obj.tooltip.fs:GetStringWidth() + 9);
obj.tooltip:SetHeight(obj.tooltip.fs:GetStringHeight() + 9);
obj:SetScript("OnEnter", function(self)
obj.tooltip:Show();
end)
obj:SetScript("OnLeave", function(self)
obj.tooltip:Hide();
end)
--Timer frame that sits above the icon when an active timer is found.
obj.timerFrame = CreateFrame("Frame", k.. "TimerFrameMini", obj, "TooltipBorderedFrameTemplate");
obj.timerFrame:SetPoint("CENTER", 0, 18);
obj.timerFrame:SetFrameStrata("FULLSCREEN");
obj.timerFrame:SetFrameLevel(9);
obj.timerFrame.fs = obj.timerFrame:CreateFontString(k .. "NWBTimerFrameFS", "ARTWORK");
obj.timerFrame.fs:SetPoint("CENTER", 0, 0.5);
obj.timerFrame.fs:SetFont(NWB.regionFont, 12);
obj.timerFrame.fs:SetText("00:00");
obj.timerFrame:SetWidth(obj.timerFrame.fs:GetStringWidth() + 14);
obj.timerFrame:SetHeight(obj.timerFrame.fs:GetStringHeight() + 9);
--obj.tooltip:SetScript("OnUpdate", function(self)
-- --Update timer when icon is hovered over and tooltip is shown.
-- obj.tooltip.fs:SetText(NWB:updateFelwoodMinimapMarker(obj.type));
-- obj.tooltip:SetWidth(obj.tooltip.fs:GetStringWidth() + 16);
-- obj.tooltip:SetHeight(obj.tooltip.fs:GetStringHeight() + 11);
--end)
--Changed to show minimap timer awlways instead of on hover (if timer is active).
obj:SetScript("OnUpdate", function(self)
--Update timer when icon is hovered over and tooltip is shown.
--obj.tooltip.fs:SetText(NWB:updateFelwoodMinimapMarker(obj.type));
--obj.tooltip:SetWidth(obj.tooltip.fs:GetStringWidth() + 14);
--obj.tooltip:SetHeight(obj.tooltip.fs:GetStringHeight() + 9);
obj.timerFrame.fs:SetText(NWB:updateFelwoodMinimapMarker(obj.type));
obj.timerFrame:SetWidth(obj.timerFrame.fs:GetStringWidth() + 14);
obj.timerFrame:SetHeight(obj.timerFrame.fs:GetStringHeight() + 9);
end)
obj.tooltip:Hide();
obj:SetScript("OnMouseDown", function(self)
NWB:openBuffListFrame();
end)
end
end
function NWB:createTuberMarkers()
local iconLocation = "Interface\\Icons\\inv_misc_food_55";
for k, v in pairs(NWB.tubers) do
--Worldmap marker.
local obj = CreateFrame("Frame", k .. "NWB", WorldMapFrame);
obj.type = k;
obj.name = L["Whipper Root Tuber"];
obj.subZone = v.subZone;
local bg = obj:CreateTexture(nil, "MEDIUM");
bg:SetTexture(iconLocation);
bg:SetAllPoints(obj);
obj.texture = bg;
obj:SetSize(12, 12);
--World map tooltip.
obj.tooltip = CreateFrame("Frame", k.. "Tooltip", WorldMapFrame, "TooltipBorderedFrameTemplate");
obj.tooltip:SetPoint("CENTER", obj, "CENTER", 0, -36);
obj.tooltip:SetFrameStrata("TOOLTIP");
obj.tooltip:SetFrameLevel(9);
obj.tooltip.fs = obj.tooltip:CreateFontString(k .. "NWBTooltipFS", "ARTWORK");
obj.tooltip.fs:SetPoint("CENTER", 0, 0);
obj.tooltip.fs:SetFont(NWB.regionFont, 12);
obj.tooltip.fs:SetText("|CffDEDE42" .. L["Songflower"] .. "|r\n" .. v.subZone);
obj.tooltip:SetWidth(obj.tooltip.fs:GetStringWidth() + 18);
obj.tooltip:SetHeight(obj.tooltip.fs:GetStringHeight() + 12);
obj:SetScript("OnEnter", function(self)
obj.tooltip:Show();
end)
obj:SetScript("OnLeave", function(self)
obj.tooltip:Hide();
end)
obj.tooltip:Hide();
--Timer frame that sits above the icon when an active timer is found.
obj.timerFrame = CreateFrame("Frame", k.. "TimerFrame", WorldMapFrame, "TooltipBorderedFrameTemplate");
obj.timerFrame:SetPoint("CENTER", obj, "CENTER", 0, 17);
obj.timerFrame:SetFrameStrata("FULLSCREEN");
obj.timerFrame:SetFrameLevel(9);
obj.timerFrame.fs = obj.timerFrame:CreateFontString(k .. "NWBTimerFrameFS", "ARTWORK");
obj.timerFrame.fs:SetPoint("CENTER", 0, 0);
obj.timerFrame.fs:SetFont(NWB.regionFont, 11);
obj.timerFrame:SetWidth(38);
obj.timerFrame:SetHeight(20);
obj:SetScript("OnUpdate", function(self)
--Update timer when map is open.
obj.timerFrame.fs:SetText(NWB:updateFelwoodWorldmapMarker(obj.type));
--obj.timerFrame:SetWidth(obj.timerFrame.fs:GetStringWidth() + 15);
--obj.timerFrame:SetHeight(obj.timerFrame.fs:GetStringHeight() + 9);
end)
--Make it act like pin is the parent and not WorldMapFrame.
obj:SetScript("OnHide", function(self)
obj.timerFrame:Hide();
end)
obj:SetScript("OnShow", function(self)
obj.timerFrame:Show();
end)
obj:SetScript("OnMouseDown", function(self)
NWB:openBuffListFrame();
end)
--Minimap marker.
local obj = CreateFrame("FRAME", k .. "NWBMini");
obj.type = k;
obj.name = L["Whipper Root Tuber"];
obj.subZone = v.subZone;
local bg = obj:CreateTexture(nil, "MEDIUM");
bg:SetTexture(iconLocation);
bg:SetAllPoints(obj);
obj.texture = bg;
obj:SetSize(12, 12);
--Minimap tooltip.
obj.tooltip = CreateFrame("Frame", k.. "Tooltip", MinimMapFrame, "TooltipBorderedFrameTemplate");
obj.tooltip:SetPoint("CENTER", obj, "CENTER", 0, 18);
obj.tooltip:SetFrameStrata("TOOLTIP");
obj.tooltip:SetFrameLevel(9);
obj.tooltip.fs = obj.tooltip:CreateFontString(k .. "NWBTooltipFS", "ARTWORK");
obj.tooltip.fs:SetPoint("CENTER", 0, 0);
obj.tooltip.fs:SetFont(NWB.regionFont, 8.5);
obj.tooltip.fs:SetText("00:00");
obj.tooltip:SetWidth(obj.tooltip.fs:GetStringWidth() + 9);
obj.tooltip:SetHeight(obj.tooltip.fs:GetStringHeight() + 9);
obj:SetScript("OnEnter", function(self)
obj.tooltip:Show();
end)
obj:SetScript("OnLeave", function(self)
obj.tooltip:Hide();
end)
--Timer frame that sits above the icon when an active timer is found.
obj.timerFrame = CreateFrame("Frame", k.. "TimerFrameMini", obj, "TooltipBorderedFrameTemplate");
obj.timerFrame:SetPoint("CENTER", 0, 18);
obj.timerFrame:SetFrameStrata("FULLSCREEN");
obj.timerFrame:SetFrameLevel(9);
obj.timerFrame.fs = obj.timerFrame:CreateFontString(k .. "NWBTimerFrameFS", "ARTWORK");
obj.timerFrame.fs:SetPoint("CENTER", 0, 0.5);
obj.timerFrame.fs:SetFont(NWB.regionFont, 12);
obj.timerFrame.fs:SetText("00:00");
obj.timerFrame:SetWidth(obj.timerFrame.fs:GetStringWidth() + 14);
obj.timerFrame:SetHeight(obj.timerFrame.fs:GetStringHeight() + 9);
--Changed to show minimap timer awlways instead of on hover (if timer is active).
obj:SetScript("OnUpdate", function(self)
--Update timer when icon is hovered over and tooltip is shown.
obj.timerFrame.fs:SetText(NWB:updateFelwoodMinimapMarker(obj.type));
obj.timerFrame:SetWidth(obj.timerFrame.fs:GetStringWidth() + 14);
obj.timerFrame:SetHeight(obj.timerFrame.fs:GetStringHeight() + 9);
end)
obj.tooltip:Hide();
obj:SetScript("OnMouseDown", function(self)
NWB:openBuffListFrame();
end)
end
end
function NWB:createDragonMarkers()
local iconLocation = "Interface\\Icons\\inv_misc_food_45";
for k, v in pairs(NWB.dragons) do
--Worldmap marker.
local obj = CreateFrame("Frame", k .. "NWB", WorldMapFrame);
obj.type = k;
obj.name = L["Night Dragon's Breath"];
obj.subZone = v.subZone;
local bg = obj:CreateTexture(nil, "MEDIUM");
bg:SetTexture(iconLocation);
bg:SetAllPoints(obj);
obj.texture = bg;
obj:SetSize(12, 12);
--World map tooltip.
obj.tooltip = CreateFrame("Frame", k.. "Tooltip", WorldMapFrame, "TooltipBorderedFrameTemplate");
obj.tooltip:SetPoint("CENTER", obj, "CENTER", 0, -36);
obj.tooltip:SetFrameStrata("TOOLTIP");
obj.tooltip:SetFrameLevel(9);
obj.tooltip.fs = obj.tooltip:CreateFontString(k .. "NWBTooltipFS", "ARTWORK");
obj.tooltip.fs:SetPoint("CENTER", 0, 0);
obj.tooltip.fs:SetFont(NWB.regionFont, 12);
obj.tooltip.fs:SetText("|CffDEDE42" .. L["Songflower"] .. "|r\n" .. v.subZone);
obj.tooltip:SetWidth(obj.tooltip.fs:GetStringWidth() + 18);
obj.tooltip:SetHeight(obj.tooltip.fs:GetStringHeight() + 12);
obj:SetScript("OnEnter", function(self)
obj.tooltip:Show();
end)
obj:SetScript("OnLeave", function(self)
obj.tooltip:Hide();
end)
obj.tooltip:Hide();
--Timer frame that sits above the icon when an active timer is found.
obj.timerFrame = CreateFrame("Frame", k.. "TimerFrame", WorldMapFrame, "TooltipBorderedFrameTemplate");
obj.timerFrame:SetPoint("CENTER", obj, "CENTER", 0, 17);
obj.timerFrame:SetFrameStrata("FULLSCREEN");
obj.timerFrame:SetFrameLevel(9);
obj.timerFrame.fs = obj.timerFrame:CreateFontString(k .. "NWBTimerFrameFS", "ARTWORK");
obj.timerFrame.fs:SetPoint("CENTER", 0, 0);
obj.timerFrame.fs:SetFont(NWB.regionFont, 11);
obj.timerFrame:SetWidth(38);
obj.timerFrame:SetHeight(20);
obj:SetScript("OnUpdate", function(self)
--Update timer when map is open.
obj.timerFrame.fs:SetText(NWB:updateFelwoodWorldmapMarker(obj.type));
--obj.timerFrame:SetWidth(obj.timerFrame.fs:GetStringWidth() + 15);
--obj.timerFrame:SetHeight(obj.timerFrame.fs:GetStringHeight() + 9);
end)
--Make it act like pin is the parent and not WorldMapFrame.
obj:SetScript("OnHide", function(self)
obj.timerFrame:Hide();
end)
obj:SetScript("OnShow", function(self)
obj.timerFrame:Show();
end)
obj:SetScript("OnMouseDown", function(self)
NWB:openBuffListFrame();
end)
--Minimap marker.
local obj = CreateFrame("FRAME", k .. "NWBMini");
obj.type = k;
obj.name = L["Night Dragon's Breath"];
obj.subZone = v.subZone;
local bg = obj:CreateTexture(nil, "MEDIUM");
bg:SetTexture(iconLocation);
bg:SetAllPoints(obj);
obj.texture = bg;
obj:SetSize(12, 12);
--Minimap tooltip.
obj.tooltip = CreateFrame("Frame", k.. "Tooltip", MinimMapFrame, "TooltipBorderedFrameTemplate");
obj.tooltip:SetPoint("CENTER", obj, "CENTER", 0, 18);
obj.tooltip:SetFrameStrata("TOOLTIP");
obj.tooltip:SetFrameLevel(9);
obj.tooltip.fs = obj.tooltip:CreateFontString(k .. "NWBTooltipFS", "ARTWORK");
obj.tooltip.fs:SetPoint("CENTER", 0, 0);
obj.tooltip.fs:SetFont(NWB.regionFont, 8.5);
obj.tooltip.fs:SetText("00:00");
obj.tooltip:SetWidth(obj.tooltip.fs:GetStringWidth() + 9);
obj.tooltip:SetHeight(obj.tooltip.fs:GetStringHeight() + 9);
obj:SetScript("OnEnter", function(self)
obj.tooltip:Show();
end)
obj:SetScript("OnLeave", function(self)
obj.tooltip:Hide();
end)
--Timer frame that sits above the icon when an active timer is found.
obj.timerFrame = CreateFrame("Frame", k.. "TimerFrameMini", obj, "TooltipBorderedFrameTemplate");
obj.timerFrame:SetPoint("CENTER", 0, 18);
obj.timerFrame:SetFrameStrata("FULLSCREEN");
obj.timerFrame:SetFrameLevel(9);
obj.timerFrame.fs = obj.timerFrame:CreateFontString(k .. "NWBTimerFrameFS", "ARTWORK");
obj.timerFrame.fs:SetPoint("CENTER", 0, 0.5);
obj.timerFrame.fs:SetFont(NWB.regionFont, 12);
obj.timerFrame.fs:SetText("00:00");
obj.timerFrame:SetWidth(obj.timerFrame.fs:GetStringWidth() + 14);
obj.timerFrame:SetHeight(obj.timerFrame.fs:GetStringHeight() + 9);
--Changed to show minimap timer awlways instead of on hover (if timer is active).
obj:SetScript("OnUpdate", function(self)
--Update timer when icon is hovered over and tooltip is shown.
obj.timerFrame.fs:SetText(NWB:updateFelwoodMinimapMarker(obj.type));
obj.timerFrame:SetWidth(obj.timerFrame.fs:GetStringWidth() + 14);
obj.timerFrame:SetHeight(obj.timerFrame.fs:GetStringHeight() + 9);
end)
obj.tooltip:Hide();
obj:SetScript("OnMouseDown", function(self)
NWB:openBuffListFrame();
end)
end
end
function NWB:refreshFelwoodMarkers()
for k, v in pairs(NWB.songFlowers) do
NWB.dragonLibPins:RemoveWorldMapIcon(k .. "NWB", _G[k .. "NWB"]);
NWB.dragonLibPins:RemoveMinimapIcon(k .. "NWBMini", _G[k .. "NWBMini"]);
if (NWB.db.global.showSongflowerWorldmapMarkers) then
NWB.dragonLibPins:AddWorldMapIconMap(k .. "NWB", _G[k .. "NWB"], 1448, v.x/100, v.y/100);
end
if (NWB.db.global.showSongflowerMinimapMarkers) then
NWB.dragonLibPins:AddMinimapIconMap(k .. "NWBMini", _G[k .. "NWBMini"], 1448, v.x/100, v.y/100);
end
end
for k, v in pairs(NWB.tubers) do
NWB.dragonLibPins:RemoveWorldMapIcon(k .. "NWB", _G[k .. "NWB"]);
NWB.dragonLibPins:RemoveMinimapIcon(k .. "NWBMini", _G[k .. "NWBMini"]);
if (NWB.db.global.showTuberWorldmapMarkers) then
NWB.dragonLibPins:AddWorldMapIconMap(k .. "NWB", _G[k .. "NWB"], 1448, v.x/100, v.y/100);
end
if (NWB.db.global.showTuberMinimapMarkers) then
NWB.dragonLibPins:AddMinimapIconMap(k .. "NWBMini", _G[k .. "NWBMini"], 1448, v.x/100, v.y/100);
end
end
for k, v in pairs(NWB.dragons) do
NWB.dragonLibPins:RemoveWorldMapIcon(k .. "NWB", _G[k .. "NWB"]);
NWB.dragonLibPins:RemoveMinimapIcon(k .. "NWBMini", _G[k .. "NWBMini"]);
if (NWB.db.global.showDragonWorldmapMarkers) then
NWB.dragonLibPins:AddWorldMapIconMap(k .. "NWB", _G[k .. "NWB"], 1448, v.x/100, v.y/100);
end
if (NWB.db.global.showDragonMinimapMarkers) then
NWB.dragonLibPins:AddMinimapIconMap(k .. "NWBMini", _G[k .. "NWBMini"], 1448, v.x/100, v.y/100);
end
end
end
---====================---
---Worldbuff Map Frames---
---====================---
--Update timers for worldmap when the map is open.
function NWB:updateWorldbuffMarkers(type, layer)
--Seconds left.
local time = 0;
if (NWB.isLayered and layer) then
--I've adapted this to show all layers at once on the world map.
--Its ugly here so I don't have to change a lot of code elsewhere and it can keep using most of the non-layered stuff.
if (type == "ony") then
local count = 0;
for k, v in NWB:pairsByKeys(NWB.data.layers) do
count = count + 1;
if (k == tonumber(layer)) then
break;
end
end
_G[type .. layer .. "NWBWorldMap"].fsLayer:SetText("|cff00ff00[Layer " .. count.. "]");
end
if (NWB.data.layers[layer]) then
time = (NWB.data.layers[layer][type .. "Timer"] + NWB.db.global[type .. "RespawnTime"]) - GetServerTime() or 0;
else
time = 0;
end
if (type == "ony" or type == "nef") then
if (NWB.data[type .. "NpcDied"] > NWB.data[type .. "Timer"]) then
local killedAgo = NWB:getTimeString(GetServerTime() - NWB.data[type .. "NpcDied"], true)
local tooltipString = "|CffDEDE42" .. _G[type .. layer .. "NWBWorldMap"].name .. "\n"
.. L["noTimer"] .. "\n"
.. string.format(L["anyNpcKilledAllianceWithTimer"], killedAgo);
_G[type .. layer .. "NWBWorldMap"].tooltip.fs:SetText(tooltipString);
_G[type .. layer .. "NWBWorldMap"].tooltip:SetWidth(_G[type .. layer .. "NWBWorldMap"].tooltip.fs:GetStringWidth() + 18);
_G[type .. layer .. "NWBWorldMap"].tooltip:SetHeight(_G[type .. layer .. "NWBWorldMap"].tooltip.fs:GetStringHeight() + 12);
return L["noTimer"];
end
end
local timeStringShort;
if (time > 0) then
local timeString = NWB:getTimeString(time, true);
timeStringShort = NWB:getTimeString(time, true, true);
local timeStamp = NWB:getTimeFormat(NWB.data.layers[layer][type .. "Timer"] + NWB.db.global[type .. "RespawnTime"]);
local tooltipString = "|CffDEDE42" .. _G[type .. layer .. "NWBWorldMap"].name .. "\n"
.. timeString .. "\n"
.. timeStamp;
_G[type .. layer .. "NWBWorldMap"].tooltip.fs:SetText(tooltipString);
_G[type .. layer .. "NWBWorldMap"].tooltip:SetWidth(_G[type .. layer .. "NWBWorldMap"].tooltip.fs:GetStringWidth() + 18);
_G[type .. layer .. "NWBWorldMap"].tooltip:SetHeight(_G[type .. layer .. "NWBWorldMap"].tooltip.fs:GetStringHeight() + 12);
else
_G[type .. layer .. "NWBWorldMap"].tooltip.fs:SetText("|CffDEDE42" .. _G[type .. layer .. "NWBWorldMap"].name);
end
local _, _, zone = NWB.dragonLib:GetPlayerZonePosition();
if (_G["nef" .. layer .. "NWBWorldMap"].noLayerFrame) then
if (NWB.faction == "Horde" and zone == 1454) then
if (NWB.currentLayer > 0) then
local layerMsg = L["cityMapLayerMsgHorde"];
local layerString = "|cff00ff00[Layer " .. NWB.currentLayer .. "]|cff9CD6DE";
_G["nef" .. layer .. "NWBWorldMap"].fs2:SetText("|cff9CD6DE" .. string.format(layerMsg, layerString));
_G["nef" .. layer .. "NWBWorldMap"].noLayerFrame:Hide();
else
_G["nef" .. layer .. "NWBWorldMap"].fs2:SetText("");
_G["nef" .. layer .. "NWBWorldMap"].noLayerFrame:Show();
end
elseif (NWB.faction == "Alliance" and zone == 1453) then
if (NWB.currentLayer > 0) then
local layerMsg = L["cityMapLayerMsgAlliance"];
local layerString = "|cff00ff00[Layer " .. NWB.currentLayer .. "]|cff9CD6DE";
_G["nef" .. layer .. "NWBWorldMap"].fs2:SetText("|cff9CD6DE" .. string.format(layerMsg, layerString));
_G["nef" .. layer .. "NWBWorldMap"].noLayerFrame:Hide();
else
_G["nef" .. layer .. "NWBWorldMap"].fs2:SetText("");
_G["nef" .. layer .. "NWBWorldMap"].noLayerFrame:Show();
end
else
_G["nef" .. layer .. "NWBWorldMap"].noLayerFrame:Show();
end
end
if (time > 0) then
return timeStringShort;
end
_G[type .. layer .. "NWBWorldMap"].tooltip.fs:SetText("|CffDEDE42" .. _G[type .. layer .. "NWBWorldMap"].name);
return L["noTimer"];
else
time = (NWB.data[type .. "Timer"] + NWB.db.global[type .. "RespawnTime"]) - GetServerTime();
if (type == "ony" or type == "nef") then
if (NWB.data[type .. "NpcDied"] > NWB.data[type .. "Timer"]) then
local killedAgo = NWB:getTimeString(GetServerTime() - NWB.data[type .. "NpcDied"], true)
local tooltipString = "|CffDEDE42" .. _G[type .. "NWBWorldMap"].name .. "\n"
.. L["noTimer"] .. "\n"
.. string.format(L["anyNpcKilledAllianceWithTimer"], killedAgo);
_G[type .. "NWBWorldMap"].tooltip.fs:SetText(tooltipString);
_G[type .. "NWBWorldMap"].tooltip:SetWidth(_G[type .. "NWBWorldMap"].tooltip.fs:GetStringWidth() + 18);
_G[type .. "NWBWorldMap"].tooltip:SetHeight(_G[type .. "NWBWorldMap"].tooltip.fs:GetStringHeight() + 12);
return L["noTimer"];
end
end
if (time > 0) then
local timeString = NWB:getTimeString(time, true);
local timeStringShort = NWB:getTimeString(time, true, true);
local timeStamp = 0;
if (type == "zanCity" or type == "zanStv") then
timeStamp = NWB:getTimeFormat(NWB.data["zanTimer"] + NWB.db.global["zanRespawnTime"]);
else
timeStamp = NWB:getTimeFormat(NWB.data[type .. "Timer"] + NWB.db.global[type .. "RespawnTime"]);
end
local tooltipString = "|CffDEDE42" .. _G[type .. "NWBWorldMap"].name .. "\n"
.. timeString .. "\n"
.. timeStamp;
_G[type .. "NWBWorldMap"].tooltip.fs:SetText(tooltipString);
_G[type .. "NWBWorldMap"].tooltip:SetWidth(_G[type .. "NWBWorldMap"].tooltip.fs:GetStringWidth() + 18);
_G[type .. "NWBWorldMap"].tooltip:SetHeight(_G[type .. "NWBWorldMap"].tooltip.fs:GetStringHeight() + 12);
return timeStringShort;
end
_G[type .. "NWBWorldMap"].tooltip.fs:SetText("|CffDEDE42" .. _G[type .. "NWBWorldMap"].name);
return L["noTimer"];
end
end
function NWB:createWorldbuffMarkersTable()
if (LOCALE_koKR or LOCALE_zhCN or LOCALE_zhTW) then
--Adjust for icon position non-english fonts in the timer frame.
if (NWB.faction == "Alliance") then
NWB.worldBuffMapMarkerTypes = {
["rend"] = {x = 71.5, y = 73.0, mapID = 1453, icon = "Interface\\Icons\\spell_arcane_teleportorgrimmar", name = L["rend"]},
["ony"] = {x = 79.5, y = 73.0, mapID = 1453, icon = "Interface\\Icons\\inv_misc_head_dragon_01", name = L["onyxia"]},
["nef"] = {x = 87.5, y = 73.0, mapID = 1453, icon = "Interface\\Icons\\inv_misc_head_dragon_black", name = L["nefarian"]},
--["zanCity"] = {x = 95.5, y = 73.0, mapID = 1453, icon = "Interface\\Icons\\ability_creature_poison_05", name = L["Zandalar"]},
--["zanStv"] = {x = 11.0, y = 20.5, mapID = 1434, icon = "Interface\\Icons\\ability_creature_poison_05", name = L["Zandalar"]},
};
else
NWB.worldBuffMapMarkerTypes = {
["rend"] = {x = 60.0, y = 79.0, mapID = 1454, icon = "Interface\\Icons\\spell_arcane_teleportorgrimmar", name = L["rend"]},
["ony"] = {x = 68, y = 79.0, mapID = 1454, icon = "Interface\\Icons\\inv_misc_head_dragon_01", name = L["onyxia"]},
["nef"] = {x = 76.0, y = 79.0, mapID = 1454, icon = "Interface\\Icons\\inv_misc_head_dragon_black", name = L["nefarian"]},
--["zanCity"] = {x = 84.0, y = 79.0, mapID = 1454, icon = "Interface\\Icons\\ability_creature_poison_05", name = L["Zandalar"]},
--["zanStv"] = {x = 11.0, y = 20.5, mapID = 1434, icon = "Interface\\Icons\\ability_creature_poison_05", name = L["Zandalar"]},
};
end
else
if (NWB.faction == "Alliance") then
NWB.worldBuffMapMarkerTypes = {
["rend"] = {x = 74.0, y = 73.0, mapID = 1453, icon = "Interface\\Icons\\spell_arcane_teleportorgrimmar", name = L["rend"]},
["ony"] = {x = 79.5, y = 73.0, mapID = 1453, icon = "Interface\\Icons\\inv_misc_head_dragon_01", name = L["onyxia"]},
["nef"] = {x = 85.0, y = 73.0, mapID = 1453, icon = "Interface\\Icons\\inv_misc_head_dragon_black", name = L["nefarian"]},
--["zanCity"] = {x = 90.5, y = 73.0, mapID = 1453, icon = "Interface\\Icons\\ability_creature_poison_05", name = L["Zandalar"]},
--["zanStv"] = {x = 11.0, y = 20.5, mapID = 1434, icon = "Interface\\Icons\\ability_creature_poison_05", name = L["Zandalar"]},
};
else
NWB.worldBuffMapMarkerTypes = {
["rend"] = {x = 59.0, y = 79.0, mapID = 1454, icon = "Interface\\Icons\\spell_arcane_teleportorgrimmar", name = L["rend"]},
["ony"] = {x = 64.5, y = 79.0, mapID = 1454, icon = "Interface\\Icons\\inv_misc_head_dragon_01", name = L["onyxia"]},
["nef"] = {x = 70.0, y = 79.0, mapID = 1454, icon = "Interface\\Icons\\inv_misc_head_dragon_black", name = L["nefarian"]},
--["zanCity"] = {x = 75.5, y = 79.0, mapID = 1454, icon = "Interface\\Icons\\ability_creature_poison_05", name = L["Zandalar"]},
--["zanStv"] = {x = 11.0, y = 20.5, mapID = 1434, icon = "Interface\\Icons\\ability_creature_poison_05", name = L["Zandalar"]},
};
end
end
end
function NWB:createWorldbuffMarkers()
if (NWB.isLayered) then
local count = 0;
for layer, data in NWB:pairsByKeys(NWB.data.layers) do
count = count + 1;
for k, v in pairs(NWB.worldBuffMapMarkerTypes) do
if (not _G[k .. layer .. "NWBWorldMap"]) then
NWB:createWorldbuffMarker(k, v, layer, count);
end
end
end
end
--Create non layered icons also on layered realms, they are shown when no layers found.
for k, v in pairs(NWB.worldBuffMapMarkerTypes) do
NWB:createWorldbuffMarker(k, v);
end
NWB:refreshWorldbuffMarkers();
end
local mapMarkers = {};
function NWB:createWorldbuffMarker(type, data, layer, count)
if (layer) then
if (not _G[type .. layer .. "NWBWorldMap"]) then
--Worldmap marker.
local obj = CreateFrame("Frame", type .. layer .. "NWBWorldMap", WorldMapFrame);
obj.name = data.name;
local bg = obj:CreateTexture(nil, "MEDIUM");
bg:SetTexture(data.icon);
bg:SetAllPoints(obj);
obj.texture = bg;
obj:SetSize(23, 23);
--Worldmap tooltip.
obj.tooltip = CreateFrame("Frame", type .. layer .. "WorldMapTooltip", WorldMapFrame, "TooltipBorderedFrameTemplate");
obj.tooltip:SetPoint("CENTER", obj, "CENTER", 0, -46);
--obj.tooltip:SetPoint("CENTER", obj, "CENTER", 0, -26);
obj.tooltip:SetFrameStrata("TOOLTIP");
obj.tooltip:SetFrameLevel(9999);
obj.tooltip.fs = obj.tooltip:CreateFontString(type .. layer .. "NWBWorldMapTooltipFS", "ARTWORK");
obj.tooltip.fs:SetPoint("CENTER", 0, 0);
obj.tooltip.fs:SetFont(NWB.regionFont, 14);
obj.tooltip.fs:SetText("|CffDEDE42" .. data.name);
obj.tooltip:SetWidth(obj.tooltip.fs:GetStringWidth() + 18);
obj.tooltip:SetHeight(obj.tooltip.fs:GetStringHeight() + 12);
--obj.tooltip:SetParent(WorldMapFrame); --Make tooltip float on top of other pins.
obj:SetScript("OnEnter", function(self)
obj.tooltip:Show();
end)
obj:SetScript("OnLeave", function(self)
obj.tooltip:Hide();
end)
obj.tooltip:Hide();
--Timer frame that sits above the icon when an active timer is found.
obj.timerFrame = CreateFrame("Frame", type .. layer .. "WorldMapTimerFrame", WorldMapFrame, "TooltipBorderedFrameTemplate");
obj.timerFrame:SetPoint("CENTER", obj, "CENTER", 0, 21);
obj.timerFrame:SetFrameStrata("FULLSCREEN");
obj.timerFrame:SetFrameLevel(9);
obj.timerFrame.fs = obj.timerFrame:CreateFontString(type .. "NWBWorldMapTimerFrameFS", "ARTWORK");
obj.timerFrame.fs:SetPoint("CENTER", 0, 0);
obj.timerFrame.fs:SetFont(NWB.regionFont, 13);
obj.timerFrame:SetWidth(54);
obj.timerFrame:SetHeight(24);
obj:SetScript("OnUpdate", function(self)
--Update timer when map is open.
obj.timerFrame.fs:SetText(NWB:updateWorldbuffMarkers(type, layer));
--Adjust for non-english fonts.
if (LOCALE_koKR or LOCALE_zhCN or LOCALE_zhTW or LOCALE_ruRU) then
obj.timerFrame:SetWidth(obj.timerFrame.fs:GetStringWidth() + 18);
obj.timerFrame:SetHeight(obj.timerFrame.fs:GetStringHeight() + 12);
end
end)
--Make it act like pin is the parent and not WorldMapFrame.
obj:SetScript("OnHide", function(self)
obj.timerFrame:Hide();
end)
obj:SetScript("OnShow", function(self)
obj.timerFrame:Show();
end)
if (type == "nef" and count == 1) then
--/buffs text below the city map icons.
obj.fs = obj:CreateFontString(type .. "NWBWorldMapBuffCmdFS", "ARTWORK");
obj.fs:SetFont(NWB.regionFont, 14);
obj.fs:SetText("|CffDEDE42" .. L["worldMapBuffsMsg"]);
--Layer info text above the city map icons.
obj.noLayerFrame = CreateFrame("Frame", type.. "WorldMapNoLayerFrame", obj, "TooltipBorderedFrameTemplate");
obj.noLayerFrame:SetFrameStrata("FULLSCREEN");
obj.noLayerFrame:SetFrameLevel(9);
obj.noLayerFrame:SetAlpha(.85);
obj.noLayerFrame.fs = obj.noLayerFrame:CreateFontString(type .. "NWBWorldMapNoLayerFS", "ARTWORK");
obj.noLayerFrame.fs:SetPoint("CENTER", 0, 0);
obj.noLayerFrame.fs:SetFont(NWB.regionFont, 14);
obj.fs2 = obj:CreateFontString(type .. "NWBWorldMapBuffCmdFS", "ARTWORK");
obj.fs2:SetFont(NWB.regionFont, 14);
if (NWB.faction == "Horde") then
obj.fs:SetPoint("RIGHT", -180, 20);
obj.noLayerFrame:SetPoint("CENTER", obj, "CENTER", -255, 70);
obj.fs2:SetPoint("CENTER", -260, 80);
obj.noLayerFrame.fs:SetText("|cff9CD6DE" .. L["noLayerYetHorde"]);
else
obj.fs:SetPoint("RIGHT", -70, -35);
obj.noLayerFrame:SetPoint("CENTER", obj, "CENTER", -195, 20);
obj.fs2:SetPoint("CENTER", -195, 20);
obj.noLayerFrame.fs:SetText("|cff9CD6DE" .. L["noLayerYetAlliance"]);
end
obj.noLayerFrame:SetWidth(obj.noLayerFrame.fs:GetStringWidth() + 4);
obj.noLayerFrame:SetHeight(obj.noLayerFrame.fs:GetStringHeight() + 12);
obj.noLayerFrame:Hide();
end
if (type == "ony") then
--Attach layer text to ony frame.
obj.fsLayer = obj:CreateFontString(type .. "NWBWorldMapBuffCmdFS", "ARTWORK");
obj.fsLayer:SetPoint("TOP", 0, 35);
obj.fsLayer:SetFont(NWB.regionFont, 14);
end
obj:SetScript("OnMouseDown", function(self)
NWB:openBuffListFrame();
end)
mapMarkers[type .. layer .. "NWBWorldMap"] = true;
end
else
--Worldmap marker.
local obj = CreateFrame("Frame", type .. "NWBWorldMap", WorldMapFrame);
obj.name = data.name;
local bg = obj:CreateTexture(nil, "MEDIUM");
bg:SetTexture(data.icon);
bg:SetAllPoints(obj);
obj.texture = bg;
obj:SetSize(23, 23);
--Worldmap tooltip.
obj.tooltip = CreateFrame("Frame", type.. "WorldMapTooltip", WorldMapFrame, "TooltipBorderedFrameTemplate");
obj.tooltip:SetPoint("CENTER", obj, "CENTER", 0, -46);
obj.tooltip:SetFrameStrata("TOOLTIP");
obj.tooltip:SetFrameLevel(9999);
obj.tooltip.fs = obj.tooltip:CreateFontString(type .. "NWBWorldMapTooltipFS", "ARTWORK");
obj.tooltip.fs:SetPoint("CENTER", 0, 0);
obj.tooltip.fs:SetFont(NWB.regionFont, 14);
obj.tooltip.fs:SetText("|CffDEDE42" .. data.name);
obj.tooltip:SetWidth(obj.tooltip.fs:GetStringWidth() + 18);
obj.tooltip:SetHeight(obj.tooltip.fs:GetStringHeight() + 12);
--obj.tooltip:SetParent(WorldMapFrame); --Make tooltip float on top of other pins.
obj:SetScript("OnEnter", function(self)
obj.tooltip:Show();
end)
obj:SetScript("OnLeave", function(self)
obj.tooltip:Hide();
end)
obj.tooltip:Hide();
--Timer frame that sits above the icon when an active timer is found.
obj.timerFrame = CreateFrame("Frame", type.. "WorldMapTimerFrame", WorldMapFrame, "TooltipBorderedFrameTemplate");
obj.timerFrame:SetPoint("CENTER", obj, "CENTER", 0, 21);
obj.timerFrame:SetFrameStrata("FULLSCREEN");
obj.timerFrame:SetFrameLevel(9);
obj.timerFrame.fs = obj.timerFrame:CreateFontString(type .. "NWBWorldMapTimerFrameFS", "ARTWORK");
obj.timerFrame.fs:SetPoint("CENTER", 0, 0);
obj.timerFrame.fs:SetFont(NWB.regionFont, 13);
obj.timerFrame:SetWidth(54);
obj.timerFrame:SetHeight(24);
obj:SetScript("OnUpdate", function(self)
--Update timer when map is open.
obj.timerFrame.fs:SetText(NWB:updateWorldbuffMarkers(type));
--Adjust for non-english fonts.
if (LOCALE_koKR or LOCALE_zhCN or LOCALE_zhTW or LOCALE_ruRU) then
obj.timerFrame:SetWidth(obj.timerFrame.fs:GetStringWidth() + 18);
obj.timerFrame:SetHeight(obj.timerFrame.fs:GetStringHeight() + 12);
end
end)
--Make it act like pin is the parent and not WorldMapFrame.
obj:SetScript("OnHide", function(self)
obj.timerFrame:Hide();
end)
obj:SetScript("OnShow", function(self)
obj.timerFrame:Show();
end)
if (type == "nef") then
--/buffs text below the city map icons.
obj.fs = obj:CreateFontString(type .. "NWBWorldMapBuffCmdFS", "ARTWORK");
obj.fs:SetPoint("RIGHT", 40, -40);
obj.fs:SetFont(NWB.regionFont, 14);
obj.fs:SetText("|CffDEDE42" .. L["worldMapBuffsMsg"]);
--Layer info text above the city map icons.
obj.noLayerFrame = CreateFrame("Frame", type.. "WorldMapNoLayerFrame", obj, "TooltipBorderedFrameTemplate");
obj.noLayerFrame:SetPoint("CENTER", obj, "CENTER", 10, 70);
obj.noLayerFrame:SetFrameStrata("FULLSCREEN");
obj.noLayerFrame:SetFrameLevel(9);
obj.noLayerFrame:SetAlpha(.85);
obj.noLayerFrame.fs = obj.noLayerFrame:CreateFontString(type .. "NWBWorldMapNoLayerFS", "ARTWORK");
obj.noLayerFrame.fs:SetPoint("CENTER", 0, 0);
obj.noLayerFrame.fs:SetFont(NWB.regionFont, 14);
obj.noLayerFrame:SetWidth(54);
obj.noLayerFrame:SetHeight(24);
obj.noLayerFrame:Hide();
obj.fs2 = obj:CreateFontString(type .. "NWBWorldMapBuffCmdFS", "ARTWORK");
obj.fs2:SetPoint("CENTER", -10, 60);
obj.fs2:SetFont(NWB.regionFont, 14);
end
obj:SetScript("OnMouseDown", function(self)
NWB:openBuffListFrame();
end)
end
end
function NWB:refreshWorldbuffMarkers()
if (NWB.isLayered) then
local count = 0;
local offset = 0;
local foundLayers;
for layer, data in NWB:pairsByKeys(NWB.data.layers) do
--[[for k, v in pairs(NWB.worldBuffMapMarkerTypes) do
--if (not NWB.data.layers[layer] and _G[k .. layer .. "NWBWorldMap"]) then
if (_G[k .. layer .. "NWBWorldMap"]) then
--Remove all icons first so it fixes any layer changes or data reset after server restart etc.
NWB.dragonLibPins:RemoveWorldMapIcon(k .. layer .. "NWBWorldMap", _G[k .. layer .. "NWBWorldMap"]);
end
end]]
for k, v in pairs(mapMarkers) do
--Remove all icons first so it fixes any layer changes or data reset after server restart etc.
NWB.dragonLibPins:RemoveWorldMapIcon(k, _G[k]);
end
end
for layer, data in NWB:pairsByKeys(NWB.data.layers) do
foundLayers = true;
count = count + 1;
for k, v in pairs(NWB.worldBuffMapMarkerTypes) do
--Change position to bottom corner of map so they can be stacked on top of each other for layered realms.
NWB.dragonLibPins:RemoveWorldMapIcon(k .. layer .. "NWBWorldMap", _G[k .. "NWBWorldMap"]);
if (NWB.db.global.showWorldMapMarkers and _G[k .. layer .. "NWBWorldMap"]) then
if (NWB.faction == "Horde") then
NWB.dragonLibPins:AddWorldMapIconMap(k .. layer .. "NWBWorldMap", _G[k .. layer .. "NWBWorldMap"],
v.mapID, (v.x + 22) / 100, (v.y + 9 + offset) / 100, HBD_PINS_WORLDMAP_SHOW_PARENT);
else
NWB.dragonLibPins:AddWorldMapIconMap(k .. layer .. "NWBWorldMap", _G[k .. layer .. "NWBWorldMap"],
v.mapID, (v.x + 8) / 100, (v.y + 15 + offset) / 100, HBD_PINS_WORLDMAP_SHOW_PARENT);
end
if (NWB.faction == "Alliance" and k == "rend") then
if (not NWB.db.global.allianceEnableRend) then
NWB.dragonLibPins:RemoveWorldMapIcon(k .. layer .. "NWBWorldMap", _G[k .. layer .. "NWBWorldMap"]);
end
end
if (string.match(k, "zan") and not NWB.zand) then
--Temp debug.
NWB.dragonLibPins:RemoveWorldMapIcon(k .. "NWBWorldMap", _G[k .. "NWBWorldMap"]);
end
end
if (NWB.faction == "Alliance" and k == "nef" and count == 1 and NWB.db.global.allianceEnableRend
--These need more adjusting, if layer 1 timers run out I think the new layer 1 won't have the noLayerFrame attached.
--Maybe I'll remove the count check when creating nef frames and just attach one to all layers nef frame.
--Anyway it's a kinda rare case issue when the first layer has no timers for over 6 hours.
and _G[k .. layer .. "NWBWorldMap"].noLayerFrame) then
_G[k .. layer .. "NWBWorldMap"].noLayerFrame:SetPoint("CENTER", _G[k .. layer .. "NWBWorldMap"], "CENTER", -245, 20);
_G[k .. layer .. "NWBWorldMap"].fs2:SetPoint("CENTER", -245, 15);
elseif (NWB.faction == "Alliance" and k == "nef" and count == 1
and _G[k .. layer .. "NWBWorldMap"].noLayerFrame) then
_G[k .. layer .. "NWBWorldMap"].noLayerFrame:SetPoint("CENTER", _G[k .. layer .. "NWBWorldMap"], "CENTER", -195, 20);
_G[k .. layer .. "NWBWorldMap"].fs2:SetPoint("CENTER", -195, 20);
end
end
offset = offset - 10;
end
--This will add layer icons and remove default non-layer icons when we go from having no timer info to got new layers timer info.
if (not foundLayers) then
for k, v in pairs(NWB.worldBuffMapMarkerTypes) do
NWB.dragonLibPins:RemoveWorldMapIcon(k .. "NWBWorldMap", _G[k .. "NWBWorldMap"]);
if (NWB.db.global.showWorldMapMarkers and _G[k .. "NWBWorldMap"]) then
NWB.dragonLibPins:AddWorldMapIconMap(k .. "NWBWorldMap", _G[k .. "NWBWorldMap"], v.mapID,
v.x / 100, v.y / 100, HBD_PINS_WORLDMAP_SHOW_PARENT);
if (NWB.faction == "Alliance" and k == "rend") then
if (not NWB.db.global.allianceEnableRend) then
NWB.dragonLibPins:RemoveWorldMapIcon(k .. "NWBWorldMap", _G[k .. "NWBWorldMap"]);
end
end
if (string.match(k, "zan") and not NWB.zand) then
--Temp debug.
NWB.dragonLibPins:RemoveWorldMapIcon(k .. "NWBWorldMap", _G[k .. "NWBWorldMap"]);
end
end
end
else
for k, v in pairs(NWB.worldBuffMapMarkerTypes) do
NWB.dragonLibPins:RemoveWorldMapIcon(k .. "NWBWorldMap", _G[k .. "NWBWorldMap"]);
end
end
else
for k, v in pairs(NWB.worldBuffMapMarkerTypes) do
NWB.dragonLibPins:RemoveWorldMapIcon(k .. "NWBWorldMap", _G[k .. "NWBWorldMap"]);
if (NWB.db.global.showWorldMapMarkers and _G[k .. "NWBWorldMap"]) then
NWB.dragonLibPins:AddWorldMapIconMap(k .. "NWBWorldMap", _G[k .. "NWBWorldMap"], v.mapID,
v.x / 100, v.y / 100, HBD_PINS_WORLDMAP_SHOW_PARENT);
if (NWB.faction == "Alliance" and k == "rend") then
if (not NWB.db.global.allianceEnableRend) then
NWB.dragonLibPins:RemoveWorldMapIcon(k .. "NWBWorldMap", _G[k .. "NWBWorldMap"]);
end
end
if (string.match(k, "zan") and not NWB.zand) then
--Temp debug.
NWB.dragonLibPins:RemoveWorldMapIcon(k .. "NWBWorldMap", _G[k .. "NWBWorldMap"]);
end
end
end
end
end
---=============---
---Darkoon Faire---
---=============---
SLASH_NWBDMFCMD1 = '/dmf';
function SlashCmdList.NWBDMFCMD(msg, editBox)
if (msg) then
msg = string.lower(msg);
end
if (msg == "map") then
WorldMapFrame:Show();
if (NWB.dmfZone == "Mulgore") then
WorldMapFrame:SetMapID(1412);
else
WorldMapFrame:SetMapID(1429);
end
return;
end
if (msg == "options" or msg == "option" or msg == "config" or msg == "menu") then
--Opening the frame needs to be run twice to avoid a bug.
InterfaceOptionsFrame_OpenToCategory("NovaWorldBuffs");
--Hack to fix the issue of interface options not opening to menus below the current scroll range.
--This addon name starts with N and will always be closer to the middle so just scroll to the middle when opening.
local min, max = InterfaceOptionsFrameAddOnsListScrollBar:GetMinMaxValues();
if (min < max) then
InterfaceOptionsFrameAddOnsListScrollBar:SetValue(math.floor(max/2));
end
InterfaceOptionsFrame_OpenToCategory("NovaWorldBuffs");
return;
end
local output, zone, dmfFound;
if (NWB.dmfZone == "Mulgore") then
zone = L["mulgore"];
else
zone = L["elwynnForest"];
end
output = NWB:getDmfTimeString() .. " (" .. zone .. ")";
if (output) then
if (msg ~= nil and msg ~= "") then
NWB:print(output, msg);
else
NWB:print(output);
end
end
if (NWB.data.myChars[UnitName("player")].buffs) then
for k, v in pairs(NWB.data.myChars[UnitName("player")].buffs) do
--if (v.type == "dmf" and v.timeLeft > 0) then
if (v.type == "dmf" and (v.timeLeft + 7200) > 0) then
--output = string.format(L["dmfBuffCooldownMsg"], NWB:getTimeString(v.timeLeft, true));
output = string.format(L["dmfBuffCooldownMsg"], NWB:getTimeString(v.timeLeft + 7200, true));
dmfFound = true;
break;
end
end
end
if (not dmfFound) then
output = L["dmfBuffReady"];
end
if (msg == nil or msg == "") then
NWB:print(output);
end
end
function NWB:getDmfTimeString()
local timestamp, timeLeft, type = NWB:getDmfData();
local msg, dateString;
if (timestamp) then
if (NWB.db.global.timeStampFormat == 12) then
dateString = date("%a %b %d", timestamp) .. " " .. gsub(string.lower(date("%I:%M%p", timestamp)), "^0", "");
else
dateString = date("%x %X", timestamp);
end
dateString = NWB:getTimeFormat(timestamp, true);
if (type == "start") then
msg = string.format(L["dmfSpawns"], NWB:getTimeString(timeLeft, true), dateString);
else
msg = string.format(L["dmfEnds"],NWB:getTimeString(timeLeft, true), dateString);
end
return msg;
end
end
--DMF spawns the following monday after first friday of the month at daily reset time.
--Whole region shares time of day for spawn (I think).
--Realms within the region possibly don't all spawn at same moment though, realms may wait for their own monday.
function NWB:getDmfStartEnd(month, nextYear)
local startOffset, endOffset, validRegion, isDst;
local minOffset, hourOffset, dayOffset = 0, 0, 0;
local region = GetCurrentRegion();
--I may change this to realm names later instead, region may be unreliable with US client on EU region if that issue still exists.
if (NWB.realm == "Arugal" or NWB.realm == "Felstriker" or NWB.realm == "Remulos" or NWB.realm == "Yojamba") then
--OCE Sunday 12pm UTC reset time (4am server time).
dayOffset = 2; --2 days after friday (sunday).
hourOffset = 18; -- 6pm.
validRegion = true;
elseif (NWB.realm == "Arcanite Reaper" or NWB.realm == "Old Blanchy" or NWB.realm == "Anathema" or NWB.realm == "Azuresong"
or NWB.realm == "Kurinnaxx" or NWB.realm == "Myzrael" or NWB.realm == "Rattlegore" or NWB.realm == "Smolderweb"
or NWB.realm == "Thunderfury" or NWB.realm == "Atiesh" or NWB.realm == "Bigglesworth" or NWB.realm == "Blaumeux"
or NWB.realm == "Fairbanks" or NWB.realm == "Grobbulus" or NWB.realm == "Whitemane") then
--US west Sunday 11am UTC reset time (4am server time).
dayOffset = 3; --3 days after friday (monday).
hourOffset = 11; -- 11am.
validRegion = true;
elseif (region == 1) then
--US east + Latin Monday 8am UTC reset time (4am server time).
dayOffset = 3; --3 days after friday (monday).
hourOffset = 8; -- 8am.
validRegion = true;
elseif (region == 2) then
--Korea 1am UTC monday (9am monday local) reset time.
--(TW seems to be region 2 for some reason also? Hopefully they have same DMF spawn).
--I can change it to server name based if someone from KR says this spawn time is wrong.
dayOffset = 3;
hourOffset = 1;
validRegion = true;
elseif (region == 3) then
--EU Monday 4am UTC reset time.
dayOffset = 3; --3 days after friday (monday).
hourOffset = 4; -- 4am.
validRegion = true;
elseif (region == 4) then
--Taiwan 1am UTC monday (9am monday local) reset time.
dayOffset = 3;
hourOffset = 1;
validRegion = true;
elseif (region == 5) then
--China 8pm UTC sunday (4am monday local) reset time.
dayOffset = 2;
hourOffset = 20;
validRegion = true;
end
--Create current UTC date table.
local data = date("!*t", GetServerTime());
--If month is specified then use that month instead (next dmf spawn is next month);
if (month) then
data.month = month;
end
--If nextYear is true then next dmf spawn is next year (we're in december right now).
if (nextYear) then
data.year = data.year + 1;
end
local dmfStartDay;
for i = 1, 7 do
--Iterate the first 7 days in the month to find first friday.
local time = date("!*t", time({year = data.year, month = data.month, day = i}));
if (time.wday == 6) then
--If day of the week (wday) is 6 (friday) then set this as first friday of the month.
dmfStartDay = i;
end
end
local timeTable = {year = data.year, month = data.month, day = dmfStartDay + dayOffset, hour = hourOffset, min = minOffset, sec = 0};
local utcdate = date("!*t", GetServerTime());
local localdate = date("*t", GetServerTime());
localdate.isdst = false;
local secondsDiff = difftime(time(utcdate), time(localdate));
local dmfStart = time(timeTable) - secondsDiff;
if (date("%w", dmfStart) == "0") then
--Not sure if whole region spawns at the same moment or if each realm waits for their own monday.
--All realms spawn same time of day, but possibly not same UTC day depending on timezone.
--Just incase each realm waits for monday we can add a day here.
dmfStart = dmfStart + 86400;
end
--Add 7 days to get end timestamp.
local dmfEnd = dmfStart + 604800;
--Only return if we have set daily reset offsets for this region.
if (validRegion) then
return dmfStart, dmfEnd;
end
end
function NWB:getDmfData()
local dmfStart, dmfEnd = NWB:getDmfStartEnd();
local timestamp, timeLeft, type;
--local locale = GetLocale();
--OCE region only just for now.
if (dmfStart and dmfEnd) then
if (GetServerTime() < dmfStart) then
--It's before the start of dmf.
timestamp = dmfStart;
type = "start";
timeLeft = dmfStart - GetServerTime();
NWB.isDmfUp = nil;
elseif (GetServerTime() < dmfEnd) then
--It's after dmf started and before the end.
timestamp = dmfEnd;
type = "end";
timeLeft = dmfEnd - GetServerTime();
NWB.isDmfUp = true;
elseif (GetServerTime() > dmfEnd) then
--It's after dmf ended so calc next months dmf instead.
local data = date("!*t", GetServerTime());
if (data.month == 12) then
dmfStart, dmfEnd = NWB:getDmfStartEnd(1, true);
else
dmfStart, dmfEnd = NWB:getDmfStartEnd(data.month + 1);
end
timestamp = dmfStart;
type = "start";
timeLeft = dmfStart - GetServerTime();
NWB.isDmfUp = nil;
end
local zone;
if (date("%m", dmfStart) % 2 == 0) then
zone = "Mulgore";
else
zone = "Elwynn Forest";
end
NWB.dmfZone = zone;
--Timestamp of next start or end event, seconds left untill that event, and type of event.
return timestamp, timeLeft, type;
end
end
function NWB:updateDmfMarkers(type)
local timestamp, timeLeft, type = NWB:getDmfData();
local text = "";
if (not timestamp or timestamp < 1) then
text = text .. L["noTimer"];
else
if (type == "start") then
text = text .. string.format(L["startsIn"], NWB:getTimeString(timeLeft, true, true));
else
text = text .. string.format(L["endsIn"], NWB:getTimeString(timeLeft, true, true));
end
end
if (timeLeft > 0) then
local tooltipText = "|Cff00ff00" .. L["Darkmoon Faire"] .. "|CffDEDE42\n";
if (type == "start") then
tooltipText = tooltipText .. string.format(L["startsIn"], NWB:getTimeString(timeLeft, true)) .. "\n";
else
tooltipText = tooltipText .. string.format(L["endsIn"], NWB:getTimeString(timeLeft, true)) .. "\n";
end
tooltipText = tooltipText .. NWB:getTimeFormat(timestamp, true);
local dmfFound;
local buffText = "";
if (NWB.isDmfUp) then
if (NWB.data.myChars[UnitName("player")].buffs) then
for k, v in pairs(NWB.data.myChars[UnitName("player")].buffs) do
if (v.type == "dmf" and (v.timeLeft + 7200) > 0) then
buffText = "\n" .. string.format(L["dmfBuffCooldownMsg"], NWB:getTimeString((v.timeLeft + 7200), true));
dmfFound = true;
break;
end
end
end
if (not dmfFound) then
buffText = "\n" .. L["dmfBuffReady"];
end
end
tooltipText = tooltipText .. buffText;
_G["NWBDMF"].tooltip.fs:SetText(tooltipText);
_G["NWBDMF"].tooltip:SetWidth(_G["NWBDMF"].tooltip.fs:GetStringWidth() + 18);
_G["NWBDMF"].tooltip:SetHeight(_G["NWBDMF"].tooltip.fs:GetStringHeight() + 12);
_G["NWBDMFContinent"].tooltip.fs:SetText(tooltipText);
_G["NWBDMFContinent"].tooltip:SetWidth(_G["NWBDMFContinent"].tooltip.fs:GetStringWidth() + 12);
_G["NWBDMFContinent"].tooltip:SetHeight(_G["NWBDMFContinent"].tooltip.fs:GetStringHeight() + 12);
end
return text;
end
function NWB:createDmfMarkers()
--Darkmoon Faire zone map marker.
local icon = "Interface\\AddOns\\NovaWorldBuffs\\Media\\dmf";
local obj = CreateFrame("Frame", "NWBDMF", WorldMapFrame);
local bg = obj:CreateTexture(nil, "MEDIUM");
bg:SetTexture(icon);
bg:SetAllPoints(obj);
obj.texture = bg;
obj:SetSize(23, 23);
--Worldmap tooltip.
obj.tooltip = CreateFrame("Frame", "NWBDMFTooltip", WorldMapFrame, "TooltipBorderedFrameTemplate");
obj.tooltip:SetPoint("CENTER", obj, "CENTER", 0, 46);
obj.tooltip:SetFrameStrata("TOOLTIP");
obj.tooltip:SetFrameLevel(9);
obj.tooltip.fs = obj.tooltip:CreateFontString("NWBDMFTooltipFS", "ARTWORK");
obj.tooltip.fs:SetPoint("CENTER", 0, 0);
obj.tooltip.fs:SetFont(NWB.regionFont, 14);
obj.tooltip.fs:SetText("|Cff00ff00Darkmoon Faire");
obj.tooltip:SetWidth(obj.tooltip.fs:GetStringWidth() + 18);
obj.tooltip:SetHeight(obj.tooltip.fs:GetStringHeight() + 12);
obj:SetScript("OnEnter", function(self)
obj.tooltip:Show();
end)
obj:SetScript("OnLeave", function(self)
obj.tooltip:Hide();
end)
obj.tooltip:Hide();
--Timer frame that sits above the icon when an active timer is found.
obj.timerFrame = CreateFrame("Frame", "NWBDMFTimerFrame", WorldMapFrame, "TooltipBorderedFrameTemplate");
obj.timerFrame:SetPoint("CENTER", obj, "CENTER", 0, -21);
obj.timerFrame:SetFrameStrata("FULLSCREEN");
obj.timerFrame:SetFrameLevel(9);
obj.timerFrame.fs = obj.timerFrame:CreateFontString("NWBDMFTimerFrameFS", "ARTWORK");
obj.timerFrame.fs:SetPoint("CENTER", 0, 0);
obj.timerFrame.fs:SetFont(NWB.regionFont, 13);
obj.timerFrame:SetWidth(54);
obj.timerFrame:SetHeight(24);
obj:SetScript("OnUpdate", function(self)
--Update timer when map is open.
obj.timerFrame.fs:SetText(NWB:updateDmfMarkers());
obj.timerFrame:SetWidth(obj.timerFrame.fs:GetStringWidth() + 10);
obj.timerFrame:SetHeight(obj.timerFrame.fs:GetStringHeight() + 10);
end)
--Make it act like pin is the parent and not WorldMapFrame.
obj:SetScript("OnHide", function(self)
obj.timerFrame:Hide();
end)
obj:SetScript("OnShow", function(self)
obj.timerFrame:Show();
end)
obj:SetScript("OnMouseDown", function(self)
NWB:openBuffListFrame();
end)
--Darkmoon Faire continent marker.
local obj = CreateFrame("Frame", "NWBDMFContinent", WorldMapFrame);
local bg = obj:CreateTexture(nil, "MEDIUM");
bg:SetTexture(icon);
bg:SetAllPoints(obj);
obj.texture = bg;
obj:SetSize(14, 14);
obj:SetFrameStrata("High");
obj:SetFrameLevel(9);
--Worldmap tooltip.
obj.tooltip = CreateFrame("Frame", "NWBDMFContinentTooltip", WorldMapFrame, "TooltipBorderedFrameTemplate");
obj.tooltip:SetPoint("CENTER", obj, "CENTER", 0, 46);
obj.tooltip:SetFrameStrata("TOOLTIP");
obj.tooltip:SetFrameLevel(9);
obj.tooltip.fs = obj.tooltip:CreateFontString("NWBDMFContinentTooltipFS", "HIGH");
obj.tooltip.fs:SetPoint("CENTER", 0, 0);
obj.tooltip.fs:SetFont(NWB.regionFont, 14);
obj.tooltip.fs:SetText("|Cff00ff00Darkmoon Faire");
obj.tooltip:SetWidth(obj.tooltip.fs:GetStringWidth() + 18);
obj.tooltip:SetHeight(obj.tooltip.fs:GetStringHeight() + 12);
obj:SetScript("OnEnter", function(self)
obj.tooltip:Show(); --5:34 2h4m
end)
obj:SetScript("OnLeave", function(self)
obj.tooltip:Hide();
end)
obj.tooltip:Hide();
obj:SetScript("OnUpdate", function(self)
--Updatetooltip timer when map is open.
NWB:updateDmfMarkers();
end)
obj:SetScript("OnMouseDown", function(self)
NWB:openBuffListFrame();
end)
NWB:refreshDmfMarkers();
end
function NWB:refreshDmfMarkers()
local x, y, mapID, worldX, worldY, worldMapID;
if (NWB.dmfZone == "Mulgore") then
x, y, mapID = 36.8, 37.6, 1412;
worldX, worldY, worldMapID = 46, 63, 1414;
else
x, y, mapID = 42, 70, 1429;
worldX, worldY, worldMapID = 45.7, 71.4, 1415;
end
NWB.dragonLibPins:RemoveWorldMapIcon("NWBDMF", _G["NWBDMF"]);
if (NWB.db.global.showDmfMap) then
NWB.dragonLibPins:AddWorldMapIconMap("NWBDMF", _G["NWBDMF"], mapID, x/100, y/100, HBD_PINS_WORLDMAP_SHOW_PARENT);
NWB.dragonLibPins:AddWorldMapIconMap("NWBDMFContinent", _G["NWBDMFContinent"], worldMapID, worldX/100, worldY/100, HBD_PINS_WORLDMAP_SHOW_WORLD, "TOOLTIP");
end
end
WorldMapFrame:HookScript("OnShow", function()
NWB:refreshDmfMarkers();
NWB:refreshWorldbuffMarkers();
end)
function NWB:fixMapMarkers()
--Fix a bug with tooltips not showing first time opening the map.
--Running this twice taints the blizzard raid frames (wtf?)
--WorldMapFrame:Show();
--WorldMapFrame:SetMapID(1448);
--WorldMapFrame:Hide();
end
---===================---
---Buff tracking frame---
---===================---
local NWBbuffListFrame = CreateFrame("ScrollFrame", "NWBbuffListFrame", UIParent, "InputScrollFrameTemplate");
NWBbuffListFrame:Hide();
NWBbuffListFrame:SetToplevel(true);
NWBbuffListFrame:SetMovable(true);
NWBbuffListFrame:EnableMouse(true);
tinsert(UISpecialFrames, "NWBbuffListFrame");
NWBbuffListFrame:SetPoint("CENTER", UIParent, 20, 120);
NWBbuffListFrame:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8x8",insets = {top = 0, left = 0, bottom = 0, right = 0}});
NWBbuffListFrame:SetBackdropColor(0,0,0,.5);
NWBbuffListFrame.CharCount:Hide();
--NWBbuffListFrame:SetFrameLevel(128);
NWBbuffListFrame:SetFrameStrata("MEDIUM");
NWBbuffListFrame.EditBox:SetAutoFocus(false);
NWBbuffListFrame.EditBox:SetScript("OnKeyDown", function(self, arg)
--If control key is down keep focus for copy/paste to work.
--Otherwise remove focus so "enter" can be used to open chat and not have a stuck cursor on this edit box.
if (not IsControlKeyDown()) then
NWBbuffListFrame.EditBox:ClearFocus();
end
end)
NWBbuffListFrame.EditBox:SetScript("OnShow", function(self, arg)
NWBbuffListFrame:SetVerticalScroll(0);
end)
local buffUpdateTime = 0;
NWBbuffListFrame:HookScript("OnUpdate", function(self, arg)
--Only update once per second.
if (GetServerTime() - buffUpdateTime > 0 and self:GetVerticalScrollRange() == 0) then
NWB:recalcBuffListFrame();
buffUpdateTime = GetServerTime();
end
end)
NWBbuffListFrame.fs = NWBbuffListFrame:CreateFontString("NWBbuffListFrameFS", "HIGH");
NWBbuffListFrame.fs:SetPoint("TOP", 0, 0);
NWBbuffListFrame.fs:SetFont(NWB.regionFont, 14);
NWBbuffListFrame.fs:SetText("|cffffff00" .. L["Your Current World Buffs"]);
local NWBbuffListDragFrame = CreateFrame("Frame", "NWBbuffListDragFrame", NWBbuffListFrame);
--NWBbuffListDragFrame:SetToplevel(true);
NWBbuffListDragFrame:EnableMouse(true);
NWBbuffListDragFrame:SetWidth(205);
NWBbuffListDragFrame:SetHeight(38);
NWBbuffListDragFrame:SetPoint("TOP", 0, 4);
NWBbuffListDragFrame:SetFrameLevel(131);
NWBbuffListDragFrame.tooltip = CreateFrame("Frame", "NWBbuffListDragTooltip", NWBbuffListDragFrame, "TooltipBorderedFrameTemplate");
NWBbuffListDragFrame.tooltip:SetPoint("CENTER", NWBbuffListDragFrame, "TOP", 0, 12);
NWBbuffListDragFrame.tooltip:SetFrameStrata("TOOLTIP");
NWBbuffListDragFrame.tooltip:SetFrameLevel(9);
NWBbuffListDragFrame.tooltip:SetAlpha(.8);
NWBbuffListDragFrame.tooltip.fs = NWBbuffListDragFrame.tooltip:CreateFontString("NWBbuffListDragTooltipFS", "HIGH");
NWBbuffListDragFrame.tooltip.fs:SetPoint("CENTER", 0, 0.5);
NWBbuffListDragFrame.tooltip.fs:SetFont(NWB.regionFont, 12);
NWBbuffListDragFrame.tooltip.fs:SetText("Hold to drag");
NWBbuffListDragFrame.tooltip:SetWidth(NWBbuffListDragFrame.tooltip.fs:GetStringWidth() + 16);
NWBbuffListDragFrame.tooltip:SetHeight(NWBbuffListDragFrame.tooltip.fs:GetStringHeight() + 10);
NWBbuffListDragFrame:SetScript("OnEnter", function(self)
NWBbuffListDragFrame.tooltip:Show();
end)
NWBbuffListDragFrame:SetScript("OnLeave", function(self)
NWBbuffListDragFrame.tooltip:Hide();
end)
NWBbuffListDragFrame.tooltip:Hide();
NWBbuffListDragFrame:SetScript("OnMouseDown", function(self, button)
if (button == "LeftButton" and not self:GetParent().isMoving) then
self:GetParent().EditBox:ClearFocus();
self:GetParent():StartMoving();
self:GetParent().isMoving = true;
--self:GetParent():SetUserPlaced(false);
end
end)
NWBbuffListDragFrame:SetScript("OnMouseUp", function(self, button)
if (button == "LeftButton" and self:GetParent().isMoving) then
self:GetParent():StopMovingOrSizing();
self:GetParent().isMoving = false;
end
end)
NWBbuffListDragFrame:SetScript("OnHide", function(self)
if (self:GetParent().isMoving) then
self:GetParent():StopMovingOrSizing();
self:GetParent().isMoving = false;
end
end)
--Top right X close button.
local NWBbuffListFrameClose = CreateFrame("Button", "NWBbuffListFrameClose", NWBbuffListFrame, "UIPanelCloseButton");
NWBbuffListFrameClose:SetPoint("TOPRIGHT", -5, 8.6);
NWBbuffListFrameClose:SetWidth(31);
NWBbuffListFrameClose:SetHeight(31);
NWBbuffListFrameClose:SetScript("OnClick", function(self, arg)
NWBbuffListFrame:Hide();
end)
--Config button.
local NWBbuffListFrameConfButton = CreateFrame("Button", "NWBbuffListFrameConfButton", NWBbuffListFrameClose, "UIPanelButtonTemplate");
NWBbuffListFrameConfButton:SetPoint("CENTER", -58, 1);
NWBbuffListFrameConfButton:SetWidth(90);
NWBbuffListFrameConfButton:SetHeight(17);
NWBbuffListFrameConfButton:SetText(L["Options"]);
NWBbuffListFrameConfButton:SetNormalFontObject("GameFontNormalSmall");
NWBbuffListFrameConfButton:SetScript("OnClick", function(self, arg)
--Opening the frame needs to be run twice to avoid a bug.
InterfaceOptionsFrame_OpenToCategory("NovaWorldBuffs");
--Hack to fix the issue of interface options not opening to menus below the current scroll range.
--This addon name starts with N and will always be closer to the middle so just scroll to the middle when opening.
local min, max = InterfaceOptionsFrameAddOnsListScrollBar:GetMinMaxValues();
if (min < max) then
InterfaceOptionsFrameAddOnsListScrollBar:SetValue(math.floor(max/2));
end
InterfaceOptionsFrame_OpenToCategory("NovaWorldBuffs");
end)
NWBbuffListFrameConfButton:SetScript("OnMouseDown", function(self, button)
if (button == "LeftButton" and not self:GetParent():GetParent().isMoving) then
self:GetParent():GetParent().EditBox:ClearFocus();
self:GetParent():GetParent():StartMoving();
self:GetParent():GetParent().isMoving = true;
end
end)
NWBbuffListFrameConfButton:SetScript("OnMouseUp", function(self, button)
if (button == "LeftButton" and self:GetParent():GetParent().isMoving) then
self:GetParent():GetParent():StopMovingOrSizing();
self:GetParent():GetParent().isMoving = false;
end
end)
NWBbuffListFrameConfButton:SetScript("OnHide", function(self)
if (self:GetParent():GetParent().isMoving) then
self:GetParent():GetParent():StopMovingOrSizing();
self:GetParent():GetParent().isMoving = false;
end
end)
--Timers button (layered realms only).
local NWBbufflistFrameTimersButton = CreateFrame("Button", "NWBbufflistFrameTimersButton", NWBbuffListFrameClose, "UIPanelButtonTemplate");
NWBbufflistFrameTimersButton:SetPoint("CENTER", -58, -13);
NWBbufflistFrameTimersButton:SetWidth(90);
NWBbufflistFrameTimersButton:SetHeight(17);
NWBbufflistFrameTimersButton:SetText("Timers");
NWBbufflistFrameTimersButton:SetNormalFontObject("GameFontNormalSmall");
NWBbufflistFrameTimersButton:SetScript("OnClick", function(self, arg)
NWB:openLayerFrame();
end)
NWBbufflistFrameTimersButton:SetScript("OnMouseDown", function(self, button)
if (button == "LeftButton" and not self:GetParent():GetParent().isMoving) then
self:GetParent():GetParent().EditBox:ClearFocus();
self:GetParent():GetParent():StartMoving();
self:GetParent():GetParent().isMoving = true;
end
end)
NWBbufflistFrameTimersButton:SetScript("OnMouseUp", function(self, button)
if (button == "LeftButton" and self:GetParent():GetParent().isMoving) then
self:GetParent():GetParent():StopMovingOrSizing();
self:GetParent():GetParent().isMoving = false;
end
end)
NWBbufflistFrameTimersButton:SetScript("OnHide", function(self)
if (self:GetParent():GetParent().isMoving) then
self:GetParent():GetParent():StopMovingOrSizing();
self:GetParent():GetParent().isMoving = false;
end
end)
NWBbufflistFrameTimersButton:Hide();
--Wipe data button.
local NWBbuffListFrameWipeButton = CreateFrame("Button", "NWBbuffListFrameWipeButton", NWBbuffListFrame, "UIPanelButtonTemplate");
NWBbuffListFrameWipeButton:SetPoint("BOTTOMRIGHT", -34, -1);
NWBbuffListFrameWipeButton:SetWidth(90);
NWBbuffListFrameWipeButton:SetHeight(17);
NWBbuffListFrameWipeButton:SetText(L["Reset Data"]);
NWBbuffListFrameWipeButton:SetNormalFontObject("GameFontNormalSmall");
NWBbuffListFrameWipeButton:SetScript("OnClick", function(self, arg)
NWB:resetBuffData();
end)
function NWB:openBuffListFrame()
NWBbuffListFrame.fs:SetFont(NWB.regionFont, 14);
if (NWBbuffListFrame:IsShown()) then
NWBbuffListFrame:Hide();
else
if (NWB.isLayered) then
NWBbufflistFrameTimersButton:Show();
end
NWB:syncBuffsWithCurrentDuration();
NWBbuffListFrame:SetHeight(300);
NWBbuffListFrame:SetWidth(450);
local fontSize = false
NWBbuffListFrame.EditBox:SetFont(NWB.regionFont, 14);
NWB:recalcBuffListFrame();
NWBbuffListFrame.EditBox:SetWidth(NWBbuffListFrame:GetWidth() - 30);
NWBbuffListFrame:Show();
--Changing scroll position requires a slight delay.
--Second delay is a backup.
C_Timer.After(0.05, function()
NWBbuffListFrame:SetVerticalScroll(0);
end)
C_Timer.After(0.3, function()
NWBbuffListFrame:SetVerticalScroll(0);
end)
--So interface options and this frame will open on top of each other.
if (InterfaceOptionsFrame:IsShown()) then
NWBbuffListFrame:SetFrameStrata("DIALOG")
else
NWBbuffListFrame:SetFrameStrata("HIGH")
end
end
end
function NWB:recalcBuffListFrame()
--local scroll = NWBbuffListFrame:GetVerticalScroll();
if (NWB.isDmfUp) then
local buffText, dmfFound;
if (NWB.data.myChars[UnitName("player")].buffs) then
for k, v in pairs(NWB.data.myChars[UnitName("player")].buffs) do
if (v.type == "dmf" and (v.timeLeft + 7200) > 0) then
buffText = string.format(L["dmfBuffCooldownMsg"], NWB:getTimeString(v.timeLeft + 7200, true));
dmfFound = true;
break;
end
end
end
if (not dmfFound) then
buffText = L["dmfBuffReady"];
end
NWBbuffListFrame.EditBox:SetText("\n" .. buffText .. "\n");
else
NWBbuffListFrame.EditBox:SetText("\n\n");
end
local count = 0;
local foundChars;
for k, v in NWB:pairsByKeys(NWB.db.global) do --Iterate realms.
local msg = "";
if (type(v) == "table") then --The only tables in db.global are realm names.
local realm = k;
for k, v in NWB:pairsByKeys(v) do --Iterate factions.
local msg2 = "";
local coloredFaction = "";
--if (k == "Horde") then
-- coloredFaction = "|cffe50c11" .. k .. "|r";
--else
-- coloredFaction = "|cff4954e8" .. k .. "|r";
--end
--local foundActiveBuff;
msg2 = "|cff00ff00[" .. realm .. "]|r\n";
--Have to check if the myChars table exists here.
--There was a lua error when much older versions upgraded to the buff tracking version.
--They had realmdata in thier db file without the myChars table and it won't create it until they log on that realm.
local foundAnyBuff;
if (v.myChars) then
local foundActiveBuff;
for k, v in NWB:pairsByKeys(v.myChars) do --Iterate characters.
foundActiveBuff = nil;
local msg3 = "";
local _, _, _, classColor = GetClassColor(v.englishClass);
msg3 = msg3 .. " -|c" .. classColor .. k .. "|r\n";
for k, v in NWB:pairsByKeys(v.buffs) do--Iterate buffs.
if (v.track and v.timeLeft > 0) then
local icon = "";
if (v.type == "rend") then
icon = "|TInterface\\Icons\\spell_arcane_teleportorgrimmar:12:12:0:0|t";
elseif (v.type == "ony") then
icon = "|TInterface\\Icons\\inv_misc_head_dragon_01:12:12:0:0|t";
elseif (v.type == "nef") then
icon = "|TInterface\\Icons\\inv_misc_head_dragon_01:12:12:0:0|t";
elseif (v.type == "dmf") then
icon = "|TInterface\\Icons\\inv_misc_orb_02:12:12:0:0|t";
elseif (v.type == "zan") then
icon = "|TInterface\\Icons\\ability_creature_poison_05:12:12:0:0|t";
elseif (v.type == "moxie") then
icon = "|TInterface\\Icons\\spell_nature_massteleport:12:12:0:0|t";
elseif (v.type == "ferocity") then
icon = "|TInterface\\Icons\\spell_nature_undyingstrength:12:12:0:0|t";
elseif (v.type == "savvy") then
icon = "|TInterface\\Icons\\spell_holy_lesserheal02:12:12:0:0|t";
elseif (v.type == "flaskPower") then
icon = "|TInterface\\Icons\\inv_potion_41:12:12:0:0|t";
elseif (v.type == "flaskTitans") then
icon = "|TInterface\\Icons\\inv_potion_62:12:12:0:0|t";
elseif (v.type == "flaskWisdom") then
icon = "|TInterface\\Icons\\inv_potion_97:12:12:0:0|t";
elseif (v.type == "flaskResistance") then
icon = "|TInterface\\Icons\\inv_potion_48:12:12:0:0|t";
elseif (v.type == "songflower") then
icon = "|TInterface\\Icons\\spell_holy_mindvision:12:12:0:0|t";
elseif (v.type == "resistFire") then
icon = "|TInterface\\Icons\\spell_fire_firearmor:12:12:0:0|t";
elseif (v.type == "blackfathom") then
icon = "|TInterface\\Icons\\spell_frost_frostward:12:12:0:0|t";
end
msg3 = msg3 .. " " .. icon .. " |cFFFFAE42" .. k .. " ";
msg3 = msg3 .. "|cFF9CD6DE" .. NWB:getTimeString(v.timeLeft, true) .. ".|r\n";
foundActiveBuff = true;
end
end
if (NWB.db.global.showAllAlts or foundActiveBuff) then
msg2 = msg2 .. msg3;
foundChars = true;
foundAnyBuff = true;
end
end
if (NWB.db.global.showAllAlts or foundAnyBuff) then
msg = msg .. msg2;
foundChars = true;
end
end
end
end
NWBbuffListFrame.EditBox:Insert(msg);
end
if (not foundChars) then
NWBbuffListFrame.EditBox:Insert("|cffffff00No characters with buffs found.");
end
--NWBbuffListFrame:SetVerticalScroll(scroll);
end
--Reset data if name changes, server xfer etc.
function NWB:resetBuffData()
for k, v in NWB:pairsByKeys(NWB.db.global) do --Iterate realms.
local msg = "";
if (type(v) == "table") then --The only tables in db.global are realm names.
local realm = k;
for k, v in NWB:pairsByKeys(v) do --Iterate factions.
local f = k;
if (v.myChars) then
for k, v in NWB:pairsByKeys(v.myChars) do --Iterate characters.
NWB.db.global[realm][f].myChars[k].buffs = {};
end
end
end
end
end
NWB:print("Buff records have been reset.");
C_Timer.After(3, function()
NWB:syncBuffsWithCurrentDuration();
end)
end
SLASH_NWBDMFBUFFSCMD1, SLASH_NWBDMFBUFFSCMD2 = '/buff', '/buffs';
function SlashCmdList.NWBDMFBUFFSCMD(msg, editBox)
NWB:openBuffListFrame();
end
---====================---
---Layer tracking frame---
---====================---
local NWBlayerFrame = CreateFrame("ScrollFrame", "NWBlayerFrame", UIParent, "InputScrollFrameTemplate");
NWBlayerFrame:Hide();
NWBlayerFrame:SetToplevel(true);
NWBlayerFrame:SetMovable(true);
NWBlayerFrame:EnableMouse(true);
tinsert(UISpecialFrames, "NWBlayerFrame");
NWBlayerFrame:SetPoint("CENTER", UIParent, 0, 100);
NWBlayerFrame:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8x8",insets = {top = 0, left = 0, bottom = 0, right = 0}});
NWBlayerFrame:SetBackdropColor(0,0,0,.5);
NWBlayerFrame.CharCount:Hide();
NWBlayerFrame:SetFrameStrata("HIGH");
NWBlayerFrame.EditBox:SetAutoFocus(false);
NWBlayerFrame.EditBox:SetScript("OnKeyDown", function(self, arg)
--If control key is down keep focus for copy/paste to work.
--Otherwise remove focus so "enter" can be used to open chat and not have a stuck cursor on this edit box.
if (not IsControlKeyDown()) then
NWBlayerFrame.EditBox:ClearFocus();
end
end)
NWBlayerFrame.EditBox:SetScript("OnShow", function(self, arg)
NWBlayerFrame:SetVerticalScroll(0);
end)
local buffUpdateTime = 0;
NWBlayerFrame:HookScript("OnUpdate", function(self, arg)
--Only update once per second.
if (GetServerTime() - buffUpdateTime > 0 and self:GetVerticalScrollRange() == 0) then
NWB:recalclayerFrame();
buffUpdateTime = GetServerTime();
end
end)
NWBlayerFrame.fs = NWBlayerFrame:CreateFontString("NWBlayerFrameFS", "HIGH");
NWBlayerFrame.fs:SetPoint("TOP", 0, -0);
NWBlayerFrame.fs:SetFont(NWB.regionFont, 14);
NWBlayerFrame.fs:SetText("|cFFFF5100NovaWorldBuffs v" .. version .. "|r");
NWBlayerFrame.fs2 = NWBlayerFrame:CreateFontString("NWBlayerFrameFS", "HIGH");
NWBlayerFrame.fs2:SetPoint("TOPLEFT", 0, -14);
NWBlayerFrame.fs2:SetFont(NWB.regionFont, 14);
NWBlayerFrame.fs2:SetText("|cFF9CD6DETarget any NPC to see your current layer.|r");
NWBlayerFrame.fs3 = NWBlayerFrame:CreateFontString("NWBbuffListFrameFS", "HIGH");
NWBlayerFrame.fs3:SetPoint("BOTTOM", 0, 2);
NWBlayerFrame.fs3:SetFont(NWB.regionFont, 14);
NWBlayerFrame.fs3:SetText("|cFFDEDE42Layers may be inaccurate for a few hours after server restarts.\n"
.. "Layers will disappear from here 6 hours after having no timers.");
local NWBlayerDragFrame = CreateFrame("Frame", "NWBlayerDragFrame", NWBlayerFrame);
NWBlayerDragFrame:SetToplevel(true);
NWBlayerDragFrame:EnableMouse(true);
NWBlayerDragFrame:SetWidth(205);
NWBlayerDragFrame:SetHeight(38);
NWBlayerDragFrame:SetPoint("TOP", 0, 4);
NWBlayerDragFrame:SetFrameLevel(131);
NWBlayerDragFrame.tooltip = CreateFrame("Frame", "NWBlayerDragTooltip", NWBlayerDragFrame, "TooltipBorderedFrameTemplate");
NWBlayerDragFrame.tooltip:SetPoint("CENTER", NWBlayerDragFrame, "TOP", 0, 12);
NWBlayerDragFrame.tooltip:SetFrameStrata("TOOLTIP");
NWBlayerDragFrame.tooltip:SetFrameLevel(9);
NWBlayerDragFrame.tooltip:SetAlpha(.8);
NWBlayerDragFrame.tooltip.fs = NWBlayerDragFrame.tooltip:CreateFontString("NWBlayerDragTooltipFS", "HIGH");
NWBlayerDragFrame.tooltip.fs:SetPoint("CENTER", 0, 0.5);
NWBlayerDragFrame.tooltip.fs:SetFont(NWB.regionFont, 12);
NWBlayerDragFrame.tooltip.fs:SetText("Hold to drag");
NWBlayerDragFrame.tooltip:SetWidth(NWBlayerDragFrame.tooltip.fs:GetStringWidth() + 16);
NWBlayerDragFrame.tooltip:SetHeight(NWBlayerDragFrame.tooltip.fs:GetStringHeight() + 10);
NWBlayerDragFrame:SetScript("OnEnter", function(self)
NWBlayerDragFrame.tooltip:Show();
end)
NWBlayerDragFrame:SetScript("OnLeave", function(self)
NWBlayerDragFrame.tooltip:Hide();
end)
NWBlayerDragFrame.tooltip:Hide();
NWBlayerDragFrame:SetScript("OnMouseDown", function(self, button)
if (button == "LeftButton" and not self:GetParent().isMoving) then
self:GetParent().EditBox:ClearFocus();
self:GetParent():StartMoving();
self:GetParent().isMoving = true;
--self:GetParent():SetUserPlaced(false);
end
end)
NWBlayerDragFrame:SetScript("OnMouseUp", function(self, button)
if (button == "LeftButton" and self:GetParent().isMoving) then
self:GetParent():StopMovingOrSizing();
self:GetParent().isMoving = false;
end
end)
NWBlayerDragFrame:SetScript("OnHide", function(self)
if (self:GetParent().isMoving) then
self:GetParent():StopMovingOrSizing();
self:GetParent().isMoving = false;
end
end)
--Top right X close button.
local NWBlayerFrameClose = CreateFrame("Button", "NWBlayerFrameClose", NWBlayerFrame, "UIPanelCloseButton");
NWBlayerFrameClose:SetPoint("TOPRIGHT", -5, 8.6);
NWBlayerFrameClose:SetWidth(31);
NWBlayerFrameClose:SetHeight(31);
NWBlayerFrameClose:SetScript("OnClick", function(self, arg)
NWBlayerFrame:Hide();
end)
--Config button.
local NWBlayerFrameConfButton = CreateFrame("Button", "NWBlayerFrameConfButton", NWBlayerFrameClose, "UIPanelButtonTemplate");
NWBlayerFrameConfButton:SetPoint("CENTER", -58, 1);
NWBlayerFrameConfButton:SetWidth(90);
NWBlayerFrameConfButton:SetHeight(17);
NWBlayerFrameConfButton:SetText(L["Options"]);
NWBlayerFrameConfButton:SetNormalFontObject("GameFontNormalSmall");
NWBlayerFrameConfButton:SetScript("OnClick", function(self, arg)
--Opening the frame needs to be run twice to avoid a bug.
InterfaceOptionsFrame_OpenToCategory("NovaWorldBuffs");
--Hack to fix the issue of interface options not opening to menus below the current scroll range.
--This addon name starts with N and will always be closer to the middle so just scroll to the middle when opening.
local min, max = InterfaceOptionsFrameAddOnsListScrollBar:GetMinMaxValues();
if (min < max) then
InterfaceOptionsFrameAddOnsListScrollBar:SetValue(math.floor(max/2));
end
InterfaceOptionsFrame_OpenToCategory("NovaWorldBuffs");
end)
NWBlayerFrameConfButton:SetScript("OnMouseDown", function(self, button)
if (button == "LeftButton" and not self:GetParent():GetParent().isMoving) then
self:GetParent():GetParent().EditBox:ClearFocus();
self:GetParent():GetParent():StartMoving();
self:GetParent():GetParent().isMoving = true;
end
end)
NWBlayerFrameConfButton:SetScript("OnMouseUp", function(self, button)
if (button == "LeftButton" and self:GetParent():GetParent().isMoving) then
self:GetParent():GetParent():StopMovingOrSizing();
self:GetParent():GetParent().isMoving = false;
end
end)
NWBlayerFrameConfButton:SetScript("OnHide", function(self)
if (self:GetParent():GetParent().isMoving) then
self:GetParent():GetParent():StopMovingOrSizing();
self:GetParent():GetParent().isMoving = false;
end
end)
--Buffs button.
local NWBlayerFrameBuffsButton = CreateFrame("Button", "NWBlayerFrameBuffsButton", NWBlayerFrameClose, "UIPanelButtonTemplate");
NWBlayerFrameBuffsButton:SetPoint("CENTER", -58, -13);
NWBlayerFrameBuffsButton:SetWidth(90);
NWBlayerFrameBuffsButton:SetHeight(17);
NWBlayerFrameBuffsButton:SetText("Buffs");
NWBlayerFrameBuffsButton:SetNormalFontObject("GameFontNormalSmall");
NWBlayerFrameBuffsButton:SetScript("OnClick", function(self, arg)
NWB:openBuffListFrame();
end)
NWBlayerFrameBuffsButton:SetScript("OnMouseDown", function(self, button)
if (button == "LeftButton" and not self:GetParent():GetParent().isMoving) then
self:GetParent():GetParent().EditBox:ClearFocus();
self:GetParent():GetParent():StartMoving();
self:GetParent():GetParent().isMoving = true;
end
end)
NWBlayerFrameBuffsButton:SetScript("OnMouseUp", function(self, button)
if (button == "LeftButton" and self:GetParent():GetParent().isMoving) then
self:GetParent():GetParent():StopMovingOrSizing();
self:GetParent():GetParent().isMoving = false;
end
end)
NWBlayerFrameBuffsButton:SetScript("OnHide", function(self)
if (self:GetParent():GetParent().isMoving) then
self:GetParent():GetParent():StopMovingOrSizing();
self:GetParent():GetParent().isMoving = false;
end
end)
function NWB:openLayerFrame()
NWB:removeOldLayers();
NWBlayerFrame.fs:SetFont(NWB.regionFont, 14);
if (NWBlayerFrame:IsShown()) then
NWBlayerFrame:Hide();
else
NWB:syncBuffsWithCurrentDuration();
NWBlayerFrame:SetHeight(300);
NWBlayerFrame:SetWidth(450);
local fontSize = false
NWBlayerFrame.EditBox:SetFont(NWB.regionFont, 14);
NWB:recalclayerFrame();
NWBlayerFrame.EditBox:SetWidth(NWBlayerFrame:GetWidth() - 30);
NWBlayerFrame:Show();
--Changing scroll position requires a slight delay.
--Second delay is a backup.
C_Timer.After(0.05, function()
NWBlayerFrame:SetVerticalScroll(0);
end)
C_Timer.After(0.3, function()
NWBlayerFrame:SetVerticalScroll(0);
end)
--So interface options and this frame will open on top of each other.
if (InterfaceOptionsFrame:IsShown()) then
NWBlayerFrame:SetFrameStrata("DIALOG")
else
NWBlayerFrame:SetFrameStrata("HIGH")
end
end
end
function NWB:createNewLayer(zoneID, GUID)
local count, remoteCount = 0, 0;
for k, v in pairs(NWB.data.layers) do
count = count + 1;
end
if (count >= NWB.limitLayerCount) then
NWB:debug("Could not create new layer", zoneID, "already at limit", NWB.limitLayerCount);
return;
end
if (GUID and GUID ~= "other" and GUID ~= "none") then
--Creating layers anywhere but from other users data requires npc validation here.
local unitType, _, _, _, zoneID, npcID = strsplit("-", GUID);
if (NWB.faction == "Horde") then
if (not NWB.orgrimmarCreatures[tonumber(npcID)] or unitType ~= "Creature") then
NWB:debug("bad layer detected", unitType, zoneID, npcID);
return;
end
elseif (NWB.faction == "Alliance") then
if (not NWB.stormwindCreatures[tonumber(npcID)] or unitType ~= "Creature") then
NWB:debug("bad layer detected", unitType, zoneID, npcID);
return;
end
end
end
if (NWB:validateLayer(zoneID)) then
NWB.data.layers[zoneID] = {
rendTimer = 0,
rendYell = 0,
rendYell2 = 0,
onyTimer = 0,
onyYell = 0,
onyYell2 = 0,
onyNpcDied = 0,
nefTimer = 0,
nefYell = 0,
nefYell2 = 0,
nefNpcDied = 0,
created = GetServerTime(),
GUID = GUID or "none",
--zanTimer = 0,
--zanYell = 0,
--zanYell2 = 0,
};
if (NWB.data.layerMapBackups and NWB.data.layerMapBackups[zoneID]
and (GetServerTime() - NWB.data.layerMapBackups[zoneID].created) < 518400) then
--Restore layermap backup if less than 6 days old.
NWB.data.layers[zoneID].layerMap = NWB.data.layerMapBackups[zoneID];
end
NWB:debug("created new layer", zoneID);
NWB:createWorldbuffMarkers();
end
end
function NWB:removeOldLayers()
local expireTime = 21600;
local removed;
if (next(NWB.data.layers)) then
for k, v in pairs(NWB.data.layers) do
--Check if this layer has any current timers old than an hour expired.
local validTimer = nil;
if (v.rendTimer and (v.rendTimer + expireTime) > (GetServerTime() - NWB.db.global.rendRespawnTime)) then
validTimer = true;
end
if (v.onyNpcDied and (v.onyNpcDied > v.onyTimer) and
(v.onyNpcDied > (GetServerTime() - NWB.db.global.onyRespawnTime))) then
validTimer = true;
elseif (v.onyTimer and (v.onyTimer + expireTime) > (GetServerTime() - NWB.db.global.onyRespawnTime)) then
validTimer = true;
end
if (v.nefNpcDied and (v.nefNpcDied > v.nefTimer) and
(v.nefNpcDied > (GetServerTime() - NWB.db.global.nefRespawnTime))) then
validTimer = true;
elseif (v.nefTimer and (v.nefTimer + expireTime) > (GetServerTime() - NWB.db.global.nefRespawnTime)) then
validTimer = true;
end
if (not v.created) then
--For older layers created before this version updated and missing this field.
v.created = 0;
end
if (not validTimer and v.created < GetServerTime() - expireTime) then
if (v.layerMap and next(v.layerMap)) then
if (not NWB.data.layerMapBackups) then
NWB.data.layerMapBackups = {};
end
NWB.data.layerMapBackups[k] = v.layerMap;
NWB.data.layerMapBackups[k].created = v.created or 0;
end
NWB.data.layers[k] = nil;
removed = true;
NWB:debug("Removed old layer", k);
end
end
end
if (NWB.data.layerMapBackups and next(NWB.data.layers)) then
for k, v in pairs(NWB.data.layerMapBackups) do
--Remove layermap backups older than 6 days.
--Thesebackups are just there to be restored when a layer dissapears because no timers for a long time (like overnight).
if (not v.created or (GetServerTime() - v.created) > 518400) then
NWB.data.layerMapBackups[k] = nil;
end
end
end
if (removed) then
NWB:refreshWorldbuffMarkers();
end
end
function NWB:recalclayerFrame()
--local scroll = NWBlayerFrame:GetVerticalScroll();
NWBlayerFrame.EditBox:SetText("\n\n");
local count = 0;
local foundTimers;
table.sort(NWB.data.layers);
--for k, v in NWB:pairsByKeys(NWB.data.layers) do
for k, v in NWB:pairsByKeys(NWB.data.layers) do
foundTimers = true;
count = count + 1;
NWBlayerFrame.EditBox:Insert("\n|cff00ff00[Layer " .. count .. "]|r |cFF989898(zone " .. k .. ")|r\n");
local msg = "";
if (NWB.faction == "Horde" or NWB.db.global.allianceEnableRend) then
if (v.rendTimer > (GetServerTime() - NWB.db.global.rendRespawnTime)) then
msg = msg .. L["rend"] .. ": " .. NWB:getTimeString(NWB.db.global.rendRespawnTime - (GetServerTime() - v.rendTimer), true) .. ".";
if (NWB.db.global.showTimeStamp) then
local timeStamp = NWB:getTimeFormat(v.rendTimer + NWB.db.global.rendRespawnTime);
msg = msg .. " (" .. timeStamp .. ")";
end
else
msg = msg .. L["rend"] .. ": " .. L["noCurrentTimer"] .. ".";
end
NWBlayerFrame.EditBox:Insert(NWB.chatColor .. msg .. "\n");
end
msg = "";
if ((v.onyNpcDied > v.onyTimer) and
(v.onyNpcDied > (GetServerTime() - NWB.db.global.onyRespawnTime))) then
if (NWB.faction == "Horde") then
msg = msg .. string.format(L["onyxiaNpcKilledHordeWithTimer"], NWB:getTimeString(GetServerTime() - v.onyNpcDied, true));
else
msg = msg .. string.format(L["onyxiaNpcKilledAllianceWithTimer"], NWB:getTimeString(GetServerTime() - v.onyNpcDied, true));
end
elseif (v.onyTimer > (GetServerTime() - NWB.db.global.onyRespawnTime)) then
msg = msg .. L["onyxia"] .. ": " .. NWB:getTimeString(NWB.db.global.onyRespawnTime - (GetServerTime() - v.onyTimer), true) .. ".";
if (NWB.db.global.showTimeStamp) then
local timeStamp = NWB:getTimeFormat(v.onyTimer + NWB.db.global.onyRespawnTime);
msg = msg .. " (" .. timeStamp .. ")";
end
else
msg = msg .. L["onyxia"] .. ": " .. L["noCurrentTimer"] .. ".";
end
NWBlayerFrame.EditBox:Insert(NWB.chatColor .. msg .. "\n");
msg = "";
if ((v.nefNpcDied > v.nefTimer) and
(v.nefNpcDied > (GetServerTime() - NWB.db.global.nefRespawnTime))) then
if (NWB.faction == "Horde") then
msg = msg .. string.format(L["nefarianNpcKilledHordeWithTimer"], NWB:getTimeString(GetServerTime() - v.nefNpcDied, true));
else
msg = msg .. string.format(L["nefarianNpcKilledAllianceWithTimer"], NWB:getTimeString(GetServerTime() - v.nefNpcDied, true));
end
elseif (v.nefTimer > (GetServerTime() - NWB.db.global.nefRespawnTime)) then
msg = L["nefarian"] .. ": " .. NWB:getTimeString(NWB.db.global.nefRespawnTime - (GetServerTime() - v.nefTimer), true) .. ".";
if (NWB.db.global.showTimeStamp) then
local timeStamp = NWB:getTimeFormat(v.nefTimer + NWB.db.global.nefRespawnTime);
msg = msg .. " (" .. timeStamp .. ")";
end
else
msg = msg .. L["nefarian"] .. ": " .. L["noCurrentTimer"] .. ".";
end
NWBlayerFrame.EditBox:Insert(NWB.chatColor .. msg .. "\n");
if ((v.rendTimer + 3600) > (GetServerTime() - NWB.db.global.rendRespawnTime)
or (v.onyTimer + 3600) > (GetServerTime() - NWB.db.global.onyRespawnTime)
or (v.nefTimer + 3600) > (GetServerTime() - NWB.db.global.nefRespawnTime)) then
NWB:removeOldLayers();
end
end
if (not foundTimers) then
NWBlayerFrame.EditBox:Insert(NWB.chatColor .. "\nNo current timers found.");
end
NWB:setCurrentLayerText();
--NWBlayerFrame.EditBox:SetText(msg2);
--NWBlayerFrame:SetVerticalScroll(scroll);
if (NWB.latestRemoteVersion and tonumber(NWB.latestRemoteVersion) > tonumber(version)) then
NWBlayerFrame.fs3:SetText("Out of date version " .. version .. " (New version: "
.. NWB.latestRemoteVersion .. ")\nPlease update so your timers are accurate.");
end
--Add 2 extra blank lines to you can scroll layer data up past text at bottom of the frame.
NWBlayerFrame.EditBox:Insert("\n\n");
end
local f = CreateFrame("Frame");
f:RegisterEvent("UNIT_TARGET");
f:RegisterEvent("PLAYER_TARGET_CHANGED");
f:RegisterEvent("UPDATE_MOUSEOVER_UNIT");
f:RegisterEvent("GROUP_JOINED");
f:RegisterEvent("ZONE_CHANGED_NEW_AREA");
f:RegisterEvent("PLAYER_ENTERING_WORLD");
f:RegisterEvent("UNIT_PHASE");
NWB.lastJoinedGroup = 0;
NWB.validLayer = false;
f:SetScript('OnEvent', function(self, event, ...)
if (event == "UNIT_TARGET" or event == "PLAYER_TARGET_CHANGED") then
--These 2 funcs need to be merged after testing.
NWB:setCurrentLayerText("target");
NWB:mapCurrentLayer("target");
elseif (event == "UPDATE_MOUSEOVER_UNIT") then
NWB:setCurrentLayerText("mouseover");
NWB:mapCurrentLayer("mouseover");
elseif (event == "GROUP_JOINED") then
NWB.lastKnownLayerMapID = 0;
NWB.lastJoinedGroup = GetServerTime();
elseif (event == "ZONE_CHANGED_NEW_AREA" or event == "PLAYER_ENTERING_WORLD") then
NWB:recalcMinimapLayerFrame();
elseif (event == "UNIT_PHASE") then
local unit = ...;
--This event fires for team members not for self.
--But seems ok way to find if you join a team to phase.
--Seems to fire even when you are in the same phase, guess it will still do for now to reset the phase frame and make user retarget a npc.
if (UnitIsGroupLeader(unit)) then
NWB.currentLayer = 0;
NWB:recalcMinimapLayerFrame();
end
end
end)
NWB.lastKnownLayer = 0;
NWB.lastKnownLayerID = 0;
NWB.lastKnownLayerMapID = 0;
function NWB:setCurrentLayerText(unit)
if (not NWB.isLayered or not unit) then
return;
end
local _, _, zone = NWB.dragonLib:GetPlayerZonePosition();
local GUID = UnitGUID(unit);
local unitType, zoneID, npcID;
if (GUID) then
unitType, _, _, _, zoneID, npcID = strsplit("-", GUID);
end
if (not zoneID) then
--NWBlayerFrame.fs2:SetText("|cFF9CD6DETarget any NPC in Orgrimmar to see your current layer.|r");
return;
end
--NWB:debug("Layer:", GUID);
if (NWB.faction == "Horde" and (zone ~= 1454 or not npcID)) then
NWBlayerFrame.fs2:SetText("|cFF9CD6DETarget any NPC in Orgrimmar to see your current layer.|r");
return;
end
if (NWB.faction == "Alliance" and (zone ~= 1453 or not npcID)) then
NWBlayerFrame.fs2:SetText("|cFF9CD6DETarget any NPC in Stormwind to see your current layer.|r");
return;
end
if (unitType ~= "Creature" or NWB.companionCreatures[tonumber(npcID)]) then
NWBlayerFrame.fs2:SetText("|cFF9CD6DETarget any NPC in Stormwind to see your current layer.|r");
return;
end
local count = 0;
for k, v in NWB:pairsByKeys(NWB.data.layers) do
count = count + 1;
if (k == tonumber(zoneID)) then
NWBlayerFrame.fs2:SetText("|cFF9CD6DEYou are currently on |cff00ff00[Layer " .. count .. "]|cFF9CD6DE.|r");
NWB.currentLayer = count;
NWB.lastKnownLayer = count;
NWB.lastKnownLayerID = k;
if ((GetServerTime() - NWB.lastJoinedGroup) > 180) then --What's the longest time it can take to change layer?
NWB.lastKnownLayerMapID = tonumber(k);
end
NWB.lastKnownLayerTime = GetServerTime();
NWB:recalcMinimapLayerFrame();
return;
end
end
if (((NWB.faction == "Alliance" and zone == 1453) or (NWB.faction == "Horde" and zone == 1454))
and tonumber(zoneID) and not NWB.data.layers[tonumber(zoneID)]) then
NWB:createNewLayer(tonumber(zoneID), GUID);
end
NWBlayerFrame.fs2:SetText("|cFF9CD6DECan't find current layer or no timers active for this layer.|r");
end
--This is in early testing and relys on a few things.
--[[If you cross a zone border but can still see mobs from the previous zone and target them it could map the previous zoneid
to the new zone, it won't overwrite an already known id so this should be fine aslong as the previous zone was
shared by someone else or we mouseovered any mob in the previous zone and recorded our own data.
On rare occasions it could map the wrong id if previous zone we came from is completly unknown,
but with the data being shared around the server, most of the time after server restarts it will just
get mapped one time by a few early players and shared around, so the chances of this bug happening is pretty low.]]
function NWB:mapCurrentLayer(unit)
--Speedy Creature-0-4671-70-27258-16547-0000312293
if (not NWB.isLayered or not unit or UnitOnTaxi("player") or IsInInstance() or UnitInBattleground("player")) then
return;
end
local _, _, zone = NWB.dragonLib:GetPlayerZonePosition();
if ((NWB.faction == "Alliance" and zone == 1453) or (NWB.faction == "Horde" and zone == 1454)) then
return;
end
local GUID = UnitGUID(unit);
local unitType, zoneID, npcID;
if (GUID) then
unitType, _, _, _, zoneID, npcID = strsplit("-", GUID);
end
if (unitType ~= "Creature" or NWB.companionCreatures[tonumber(npcID)]) then
--NWB:debug("not a creature");
return;
end
if (not zoneID) then
NWB:debug("no zone id");
return;
end
zoneID = tonumber(zoneID);
--Only start mapping if we have come from org/stormwind and know our layer already.
--And only start mapping if we haven't joined a group since leaving org.
if (NWB.lastKnownLayerMapID < 1) then
local foundOldID;
if ((GetServerTime() - NWB.lastJoinedGroup) > 180) then
for k, v in pairs(NWB.data.layers) do
if (v.layerMap and next(v.layerMap)) then
for zone, map in pairs(v.layerMap) do
if (zone == zoneID) then
--Also can start mapping if we pickup our current layer from an already known id.
NWB:debug("found mapped id");
NWB.lastKnownLayerMapID = k;
foundOldID = true;
end
end
end
end
end
if (not foundOldID or NWB.lastKnownLayerMapID < 1) then
NWB:debug("no known last layer");
return;
end
end
--Don't map a new zone if it's a guard outside capital city with the city zoneid.
if (zoneID == NWB.lastKnownLayerMapID) then
NWB:debug("trying to map zone to already known layer");
return;
end
if (NWB.data.layers[NWB.lastKnownLayerMapID]) then
if (not NWB.data.layers[NWB.lastKnownLayerMapID].layerMap) then
--Create layer map if doesn't exist.
NWB.data.layers[NWB.lastKnownLayerMapID].layerMap = {};
NWB.data.layers[NWB.lastKnownLayerMapID].layerMap.created = GetServerTime();
end
if (not NWB.data.layers[NWB.lastKnownLayerMapID].layerMap[zoneID]) then
--If zone is not mapped yet since server restart then add it.
for k, v in pairs(NWB.data.layers[NWB.lastKnownLayerMapID].layerMap) do
if (k == zoneID) then
--If we already have a zoneid with this mapid then don't overwrite it.
NWB:debug("mapid already known");
return;
end
end
NWB:debug("mapped new zone to layer id", NWB.lastKnownLayerMapID, "zoneid:", zoneID, "zone:", zone);
NWB.data.layers[NWB.lastKnownLayerMapID].layerMap[zoneID] = zone;
NWB:sendData("GUILD");
else
--NWB:debug("zoneid already known");
end
end
NWB:recalcMinimapLayerFrame();
end
function NWB:resetLayerMaps()
if (next(NWB.data.layers)) then
for k, v in pairs(NWB.data.layers) do
NWB.data.layers[k].layerMap = nil;
end
end
end
--Version guild display.
local NWBLayerMapFrame = CreateFrame("ScrollFrame", "NWBLayerMapFrame", UIParent, "InputScrollFrameTemplate");
NWBLayerMapFrame:Hide();
NWBLayerMapFrame:SetToplevel(true);
NWBLayerMapFrame:SetMovable(true);
NWBLayerMapFrame:EnableMouse(true);
tinsert(UISpecialFrames, "NWBLayerMapFrame");
NWBLayerMapFrame:SetPoint("CENTER", UIParent, 0, 100);
NWBLayerMapFrame:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8x8",insets = {top = 0, left = 0, bottom = 0, right = 0}});
NWBLayerMapFrame:SetBackdropColor(0,0,0,.5);
NWBLayerMapFrame.CharCount:Hide();
NWBLayerMapFrame:SetFrameStrata("HIGH");
NWBLayerMapFrame.EditBox:SetAutoFocus(false);
NWBLayerMapFrame.EditBox:SetScript("OnKeyDown", function(self, arg)
--If control key is down keep focus for copy/paste to work.
--Otherwise remove focus so "enter" can be used to open chat and not have a stuck cursor on this edit box.
if (not IsControlKeyDown()) then
NWBLayerMapFrame.EditBox:ClearFocus();
end
end)
NWBLayerMapFrame.EditBox:SetScript("OnShow", function(self, arg)
NWBLayerMapFrame:SetVerticalScroll(0);
end)
local buffUpdateTime = 0;
NWBLayerMapFrame:HookScript("OnUpdate", function(self, arg)
--Only update once per second.
if (GetServerTime() - buffUpdateTime > 0 and self:GetVerticalScrollRange() == 0) then
NWB:recalclayerFrame();
buffUpdateTime = GetServerTime();
end
end)
NWBLayerMapFrame.fs = NWBLayerMapFrame:CreateFontString("NWBLayerMapFrameFS", "HIGH");
NWBLayerMapFrame.fs:SetPoint("TOP", 0, -0);
NWBLayerMapFrame.fs:SetFont(NWB.regionFont, 14);
NWBLayerMapFrame.fs:SetText("|cFFFFFF00Layer Mapping for " .. GetRealmName() .. "|r");
local NWBLayerMapDragFrame = CreateFrame("Frame", "NWBLayerMapDragFrame", NWBLayerMapFrame);
NWBLayerMapDragFrame:SetToplevel(true);
NWBLayerMapDragFrame:EnableMouse(true);
NWBLayerMapDragFrame:SetWidth(205);
NWBLayerMapDragFrame:SetHeight(38);
NWBLayerMapDragFrame:SetPoint("TOP", 0, 4);
NWBLayerMapDragFrame:SetFrameLevel(131);
NWBLayerMapDragFrame.tooltip = CreateFrame("Frame", "NWBLayerMapDragTooltip", NWBLayerMapDragFrame, "TooltipBorderedFrameTemplate");
NWBLayerMapDragFrame.tooltip:SetPoint("CENTER", NWBLayerMapDragFrame, "TOP", 0, 12);
NWBLayerMapDragFrame.tooltip:SetFrameStrata("TOOLTIP");
NWBLayerMapDragFrame.tooltip:SetFrameLevel(9);
NWBLayerMapDragFrame.tooltip:SetAlpha(.8);
NWBLayerMapDragFrame.tooltip.fs = NWBLayerMapDragFrame.tooltip:CreateFontString("NWBLayerMapDragTooltipFS", "HIGH");
NWBLayerMapDragFrame.tooltip.fs:SetPoint("CENTER", 0, 0.5);
NWBLayerMapDragFrame.tooltip.fs:SetFont(NWB.regionFont, 12);
NWBLayerMapDragFrame.tooltip.fs:SetText("Hold to drag");
NWBLayerMapDragFrame.tooltip:SetWidth(NWBLayerMapDragFrame.tooltip.fs:GetStringWidth() + 16);
NWBLayerMapDragFrame.tooltip:SetHeight(NWBLayerMapDragFrame.tooltip.fs:GetStringHeight() + 10);
NWBLayerMapDragFrame:SetScript("OnEnter", function(self)
NWBLayerMapDragFrame.tooltip:Show();
end)
NWBLayerMapDragFrame:SetScript("OnLeave", function(self)
NWBLayerMapDragFrame.tooltip:Hide();
end)
NWBLayerMapDragFrame.tooltip:Hide();
NWBLayerMapDragFrame:SetScript("OnMouseDown", function(self, button)
if (button == "LeftButton" and not self:GetParent().isMoving) then
self:GetParent().EditBox:ClearFocus();
self:GetParent():StartMoving();
self:GetParent().isMoving = true;
--self:GetParent():SetUserPlaced(false);
end
end)
NWBLayerMapDragFrame:SetScript("OnMouseUp", function(self, button)
if (button == "LeftButton" and self:GetParent().isMoving) then
self:GetParent():StopMovingOrSizing();
self:GetParent().isMoving = false;
end
end)
NWBLayerMapDragFrame:SetScript("OnHide", function(self)
if (self:GetParent().isMoving) then
self:GetParent():StopMovingOrSizing();
self:GetParent().isMoving = false;
end
end)
--Top right X close button.
local NWBLayerMapFrameClose = CreateFrame("Button", "NWBLayerMapFrameClose", NWBLayerMapFrame, "UIPanelCloseButton");
NWBLayerMapFrameClose:SetPoint("TOPRIGHT", -5, 8.6);
NWBLayerMapFrameClose:SetWidth(31);
NWBLayerMapFrameClose:SetHeight(31);
NWBLayerMapFrameClose:SetScript("OnClick", function(self, arg)
NWBLayerMapFrame:Hide();
end)
function NWB:openLayerMapFrame()
if (not NWB.db.global.experimental) then
return;
end
NWBLayerMapFrame.fs:SetFont(NWB.regionFont, 14);
if (NWBLayerMapFrame:IsShown()) then
NWBLayerMapFrame:Hide();
else
NWBLayerMapFrame:SetHeight(300);
NWBLayerMapFrame:SetWidth(450);
local fontSize = false
NWBLayerMapFrame.EditBox:SetFont(NWB.regionFont, 14);
NWBLayerMapFrame.EditBox:SetWidth(NWBLayerMapFrame:GetWidth() - 30);
NWBLayerMapFrame:Show();
NWB:recalcLayerMapFrame()
--Changing scroll position requires a slight delay.
--Second delay is a backup.
C_Timer.After(0.05, function()
NWBLayerMapFrame:SetVerticalScroll(0);
end)
C_Timer.After(0.3, function()
NWBLayerMapFrame:SetVerticalScroll(0);
end)
--So interface options and this frame will open on top of each other.
if (InterfaceOptionsFrame:IsShown()) then
NWBLayerMapFrame:SetFrameStrata("DIALOG")
else
NWBLayerMapFrame:SetFrameStrata("HIGH")
end
end
end
function NWB:recalcLayerMapFrame()
NWBLayerMapFrame.EditBox:SetText("\n");
if (not IsInGuild()) then
NWBLayerMapFrame.EditBox:Insert("|cffFFFF00No zones have been mapped yet since server restart.\n");
else
local count = 0;
for k, v in NWB:pairsByKeys(NWB.data.layers) do
count = count + 1;
if (NWB.faction == "Horde") then
NWBLayerMapFrame.EditBox:Insert("\n|cff00ff00[Layer " .. count .. "]|r |cff9CD6DE(Orgrimmar " .. k .. ")|r\n");
else
NWBLayerMapFrame.EditBox:Insert("\n|cff00ff00[Layer " .. count .. "]|r |cff9CD6DE(Stormwind " .. k .. ")|r\n");
end
if (v.layerMap and next(v.layerMap)) then
for kk, vv in NWB:pairsByKeys(v.layerMap) do
local mapInfo = C_Map.GetMapInfo(vv);
local zoneInfo = "Unknown";
if (mapInfo and next(mapInfo)) then
zoneInfo = mapInfo.name;
end
---NWBLayerMapFrame.EditBox:Insert(" -|cffFFFF00" .. zoneInfo .. " ".. kk .. " |cff9CD6DE" .. vv .. "\n");
NWBLayerMapFrame.EditBox:Insert(" -|cffFFFF00" .. zoneInfo .. " |cFF989898(" .. kk .. ")|r\n");
end
else --C_Map.GetAreaInfo(
--C_Map.GetMapInfoAtPosition(1434, 1, 1)
NWBLayerMapFrame.EditBox:Insert(" -|cffFFFF00No zones mapped for this layer yet.\n");
end
end
end
end
--Reset layers one time, needed when upgrading from old version.
--Old version copys over the whole table from new version users and prevents a proper new layer being created with that id.
function NWB:resetLayerData()
if (NWB.db.global.resetLayers3) then
NWB:debug("resetting layer data");
NWB.data.layers = {};
NWB.db.global.resetLayers3 = false;
end
end
function NWB:fixLayer(layer)
if (not tonumber(NWB.data.layers[layer]['rendTimer'])) then
NWB.data.layers[layer]['rendTimer'] = 0;
end
if (not tonumber(NWB.data.layers[layer]['rendYell'])) then
NWB.data.layers[layer]['rendYell'] = 0;
end
if (not tonumber(NWB.data.layers[layer]['rendYell2'])) then
NWB.data.layers[layer]['rendYell2'] = 0;
end
if (not tonumber(NWB.data.layers[layer]['onyTimer'])) then
NWB.data.layers[layer]['onyTimer'] = 0;
end
if (not tonumber(NWB.data.layers[layer]['onyYell'])) then
NWB.data.layers[layer]['onyYell'] = 0;
end
if (not tonumber(NWB.data.layers[layer]['onyYell2'])) then
NWB.data.layers[layer]['onyYell2'] = 0;
end
if (not tonumber(NWB.data.layers[layer]['nefTimer'])) then
NWB.data.layers[layer]['rendTimer'] = 0;
end
if (not tonumber(NWB.data.layers[layer]['nefYell'])) then
NWB.data.layers[layer]['nefYell'] = 0;
end
if (not tonumber(NWB.data.layers[layer]['nefYell2'])) then
NWB.data.layers[layer]['nefYell2'] = 0;
end
end
function NWB:validateLayer(layer)
--Temp fix till I work out why sometimes the NPC zoneid is different by a few integers, it's strange....
--In testing the zoneid's had the same last and first number, but middle numbers sometimes changed depending on person.
--107 and 127 from same NPC by different people, --9914 and 9924 from same NPC by different people.
--Ignore new data if it's within close numeric range of an ID we already have.
--No 2 valid layers should ever have close together id's?
--EDIT: From a user on curse layer numbers on Auberdine for this week are 315 and 326.
for localLayer, localV in pairs(NWB.data.layers) do
if ((layer > (localLayer - 30)) and (layer < (localLayer + 30)) and localLayer ~= layer
--Some realms seem to have legit layers close together.
--Each fake close together layer I've seen so far has the same last number, it's always multiples of 10.
--Removing the strict 30 closeness check and try this instead to accomodate those close together realms.
--If it works it should atleast lower the chance of a false positive to 1 in 10.
--Can't create new chars on these locked layered realms to test so all I can do is ake these small changes and hope...
and (string.sub(layer, -1) == string.sub(localLayer, -1))) then
NWB:debug("close range layer found old:", localLayer, "new:", layer);
return;
end
end
return true;
end
--function NWB:validateLayer(layer)
-- return true;
--end
local MinimapLayerFrame = CreateFrame("Frame", "MinimapLayerFrame", Minimap, "ThinGoldEdgeTemplate");
MinimapLayerFrame:SetPoint("BOTTOM", 2, 4);
MinimapLayerFrame:SetFrameStrata("HIGH");
MinimapLayerFrame:SetFrameLevel(9);
MinimapLayerFrame:SetMovable(true);
MinimapLayerFrame.fs = MinimapLayerFrame:CreateFontString("MinimapLayerFrameFS", "ARTWORK");
MinimapLayerFrame.fs:SetPoint("CENTER", 0, 0);
MinimapLayerFrame.fs:SetFont("Fonts\\ARIALN.ttf", 10); --No region font here, "Layer" in english always.
MinimapLayerFrame.fs:SetText("Layer 1");
MinimapLayerFrame:SetWidth(46);
MinimapLayerFrame:SetHeight(17);
MinimapLayerFrame:Hide();
MinimapLayerFrame.tooltip = CreateFrame("Frame", "NWBVersionDragTooltip", MinimapLayerFrame, "TooltipBorderedFrameTemplate");
MinimapLayerFrame.tooltip:SetPoint("CENTER", MinimapLayerFrame, "TOP", 0, 12);
MinimapLayerFrame.tooltip:SetFrameStrata("TOOLTIP");
MinimapLayerFrame.tooltip:SetFrameLevel(9);
--MinimapLayerFrame.tooltip:SetAlpha(.9);
MinimapLayerFrame.tooltip.fs = MinimapLayerFrame.tooltip:CreateFontString("NWBVersionDragTooltipFS", "HIGH");
MinimapLayerFrame.tooltip.fs:SetPoint("CENTER", 0, 0.5);
MinimapLayerFrame.tooltip.fs:SetFont(NWB.regionFont, 10);
MinimapLayerFrame.tooltip.fs:SetText("Target a NPC to\nupdate your layer");
MinimapLayerFrame.tooltip:SetWidth(MinimapLayerFrame.tooltip.fs:GetStringWidth() + 10);
MinimapLayerFrame.tooltip:SetHeight(MinimapLayerFrame.tooltip.fs:GetStringHeight() + 10);
MinimapLayerFrame:SetScript("OnEnter", function(self)
MinimapLayerFrame.tooltip:Show();
end)
MinimapLayerFrame:SetScript("OnLeave", function(self)
MinimapLayerFrame.tooltip:Hide();
end)
MinimapLayerFrame.tooltip:Hide();
MinimapLayerFrame:SetScript("OnMouseDown", function(self, button)
if (button == "LeftButton" and not self.isMoving and IsShiftKeyDown()) then
self:StartMoving();
self.isMoving = true;
--self:SetUserPlaced(false);
else
NWB:openLayerFrame();
end
end)
MinimapLayerFrame:SetScript("OnMouseUp", function(self, button)
if (button == "LeftButton" and self.isMoving) then
self:StopMovingOrSizing();
self.isMoving = false;
end
end)
MinimapLayerFrame:SetScript("OnHide", function(self)
if (self.isMoving) then
self:StopMovingOrSizing();
self.isMoving = false;
end
end)
NWB.currentLayer = 0;
function NWB:recalcMinimapLayerFrame()
if (not NWB.db.global.minimapLayerFrame or not NWB.isLayered) then
MinimapLayerFrame:Hide();
return;
end
local _, _, zone = NWB.dragonLib:GetPlayerZonePosition();
local foundOldID, foundLayer;
--[[for k, v in pairs(NWB.data.layers) do
if (v.layerMap and next(v.layerMap)) then
for kk, vv in pairs(v.layerMap) do
if (zone == vv) then
--Also can start mapping if we pickup our current layer from an already known id.
WB:debug("found mapped id2");
NWB.lastKnownLayerMapID = k;
foundOldID = true;
end
end
end
end
local count, layerNum = 0, 0;
if (foundOldID) then
for k, v in NWB:pairsByKeys(NWB.data.layers) do
count = count + 1;
if (k == NWB.lastKnownLayerMapID) then
NWBlayerFrame.fs2:SetText("|cFF9CD6DEYou are currently on |cff00ff00[Layer " .. count .. "]|cFF9CD6DE.|r");
--NWB.currentLayer = count;
--NWB.lastKnownLayer = count;
--NWB.lastKnownLayerID = k;
--NWB.lastKnownLayerTime = GetServerTime();
layerNum = count;
foundLayer = true;
end
end
end]]
local count, layerNum = 0, 0;
if (NWB.lastKnownLayerMapID > 0) then
for k, v in NWB:pairsByKeys(NWB.data.layers) do
count = count + 1;
if (k == NWB.lastKnownLayerMapID) then
NWBlayerFrame.fs2:SetText("|cFF9CD6DEYou are currently on |cff00ff00[Layer " .. count .. "]|cFF9CD6DE.|r");
NWB.currentLayer = count;
NWB.lastKnownLayer = count;
NWB.lastKnownLayerID = k;
NWB.lastKnownLayerTime = GetServerTime();
layerNum = count;
foundLayer = true;
end
end
end
if (foundLayer or (NWB.faction == "Horde" and zone == 1454)
or (NWB.faction == "Alliance" and zone == 1453)) then
if (NWB.currentLayer > 0) then
MinimapLayerFrame.fs:SetText("Layer " .. NWB.lastKnownLayer);
MinimapLayerFrame.fs:SetFont("Fonts\\ARIALN.ttf", 12);
elseif (layerNum > 0) then
MinimapLayerFrame.fs:SetText("Layer " .. layerNum);
MinimapLayerFrame.fs:SetFont("Fonts\\ARIALN.ttf", 12);
else
MinimapLayerFrame.fs:SetText("No Layer");
MinimapLayerFrame.fs:SetFont("Fonts\\ARIALN.ttf", 10);
end
--MinimapLayerFrame:SetWidth(MinimapLayerFrame.fs:GetStringWidth() + 12);
--MinimapLayerFrame:SetHeight(MinimapLayerFrame.fs:GetStringHeight() + 12);
MinimapLayerFrame:Show();
else
NWB.currentLayer = 0;
MinimapLayerFrame:Hide();
end
end
SLASH_NWBLAYERSCMD1, SLASH_NWBLAYERSCMD2 = '/layer', '/layers';
function SlashCmdList.NWBLAYERSCMD(msg, editBox)
NWB:openLayerFrame();
end
--Version guild display.
local NWBVersionFrame = CreateFrame("ScrollFrame", "NWBVersionFrame", UIParent, "InputScrollFrameTemplate");
NWBVersionFrame:Hide();
NWBVersionFrame:SetToplevel(true);
NWBVersionFrame:SetMovable(true);
NWBVersionFrame:EnableMouse(true);
tinsert(UISpecialFrames, "NWBVersionFrame");
NWBVersionFrame:SetPoint("CENTER", UIParent, 0, 100);
NWBVersionFrame:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8x8",insets = {top = 0, left = 0, bottom = 0, right = 0}});
NWBVersionFrame:SetBackdropColor(0,0,0,.5);
NWBVersionFrame.CharCount:Hide();
NWBVersionFrame:SetFrameStrata("HIGH");
NWBVersionFrame.EditBox:SetAutoFocus(false);
NWBVersionFrame.EditBox:SetScript("OnKeyDown", function(self, arg)
--If control key is down keep focus for copy/paste to work.
--Otherwise remove focus so "enter" can be used to open chat and not have a stuck cursor on this edit box.
if (not IsControlKeyDown()) then
NWBVersionFrame.EditBox:ClearFocus();
end
end)
NWBVersionFrame.EditBox:SetScript("OnShow", function(self, arg)
NWBVersionFrame:SetVerticalScroll(0);
end)
local buffUpdateTime = 0;
NWBVersionFrame:HookScript("OnUpdate", function(self, arg)
--Only update once per second.
if (GetServerTime() - buffUpdateTime > 0 and self:GetVerticalScrollRange() == 0) then
NWB:recalclayerFrame();
buffUpdateTime = GetServerTime();
end
end)
NWBVersionFrame.fs = NWBVersionFrame:CreateFontString("NWBVersionFrameFS", "HIGH");
NWBVersionFrame.fs:SetPoint("TOP", 0, -0);
NWBVersionFrame.fs:SetFont(NWB.regionFont, 14);
NWBVersionFrame.fs:SetText("|cFFFFFF00Guild versions seen since logon|r");
local NWBVersionDragFrame = CreateFrame("Frame", "NWBVersionDragFrame", NWBVersionFrame);
NWBVersionDragFrame:SetToplevel(true);
NWBVersionDragFrame:EnableMouse(true);
NWBVersionDragFrame:SetWidth(205);
NWBVersionDragFrame:SetHeight(38);
NWBVersionDragFrame:SetPoint("TOP", 0, 4);
NWBVersionDragFrame:SetFrameLevel(131);
NWBVersionDragFrame.tooltip = CreateFrame("Frame", "NWBVersionDragTooltip", NWBVersionDragFrame, "TooltipBorderedFrameTemplate");
NWBVersionDragFrame.tooltip:SetPoint("CENTER", NWBVersionDragFrame, "TOP", 0, 12);
NWBVersionDragFrame.tooltip:SetFrameStrata("TOOLTIP");
NWBVersionDragFrame.tooltip:SetFrameLevel(9);
NWBVersionDragFrame.tooltip:SetAlpha(.8);
NWBVersionDragFrame.tooltip.fs = NWBVersionDragFrame.tooltip:CreateFontString("NWBVersionDragTooltipFS", "HIGH");
NWBVersionDragFrame.tooltip.fs:SetPoint("CENTER", 0, 0.5);
NWBVersionDragFrame.tooltip.fs:SetFont(NWB.regionFont, 12);
NWBVersionDragFrame.tooltip.fs:SetText("Hold to drag");
NWBVersionDragFrame.tooltip:SetWidth(NWBVersionDragFrame.tooltip.fs:GetStringWidth() + 16);
NWBVersionDragFrame.tooltip:SetHeight(NWBVersionDragFrame.tooltip.fs:GetStringHeight() + 10);
NWBVersionDragFrame:SetScript("OnEnter", function(self)
NWBVersionDragFrame.tooltip:Show();
end)
NWBVersionDragFrame:SetScript("OnLeave", function(self)
NWBVersionDragFrame.tooltip:Hide();
end)
NWBVersionDragFrame.tooltip:Hide();
NWBVersionDragFrame:SetScript("OnMouseDown", function(self, button)
if (button == "LeftButton" and not self:GetParent().isMoving) then
self:GetParent().EditBox:ClearFocus();
self:GetParent():StartMoving();
self:GetParent().isMoving = true;
--self:GetParent():SetUserPlaced(false);
end
end)
NWBVersionDragFrame:SetScript("OnMouseUp", function(self, button)
if (button == "LeftButton" and self:GetParent().isMoving) then
self:GetParent():StopMovingOrSizing();
self:GetParent().isMoving = false;
end
end)
NWBVersionDragFrame:SetScript("OnHide", function(self)
if (self:GetParent().isMoving) then
self:GetParent():StopMovingOrSizing();
self:GetParent().isMoving = false;
end
end)
--Top right X close button.
local NWBVersionFrameClose = CreateFrame("Button", "NWBVersionFrameClose", NWBVersionFrame, "UIPanelCloseButton");
NWBVersionFrameClose:SetPoint("TOPRIGHT", -5, 8.6);
NWBVersionFrameClose:SetWidth(31);
NWBVersionFrameClose:SetHeight(31);
NWBVersionFrameClose:SetScript("OnClick", function(self, arg)
NWBVersionFrame:Hide();
end)
function NWB:openVersionFrame()
NWBVersionFrame.fs:SetFont(NWB.regionFont, 14);
if (NWBVersionFrame:IsShown()) then
NWBVersionFrame:Hide();
else
NWBVersionFrame:SetHeight(300);
NWBVersionFrame:SetWidth(450);
local fontSize = false
NWBVersionFrame.EditBox:SetFont(NWB.regionFont, 14);
NWBVersionFrame.EditBox:SetWidth(NWBVersionFrame:GetWidth() - 30);
NWBVersionFrame:Show();
NWB:recalcVersionFrame();
--Changing scroll position requires a slight delay.
--Second delay is a backup.
C_Timer.After(0.05, function()
NWBVersionFrame:SetVerticalScroll(0);
end)
C_Timer.After(0.3, function()
NWBVersionFrame:SetVerticalScroll(0);
end)
--So interface options and this frame will open on top of each other.
if (InterfaceOptionsFrame:IsShown()) then
NWBVersionFrame:SetFrameStrata("DIALOG")
else
NWBVersionFrame:SetFrameStrata("HIGH")
end
end
end
function NWB:recalcVersionFrame()
NWBVersionFrame.EditBox:SetText("\n\n");
if (not IsInGuild()) then
NWBVersionFrame.EditBox:Insert("|cffFFFF00You have no guild, this command shows guild members only.\n");
else
GuildRoster();
local numTotalMembers = GetNumGuildMembers();
local onlineMembers = {};
local me = UnitName("player") .. "-" .. GetNormalizedRealmName();
local sorted = {};
local guild = {};
for i = 1, numTotalMembers do
local name, _, _, _, _, zone, _, _, online, _, _, _, _, isMobile = GetGuildRosterInfo(i);
name = string.gsub(string.gsub(name, "'", ""), " ", "");
guild[name] = true;
end
for k, v in pairs(NWB.hasAddon) do
if (not sorted[v]) then
sorted[v] = {};
end
if (guild[k]) then
local who, realm = strsplit("-", k, 2);
sorted[v][who] = true;
end
end
for k, v in NWB:pairsByKeys(sorted) do
for kk, vv in NWB:pairsByKeys(v) do
if (tonumber(k) > 0 or NWB.isDebug) then
NWBVersionFrame.EditBox:Insert("|cffFFFF00" .. k .. " |cff9CD6DE" .. kk .. "\n");
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment