diff --git a/README.md b/README.md index 344a833..3ae67db 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # SuperGuildInviteReborn Repository for addon hosted at: -https://wow.curseforge.com/projects/superguildinvite-reborn -https://www.wowinterface.com/downloads/info24080-SuperGuildInvite2.html#info +[CurseForge](https://wow.curseforge.com/projects/superguildinvite-reborn) +and also at [WoWInterface](https://www.wowinterface.com/downloads/info24080-SuperGuildInvite2.html#info) +If you would like to show your appreciation, you can donate [Here](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=NE78S2XQG9D6Q) diff --git a/SuperGuildInviteReborn.toc b/SuperGuildInviteReborn.toc index e1dd175..2bc5e65 100644 --- a/SuperGuildInviteReborn.toc +++ b/SuperGuildInviteReborn.toc @@ -1,21 +1,12 @@ -## Interface: 70300 +## Interface: 80000 ## Author: Janniie - Stormreaver EU ## Updated by: Snowenn - Zul'jin US ## Title: Super Guild Invite Reborn -## Notes: Version 7.7.0 -## Version: 7.7.0 +## Notes: Version 8.0.0 +## Version: 8.0.0 ## SavedVariables: SGI_DATA ## SavedVariablesPerCharacter: SGI_BACKUP - -libs\GuildShield\GuildShield.lua -libs\ChatIntercept\ChatIntercept.lua -libs\Alerts\Alerts.lua - -libs\LibWho-2.0\libs\LibStub\LibStub.lua -libs\LibWho-2.0\libs\CallbackHandler-1.0\CallbackHandler-1.0.lua -libs\LibWho-2.0\LibWho-2.0\LibWho-2.0.lua - -locale\localization.lua +embeds.xml core\SGI_Constants.lua core\SGI_Core.lua @@ -27,4 +18,4 @@ core\SuperScan.lua core\SGI_System_Message.lua core\SGI_Events.lua -core\SGI_GUI.lua +core\SGI_GUI.xml diff --git a/core/SGI_AddOn_Message.lua b/core/SGI_AddOn_Message.lua index 2b89e69..2c1773a 100644 --- a/core/SGI_AddOn_Message.lua +++ b/core/SGI_AddOn_Message.lua @@ -1,81 +1,81 @@ -local ID_REQUEST = "SGI_REQ"; -ID_MASSLOCK = "SGI_MASS"; -local ID_LOCK = "SGI_LOCK"; -local ID_SHIELD = "I_HAVE_SHIELD"; -local ID_VERSION = "SGI_VERSION"; -local ID_LIVE_SYNC = "SGI_LIVE_SYNC"; -local ID_PING = "SGI_PING"; -local ID_PONG = "SGI_PONG"; -local ID_STOP = "SGI_STOP"; -RegisterAddonMessagePrefix(ID_REQUEST); -RegisterAddonMessagePrefix(ID_LOCK); -RegisterAddonMessagePrefix(ID_SHIELD); -RegisterAddonMessagePrefix(ID_MASSLOCK); -RegisterAddonMessagePrefix(ID_VERSION); -RegisterAddonMessagePrefix(ID_LIVE_SYNC); -RegisterAddonMessagePrefix(ID_PING); -RegisterAddonMessagePrefix(ID_STOP); - - -function SGI:AddonMessage(event,...) - local ID, msg, channel, sender = ...; - if (not SGI_DATA[SGI_DATA_INDEX].debug and sender == UnitName("player")) then return end - - - if (ID == ID_SHIELD) then - SGI:LockPlayer(sender); - SGI:RemoveShielded(sender); - SGI:debug("SHIELD: "..ID.." "..msg.." "..sender); - elseif (ID == ID_LOCK) then - SGI:LockPlayer(sender); - SGI:debug("LOCKING: "..ID.." "..msg.." "..sender); - elseif (ID == ID_REQUEST) then - SGI:ShareLocks(sender); - SGI:debug("SHARING: "..ID.." "..msg.." "..sender); - elseif (ID == ID_MASSLOCK) then - SGI:ReceivedNewLocks(msg); - SGI:debug("RECEIVING: "..ID.." "..msg.." "..sender); - elseif (ID == ID_VERSION) then - SGI:debug("VERSION: "..ID.." "..msg.." "..sender); - local receivedVersion = msg; - - if (new == SGI:CompareVersions(SGI.VERSION_MAJOR, receivedVersion)) then - SGI:print("|cffffff00A new version (|r|cff00A2FF"..new.."|r|cffffff00) of |r|cff16ABB5SuperGuildInvite|r|cffffff00 is available at curse.com!"); - if Alerter and not SGI.VERSION_ALERT_COOLDOWN then - Alerter:SendAlert("|cffffff00A new version (|r|cff00A2FF"..new.."|r|cffffff00) of |r|cff16ABB5SuperGuildInvite|r|cffffff00 is available at curse.com!",1.5) - SGI.VERSION_ALERT_COOLDOWN = true; - end - end - - elseif (ID == ID_LIVE_SYNC) then - SGI:debug("LIVESYNC: "..ID.." "..msg.." "..sender); - SGI:RemoveQueued(msg); - elseif (ID == ID_STOP) then - - elseif (ID == ID_PING) then - SGI:PingedByJanniie(sender); - end -end - -function SGI:LiveSync(player) - SendAddonMessage(ID_LIVE_SYNC, player, "GUILD"); -end - -function SGI:BroadcastVersion(target) - if (target == "GUILD") then - SendAddonMessage(ID_VERSION, SGI.VERSION_MAJOR, "GUILD"); - else - SendAddonMessage(ID_VERSION, SGI.VERSION_MAJOR, "WHISPER", target); - end -end - -function SGI:PingedByJanniie(sender) - SendAddonMessage("SGI_PONG", SGI.VERSION_MAJOR, "WHISPER", sender); -end - -function SGI:RequestSync() - SendAddonMessage(ID_REQUEST, "", "GUILD"); -end - - -SGI:debug(">> AddOn_Message.lua"); +local ID_REQUEST = "SGI_REQ"; +ID_MASSLOCK = "SGI_MASS"; +local ID_LOCK = "SGI_LOCK"; +local ID_SHIELD = "I_HAVE_SHIELD"; +local ID_VERSION = "SGI_VERSION"; +local ID_LIVE_SYNC = "SGI_LIVE_SYNC"; +local ID_PING = "SGI_PING"; +local ID_PONG = "SGI_PONG"; +local ID_STOP = "SGI_STOP"; +C_ChatInfo.RegisterAddonMessagePrefix(ID_REQUEST); +C_ChatInfo.RegisterAddonMessagePrefix(ID_LOCK); +C_ChatInfo.RegisterAddonMessagePrefix(ID_SHIELD); +C_ChatInfo.RegisterAddonMessagePrefix(ID_MASSLOCK); +C_ChatInfo.RegisterAddonMessagePrefix(ID_VERSION); +C_ChatInfo.RegisterAddonMessagePrefix(ID_LIVE_SYNC); +C_ChatInfo.RegisterAddonMessagePrefix(ID_PING); +C_ChatInfo.RegisterAddonMessagePrefix(ID_STOP); + + +function SGI:AddonMessage(event,...) + local ID, msg, channel, sender = ...; + if (not SGI_DATA[SGI_DATA_INDEX].debug and sender == UnitName("player")) then return end + + + if (ID == ID_SHIELD) then + SGI:LockPlayer(sender); + SGI:RemoveShielded(sender); + SGI:debug("SHIELD: "..ID.." "..msg.." "..sender); + elseif (ID == ID_LOCK) then + SGI:LockPlayer(sender); + SGI:debug("LOCKING: "..ID.." "..msg.." "..sender); + elseif (ID == ID_REQUEST) then + SGI:ShareLocks(sender); + SGI:debug("SHARING: "..ID.." "..msg.." "..sender); + elseif (ID == ID_MASSLOCK) then + SGI:ReceivedNewLocks(msg); + SGI:debug("RECEIVING: "..ID.." "..msg.." "..sender); + elseif (ID == ID_VERSION) then + SGI:debug("VERSION: "..ID.." "..msg.." "..sender); + local receivedVersion = msg; + + if (new == SGI:CompareVersions(SGI.VERSION_MAJOR, receivedVersion)) then + SGI:print("|cffffff00A new version (|r|cff00A2FF"..new.."|r|cffffff00) of |r|cff16ABB5SuperGuildInvite|r|cffffff00 is available at curse.com!"); + if Alerter and not SGI.VERSION_ALERT_COOLDOWN then + Alerter:SendAlert("|cffffff00A new version (|r|cff00A2FF"..new.."|r|cffffff00) of |r|cff16ABB5SuperGuildInvite|r|cffffff00 is available at curse.com!",1.5) + SGI.VERSION_ALERT_COOLDOWN = true; + end + end + + elseif (ID == ID_LIVE_SYNC) then + SGI:debug("LIVESYNC: "..ID.." "..msg.." "..sender); + SGI:RemoveQueued(msg); + elseif (ID == ID_STOP) then + + elseif (ID == ID_PING) then + SGI:PingedByJanniie(sender); + end +end + +function SGI:LiveSync(player) + C_ChatInfo.SendAddonMessageLogged(ID_LIVE_SYNC, player, "GUILD"); +end + +function SGI:BroadcastVersion(target) + if (target == "GUILD") then + C_ChatInfo.SendAddonMessageLogged(ID_VERSION, SGI.VERSION_MAJOR, "GUILD"); + else + C_ChatInfo.SendAddonMessageLogged(ID_VERSION, SGI.VERSION_MAJOR, "WHISPER", target); + end +end + +function SGI:PingedByJanniie(sender) + C_ChatInfo.SendAddonMessageLogged("SGI_PONG", SGI.VERSION_MAJOR, "WHISPER", sender); +end + +function SGI:RequestSync() + C_ChatInfo.SendAddonMessageLogged(ID_REQUEST, "", "GUILD"); +end + + +SGI:debug(">> AddOn_Message.lua"); diff --git a/core/SGI_Blacklist.lua b/core/SGI_Blacklist.lua index 7d61e01..4c228f7 100644 --- a/core/SGI_Blacklist.lua +++ b/core/SGI_Blacklist.lua @@ -1,114 +1,114 @@ -local MessageQueue = {}; -SGI.ForceStop = {}; - -CreateFrame("Frame", "SGI_MESSAGE_TIMER"); -SGI_MESSAGE_TIMER.update = 0; -SGI_MESSAGE_TIMER:SetScript("OnUpdate", function() - if (SGI_MESSAGE_TIMER.update < GetTime()) then - - for i = 1,5 do - local key, messageToBeSent = next(MessageQueue); - - if (key and messageToBeSent) then - if (SGI.ForceStop[messageToBeSent.receiver]) then - MessageQueue[key] = nil; - SGI.ForceStop[messageToBeSent.receiver] = nil; - SGI:debug("Forced sendstop!"); - return; - end - SendAddonMessage(ID_MASSLOCK, messageToBeSent.msg, "WHISPER", messageToBeSent.receiver); - MessageQueue[key] = nil; - SGI:debug("Send AddonMessage ("..messageToBeSent.msg..") to "..messageToBeSent.receiver); - - end - end - SGI_MESSAGE_TIMER.update = GetTime() + 2; - end -end) - -local function AddMessage(message, receiver) - local newMessage = { - msg = message, - receiver = receiver, - }; - tinsert(MessageQueue, newMessage); -end - -function SGI:StopMassShare(player) - SGI.ForceStop[player] = true; -end - -function SGI:IsSharing(player) - for key, message in pairs(MessageQueue) do - if (message.receiver == player) then - return true; - end - end -end - -local function RemoveLock(name) - SGI_DATA.lock[name] = nil; -end - -function SGI:IsLocked(name) - return SGI_DATA.lock[name]; -end - -function SGI:LockPlayer(name) - if (not SGI:IsLocked(name)) then - SGI_DATA.lock[name] = tonumber(date("%m")); - end -end - -function SGI:UnlockPlayer(name) - RemoveLock(name); -end - -function SGI:ShareLocks(name) - local part = ID_MASSLOCK; - - for k,_ in pairs(SGI_DATA.lock) do - if (strlen(part..":"..k) > 250) then - AddMessage(part, name); - part = ID_MASSLOCK; - end - part = part..":"..k; - end - - AddMessage(part, name); -end - -function SGI:ReceivedNewLocks(rawLocks) - local locks = SGI:divideString(rawLocks, ":"); - - for k,_ in pairs(locks) do - SGI:LockPlayer(locks[k]); - end - SGI:debug("Received locks!"); -end - -function SGI:RemoveOutdatedLocks() - local month = tonumber(date("%m")); - - for k,_ in pairs(SGI_DATA.lock) do - if (month - 1) > SGI_DATA.lock[k] or (month < SGI_DATA.lock[k] and month > 1) then - RemoveLock(k); - end - end - -end - - - - - - - - - - - - - - -SGI:debug(">> Blacklist.lua"); \ No newline at end of file +local MessageQueue = {}; +SGI.ForceStop = {}; + +CreateFrame("Frame", "SGI_MESSAGE_TIMER"); +SGI_MESSAGE_TIMER.update = 0; +SGI_MESSAGE_TIMER:SetScript("OnUpdate", function() + if (SGI_MESSAGE_TIMER.update < GetTime()) then + + for i = 1,5 do + local key, messageToBeSent = next(MessageQueue); + + if (key and messageToBeSent) then + if (SGI.ForceStop[messageToBeSent.receiver]) then + MessageQueue[key] = nil; + SGI.ForceStop[messageToBeSent.receiver] = nil; + SGI:debug("Forced sendstop!"); + return; + end + C_ChatInfo.SendAddonMessageLogged(ID_MASSLOCK, messageToBeSent.msg, "WHISPER", messageToBeSent.receiver); + MessageQueue[key] = nil; + SGI:debug("Send AddonMessage ("..messageToBeSent.msg..") to "..messageToBeSent.receiver); + + end + end + SGI_MESSAGE_TIMER.update = GetTime() + 2; + end +end) + +local function AddMessage(message, receiver) + local newMessage = { + msg = message, + receiver = receiver, + }; + tinsert(MessageQueue, newMessage); +end + +function SGI:StopMassShare(player) + SGI.ForceStop[player] = true; +end + +function SGI:IsSharing(player) + for key, message in pairs(MessageQueue) do + if (message.receiver == player) then + return true; + end + end +end + +local function RemoveLock(name) + SGI_DATA.lock[name] = nil; +end + +function SGI:IsLocked(name) + return SGI_DATA.lock[name]; +end + +function SGI:LockPlayer(name) + if (not SGI:IsLocked(name)) then + SGI_DATA.lock[name] = tonumber(date("%m")); + end +end + +function SGI:UnlockPlayer(name) + RemoveLock(name); +end + +function SGI:ShareLocks(name) + local part = ID_MASSLOCK; + + for k,_ in pairs(SGI_DATA.lock) do + if (strlen(part..":"..k) > 250) then + AddMessage(part, name); + part = ID_MASSLOCK; + end + part = part..":"..k; + end + + AddMessage(part, name); +end + +function SGI:ReceivedNewLocks(rawLocks) + local locks = SGI:divideString(rawLocks, ":"); + + for k,_ in pairs(locks) do + SGI:LockPlayer(locks[k]); + end + SGI:debug("Received locks!"); +end + +function SGI:RemoveOutdatedLocks() + local month = tonumber(date("%m")); + + for k,_ in pairs(SGI_DATA.lock) do + if (month - 1) > SGI_DATA.lock[k] or (month < SGI_DATA.lock[k] and month > 1) then + RemoveLock(k); + end + end + +end + + + + + + + + + + + + + + +SGI:debug(">> Blacklist.lua"); diff --git a/core/SGI_Constants.lua b/core/SGI_Constants.lua index 5f1f74b..4e9c9d2 100644 --- a/core/SGI_Constants.lua +++ b/core/SGI_Constants.lua @@ -1,73 +1,73 @@ -SGI = {}; - --- General -SGI.LOGO = "|cffffff00<|r|cff16ABB5SGI|r|cffffff00>|r "; -SLASH_SUPERGUILDINVITE1 = "/sgi"; -SLASH_SUPERGUILDINVITE2 = "/superguildinvite"; -SGI_DATA_INDEX = UnitName("player").." - "..GetRealmName() or "?"; -SGI.VERSION_ALERT_COOLDOWN = false; - -SGI_MAX_LEVEL_SUPER_SCAN = 110; -SGI_BREAK_POINT_SUPER_SCAN = 90; -SGI_MIN_LEVEL_SUPER_SCAN = 1; - --- Version realted -SGI.VERSION_MAJOR = "7.7"; -SGI.VERSION_MINOR = ".0"; -SGI.versionChanges = { - version = "Version |cff55EE55"..SGI.VERSION_MAJOR..SGI.VERSION_MINOR.."|r", - items = { - "Added Races and bug fixes..", - }, -} - -SGI.CommonIssues = { - "Please post bug reports on WoWInterface or curseforge and I'll fix them.", - "Test2", - "Test3", -} - -local function defaultFunc(L,key) - return "857C7C" -end - - - -SGI_CLASS_COLORS = { - ["DEATHKNIGHT"] = "C41F3B", - ["DEMONHUNTER"] = "A330C9", - ["DRUID"] = "FF7D0A", - ["HUNTER"] = "ABD473", - ["MAGE"] = "69CCF0", - ["MONK"] = "00FF96", - ["PALADIN"] = "F58CBA", - ["PRIEST"] = "FFFFFF", - ["ROGUE"] = "FFF569", - ["SHAMAN"] = "0070DE", - ["WARLOCK"] = "9482C9", - ["WARRIOR"] = "C79C6E", -} - -SGI_CLASS_COLORS = setmetatable(SGI_CLASS_COLORS, {__index=defaultFunc}) - - -local debugMode = false; -local old = print -function SGI:print(...) - if (SGI_DATA_INDEX == "?" or type(SGI_DATA) ~= "table") then return end - if (not SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_SGI_MUTE"]) then - old("|cffffff00<|r|cff16ABB5SGI|r|cffffff00>|r|cffffff00",...,"|r") - end -end -function SGI:debug(...) - if (debugMode) then - old("|cffffff00<|r|cff16ABB5SGI|r|cffffff00>|r|cffff3300",...,"|r") - end -end - -function SGI:DebugState(state) - debugMode = state; -end - -SGI:debug("Loading SGI files:"); -SGI:debug(">> Constants.lua"); +SGI = {}; + +-- General +SGI.LOGO = "|cffffff00<|r|cff16ABB5SGI|r|cffffff00>|r "; +SLASH_SUPERGUILDINVITE1 = "/sgi"; +SLASH_SUPERGUILDINVITE2 = "/superguildinvite"; +SGI_DATA_INDEX = UnitName("player").." - "..GetRealmName() or "?"; +SGI.VERSION_ALERT_COOLDOWN = false; + +SGI_MAX_LEVEL_SUPER_SCAN = 120; +SGI_BREAK_POINT_SUPER_SCAN = 90; +SGI_MIN_LEVEL_SUPER_SCAN = 1; + +-- Version realted +SGI.VERSION_MAJOR = "8.0"; +SGI.VERSION_MINOR = ".1"; +SGI.versionChanges = { + version = "Version |cff55EE55"..SGI.VERSION_MAJOR..SGI.VERSION_MINOR.."|r", + items = { + "Added Races and bug fixes..", + }, +} + +SGI.CommonIssues = { + "Please post bug reports on WoWInterface or curseforge and I'll fix them.", + "Test2", + "Test3", +} + +local function defaultFunc(L,key) + return "857C7C" +end + + + +SGI_CLASS_COLORS = { + ["DEATHKNIGHT"] = "C41F3B", + ["DEMONHUNTER"] = "A330C9", + ["DRUID"] = "FF7D0A", + ["HUNTER"] = "ABD473", + ["MAGE"] = "69CCF0", + ["MONK"] = "00FF96", + ["PALADIN"] = "F58CBA", + ["PRIEST"] = "FFFFFF", + ["ROGUE"] = "FFF569", + ["SHAMAN"] = "0070DE", + ["WARLOCK"] = "9482C9", + ["WARRIOR"] = "C79C6E", +} + +SGI_CLASS_COLORS = setmetatable(SGI_CLASS_COLORS, {__index=defaultFunc}) + + +local debugMode = false; +local old = print +function SGI:print(...) + if (SGI_DATA_INDEX == "?" or type(SGI_DATA) ~= "table") then return end + if (not SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_SGI_MUTE"]) then + old("|cffffff00<|r|cff16ABB5SGI|r|cffffff00>|r|cffffff00",...,"|r") + end +end +function SGI:debug(...) + if (debugMode) then + old("|cffffff00<|r|cff16ABB5SGI|r|cffffff00>|r|cffff3300",...,"|r") + end +end + +function SGI:DebugState(state) + debugMode = state; +end + +SGI:debug("Loading SGI files:"); +SGI:debug(">> Constants.lua"); diff --git a/core/SGI_Core.lua b/core/SGI_Core.lua index 14ce9eb..8b2940e 100644 --- a/core/SGI_Core.lua +++ b/core/SGI_Core.lua @@ -1,190 +1,190 @@ -local L; - - -function SGI:LoadLocale() - local Locale = GetLocale() - if SGI_Locale[Locale] then - SGI.L = SGI_Locale[Locale] - L = SGI.L; - SGI:print(L["English Locale loaded"]..L["Author"]) - return true - else - SGI.L = SGI_Locale["enGB"] - SGI:print("|cffffff00Locale missing! Loaded English.|r") - return false - end - -end - -function SGI:FormatTime2(T) - local R,S,M,H = "" - T = floor(T) - H = floor(T/3600) - M = floor((T-3600*H)/60) - S = T-(3600*H + 60*M) - - if T <= 0 then - return L[" < 1 sec"] - end - - if H ~= 0 then - R = R..H..L["h "] - end - if M ~= 0 then - R = R..M..L["m "] - end - if S ~= 0 then - R = R..S..L["s"] - end - - return R -end - -function SGI:FormatTime(T) - local R,S,M,H = "" - T = floor(T); - H = floor(T/3600) - M = floor((T-3600*H)/60) - S = T-(3600*H + 60*M) - - if (T <= 0) then - return SGI.L[" < 1 sec"]; - end - - if (H > 0) then - R = R..H..":"; - end - if (M > 9) then - R = R..M..":"; - elseif (M > 0) then - R = R.."0"..M..":"; - elseif (M == 0) then - R = R.."00:"; - end - if (S > 9) then - R = R..S; - elseif (S > 0) then - R = R.."0"..S; - elseif (S == 0) then - R = R.."00"; - end - - return R; -end - - -function SGI:CountTable(T) - local i = 0 - if type(T) ~= "table" then - return i - end - for k,_ in pairs(T) do - i = i + 1 - end - return i -end - -function SGI:GetClassColor(classFileName) - return SGI_CLASS_COLORS[classFileName]; -end - -function SGI:CompareVersions(V1, V2) - local p11 = tonumber(strsub(V1,1,strfind(V1,".",1,true)-1)); - local p12 = tonumber(strsub(V1,strfind(V1,".",1,true)+1)); - local p21 = tonumber(strsub(V2,1,strfind(V2,".",1,true)-1)); - local p22 = tonumber(strsub(V2,strfind(V2,".",1,true)+1)); - - if (p11 == p21) then - if (p22 > p12) then - return V2; - else - return V1; - end - elseif (p21 > p11) then - return V2; - else - return V1; - end -end - -function SGI:ResetFix() - if (not SGI_DATA.resetFix) then - SGI_DATA = {}; - SGI_DATA.resetFix = true; - end -end - -function SGI:divideString(str,div) - local out = {} - local i = 0 - while strfind(str,div) do - i = i + 1 - out[i] = strsub(str,1,strfind(str,div)-1) - str = strsub(str,strfind(str,div)+1) - end - out[i+1] = str - return out -end - -local function FrameReset() - SGI_DATA[SGI_DATA_INDEX].settings.frames = {} - ReloadUI(); -end - -local reloadWarning = true; -local reloadWarning2 = true; -function SlashCmdList.SUPERGUILDINVITE(msg) - - msg = strlower(msg); - - if msg == "reset" then - local lock = SGI_DATA.lock - SGI_DATA = nil - SGI_EVENTS["PLAYER_LOGIN"]() - SGI_DATA.lock = lock - elseif (msg == "framereset") then - if (reloadWarning) then - SGI:print("WARNING: Reseting your frames requires a reload of the User Interface! If you wish to proceed, type \"/sgi framereset\" again!"); - reloadWarning = false; - else - FrameReset(); - end - elseif (msg == "opt" or msg == "options" or msp == "config" or msg == "settings" or msg == "show") then - SGI:ShowOptions(); - elseif (msg == "debug") then - SGI_DATA[SGI_DATA_INDEX].debug = not SGI_DATA[SGI_DATA_INDEX].debug; - if (SGI_DATA[SGI_DATA_INDEX].debug) then - SGI:print("Activated debugging!"); - else - SGI:print("Deactivated debugging!"); - end - SGI:DebugState(SGI_DATA[SGI_DATA_INDEX].debug); - elseif (msg == "changes") then - SGI:ShowChanges(); - elseif (msg == "stats") then - local amountScanned, amountGuildless, amountQueued, sessionTotal = SGI:GetSuperScanStats(); - SGI:print("Scanned players this scan: |r|cff0062FF"..amountScanned.."|r"); - SGI:print("Guildless players this scan: |r|cff0062FF"..amountGuildless.."|r"); - SGI:print("Queued players this scan: |r|cff0062FF"..amountQueued.."|r"); - SGI:print("Total players scanned this session: |r|cff0062FF"..sessionTotal.."|r"); - elseif (msg == "unbind" or msg == "removekeybind") then - SGI:print("Cleared SGI invite keybind"); - SGI_DATA[SGI_DATA_INDEX].keyBind = nil; - elseif (strfind(msg, "lock")) then - local name = strsub(msg, 6); - if (name) then - SGI:LockPlayer(name); - end - else - local temp = SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_SGI_MUTE"]; - SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_SGI_MUTE"] = false; - SGI:print("|cffffff00Commands: |r|cff00A2FF/sgi or /superguildinvite|r") - SGI:print("|cff00A2FFreset |r|cffffff00to reset all data except locks|r") - SGI:print("|cff00A2FFframereset|r|cffffff00 resets the positions of the frames |r") - SGI:print("|cff00A2FFunbind|r|cffffff00 removes the saved keybind|r"); - SGI:print("|cff00A2FFoptions|r|cffffff00 shows the options. Same effect as clicking the minimap button|r") - SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_SGI_MUTE"] = temp; - end -end - -SGI:debug(">> Core.lua"); \ No newline at end of file +local L; + + +function SGI:LoadLocale() + local Locale = GetLocale() + if SGI_Locale[Locale] then + SGI.L = SGI_Locale[Locale] + L = SGI.L; +-- SGI:print(L["English Locale loaded"]..L["Author"]) + return true + else + SGI.L = SGI_Locale["enGB"] +-- SGI:print("|cffffff00Locale missing! Loaded English.|r") + return false + end + +end + +function SGI:FormatTime2(T) + local R,S,M,H = "" + T = floor(T) + H = floor(T/3600) + M = floor((T-3600*H)/60) + S = T-(3600*H + 60*M) + + if T <= 0 then + return L[" < 1 sec"] + end + + if H ~= 0 then + R = R..H..L["h "] + end + if M ~= 0 then + R = R..M..L["m "] + end + if S ~= 0 then + R = R..S..L["s"] + end + + return R +end + +function SGI:FormatTime(T) + local R,S,M,H = "" + T = floor(T); + H = floor(T/3600) + M = floor((T-3600*H)/60) + S = T-(3600*H + 60*M) + + if (T <= 0) then + return SGI.L[" < 1 sec"]; + end + + if (H > 0) then + R = R..H..":"; + end + if (M > 9) then + R = R..M..":"; + elseif (M > 0) then + R = R.."0"..M..":"; + elseif (M == 0) then + R = R.."00:"; + end + if (S > 9) then + R = R..S; + elseif (S > 0) then + R = R.."0"..S; + elseif (S == 0) then + R = R.."00"; + end + + return R; +end + + +function SGI:CountTable(T) + local i = 0 + if type(T) ~= "table" then + return i + end + for k,_ in pairs(T) do + i = i + 1 + end + return i +end + +function SGI:GetClassColor(classFileName) + return SGI_CLASS_COLORS[classFileName]; +end + +function SGI:CompareVersions(V1, V2) + local p11 = tonumber(strsub(V1,1,strfind(V1,".",1,true)-1)); + local p12 = tonumber(strsub(V1,strfind(V1,".",1,true)+1)); + local p21 = tonumber(strsub(V2,1,strfind(V2,".",1,true)-1)); + local p22 = tonumber(strsub(V2,strfind(V2,".",1,true)+1)); + + if (p11 == p21) then + if (p22 > p12) then + return V2; + else + return V1; + end + elseif (p21 > p11) then + return V2; + else + return V1; + end +end + +function SGI:ResetFix() + if (not SGI_DATA.resetFix) then + SGI_DATA = {}; + SGI_DATA.resetFix = true; + end +end + +function SGI:divideString(str,div) + local out = {} + local i = 0 + while strfind(str,div) do + i = i + 1 + out[i] = strsub(str,1,strfind(str,div)-1) + str = strsub(str,strfind(str,div)+1) + end + out[i+1] = str + return out +end + +local function FrameReset() + SGI_DATA[SGI_DATA_INDEX].settings.frames = {} + ReloadUI(); +end + +local reloadWarning = true; +local reloadWarning2 = true; +function SlashCmdList.SUPERGUILDINVITE(msg) + + msg = strlower(msg); + + if msg == "reset" then + local lock = SGI_DATA.lock + SGI_DATA = nil + SGI_EVENTS["ADDON_LOADED"]() + SGI_DATA.lock = lock + elseif (msg == "framereset") then + if (reloadWarning) then + SGI:print("WARNING: Reseting your frames requires a reload of the User Interface! If you wish to proceed, type \"/sgi framereset\" again!"); + reloadWarning = false; + else + FrameReset(); + end + elseif (msg == "opt" or msg == "options" or msp == "config" or msg == "settings" or msg == "show") then + SGI:ShowOptions(); + elseif (msg == "debug") then + SGI_DATA[SGI_DATA_INDEX].debug = not SGI_DATA[SGI_DATA_INDEX].debug; + if (SGI_DATA[SGI_DATA_INDEX].debug) then + SGI:print("Activated debugging!"); + else + SGI:print("Deactivated debugging!"); + end + SGI:DebugState(SGI_DATA[SGI_DATA_INDEX].debug); + elseif (msg == "changes") then + SGI:ShowChanges(); + elseif (msg == "stats") then + local amountScanned, amountGuildless, amountQueued, sessionTotal = SGI:GetSuperScanStats(); + SGI:print("Scanned players this scan: |r|cff0062FF"..amountScanned.."|r"); + SGI:print("Guildless players this scan: |r|cff0062FF"..amountGuildless.."|r"); + SGI:print("Queued players this scan: |r|cff0062FF"..amountQueued.."|r"); + SGI:print("Total players scanned this session: |r|cff0062FF"..sessionTotal.."|r"); + elseif (msg == "unbind" or msg == "removekeybind") then + SGI:print("Cleared SGI invite keybind"); + SGI_DATA[SGI_DATA_INDEX].keyBind = nil; + elseif (strfind(msg, "lock")) then + local name = strsub(msg, 6); + if (name) then + SGI:LockPlayer(name); + end + else + local temp = SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_SGI_MUTE"]; + SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_SGI_MUTE"] = false; + SGI:print("|cffffff00Commands: |r|cff00A2FF/sgi or /superguildinvite|r") + SGI:print("|cff00A2FFreset |r|cffffff00to reset all data except locks|r") + SGI:print("|cff00A2FFframereset|r|cffffff00 resets the positions of the frames |r") + SGI:print("|cff00A2FFunbind|r|cffffff00 removes the saved keybind|r"); + SGI:print("|cff00A2FFoptions|r|cffffff00 shows the options. Same effect as clicking the minimap button|r") + SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_SGI_MUTE"] = temp; + end +end + +SGI:debug(">> Core.lua"); diff --git a/core/SGI_Events.lua b/core/SGI_Events.lua index 2926ea0..e8b438e 100644 --- a/core/SGI_Events.lua +++ b/core/SGI_Events.lua @@ -1,141 +1,165 @@ -CreateFrame("Frame","SGI_EVENT_HANDLER"); -SGI_EVENTS = {}; - -function SGI_EVENTS:PLAYER_LOGIN() - - - - -- Index used to separate settings for different characters. - SGI_DATA_INDEX = UnitName("player").." - "..GetRealmName(); - - -- Make sure the saved variables are correct. - --General settings: - if (type(SGI_DATA) ~= "table") then - SGI_DATA = {}; - end - - -- Fix transition from 6.x to 7.x - SGI:ResetFix() - - if (type(SGI_DATA.lock) ~= "table") then - SGI_DATA.lock = {}; - end - if (type(SGI_DATA.guildList) ~= "table") then - SGI_DATA.guildList = {} - end - if (type(SGI_DATA.guildList[GetRealmName()]) ~= "table") then - SGI_DATA.guildList[GetRealmName()] = {}; - end - - --Character based settings. - if type(SGI_DATA[SGI_DATA_INDEX]) ~= "table" then - SGI_DATA[SGI_DATA_INDEX] = {} - end - if type(SGI_DATA[SGI_DATA_INDEX].settings) ~= "table" then - SGI_DATA[SGI_DATA_INDEX].settings = { - inviteMode = 1, - lowLimit = SGI_MIN_LEVEL_SUPER_SCAN, - highLimit = SGI_MAX_LEVEL_SUPER_SCAN, - raceStart = SGI_MAX_LEVEL_SUPER_SCAN, - classStart = SGI_MAX_LEVEL_SUPER_SCAN, - interval = 5, - checkBox = {}, - dropDown = {}, - frames = {}, - filters = {}, - } - end - if type(SGI_DATA[SGI_DATA_INDEX].settings.whispers) ~= "table" then - SGI_DATA[SGI_DATA_INDEX].settings.whispers = {} - end - if type(SGI_BACKUP) ~= "table" then - SGI_BACKUP = SGI_DATA.lock - end - - -- If there is a saved keybind, activate it. - if (SGI_DATA[SGI_DATA_INDEX].keyBind) then - SetBindingClick(SGI_DATA[SGI_DATA_INDEX].keyBind,"SGI_INVITE_BUTTON"); - end - - -- Anti spam. Users of the AddOn GuildShield are ignored. - GuildShield:Initiate(SGI.RemoveShielded); - -- Load locale - SGI:LoadLocale(); - -- Load the minimap button - if (not SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_HIDE_MINIMAP"]) then - SGI:ShowMinimapButton(); - end - -- Activate the keybind, if any. - if (SGI_DATA[SGI_DATA_INDEX].keyBind) then - SetBindingClick(SGI_DATA[SGI_DATA_INDEX].keyBind, "SGI_INVITE_BUTTON2"); - end - --Debugging, used for development - SGI:DebugState(SGI_DATA[SGI_DATA_INDEX].debug); - --Tell guildies what version you're running - SGI:BroadcastVersion("GUILD"); - --Request lock sync from guildies - SGI:RequestSync(); - --Remove locks that are > 2 months old - SGI:RemoveOutdatedLocks(); - --Chat Intercept - ChatIntercept:StateSystem(SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_HIDE_SYSTEM"]); - ChatIntercept:StateWhisper(SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_HIDE_WHISPER"]); - ChatIntercept:StateRealm(true); - --Show changes, if needed - --SGI:debug((SGI_DATA[SGI_DATA_INDEX].settings.checkBox["SGI_CHANGES"] and "true" or "nil").." "..(SGI_DATA.showChanges and "true" or "nil")); - if (not SGI_DATA[SGI_DATA_INDEX].settings.checkBox["SGI_CHANGES"] and SGI_DATA.showChanges ~= SGI.VERSION_MAJOR) then - SGI:ShowChanges(); - SGI_DATA.showChanges = SGI.VERSION_MAJOR; - SGI:debug("Show changes"); - end - --Need to load the SuperScan frame for certain functions - SGI:CreateSmallSuperScanFrame(); - SuperScanFrame:Hide(); -end - -function SGI_EVENTS:UPDATE_MOUSEOVER_UNIT() - -- Create a list of players and their guild (if any). - -- Used to prevent false positives. - if (UnitIsPlayer("mouseover")) then - local name = UnitName("mouseover"); - local guild = GetGuildInfo("mouseover"); - local realm = GetRealmName(); - - if (not guild or guild == "") then return end - - if (type(SGI_DATA.guildList[realm][guild]) ~= "table") then - SGI_DATA.guildList[realm][guild] = {}; - end - for k,v in pairs(SGI_DATA.guildList[realm][guild]) do - if (v == name) then - return; - end - end - tinsert(SGI_DATA.guildList[realm][guild], name); - --SGI_DATA.guildList[realm][name] = guild; - end -end - -function SGI_EVENTS:PLAYER_LOGOUT() - SendAddonMessage("SGI_STOP", "", "GUILD"); -end - -function SGI_EVENTS:CHAT_MSG_ADDON(event, ...) - SGI:AddonMessage(event, ...); -end - -function SGI_EVENTS:CHAT_MSG_SYSTEM(event, ...) - SGI:SystemMessage(event,message,...) -end - - -for event,_ in pairs(SGI_EVENTS) do - SGI_EVENT_HANDLER:RegisterEvent(event); -end - - -SGI_EVENT_HANDLER:SetScript("OnEvent", function(self,event,...) - SGI_EVENTS[event](self, event, ...); -end) - -SGI:debug(">> Events.lua"); \ No newline at end of file +CreateFrame("Frame","SGI_EVENT_HANDLER"); +SGI_EVENTS = {}; + +function SGI_EVENTS:ADDON_LOADED() + + + -- Index used to separate settings for different characters. + SGI_DATA_INDEX = UnitName("player").." - "..GetRealmName(); + + + + -- Make sure the saved variables are correct. + --General settings: + if (type(SGI_DATA) ~= "table") then + SGI_DATA = {}; + end + + -- Fix transition from 6.x to 7.x + SGI:ResetFix() + + if (type(SGI_DATA.lock) ~= "table") then + SGI_DATA.lock = {}; + end + if (type(SGI_DATA.guildList) ~= "table") then + SGI_DATA.guildList = {} + end + if (type(SGI_DATA.guildList[GetRealmName()]) ~= "table") then + SGI_DATA.guildList[GetRealmName()] = {}; + end + + --Character based settings. + if type(SGI_DATA[SGI_DATA_INDEX]) ~= "table" then + SGI_DATA[SGI_DATA_INDEX] = {} + end + if type(SGI_DATA[SGI_DATA_INDEX].settings) ~= "table" then + SGI_DATA[SGI_DATA_INDEX].settings = { + inviteMode = 2, + lowLimit = SGI_MIN_LEVEL_SUPER_SCAN, + highLimit = SGI_MAX_LEVEL_SUPER_SCAN, + raceStart = SGI_MAX_LEVEL_SUPER_SCAN, + classStart = SGI_MAX_LEVEL_SUPER_SCAN, + interval = 5, + checkBox = {}, + dropDown = {}, + frames = {}, + filters = {}, + } + end + if type(SGI_DATA[SGI_DATA_INDEX].settings.whispers) ~= "table" then + SGI_DATA[SGI_DATA_INDEX].settings.whispers = {} + end + if type(SGI_BACKUP) ~= "table" then + SGI_BACKUP = SGI_DATA.lock + end + + -- If there is a saved keybind, activate it. +-- if (SGI_DATA[SGI_DATA_INDEX].keyBind) then +-- SetBindingClick(SGI_DATA[SGI_DATA_INDEX].keyBind,"SGI_INVITE_BUTTON"); +-- end + + -- Anti spam. Users of the AddOn GuildShield are ignored. +-- GuildShield:Initiate(SGI.RemoveShielded); + -- Load locale + SGI:LoadLocale(); + -- Load the minimap button + if (not SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_HIDE_MINIMAP"]) then + SGI:ShowMinimapButton(); + end +-- if (not SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_ADV_SCAN"]) then +-- SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_ADV_SCAN"] = FALSE; +-- end + + + + + + -- Removed Keybind button, too dangerous code. + -- Activate the keybind, if any. +-- if (SGI_DATA[SGI_DATA_INDEX].keyBind) then +-- SetBindingClick(SGI_DATA[SGI_DATA_INDEX].keyBind, "SGI_INVITE_BUTTON2"); +-- end + + + + --Debugging, used for development +-- SGI:DebugState(SGI_DATA[SGI_DATA_INDEX].debug); + --Tell guildies what version you're running + -- SGI:BroadcastVersion("GUILD"); legacy + --Request lock sync from guildies + --SGI:RequestSync(); + --Remove locks that are > 2 months old + --SGI:RemoveOutdatedLocks(); + + + --SGI_DATA[SGI_DATA_INDEX].settings.checkBox["Mute SGI"]=true + --SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_HIDE_SYSTEM"]=true + --print(SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_HIDE_SYSTEM"]); + + --Chat Intercept + --ChatIntercept:StateSystem(SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_HIDE_SYSTEM"]); + ChatIntercept:StateSystem(false); + + + ChatIntercept:StateWhisper(SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_HIDE_WHISPER"]); + --ChatIntercept:StateRealm(true); + + --Show changes, if needed + --SGI:debug((SGI_DATA[SGI_DATA_INDEX].settings.checkBox["SGI_CHANGES"] and "true" or "nil").." "..(SGI_DATA.showChanges and "true" or "nil")); + if (not SGI_DATA[SGI_DATA_INDEX].settings.checkBox["SGI_CHANGES"] and SGI_DATA.showChanges ~= SGI.VERSION_MAJOR) then +-- SGI:ShowChanges(); +-- SGI_DATA.showChanges = SGI.VERSION_MAJOR; +-- SGI:debug("Show changes"); + end + --Need to load the SuperScan frame for certain functions + SGI:CreateSmallSuperScanFrame(); + SuperScanFrame:Hide(); + +end + +function SGI_EVENTS:UPDATE_MOUSEOVER_UNIT() + -- Create a list of players and their guild (if any). + -- Used to prevent false positives. + if (UnitIsPlayer("mouseover")) then + local name = UnitName("mouseover"); + local guild = GetGuildInfo("mouseover"); + local realm = GetRealmName(); + + if (not guild or guild == "") then return end + + if (type(SGI_DATA.guildList[realm][guild]) ~= "table") then + SGI_DATA.guildList[realm][guild] = {}; + end + for k,v in pairs(SGI_DATA.guildList[realm][guild]) do + if (v == name) then + return; + end + end + tinsert(SGI_DATA.guildList[realm][guild], name); + --SGI_DATA.guildList[realm][name] = guild; + end +end + +function SGI_EVENTS:PLAYER_LOGOUT() + C_ChatInfo.SendAddonMessageLogged("SGI_STOP", "", "GUILD"); +end + +function SGI_EVENTS:CHAT_MSG_ADDON(event, ...) + SGI:AddonMessage(event, ...); +end + +function SGI_EVENTS:CHAT_MSG_SYSTEM(event, ...) + SGI:SystemMessage(event,message,...) +end + + +for event,_ in pairs(SGI_EVENTS) do + SGI_EVENT_HANDLER:RegisterEvent(event); +end + + +SGI_EVENT_HANDLER:SetScript("OnEvent", function(self,event,...) + SGI_EVENTS[event](self, event, ...); +end) + +SGI:debug(">> Events.lua"); diff --git a/core/SGI_Filter.lua b/core/SGI_Filter.lua index f9c6ad0..8b64d63 100644 --- a/core/SGI_Filter.lua +++ b/core/SGI_Filter.lua @@ -1,211 +1,211 @@ ---[[ - Filter structure: - = { - nameFilter = "A", - exclusiveFilter = true, - maxLvl = 10, - minLvL = 1, - race = { - ["Tauren"] = true, - }, - class = { - ["DEATHKNIGHT"] = true, - }, - } - - - - -]] - -local function AddFilter(filter) - tinsert(SGI_DATA[SGI_DATA_INDEX].settings.filters, filter); -end - -function SGI:CreateFilter(nameOfFilter,class, name, minLvl, maxLvl, race, maxVowels, maxConsonants, active) - - if (not nameOfFilter) then - return; - end - - local filter = { - nameOfFilter = nameOfFilter, - race = race, - class = class, - name = name, - minLvl = minLvl, - maxLvl = maxLvl, - maxVowels = maxVowels, - maxConsonants = maxConsonants, - active = active, - } - - AddFilter(filter); -end - -function SGI:RemoveFilter(filterName) - -end - -local function GetMaxNumberConsequtiveVowels(word) - - local vowels = { - ["a"] = 1, - ["o"] = 1, - ["u"] = 1, - ["y"] = 1, - ["i"] = 1, - ["e"] = 1, - } - local c = 0; - local max = 0; - for i = 1, strlen(word) do - if (vowels[strsub(word, i, i)]) then - c = c + 1; - else - c = 0; - end - if (c > max) then - max = c; - end - end - - return max; - -end - -local function GetMaxNumberConsequtiveConsonants(word) - local vowels = { - ["a"] = 1, - ["o"] = 1, - ["u"] = 1, - ["y"] = 1, - ["i"] = 1, - ["e"] = 1, - } - local c = 0; - local max = 0; - for i = 1, strlen(word) do - if (vowels[strsub(word, i, i)]) then - c = 0; - else - c = c + 1; - end - if (c > max) then - max = c; - end - end - - return max; -end - -function SGI:TestCharacters(word) - local V = GetMaxNumberConsequtiveVowels(word); - local C = GetMaxNumberConsequtiveConsonants(word); - - SGI:print("Vowels: "..V.." Consonants: "..C); -end - -local function debugPlayer(player) - local text = "|cff"..SGI:GetClassColor(player.class)..player.name.."|r ("..player.level..") ("..player.race..")"; - return text -end - -local function match(filter, player) - - --Is this filter for the players class/race? - if (type(filter.race) == "table" and SGI:CountTable(filter.race) ~= 0) then - if (not filter.race[player.race]) then - return false; - end - end - - if (type(filter.class) == "table" and SGI:CountTable(filter.class) ~= 0) then - if (not filter.class[player.class]) then - return false; - end - end - - -- Is the player within the level range? - if (type(filter.minLvl) == "number") then - if (filter.minLvl > player.level) then - return false; - end - end - - if (type(filter.maxLvl) == "number") then - if (filter.maxLvl < player.level) then - return false; - end - end - - if (type(filter.name) == "string" and filter.name ~= "") then - if not (strfind(player.name,filter.name)) then - return false; - end - end - - if (type(filter.maxVowels) == "number") then - if (filter.maxVowels >= GetMaxNumberConsequtiveVowels(player.name)) then - return false; - end - end - - if (type(filter.maxConsonants) == "number") then - if (filter.maxConsonants >= GetMaxNumberConsequtiveConsonants(player.name)) then - return false; - end - end - - SGI:debug("Filter: "..filter.nameOfFilter.." "..debugPlayer(player)); - return true; - -end - -local function GetActiveFilters() - local filters, activeFilters = SGI_DATA[SGI_DATA_INDEX].settings.filters, {}; - if (type(filters) ~= "table") then - return {}; - end - for k,_ in pairs(filters) do - if (filters[k]["active"]) then - activeFilters[k] = filters[k]; - end - end - return activeFilters; -end - -function SGI:FilterPlayer(player) - local filters = GetActiveFilters();--SGI_DATA[SGI_DATA_INDEX].settings.filters; - - if (type(filters) ~= "table" or type(player) ~= "table") then - --if invalid parameter, return as filtered - SGI:debug("Error: Filter or player is not a table!"); - return false; - end - - for k,_ in pairs(filters) do - if (match(filters[k], player)) then - return false; - end - end - - return true; - -end - - - - - - - - - - - - - - - -SGI:debug(">> Filter.lua"); \ No newline at end of file +--[[ + Filter structure: + = { + nameFilter = "A", + exclusiveFilter = true, + maxLvl = 10, + minLvL = 1, + race = { + ["Tauren"] = true, + }, + class = { + ["DEATHKNIGHT"] = true, + }, + } + + + + +]] + +local function AddFilter(filter) + tinsert(SGI_DATA[SGI_DATA_INDEX].settings.filters, filter); +end + +function SGI:CreateFilter(nameOfFilter,class, name, minLvl, maxLvl, race, maxVowels, maxConsonants, active) + + if (not nameOfFilter) then + return; + end + + local filter = { + nameOfFilter = nameOfFilter, + race = race, + class = class, + name = name, + minLvl = minLvl, + maxLvl = maxLvl, + maxVowels = maxVowels, + maxConsonants = maxConsonants, + active = active, + } + + AddFilter(filter); +end + +function SGI:RemoveFilter(filterName) + +end + +local function GetMaxNumberConsequtiveVowels(word) + + local vowels = { + ["a"] = 1, + ["o"] = 1, + ["u"] = 1, + ["y"] = 1, + ["i"] = 1, + ["e"] = 1, + } + local c = 0; + local max = 0; + for i = 1, strlen(word) do + if (vowels[strsub(word, i, i)]) then + c = c + 1; + else + c = 0; + end + if (c > max) then + max = c; + end + end + + return max; + +end + +local function GetMaxNumberConsequtiveConsonants(word) + local vowels = { + ["a"] = 1, + ["o"] = 1, + ["u"] = 1, + ["y"] = 1, + ["i"] = 1, + ["e"] = 1, + } + local c = 0; + local max = 0; + for i = 1, strlen(word) do + if (vowels[strsub(word, i, i)]) then + c = 0; + else + c = c + 1; + end + if (c > max) then + max = c; + end + end + + return max; +end + +function SGI:TestCharacters(word) + local V = GetMaxNumberConsequtiveVowels(word); + local C = GetMaxNumberConsequtiveConsonants(word); + + SGI:print("Vowels: "..V.." Consonants: "..C); +end + +local function debugPlayer(player) + local text = "|cff"..SGI:GetClassColor(player.class)..player.name.."|r ("..player.level..") ("..player.race..")"; + return text +end + +local function match(filter, player) + + --Is this filter for the players class/race? + if (type(filter.race) == "table" and SGI:CountTable(filter.race) ~= 0) then + if (not filter.race[player.race]) then + return false; + end + end + + if (type(filter.class) == "table" and SGI:CountTable(filter.class) ~= 0) then + if (not filter.class[player.class]) then + return false; + end + end + + -- Is the player within the level range? + if (type(filter.minLvl) == "number") then + if (filter.minLvl > player.level) then + return false; + end + end + + if (type(filter.maxLvl) == "number") then + if (filter.maxLvl < player.level) then + return false; + end + end + + if (type(filter.name) == "string" and filter.name ~= "") then + if not (strfind(player.name,filter.name)) then + return false; + end + end + + if (type(filter.maxVowels) == "number") then + if (filter.maxVowels >= GetMaxNumberConsequtiveVowels(player.name)) then + return false; + end + end + + if (type(filter.maxConsonants) == "number") then + if (filter.maxConsonants >= GetMaxNumberConsequtiveConsonants(player.name)) then + return false; + end + end + + SGI:debug("Filter: "..filter.nameOfFilter.." "..debugPlayer(player)); + return true; + +end + +local function GetActiveFilters() + local filters, activeFilters = SGI_DATA[SGI_DATA_INDEX].settings.filters, {}; + if (type(filters) ~= "table") then + return {}; + end + for k,_ in pairs(filters) do + if (filters[k]["active"]) then + activeFilters[k] = filters[k]; + end + end + return activeFilters; +end + +function SGI:FilterPlayer(player) + local filters = GetActiveFilters();--SGI_DATA[SGI_DATA_INDEX].settings.filters; + + if (type(filters) ~= "table" or type(player) ~= "table") then + --if invalid parameter, return as filtered + SGI:debug("Error: Filter or player is not a table!"); + return false; + end + + for k,_ in pairs(filters) do + if (match(filters[k], player)) then + return false; + end + end + + return true; + +end + + + + + + + + + + + + + + + +SGI:debug(">> Filter.lua"); diff --git a/core/SGI_GUI.lua b/core/SGI_GUI.lua index 2d82056..7b533b4 100644 --- a/core/SGI_GUI.lua +++ b/core/SGI_GUI.lua @@ -1,1785 +1,1816 @@ - -local function onClickTester(self) - if self then - SGI:print("Click on "..self:GetName()); - end -end - -local function CreateButton(name, parent, width, height, label, anchor, onClick) - local f = CreateFrame("Button", name, parent, "UIPanelButtonTemplate"); - f:SetWidth(width); - f:SetHeight(height); - f.label = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall"); - f.label:SetText(label); - f.label:SetPoint("CENTER"); - f:SetWidth(width - 10); - - if (type(anchor) == "table") then - f:SetPoint(anchor.point,parent,anchor.relativePoint,anchor.xOfs,anchor.yOfs); - end - - f:SetScript("OnClick", onClick); - return f; -end - -local function CreateCheckbox(name, parent, label, anchor) - local f = CreateFrame("CheckButton", name, parent, "OptionsBaseCheckButtonTemplate"); - f.label = f:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - f.label:SetText(label); - f.label:SetPoint("LEFT", f, "RIGHT", 5, 1); - - if (type(anchor) == "table") then - f:SetPoint(anchor.point,parent,anchor.relativePoint,anchor.xOfs,anchor.yOfs); - end - - f:HookScript("OnClick", function(self) - SGI_DATA[SGI_DATA_INDEX].settings.checkBox[name] = self:GetChecked() - end) - if SGI_DATA[SGI_DATA_INDEX].settings.checkBox[name] then - f:SetChecked() - end - return f; -end - -local function CreateDropDown(name, parent, label, items, anchor) - local f = CreateFrame("Button", name, parent, "UIDropDownMenuTemplate"); - f:ClearAllPoints(); - f:SetPoint(anchor.point,parent,anchor.relativePoint,anchor.xOfs,anchor.yOfs) - f:Show() - - f.label = f:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - f.label:SetPoint("BOTTOMLEFT", f, "TOPLEFT", 20, 5); - f.label:SetText(label); - - local function OnClick(self) - UIDropDownMenu_SetSelectedID(f, self:GetID()); - SGI_DATA[SGI_DATA_INDEX].settings.dropDown[name] = self:GetID(); - end - - local function initialize(self, level) - local info = UIDropDownMenu_CreateInfo(); - for k,v in pairs(items) do - info = UIDropDownMenu_CreateInfo(); - info.text = v; - info.value = v; - info.func = OnClick; - UIDropDownMenu_AddButton(info, level); - end - end - - UIDropDownMenu_Initialize(f, initialize) - UIDropDownMenu_SetWidth(f, 100); - UIDropDownMenu_SetButtonWidth(f, 124) - SGI_DATA[SGI_DATA_INDEX].settings.dropDown[name] = SGI_DATA[SGI_DATA_INDEX].settings.dropDown[name] or 1 - UIDropDownMenu_SetSelectedID(f, SGI_DATA[SGI_DATA_INDEX].settings.dropDown[name] or 1) - UIDropDownMenu_JustifyText(f, "LEFT") - return f -end - -local function SetFramePosition(frame) - if (type(SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()]) ~= "table") then - if (frame:GetName() == "SGI_MiniMapButton") then - SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()] = {point = "CENTER", relativePoint = "CENTER", xOfs = -71, yOfs = -31}; - else - frame:SetPoint("CENTER"); - SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()] = {point = "CENTER", relativePoint = "CENTER", xOfs = 0, yOfs = 0}; - return; - end - end - if (frame:GetName() == "SGI_MiniMapButton") then - frame:SetPoint( - SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].point, - Minimap, - SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].relativePoint, - SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].xOfs, - SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].yOfs - ); - else - frame:SetPoint( - SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].point, - UIParent, - SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].relativePoint, - SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].xOfs, - SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].yOfs - ); - end -end - -local function SaveFramePosition(frame) - if (type(SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()]) ~= "table") then - SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()] = {}; - end - local point, parent, relativePoint, xOfs, yOfs = frame:GetPoint(); - SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()] = {point = point, relativePoint = relativePoint, xOfs = xOfs, yOfs = yOfs}; -end - - -local function CreateInviteListFrame() - CreateFrame("Frame","SGI_Invites") - local SGI_QUEUE = SGI:GetInviteQueue(); - SGI_Invites:SetWidth(370) - SGI_Invites:SetHeight(20*SGI:CountTable(SGI_QUEUE) + 40) - SGI_Invites:SetMovable(true) - SetFramePosition(SGI_Invites) - SGI_Invites:SetScript("OnMouseDown",function(self) - self:StartMoving() - end) - SGI_Invites:SetScript("OnMouseUp",function(self) - self:StopMovingOrSizing() - SaveFramePosition(SGI_Invites) - end) - local backdrop = - { - bgFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Background", - edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border", - tile = true, - tileSize = 16, - edgeSize = 16, - insets = { left = 4, right = 4, top = 4, bottom = 4 } - } - SGI_Invites:SetBackdrop(backdrop) - - SGI_Invites.text = SGI_Invites:CreateFontString(nil,"OVERLAY","GameFontNormal") - SGI_Invites.text:SetPoint("TOP",SGI_Invites,"TOP",-15,-15) - SGI_Invites.text:SetText(SGI.L["Click on the players you wish to invite"]) - SGI_Invites.tooltip = CreateFrame("Frame","InviteTime",SGI_Invites,"GameTooltipTemplate") - SGI_Invites.tooltip.text = SGI_Invites.tooltip:CreateFontString(nil,"OVERLAY","GameFontNormal") - SGI_Invites.tooltip:SetPoint("TOP",SGI_Invites,"BOTTOM",0,-2) - SGI_Invites.tooltip.text:SetText("Unknown") - SGI_Invites.tooltip.text:SetPoint("CENTER") - - local close = CreateFrame("Button",nil,SGI_Invites,"UIPanelCloseButton") - close:SetPoint("TOPRIGHT",SGI_Invites,"TOPRIGHT",-4,-4) - - SGI_Invites.items = {} - local update = 0 - local toolUpdate = 0 - SGI_Invites:SetScript("OnUpdate",function() - if (not SGI_Invites:IsShown() or GetTime() < update) then return end - - SGI_QUEUE = SGI:GetInviteQueue(); - - for k,_ in pairs(SGI_Invites.items) do - SGI_Invites.items[k]:Hide() - end - - local i = 0 - local x,y = 10,-30 - for i = 1,30 do - if not SGI_Invites.items[i] then - SGI_Invites.items[i] = CreateFrame("Button","InviteBar"..i,SGI_Invites) - SGI_Invites.items[i]:SetWidth(350) - SGI_Invites.items[i]:SetHeight(20) - SGI_Invites.items[i]:EnableMouse(true) - SGI_Invites.items[i]:SetPoint("TOP",SGI_Invites,"TOP",0,y) - SGI_Invites.items[i].text = SGI_Invites.items[i]:CreateFontString(nil,"OVERLAY","GameFontNormal") - SGI_Invites.items[i].text:SetPoint("LEFT",SGI_Invites.items[i],"LEFT",3,0) - SGI_Invites.items[i].text:SetJustifyH("LEFT") - SGI_Invites.items[i].text:SetWidth(SGI_Invites.items[i]:GetWidth()-10); - SGI_Invites.items[i].player = "unknown" - SGI_Invites.items[i]:RegisterForClicks("LeftButtonDown","RightButtonDown") - SGI_Invites.items[i]:SetScript("OnClick",SGI.SendGuildInvite) - - SGI_Invites.items[i].highlight = SGI_Invites.items[i]:CreateTexture() - SGI_Invites.items[i].highlight:SetAllPoints() - SGI_Invites.items[i].highlight:SetTexture(1,1,0,0.2) - SGI_Invites.items[i].highlight:Hide() - - SGI_Invites.items[i]:SetScript("OnEnter",function() - SGI_Invites.items[i].highlight:Show() - SGI_Invites.tooltip:Show() - SGI_Invites.items[i]:SetScript("OnUpdate",function() - if GetTime() > toolUpdate and SGI_QUEUE[SGI_Invites.items[i].player] then - SGI_Invites.tooltip.text:SetText("Found |cff"..SGI:GetClassColor(SGI_QUEUE[SGI_Invites.items[i].player].classFile)..SGI_Invites.items[i].player.."|r "..SGI:FormatTime(floor(GetTime()-SGI_QUEUE[SGI_Invites.items[i].player].found)).." ago") - local h,w = SGI_Invites.tooltip.text:GetHeight(),SGI_Invites.tooltip.text:GetWidth() - SGI_Invites.tooltip:SetWidth(w+20) - SGI_Invites.tooltip:SetHeight(h+20) - toolUpdate = GetTime() + 0.1 - end - end) - end) - SGI_Invites.items[i]:SetScript("OnLeave",function() - SGI_Invites.items[i].highlight:Hide() - SGI_Invites.tooltip:Hide() - SGI_Invites.items[i]:SetScript("OnUpdate",nil) - end) - end - y = y - 20 - end - i = 0 - for k,_ in pairs(SGI_QUEUE) do - i = i + 1 - local level,classFile,race,class,found = SGI_QUEUE[k].level, SGI_QUEUE[k].classFile, SGI_QUEUE[k].race, SGI_QUEUE[k].class, SGI_QUEUE[k].found - local Text = i..". |cff"..SGI:GetClassColor(classFile)..k.."|r Lvl "..level.." "..race.." |cff"..SGI:GetClassColor(classFile)..class.."|r" - SGI_Invites.items[i].text:SetText(Text) - SGI_Invites.items[i].player = k - SGI_Invites.items[i]:Show() - if i >= 30 then break end - end - SGI_Invites:SetHeight(i * 20 + 40) - update = GetTime() + 0.5 - end) -end - - -function SGI:ShowInviteList() - if (not SGI_Invites) then - CreateInviteListFrame(); - end - SGI_Invites:Show(); -end - -function SGI:HideInviteList() - if (SGI_Invites) then - SGI_Invites:Hide(); - end -end - - -local function SSBtn3_OnClick(self) - if (SGI:IsScanning()) then - SGI:StopSuperScan(); - self:SetNormalTexture("Interface\\Buttons\\UI-SpellbookIcon-NextPage-Up"); - else - SGI:StartSuperScan(); - self:SetNormalTexture("Interface\\TimeManager\\PauseButton"); - end -end - -function SGI:CreateSmallSuperScanFrame() - CreateFrame("Frame", "SuperScanFrame"); - SuperScanFrame:SetWidth(130); - SuperScanFrame:SetHeight(30); - local backdrop = - { - bgFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Background", - edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border", - tile = true, - tileSize = 16, - edgeSize = 16, - insets = { left = 4, right = 4, top = 4, bottom = 4 } - } - SetFramePosition(SuperScanFrame) - SuperScanFrame:SetMovable(true) - SuperScanFrame:SetScript("OnMouseDown",function(self) - self:StartMoving() - end) - SuperScanFrame:SetScript("OnMouseUp",function(self) - self:StopMovingOrSizing() - SaveFramePosition(self) - end) - SuperScanFrame:SetBackdrop(backdrop) - - local close = CreateFrame("Button",nil,SuperScanFrame,"UIPanelCloseButton") - close:SetPoint("LEFT",SuperScanFrame,"RIGHT",-5,0) - - SuperScanFrame.time = SuperScanFrame:CreateFontString(nil,"OVERLAY","GameFontNormal") - SuperScanFrame.time:SetPoint("CENTER") - SuperScanFrame.time:SetText(format("|cff00ff00%d%%|r|cffffff00 %s|r",0,SGI:GetSuperScanETR())) - - SuperScanFrame.progressTexture = SuperScanFrame:CreateTexture(); - SuperScanFrame.progressTexture:SetPoint("LEFT", 5, 0); - SuperScanFrame.progressTexture:SetHeight(18); - SuperScanFrame.progressTexture:SetWidth(120); - SuperScanFrame.progressTexture:SetTexture(1,0.5,0,0.4); - - local anchor = { - point = "TOPLEFT", - relativePoint = "BOTTOMLEFT", - xOfs = 0, - yOfs = 0, - } - - SuperScanFrame.button1 = CreateButton("SGI_INVITE_BUTTON2", SuperScanFrame, 70, 30, format("Invite: %d",SGI:GetNumQueued()), anchor, SGI.SendGuildInvite) - anchor.xOfs = 85; - SuperScanFrame.button2 = CreateButton("SGI_PURGE_QUEUE", SuperScanFrame, 55, 30, "Purge", anchor, SGI.PurgeQueue); - anchor.xOfs = 57; - SuperScanFrame.button2 = CreateButton("SGI_SUPERSCAN_PLAYPAUSE", SuperScanFrame, 40,30,"",anchor,SSBtn3_OnClick); - SGI_SUPERSCAN_PLAYPAUSE:SetNormalTexture("Interface\\TimeManager\\PauseButton"); - - SuperScanFrame.nextUpdate = 0; - SuperScanFrame:SetScript("OnUpdate", function() - if (SuperScanFrame.nextUpdate < GetTime()) then - - SuperScanFrame.button1.label:SetText(format("Invite: %d",SGI:GetNumQueued())); - - if (SGI:IsScanning() and SuperScanFrame.ETR and SuperScanFrame.lastETR) then - local remainingTime = SuperScanFrame.ETR - (GetTime() - SuperScanFrame.lastETR); - local totalScanTime = SGI:GetTotalScanTime(); - local percentageDone = (totalScanTime - remainingTime) / totalScanTime; - SuperScanFrame.time:SetText(format("|cff00ff00%d%%|r|cffffff00 %s|r",100*(percentageDone > 1 and 1 or percentageDone),SGI:FormatTime(remainingTime))) - SuperScanFrame.progressTexture:SetWidth(120 * (percentageDone > 1 and 1 or percentageDone)); - end - - SuperScanFrame.nextUpdate = GetTime() + 0.2; - end - end) - - - SuperScanFrame:Hide(); - -- Interface\Buttons\UI-SpellbookIcon-NextPage-Up - -- Interface\TimeManager\PauseButton -end - -function SGI:GetPercentageDone() - if (SGI:IsScanning() and SuperScanFrame.ETR and SuperScanFrame.lastETR) then - local remainingTime = SuperScanFrame.ETR - (GetTime() - SuperScanFrame.lastETR); - local totalScanTime = SGI:GetTotalScanTime(); - local percentageDone = (totalScanTime - remainingTime) / totalScanTime; - return percentageDone * 100; - end - return 0; -end - -function SGI:GetSuperScanTimeLeft() - if (SGI:IsScanning() and SuperScanFrame.ETR and SuperScanFrame.lastETR) then - return SGI:FormatTime(SuperScanFrame.ETR - (GetTime() - SuperScanFrame.lastETR)); - end - return 0; -end - - -function SGI:ShowSuperScanFrame() - if (SuperScanFrame and not (SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_BACKGROUND_MODE"])) then - SuperScanFrame:Show(); - else - if (SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_BACKGROUND_MODE"]) then - SGI:CreateSmallSuperScanFrame(); - SuperScanFrame:Hide(); - return; - else - SGI:CreateSmallSuperScanFrame(); - SuperScanFrame:Show(); - end - - end -end - -function SGI:HideSuperScanFrame() - if (SuperScanFrame) then - SuperScanFrame:Hide(); - end -end - -local function CreateWhisperDefineFrame() - -end - - - - -local KeyHarvestFrame = CreateFrame("Frame", "SGI_KeyHarvestFrame"); -KeyHarvestFrame:SetPoint("CENTER",0,200); -KeyHarvestFrame:SetWidth(10); -KeyHarvestFrame:SetHeight(10); -KeyHarvestFrame.text = KeyHarvestFrame:CreateFontString(nil, "OVERLAY", "MovieSubtitleFont"); -KeyHarvestFrame.text:SetPoint("CENTER"); -KeyHarvestFrame.text:SetText("|cff00ff00Press the KEY you wish to bind now!|r"); -KeyHarvestFrame:Hide(); - -function KeyHarvestFrame:GetNewKeybindKey() - KeyHarvestFrame:Show(); - self:SetScript("OnKeyDown", function(self, key) - if (SetBindingClick(key, "SGI_INVITE_BUTTON2")) then - Alerter:SendAlert("|cff00ff00Successfully bound "..key.." to InviteButton!|r",1.5); - SGI:print("Successfully bound "..key.." to InviteButton!"); - SGI_DATA[SGI_DATA_INDEX].keyBind = key; - BUTTON_KEYBIND.label:SetText("Set Keybind ("..key..")"); - else - Alerter:SendAlert("|cffff0000Error binding "..key.." to InviteButton!|r",1.5); - SGI:print("Error binding "..key.." to InviteButton!"); - end - self:EnableKeyboard(false); - KeyHarvestFrame:Hide(); - end) - self:EnableKeyboard(true); - -end - -local function CreateWhisperDefineFrame() - CreateFrame("Frame","SGI_Whisper") - local backdrop = - { - bgFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Background", - edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border", - tile = true, - tileSize = 16, - edgeSize = 16, - insets = { left = 4, right = 4, top = 4, bottom = 4 } - } - SGI_Whisper:SetWidth(500) - SGI_Whisper:SetHeight(365) - SGI_Whisper:SetBackdrop(backdrop) - SetFramePosition(SGI_Whisper) - SGI_Whisper:SetMovable(true) - SGI_Whisper:SetScript("OnMouseDown",function(self) - self:StartMoving() - end) - SGI_Whisper:SetScript("OnMouseUp",function(self) - self:StopMovingOrSizing() - SaveFramePosition(SGI_Whisper) - end) - - local close = CreateFrame("Button",nil,SGI_Whisper,"UIPanelCloseButton") - close:SetPoint("TOPRIGHT",SGI_Whisper,"TOPRIGHT",-4,-4) - - SGI_Whisper.title = SGI_Whisper:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") - SGI_Whisper.title:SetText(SGI.L["SuperGuildInvite Custom Whisper"]) - SGI_Whisper.title:SetPoint("TOP",SGI_Whisper,"TOP",0,-20) - - SGI_Whisper.info = SGI_Whisper:CreateFontString(nil,"OVERLAY","GameFontNormal") - SGI_Whisper.info:SetPoint("TOPLEFT",SGI_Whisper,"TOPLEFT",33,-55) - SGI_Whisper.info:SetText(SGI.L["WhisperInstructions"]) - SGI_Whisper.info:SetWidth(450) - SGI_Whisper.info:SetJustifyH("LEFT") - - SGI_Whisper.edit = CreateFrame("EditBox",nil,SGI_Whisper) - SGI_Whisper.edit:SetWidth(450) - SGI_Whisper.edit:SetHeight(65) - SGI_Whisper.edit:SetMultiLine(true) - SGI_Whisper.edit:SetPoint("TOPLEFT",SGI_Whisper,"TOPLEFT",35,-110) - SGI_Whisper.edit:SetFontObject("GameFontNormal") - SGI_Whisper.edit:SetTextInsets(10,10,10,10) - SGI_Whisper.edit:SetMaxLetters(256) - SGI_Whisper.edit:SetBackdrop(backdrop) - SGI_Whisper.edit:SetText(SGI_DATA[SGI_DATA_INDEX].settings.whispers[SGI_DATA[SGI_DATA_INDEX].settings.dropDown["SGI_WHISPER_DROP"] or 1] or "") - SGI_Whisper.edit:SetScript("OnHide",function() - SGI_Whisper.edit:SetText(SGI_DATA[SGI_DATA_INDEX].settings.whispers[SGI_DATA[SGI_DATA_INDEX].settings.dropDown["SGI_WHISPER_DROP"] or 1] or "") - end) - SGI_Whisper.edit.text = SGI_Whisper.edit:CreateFontString(nil,"OVERLAY","GameFontNormal") - SGI_Whisper.edit.text:SetPoint("TOPLEFT",SGI_Whisper.edit,"TOPLEFT",10,13) - SGI_Whisper.edit.text:SetText(SGI.L["Enter your whisper"]) - - local yOfs = -20 - SGI_Whisper.status = {} - for i = 1,6 do - SGI_Whisper.status[i] = {} - SGI_Whisper.status[i].box = CreateFrame("Frame",nil,SGI_Whisper) - SGI_Whisper.status[i].box:SetWidth(170) - SGI_Whisper.status[i].box:SetHeight(18) - SGI_Whisper.status[i].box:SetFrameStrata("HIGH") - SGI_Whisper.status[i].box.index = i - SGI_Whisper.status[i].box:SetPoint("LEFT",SGI_Whisper,"CENTER",50,yOfs) - SGI_Whisper.status[i].box:SetScript("OnEnter",function(self) - if SGI_DATA[SGI_DATA_INDEX].settings.whispers[self.index] then - GameTooltip:SetOwner(self,"ANCHOR_CURSOR") - GameTooltip:SetText(SGI:FormatWhisper(SGI_DATA[SGI_DATA_INDEX].settings.whispers[self.index],UnitName("Player"))) - end - end) - SGI_Whisper.status[i].box:SetScript("OnLeave",function(self) - GameTooltip:Hide() - end) - SGI_Whisper.status[i].text = SGI_Whisper:CreateFontString(nil,nil,"GameFontNormal") - SGI_Whisper.status[i].text:SetText("Whisper #"..i.." status: ") - SGI_Whisper.status[i].text:SetWidth(200) - SGI_Whisper.status[i].text:SetJustifyH("LEFT") - SGI_Whisper.status[i].text:SetPoint("LEFT",SGI_Whisper,"CENTER",50,yOfs) - yOfs = yOfs - 18 - end - local whispers = { - "Whisper #1", - "Whisper #2", - "Whisper #3", - "Whisper #4", - "Whisper #5", - "Whisper #6", - } - - anchor = {} - anchor.point = "BOTTOMLEFT" - anchor.relativePoint = "BOTTOMLEFT" - anchor.xOfs = 50 - anchor.yOfs = 120 - - --CreateDropDown(name, parent, label, items, anchor) - SGI_Whisper.drop = CreateDropDown("SGI_WHISPER_DROP",SGI_Whisper,SGI.L["Select whisper"],whispers,anchor) - - anchor.xOfs = 100 - anchor.yOfs = 20 - --CreateButton(name, parent, width, height, label, anchor, onClick) - CreateButton("SGI_SAVEWHISPER",SGI_Whisper,120,30,SGI.L["Save"],anchor,function() - local text = SGI_Whisper.edit:GetText() - local ID = SGI_DATA[SGI_DATA_INDEX].settings.dropDown["SGI_WHISPER_DROP"] - SGI_DATA[SGI_DATA_INDEX].settings.whispers[ID] = text - SGI_Whisper.edit:SetText("") - end) - anchor.xOfs = 280 - CreateButton("SGI_CANCELWHISPER",SGI_Whisper,120,30,SGI.L["Cancel"],anchor,function() - SGI_Whisper:Hide() - end) - - SGI_Whisper.update = 0 - SGI_Whisper.changed = false - SGI_Whisper:SetScript("OnUpdate",function() - if GetTime() > SGI_Whisper.update then - for i = 1,6 do - if type(SGI_DATA[SGI_DATA_INDEX].settings.whispers[i]) == "string" then - SGI_Whisper.status[i].text:SetText("Whisper #"..i.." status: |cff00ff00Good|r") - else - SGI_Whisper.status[i].text:SetText("Whisper #"..i.." status: |cffff0000Undefined|r") - end - end - local ID = SGI_DATA[SGI_DATA_INDEX].settings.dropDown["SGI_WHISPER_DROP"] - SGI_Whisper.status[ID].text:SetText("Whisper #"..ID.." status: |cffff8800Editing...|r") - - if ID ~= SGI_Whisper.changed then - SGI_Whisper.changed = ID - SGI_Whisper.edit:SetText(SGI_DATA[SGI_DATA_INDEX].settings.whispers[SGI_DATA[SGI_DATA_INDEX].settings.dropDown["SGI_WHISPER_DROP"] or 1] or "") - end - - SGI_Whisper.update = GetTime() + 0.5 - end - end) - - SGI_Whisper:HookScript("OnHide", function() if (SGI_Options.showAgain) then SGI:ShowOptions() SGI_Options.showAgain = false end end) -end - -local function ShowWhisperFrame() - if SGI_Whisper then - SGI_Whisper:Show() - else - CreateWhisperDefineFrame() - SGI_Whisper:Show() - end -end - -local function HideWhisperFrame() - if SGI_Whisper then - SGI_Whisper:Hide() - end -end - -local function CreateFilterFrame() - CreateFrame("Frame","SGI_Filters") - SGI_Filters:SetWidth(550) - SGI_Filters:SetHeight(380) - SetFramePosition(SGI_Filters) - SGI_Filters:SetMovable(true) - SGI_Filters:SetScript("OnMouseDown",function(self) - self:StartMoving() - end) - SGI_Filters:SetScript("OnMouseUp",function(self) - self:StopMovingOrSizing() - SaveFramePosition(SGI_Filters) - end) - local backdrop = - { - bgFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Background", - edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border", - tile = true, - tileSize = 16, - edgeSize = 16, - insets = { left = 4, right = 4, top = 4, bottom = 4 } - } - SGI_Filters:SetBackdrop(backdrop) - local close = CreateFrame("Button",nil,SGI_Filters,"UIPanelCloseButton") - close:SetPoint("TOPRIGHT",SGI_Filters,"TOPRIGHT",-4,-4) - - SGI_Filters.title = SGI_Filters:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); - SGI_Filters.title:SetPoint("TOP", SGI_Filters, "TOP", 0, -15); - SGI_Filters.title:SetText("Edit filters"); - SGI_Filters.underTitle = SGI_Filters:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - SGI_Filters.underTitle:SetPoint("TOP", SGI_Filters, "TOP", 0, -38); - SGI_Filters.underTitle:SetText("|cffff3300Any textbox left empty, except \"Filter name\" will be excluded from the filter|r"); - SGI_Filters.underTitle:SetWidth(400); - SGI_Filters.bottomText = SGI_Filters:CreateFontString(nil, "OVERLAY", "GameFOntNormal"); - SGI_Filters.bottomText:SetPoint("BOTTOM", SGI_Filters, "BOTTOM", 0, 60); - SGI_Filters.bottomText:SetText("|cff00ff00In order to be filtered, a player has to match |r|cffFF3300ALL|r |cff00ff00criterias|r"); - - SGI_Filters.tooltip = CreateFrame("Frame", "FilterTooltip", SGI_Filters.tooltip, "GameTooltipTemplate"); - SGI_Filters.tooltip:SetWidth(150); - SGI_Filters.tooltip.text = SGI_Filters.tooltip:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - SGI_Filters.tooltip.text:SetPoint("CENTER", SGI_Filters.tooltip, "CENTER", 0, 0); - SGI_Filters.tooltip.text:SetJustifyH("LEFT"); - - SGI_Filters.editBoxName = CreateFrame("EditBox", "SGI_EditBoxName", SGI_Filters); - SGI_Filters.editBoxName:SetWidth(150); - SGI_Filters.editBoxName:SetHeight(30); - SGI_Filters.editBoxName:SetPoint("TOPRIGHT", SGI_Filters, "TOPRIGHT", -40, -90); - SGI_Filters.editBoxName:SetFontObject("GameFontNormal"); - SGI_Filters.editBoxName:SetMaxLetters(65); - SGI_Filters.editBoxName:SetBackdrop(backdrop); - SGI_Filters.editBoxName:SetText(""); - SGI_Filters.editBoxName:SetTextInsets(10,10,10,10); - SGI_Filters.editBoxName:SetScript("OnHide",function(self) - self:SetText(""); - end) - SGI_Filters.editBoxName.title = SGI_Filters.editBoxName:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - SGI_Filters.editBoxName.title:SetPoint("BOTTOMLEFT", SGI_Filters.editBoxName,"TOPLEFT", 0, 5); - SGI_Filters.editBoxName.title:SetText("Filter name"); - - SGI_Filters.editBoxNameFilter = CreateFrame("EditBox", "SGI_EditBoxNameFilter", SGI_Filters); - SGI_Filters.editBoxNameFilter:SetWidth(150); - SGI_Filters.editBoxNameFilter:SetHeight(30); - SGI_Filters.editBoxNameFilter:SetPoint("TOPRIGHT", SGI_Filters, "TOPRIGHT", -40, -150); - SGI_Filters.editBoxNameFilter:SetFontObject("GameFontNormal"); - SGI_Filters.editBoxNameFilter:SetMaxLetters(65); - SGI_Filters.editBoxNameFilter:SetBackdrop(backdrop); - SGI_Filters.editBoxNameFilter:SetText(""); - SGI_Filters.editBoxNameFilter:SetTextInsets(10,10,10,10); - SGI_Filters.editBoxNameFilter:SetScript("OnHide",function(self) - self:SetText(""); - end) - SGI_Filters.editBoxNameFilter:SetScript("OnEnter", function(self) - SGI_Filters.tooltip.text:SetText(SGI.L["Enter a phrase which you wish to include in the filter. If a player's name contains the phrase, they will not be queued"]); - SGI_Filters.tooltip.text:SetWidth(135); - SGI_Filters.tooltip:SetHeight(SGI_Filters.tooltip.text:GetHeight() + 12); - SGI_Filters.tooltip:SetPoint("TOP", self, "BOTTOM", 0, -5); - SGI_Filters.tooltip:Show(); - end) - SGI_Filters.editBoxNameFilter:SetScript("OnLeave", function() - SGI_Filters.tooltip:Hide() - end) - - SGI_Filters.editBoxNameFilter.title = SGI_Filters.editBoxNameFilter:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - SGI_Filters.editBoxNameFilter.title:SetPoint("BOTTOMLEFT", SGI_Filters.editBoxNameFilter,"TOPLEFT", 0, 5); - SGI_Filters.editBoxNameFilter.title:SetText("Name exceptions"); - - SGI_Filters.editBoxLvl = CreateFrame("EditBox", "SGI_EditBoxLvl", SGI_Filters); - SGI_Filters.editBoxLvl:SetWidth(150); - SGI_Filters.editBoxLvl:SetHeight(30); - SGI_Filters.editBoxLvl:SetPoint("TOPRIGHT", SGI_Filters, "TOPRIGHT", -40, -210); - SGI_Filters.editBoxLvl:SetFontObject("GameFontNormal"); - SGI_Filters.editBoxLvl:SetMaxLetters(65); - SGI_Filters.editBoxLvl:SetBackdrop(backdrop); - SGI_Filters.editBoxLvl:SetText(""); - SGI_Filters.editBoxLvl:SetTextInsets(10,10,10,10); - SGI_Filters.editBoxLvl:SetScript("OnHide",function(self) - self:SetText(""); - end) - SGI_Filters.editBoxLvl:SetScript("OnEnter", function(self) - SGI_Filters.tooltip.text:SetText(SGI.L["Enter the level range for the filter. \n\nExample: |cff00ff0055|r:|cff00A2FF58|r \n\nThis would result in only matching players that range from level |cff00ff0055|r to |cff00A2FF58|r (inclusive)"]); - SGI_Filters.tooltip.text:SetWidth(135); - SGI_Filters.tooltip:SetHeight(SGI_Filters.tooltip.text:GetHeight() + 12); - SGI_Filters.tooltip:SetPoint("TOP", self, "BOTTOM", 0, -5); - SGI_Filters.tooltip:Show(); - end) - SGI_Filters.editBoxLvl:SetScript("OnLeave", function() - SGI_Filters.tooltip:Hide() - end) - - SGI_Filters.editBoxLvl.title = SGI_Filters.editBoxLvl:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - SGI_Filters.editBoxLvl.title:SetPoint("BOTTOMLEFT", SGI_Filters.editBoxLvl,"TOPLEFT", 0, 5); - SGI_Filters.editBoxLvl.title:SetText("Level range (Min:Max)"); - - SGI_Filters.editBoxVC = CreateFrame("EditBox", "SGI_EditBoxVC", SGI_Filters); - SGI_Filters.editBoxVC:SetWidth(150); - SGI_Filters.editBoxVC:SetHeight(30); - SGI_Filters.editBoxVC:SetPoint("TOPRIGHT", SGI_Filters, "TOPRIGHT", -40, -270); - SGI_Filters.editBoxVC:SetFontObject("GameFontNormal"); - SGI_Filters.editBoxVC:SetMaxLetters(65); - SGI_Filters.editBoxVC:SetBackdrop(backdrop); - SGI_Filters.editBoxVC:SetText(""); - SGI_Filters.editBoxVC:SetTextInsets(10,10,10,10); - SGI_Filters.editBoxVC:SetScript("OnHide",function(self) - self:SetText(""); - end) - - SGI_Filters.editBoxVC:SetScript("OnEnter", function(self) - SGI_Filters.tooltip.text:SetText(SGI.L["Enter the maximum amount of consecutive vowels and consonants a player's name can contain.\n\nExample: |cff00ff003|r:|cff00A2FF5|r\n\nThis would cause players with more than |cff00ff003|r vowels in a row or more than |cff00A2FF5|r consonants in a row not to be queued."]); - SGI_Filters.tooltip.text:SetWidth(135); - SGI_Filters.tooltip:SetHeight(SGI_Filters.tooltip.text:GetHeight() + 12); - SGI_Filters.tooltip:SetPoint("TOP", self, "BOTTOM", 0, -5); - SGI_Filters.tooltip:Show(); - end) - SGI_Filters.editBoxVC:SetScript("OnLeave", function() - SGI_Filters.tooltip:Hide() - end) - - SGI_Filters.editBoxVC.title = SGI_Filters.editBoxVC:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - SGI_Filters.editBoxVC.title:SetPoint("BOTTOMLEFT", SGI_Filters.editBoxVC,"TOPLEFT", 0, 5); - SGI_Filters.editBoxVC.title:SetText("Max Vowels/Cons (V:C)"); - - SGI_EditBoxName:SetScript("OnEnterPressed", function() - SGI_EditBoxNameFilter:SetFocus(); - end); - SGI_EditBoxNameFilter:SetScript("OnEnterPressed", function() - SGI_EditBoxLvl:SetFocus(); - end); - SGI_EditBoxLvl:SetScript("OnEnterPressed", function() - SGI_EditBoxVC:SetFocus(); - end); - SGI_EditBoxVC:SetScript("OnEnterPressed", function() - SGI_EditBoxName:SetFocus(); - end); - SGI_EditBoxName:SetScript("OnTabPressed", function() - SGI_EditBoxNameFilter:SetFocus(); - end); - SGI_EditBoxNameFilter:SetScript("OnTabPressed", function() - SGI_EditBoxLvl:SetFocus(); - end); - SGI_EditBoxLvl:SetScript("OnTabPressed", function() - SGI_EditBoxVC:SetFocus(); - end); - SGI_EditBoxVC:SetScript("OnTabPressed", function() - SGI_EditBoxName:SetFocus(); - end); - - local CLASS = { - [SGI.L["Death Knight"]] = "DEATHKNIGHT", - [SGI.L["Demon Hunter"]] = "DEMONHUNTER", - [SGI.L["Druid"]] = "DRUID", - [SGI.L["Hunter"]] = "HUNTER", - [SGI.L["Mage"]] = "MAGE", - [SGI.L["Monk"]] = "MONK", - [SGI.L["Paladin"]] = "PALADIN", - [SGI.L["Priest"]] = "PRIEST", - [SGI.L["Rogue"]] = "ROGUE", - [SGI.L["Shaman"]] = "SHAMAN", - [SGI.L["Warlock"]] = "WARLOCK", - [SGI.L["Warrior"]] = "WARRIOR" - } - local Classes = { - SGI.L["Ignore"], - SGI.L["Death Knight"], - SGI.L["Demon Hunter"], - SGI.L["Druid"], - SGI.L["Hunter"], - SGI.L["Mage"], - SGI.L["Monk"], - SGI.L["Paladin"], - SGI.L["Priest"], - SGI.L["Rogue"], - SGI.L["Shaman"], - SGI.L["Warlock"], - SGI.L["Warrior"], - } - local Races = {} - if UnitFactionGroup("player") == "Horde" then - Races = { - SGI.L["Ignore"], - SGI.L["Orc"], - SGI.L["Blood Elf"], - SGI.L["Undead"], - SGI.L["Troll"], - SGI.L["Goblin"], - SGI.L["Tauren"], - SGI.L["Pandaren"], - SGI.L["Highmountain Tauren"], - SGI.L["Nightborne"], - } - else - Races = { - SGI.L["Ignore"], - SGI.L["Human"], - SGI.L["Dwarf"], - SGI.L["Worgen"], - SGI.L["Draenei"], - SGI.L["Night Elf"], - SGI.L["Gnome"], - SGI.L["Pandaren"], - SGI.L["Void Elf"], - SGI.L["Lightforged Draenei"], - } - end - - SGI_Filters.classText = SGI_Filters:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - SGI_Filters.raceText = SGI_Filters:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - - SGI_Filters.classCheckBoxes = {}; - local anchor = { - point = "TOPLEFT", - relativePoint = "TOPLEFT", - xOfs = 40, - yOfs = -90, - } - for k,_ in pairs(Classes) do - SGI_Filters.classCheckBoxes[k] = CreateCheckbox("CHECKBOX_FILTERS_CLASS_"..Classes[k], SGI_Filters, Classes[k], anchor) - - anchor.yOfs = anchor.yOfs - 18; - end - SGI_Filters.classText:SetPoint("BOTTOM", SGI_Filters.classCheckBoxes[1], "TOP", -5, 3); - SGI_Filters.classText:SetText(SGI.L["Classes:"]); - - if (SGI_Filters.classCheckBoxes[1]:GetChecked()) then - for i = 2,12 do - SGI_Filters.classCheckBoxes[i]:Hide(); - end - else - for i = 2,12 do - SGI_Filters.classCheckBoxes[i]:Show(); - end - end - - SGI_Filters.classCheckBoxes[1]:HookScript("PostClick", function() - if (SGI_Filters.classCheckBoxes[1]:GetChecked()) then - for i = 2,12 do - SGI_Filters.classCheckBoxes[i]:Hide(); - end - else - for i = 2,12 do - SGI_Filters.classCheckBoxes[i]:Show(); - end - end - end) - - - SGI_Filters.raceCheckBoxes = {}; - anchor = { - point = "TOPLEFT", - relativePoint = "TOPLEFT", - xOfs = 160, - yOfs = -90, - } - for k,_ in pairs(Races) do - SGI_Filters.raceCheckBoxes[k] = CreateCheckbox("CHECKBOX_FILTERS_RACE_"..Races[k], SGI_Filters, Races[k], anchor) - anchor.yOfs = anchor.yOfs - 18; - end - - SGI_Filters.raceText:SetPoint("BOTTOM", SGI_Filters.raceCheckBoxes[1], "TOP", -5, 3); - SGI_Filters.raceText:SetText(SGI.L["Races:"]); - - if (SGI_Filters.raceCheckBoxes[1]:GetChecked()) then - for i = 2,8 do - SGI_Filters.raceCheckBoxes[i]:Hide(); - end - else - for i = 2,8 do - SGI_Filters.raceCheckBoxes[i]:Show(); - end - end - - SGI_Filters.raceCheckBoxes[1]:HookScript("PostClick", function() - if (SGI_Filters.raceCheckBoxes[1]:GetChecked()) then - for i = 2,8 do - SGI_Filters.raceCheckBoxes[i]:Hide(); - end - else - for i = 2,8 do - SGI_Filters.raceCheckBoxes[i]:Show(); - end - end - end) - - - local function GetFilterData() - local FilterName = SGI_EditBoxName:GetText(); - SGI_EditBoxName:SetText(""); - if (not FilterName or strlen(FilterName) < 1) then - return; - end - SGI:debug("Filter name: "..FilterName); - local V,C = SGI_EditBoxVC:GetText(); - if (V and strlen(V) > 1) then - V,C = strsplit(":", V); - V = tonumber(V); - C = tonumber(C); - if (V == "") then V = nil end - if (C == "") then C = nil end - SGI:debug("Max Vowels: "..(V or "N/A")..", Max Consonants: "..(C or "N/A")); - end - SGI_EditBoxVC:SetText(""); - local Min,Max = SGI_EditBoxLvl:GetText(); - if (Min and strlen(Min) > 1) then - Min, Max = strsplit(":",Min); - Min = tonumber(Min); - Max = tonumber(Max); - SGI:debug("Level range: "..Min.." - "..Max); - end - SGI_EditBoxLvl:SetText(""); - - local ExceptionName = SGI_EditBoxNameFilter:GetText() - if (ExceptionName == "") then - ExceptionName = nil; - end - SGI_EditBoxNameFilter:SetText(""); - - - - local classes = {}; - if (not SGI_Filters.classCheckBoxes[1]:GetChecked()) then - for k,_ in pairs(SGI_Filters.classCheckBoxes) do - if (SGI_Filters.classCheckBoxes[k]:GetChecked()) then - classes[CLASS[SGI_Filters.classCheckBoxes[k].label:GetText()]] = true; - SGI:debug(CLASS[SGI_Filters.classCheckBoxes[k].label:GetText()]); - SGI_Filters.classCheckBoxes[k]:SetChecked(false); - end - end - end - - local races = {} - if (not SGI_Filters.raceCheckBoxes[1]:GetChecked()) then - for k,_ in pairs(SGI_Filters.raceCheckBoxes) do - if (SGI_Filters.raceCheckBoxes[k]:GetChecked()) then - races[SGI_Filters.raceCheckBoxes[k].label:GetText()] = true; - SGI:debug(SGI_Filters.raceCheckBoxes[k].label:GetText()); - SGI_Filters.raceCheckBoxes[k]:SetChecked(false); - end - end - end - SGI:CreateFilter(FilterName,classes,ExceptionName,Min,Max,races,V,C); - SGI_FilterHandle.needRedraw = true; - return true; - end - - anchor = { - point = "BOTTOM", - relativePoint = "BOTTOM", - xOfs = -60, - yOfs = 20, - } - - - SGI_Filters.button1 = CreateButton("BUTTON_SAVE_FILTER", SGI_Filters, 120, 30, SGI.L["Save"], anchor, GetFilterData); - anchor.xOfs = 60; - SGI_Filters.button2 = CreateButton("BUTTON_CANCEL_FILTER", SGI_Filters, 120, 30, SGI.L["Back"], anchor, function() SGI_Filters:Hide() end); - - SGI_Filters:HookScript("OnHide", function() SGI:ShowFilterHandle() SGI_FilterHandle.showOpt = true end); - -end - -local function ShowFilterFrame() - if (not SGI_Filters) then - CreateFilterFrame(); - end - SGI_Filters:Show(); -end - - -local function CreateFilterHandleFrame() - CreateFrame("Frame","SGI_FilterHandle") - SGI_FilterHandle:SetWidth(450) - SGI_FilterHandle:SetHeight(350) - SetFramePosition(SGI_FilterHandle) - SGI_FilterHandle:SetMovable(true) - SGI_FilterHandle:SetScript("OnMouseDown",function(self) - self:StartMoving() - end) - SGI_FilterHandle:SetScript("OnMouseUp",function(self) - self:StopMovingOrSizing() - SaveFramePosition(SGI_FilterHandle) - end) - local backdrop = - { - bgFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Background", - edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border", - tile = true, - tileSize = 16, - edgeSize = 16, - insets = { left = 4, right = 4, top = 4, bottom = 4 } - } - SGI_FilterHandle:SetBackdrop(backdrop) - local close = CreateFrame("Button",nil,SGI_FilterHandle,"UIPanelCloseButton") - close:SetPoint("TOPRIGHT",SGI_FilterHandle,"TOPRIGHT",-4,-4) - - SGI_FilterHandle.title = SGI_FilterHandle:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") - SGI_FilterHandle.title:SetText("Filters") - SGI_FilterHandle.title:SetPoint("TOP",SGI_FilterHandle,"TOP",0,-15) - SGI_FilterHandle.underTitle = SGI_FilterHandle:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - SGI_FilterHandle.underTitle:SetText("Click to toggle"); - SGI_FilterHandle.underTitle:SetPoint("TOP", SGI_FilterHandle, "TOP", 0, -35); - - local anchor = {} - anchor.point = "BOTTOM" - anchor.relativePoint = "BOTTOM" - anchor.xOfs = -60 - anchor.yOfs = 30 - - SGI_FilterHandle.button1 = CreateButton("BUTTON_EDIT_FILTERS", SGI_FilterHandle, 120, 30, SGI.L["Add filters"], anchor, function() ShowFilterFrame() SGI_FilterHandle.showOpt = false SGI_FilterHandle.showSelf = true SGI_FilterHandle:Hide() end); - anchor.xOfs = 60 - SGI_FilterHandle.button2 = CreateButton("BUTTON_EDIT_FILTERS", SGI_FilterHandle, 120, 30, SGI.L["Back"], anchor, function() close:Click() end); - - - SGI_FilterHandle.tooltip = CreateFrame("Frame", "SGI_HandleTooltip", SGI_FilterHandle, "GameTooltipTemplate"); - SGI_FilterHandle.tooltip:SetWidth(150); - SGI_FilterHandle.tooltip.text = SGI_FilterHandle.tooltip:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - SGI_FilterHandle.tooltip.text:SetPoint("CENTER", SGI_FilterHandle.tooltip, "CENTER", 0, 0); - SGI_FilterHandle.tooltip.text:SetJustifyH("LEFT"); - - local function FormatTooltipFilterText(filter) - local text = "Filter name: "..filter.nameOfFilter.."\n"; - - if (filter.active) then - text = text.."|cff00ff00[ACTIVE]|r\n"; - else - text = text.."|cffff0000[INACTIVE]|r\n"; - end - - if (filter.class) then - for k,v in pairs(filter.class) do - text = text.."|cff"..(SGI:GetClassColor(k)..k).."|r\n"; - end - end - - if (filter.race) then - for k,v in pairs(filter.race) do - text = text.."|cff16ABB5"..k.."|r\n"; - end - end - - if (filter.minLvl and filter.minLvl ~= "") then - text = text.."|cff00ff00"..filter.minLvl.."|r - "; - if (filter.maxLvl) then - text = text.."|cffff0000"..filter.maxLvl.."|r\n"; - else - text = text.."\n"; - end - end - - if (filter.maxVowels and filter.maxVowels ~= "") then - text = text.."Vowels: |cff16ABB5"..filter.maxVowels.."|r\n"; - end - - if (filter.maxConsonants and filter.maxVowels ~= "") then - text = text.."Consonants: |cff16ABB5"..filter.maxConsonants.."|r\n"; - end - - if (filter.name and filter.name ~= "") then - text = text.."Name exception: |cff16ABB5"..filter.name.."|r"; - end - - return text; - end - - SGI_FilterHandle.filterFrames = {} - SGI_FilterHandle.update = 0; - SGI_FilterHandle.needRedraw = false; - SGI_FilterHandle:SetScript("OnUpdate", function(self) - if (SGI_FilterHandle.update < GetTime()) then - - local anchor = {} - anchor.xOfs = -175 - anchor.yOfs = 110 - - local F = SGI_DATA[SGI_DATA_INDEX].settings.filters; - - if (SGI_FilterHandle.needRedraw) then - for k,_ in pairs(SGI_FilterHandle.filterFrames) do - SGI_FilterHandle.filterFrames[k]:Hide(); - end - SGI_FilterHandle.filterFrames = {}; - SGI_FilterHandle.needRedraw = false; - end - - for k,_ in pairs(F) do - if (not SGI_FilterHandle.filterFrames[k]) then - SGI_FilterHandle.filterFrames[k] = CreateFrame("Button", "FilterFrame"..k, SGI_FilterHandle); - SGI_FilterHandle.filterFrames[k]:SetWidth(80) - SGI_FilterHandle.filterFrames[k]:SetHeight(25); - SGI_FilterHandle.filterFrames[k]:EnableMouse(true); - SGI_FilterHandle.filterFrames[k]:SetPoint("CENTER", SGI_FilterHandle, "CENTER", anchor.xOfs, anchor.yOfs); - if mod(k,5) == 0 then - anchor.xOfs = -175 - anchor.yOfs = anchor.yOfs - 30 - else - anchor.xOfs = anchor.xOfs + 85 - end - SGI_FilterHandle.filterFrames[k].text = SGI_FilterHandle.filterFrames[k]:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - SGI_FilterHandle.filterFrames[k].text:SetPoint("LEFT", SGI_FilterHandle.filterFrames[k], "LEFT", 3, 0); - SGI_FilterHandle.filterFrames[k].text:SetJustifyH("LEFT"); - SGI_FilterHandle.filterFrames[k].text:SetWidth(75); - SGI_FilterHandle.filterFrames[k]:EnableMouse(true); - SGI_FilterHandle.filterFrames[k]:RegisterForClicks("LeftButtonDown","RightButtonDown"); - SGI_FilterHandle.filterFrames[k].highlight = SGI_FilterHandle.filterFrames[k]:CreateTexture(); - SGI_FilterHandle.filterFrames[k].highlight:SetAllPoints(); - if (SGI_DATA[SGI_DATA_INDEX].settings.filters[k].active) then - SGI_FilterHandle.filterFrames[k].highlight:SetTexture(0,1,0,0.2); - else - SGI_FilterHandle.filterFrames[k].highlight:SetTexture(1,0,0,0.2); - end - SGI_FilterHandle.filterFrames[k]:SetScript("OnEnter", function(self) - self.highlight:SetTexture(1,1,0,0.2); - SGI:debug("Enter: YELLOW"); - - SGI_FilterHandle.tooltip.text:SetText(FormatTooltipFilterText(F[k])); - SGI_FilterHandle.tooltip:SetPoint("TOP", self, "BOTTOM", 0, -3); - SGI_FilterHandle.tooltip:SetHeight(SGI_FilterHandle.tooltip.text:GetHeight() + 12); - SGI_FilterHandle.tooltip:SetWidth(SGI_FilterHandle.tooltip.text:GetWidth() + 10); - SGI_FilterHandle.tooltip:Show(); - end) - SGI_FilterHandle.filterFrames[k]:SetScript("OnLeave", function(self) - if (F[k] and F[k].active) then--SGI_FilterHandle.filterFrames[k].state) then - SGI_FilterHandle.filterFrames[k].highlight:SetTexture(0,1,0,0.2); - SGI:debug("Leave: GREEN"); - - else - SGI_FilterHandle.filterFrames[k].highlight:SetTexture(1,0,0,0.2); - SGI:debug("Leave: RED"); - end - - SGI_FilterHandle.tooltip:Hide(); - end) - end - - SGI_FilterHandle.filterFrames[k].filter = F[k]; - SGI_FilterHandle.filterFrames[k].text:SetText(F[k].nameOfFilter); - SGI_FilterHandle.filterFrames[k]:Show(); - - SGI_FilterHandle.filterFrames[k]:SetScript("OnClick", function(self, button) - SGI:debug(button); - if (button == "LeftButton") then - if (SGI_DATA[SGI_DATA_INDEX].settings.filters[k].active) then - SGI_DATA[SGI_DATA_INDEX].settings.filters[k].active = nil; - SGI_FilterHandle.filterFrames[k].highlight:SetTexture(1,0,0,0.2); - SGI:debug("Click: RED"); - else - SGI_DATA[SGI_DATA_INDEX].settings.filters[k].active = true; - SGI_FilterHandle.filterFrames[k].highlight:SetTexture(0,1,0,0.2); - SGI:debug("Click: GREEN"); - end - - SGI_FilterHandle.tooltip.text:SetText(FormatTooltipFilterText(F[k])); - SGI_FilterHandle.tooltip:SetPoint("TOP", self, "BOTTOM", 0, -3); - SGI_FilterHandle.tooltip:SetHeight(SGI_FilterHandle.tooltip.text:GetHeight() + 12); - SGI_FilterHandle.tooltip:SetWidth(SGI_FilterHandle.tooltip.text:GetWidth() + 10); - SGI_FilterHandle.tooltip:Show(); - else - SGI_DATA[SGI_DATA_INDEX].settings.filters[k] = nil; - SGI_FilterHandle.needRedraw = true; - end - - end) - - end - - SGI_FilterHandle.update = GetTime() + 1; - end - end) - SGI_FilterHandle.showOpt = true; - SGI_FilterHandle:HookScript("OnHide", function() if SGI_FilterHandle.showOpt then SGI:ShowOptions() end end) -end - -function SGI:ShowFilterHandle() - if (not SGI_FilterHandle) then - CreateFilterHandleFrame(); - end - SGI_FilterHandle:Show() -end - -local function ChangeLog() - CreateFrame("Frame","SGI_ChangeLog") - SGI_ChangeLog:SetWidth(550) - SGI_ChangeLog:SetHeight(350) - SGI_ChangeLog:SetBackdrop( - { - bgFile = "Interface/ACHIEVEMENTFRAME/UI-Achievement-Parchment-Horizontal", - edgeFile = "Interface/Tooltips/UI-Tooltip-Border", - tile = false, - tileSize = 16, - edgeSize = 16, - insets = { left = 4, right = 4, top = 4, bottom = 4 } - } - ) - SetFramePosition(SGI_ChangeLog) - - local anchor = {} - anchor.point = "BOTTOMRIGHT" - anchor.relativePoint = "BOTTOMRIGHT" - anchor.xOfs = -210 - anchor.yOfs = 10 - - SGI_ChangeLog.check1 = CreateCheckbox("SGI_CHANGES",SGI_ChangeLog,SGI.L["Don't show this after new updates"],anchor) - anchor.xOfs = -300 - SGI_ChangeLog.button1 = CreateButton("SGI_CLOSE_CHANGES",SGI_ChangeLog,120,30,SGI.L["Close"],anchor,function() SGI_ChangeLog:Hide() SGI_DATA.showChanges = SGI.VERSION_MAJOR end) - - SGI_ChangeLog.title = SGI_ChangeLog:CreateFontString() - SGI_ChangeLog.title:SetFont("Fonts\\FRIZQT__.TTF",22,"OUTLINE") - SGI_ChangeLog.title:SetText("|cffffff00<|r|cff16ABB5SuperGuildInvite|r|cff00ff00 Recent Changes|r|cffffff00>|r|cffffff00") - SGI_ChangeLog.title:SetPoint("TOP",SGI_ChangeLog,"TOP",0,-12) - - SGI_ChangeLog.version = SGI_ChangeLog:CreateFontString() - SGI_ChangeLog.version:SetFont("Fonts\\FRIZQT__.TTF",16,"OUTLINE") - SGI_ChangeLog.version:SetPoint("TOPLEFT",SGI_ChangeLog,"TOPLEFT",15,-40) - SGI_ChangeLog.version:SetText("") - - SGI_ChangeLog.items = {} - local y = -65 - for i = 1,10 do - SGI_ChangeLog.items[i] = SGI_ChangeLog:CreateFontString() - SGI_ChangeLog.items[i]:SetFont("Fonts\\FRIZQT__.TTF",14,"OUTLINE") - SGI_ChangeLog.items[i]:SetPoint("TOPLEFT",SGI_ChangeLog,"TOPLEFT",30,y) - SGI_ChangeLog.items[i]:SetText("") - SGI_ChangeLog.items[i]:SetJustifyH("LEFT") - SGI_ChangeLog.items[i]:SetSpacing(3) - y = y - 17 - end - SGI_ChangeLog.SetChange = function(changes) - local Y = -65 - SGI_ChangeLog.version:SetText("|cff16ABB5"..changes.version.."|r") - for k,_ in pairs(changes.items) do - SGI_ChangeLog.items[k]:SetText("|cffffff00"..changes.items[k].."|r") - SGI_ChangeLog.items[k]:SetWidth(490) - SGI_ChangeLog.items[k]:SetPoint("TOPLEFT",SGI_ChangeLog,"TOPLEFT",30,Y) - Y = Y - SGI_ChangeLog.items[k]:GetHeight() - 5 - end - end -end - -function SGI:ShowChanges() - if ( SGI_ChangeLog ) then - SGI_ChangeLog:Show() - else - ChangeLog() - SGI_ChangeLog:Show() - end - SGI_ChangeLog.SetChange(SGI.versionChanges); -end - - -local function CreateTroubleShooter() - CreateFrame("Frame","SGI_TroubleShooter") - SGI_TroubleShooter:SetWidth(300) - SGI_TroubleShooter:SetHeight(100) - SetFramePosition(SGI_TroubleShooter) - SGI_TroubleShooter:SetMovable(true) - SGI_TroubleShooter:SetScript("OnMouseDown",function(self) - self:StartMoving() - end) - SGI_TroubleShooter:SetScript("OnMouseUp",function(self) - self:StopMovingOrSizing() - SaveFramePosition(SGI_TroubleShooter) - end) - local backdrop = - { - bgFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Background", - edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border", - tile = true, - tileSize = 16, - edgeSize = 16, - insets = { left = 4, right = 4, top = 4, bottom = 4 } - } - SGI_TroubleShooter:SetBackdrop(backdrop) - local close = CreateFrame("Button",nil,SGI_TroubleShooter,"UIPanelCloseButton") - close:SetPoint("TOPRIGHT",SGI_TroubleShooter,"TOPRIGHT",-4,-4) - - SGI_TroubleShooter.title = SGI_TroubleShooter:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") - SGI_TroubleShooter.title:SetPoint("TOP",SGI_TroubleShooter,"TOP",0,-10) - SGI_TroubleShooter.title:SetText("Common issues") - - - local update = 0; - - SGI_TroubleShooter.items = {}; - SGI_TroubleShooter:SetScript("OnUpdate", function() - if (update < GetTime()) then - - - - - update = GetTime() + 0.5; - end - end) - - - SGI_TroubleShooter:HookScript("OnHide", function() if (SGI_Options.showAgain) then SGI_Options:Show() SGI_Options.showAgain = false end end); -end - -function SGI:ShowTroubleShooter() - if (not SGI_TroubleShooter) then - CreateTroubleShooter(); - end - SGI_TroubleShooter:Show(); -end - - -local function OptBtn2_OnClick() - SGI:ShowSuperScanFrame(); - SSBtn3_OnClick(SGI_SUPERSCAN_PLAYPAUSE2); -end - - -local function CreateOptions() - CreateFrame("Frame","SGI_Options") - SGI_Options:SetWidth(550) - SGI_Options:SetHeight(350) - SetFramePosition(SGI_Options) - SGI_Options:SetMovable(true) - SGI_Options:SetScript("OnMouseDown",function(self) - self:StartMoving() - end) - SGI_Options:SetScript("OnMouseUp",function(self) - self:StopMovingOrSizing() - SaveFramePosition(SGI_Options) - end) - local backdrop = - { - bgFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Background", - edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border", - tile = true, - tileSize = 16, - edgeSize = 16, - insets = { left = 4, right = 4, top = 4, bottom = 4 } - } - SGI_Options:SetBackdrop(backdrop) - local close = CreateFrame("Button",nil,SGI_Options,"UIPanelCloseButton") - close:SetPoint("TOPRIGHT",SGI_Options,"TOPRIGHT",-4,-4) - - SGI_Options.title = SGI_Options:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") - SGI_Options.title:SetText("SuperGuildInvite "..SGI.VERSION_MAJOR..SGI.VERSION_MINOR.." Options") - SGI_Options.title:SetPoint("TOP",SGI_Options,"TOP",0,-15) - SGI_Options.bottom = SGI_Options:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") - SGI_Options.bottom:SetText("Written by Janniie - Stormreaver EU") - SGI_Options.bottom:SetPoint("BOTTOM",SGI_Options,"BOTTOM",0,1) - - SGI_Options.optionHelpText = SGI_Options:CreateFontString(nil, "OVERLAY","GameFontNormal"); - SGI_Options.optionHelpText:SetText("|cff00D2FFScroll to change levels|r"); - SGI_Options.optionHelpText:SetPoint("TOP",SGI_Options,"TOP",100,-40); - - local anchor = {} - anchor.point = "TOPLEFT" - anchor.relativePoint = "TOPLEFT" - anchor.xOfs = 7 - anchor.yOfs = -50 - - local WhisperMode = { - SGI.L["Invite only"], - SGI.L["Invite, then whisper"], - SGI.L["Whisper only"], - } - - local spacing = 25; - - SGI_Options.dropDown1 = CreateDropDown("DROPDOWN_INVITE_MODE", SGI_Options, SGI.L["Invite Mode"], WhisperMode, anchor); - anchor.yOfs = anchor.yOfs - spacing - 7; - anchor.xOfs = anchor.xOfs + 13; - SGI_Options.checkBox1 = CreateCheckbox("CHECKBOX_SGI_MUTE", SGI_Options, SGI.L["Mute SGI"], anchor); - anchor.yOfs = anchor.yOfs - spacing; - SGI_Options.checkBox2 = CreateCheckbox("CHECKBOX_ADV_SCAN", SGI_Options, SGI.L["Advanced scan options"], anchor); - anchor.yOfs = anchor.yOfs - spacing; - SGI_Options.checkBox3 = CreateCheckbox("CHECKBOX_HIDE_SYSTEM", SGI_Options, SGI.L["Hide system messages"], anchor); - anchor.yOfs = anchor.yOfs - spacing; - SGI_Options.checkBox7 = CreateCheckbox("CHECKBOX_HIDE_WHISPER", SGI_Options, SGI.L["Hide outgoing whispers"], anchor); - anchor.yOfs = anchor.yOfs - spacing; - SGI_Options.checkBox4 = CreateCheckbox("CHECKBOX_HIDE_MINIMAP", SGI_Options, SGI.L["Hide minimap button"], anchor); - anchor.yOfs = anchor.yOfs - spacing; - SGI_Options.checkBox5 = CreateCheckbox("CHECKBOX_BACKGROUND_MODE", SGI_Options, SGI.L["Run SuperScan in the background"], anchor); - anchor.yOfs = anchor.yOfs - spacing; - SGI_Options.checkBox6 = CreateCheckbox("CHECKBOX_ENABLE_FILTERS", SGI_Options, SGI.L["Enable filtering"], anchor); - - SGI_Options.checkBox3:HookScript("PostClick", function(self) ChatIntercept:StateSystem(self:GetChecked()) end); - SGI_Options.checkBox7:HookScript("PostClick", function(self) ChatIntercept:StateWhisper(self:GetChecked()) end); - - anchor.point = "BOTTOMLEFT" - anchor.relativePoint = "BOTTOMLEFT" - anchor.xOfs = 20 - anchor.yOfs = 45 - - --onClickTester - SGI_Options.button1 = CreateButton("BUTTON_CUSTOM_WHISPER", SGI_Options, 120, 30, SGI.L["Customize whisper"], anchor, function(self) ShowWhisperFrame() SGI_Options:Hide() SGI_Options.showAgain = true end); - anchor.xOfs = anchor.xOfs + 125; - SGI_Options.button2 = CreateButton("BUTTON_SUPER_SCAN", SGI_Options, 120, 30, SGI.L["SuperScan"], anchor, OptBtn2_OnClick); - anchor.xOfs = anchor.xOfs + 125; - SGI_Options.button3 = CreateButton("BUTTON_INVITE", SGI_Options, 120, 30, format(SGI.L["Invite: %d"],SGI:GetNumQueued()), anchor, SGI.SendGuildInvite); - anchor.xOfs = anchor.xOfs + 125; - SGI_Options.button4 = CreateButton("BUTTON_CHOOSE_INVITES", SGI_Options, 120, 30, SGI.L["Choose invites"], anchor, SGI.ShowInviteList); - anchor.yOfs = 80; - SGI_Options.button5 = CreateButton("BUTTON_EDIT_FILTERS", SGI_Options, 120, 30, SGI.L["Filters"], anchor, function() SGI:ShowFilterHandle() SGI_Options:Hide() end); - anchor.xOfs = anchor.xOfs - 125; - --SGI_Options.button6 = CreateButton("BUTTON_HELP", SGI_Options, 120, 30, SGI.L["Help"],anchor, function() SGI:ShowTroubleShooter() SGI_Options:Hide() SGI_Options.showAgain = true end); - --anchor.xOfs = anchor.xOfs - 125; - SGI_Options.button7 = CreateButton("BUTTON_KEYBIND", SGI_Options, 120, 30, SGI.L["Set Keybind ("..(SGI_DATA[SGI_DATA_INDEX].keyBind and SGI_DATA[SGI_DATA_INDEX].keyBind or "NONE")..")"], anchor, KeyHarvestFrame.GetNewKeybindKey); - anchor.xOfs = anchor.xOfs - 125; - --SGI_Options.button8 = CreateButton("BUTTON_FILTER", SGI_Options, 120, 30, SGI.L["Filters"], anchor, onClickTester); - - - SGI_Options.limitLow = CreateFrame("Frame","SGI_LowLimit",SGI_Options) - SGI_Options.limitLow:SetWidth(40) - SGI_Options.limitLow:SetHeight(40) - SGI_Options.limitLow:SetPoint("CENTER",SGI_Options,"CENTER",20,80) - SGI_Options.limitLow.text = SGI_Options.limitLow:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") - SGI_Options.limitLow.text:SetPoint("CENTER") - SGI_Options.limitLow.texture = SGI_Options.limitLow:CreateTexture() - SGI_Options.limitLow.texture:SetAllPoints() - SGI_Options.limitLow.texture:SetTexture(1,1,0,0.2) - SGI_Options.limitLow.texture:Hide() - SGI_Options.limitTooltip = CreateFrame("Frame","LimitTool",SGI_Options.limitLow,"GameTooltipTemplate") - - SGI_Options.limitTooltip:SetPoint("TOP",SGI_Options.limitLow,"BOTTOM") - SGI_Options.limitTooltip.text = SGI_Options.limitTooltip:CreateFontString(nil,"OVERLAY","GameFontNormal") - SGI_Options.limitTooltip.text:SetPoint("LEFT",SGI_Options.limitTooltip,"LEFT",12,0) - SGI_Options.limitTooltip.text:SetJustifyH("LEFT") - SGI_Options.limitTooltip.text:SetText(SGI.L["Highest and lowest level to search for"]) - SGI_Options.limitTooltip.text:SetWidth(115) - SGI_Options.limitTooltip:SetWidth(130) - SGI_Options.limitTooltip:SetHeight(SGI_Options.limitTooltip.text:GetHeight() + 12) - - SGI_Options.limitLow:SetScript("OnEnter",function() - SGI_Options.limitLow.texture:Show() - SGI_Options.limitTooltip:Show() - end) - SGI_Options.limitLow:SetScript("OnLeave",function() - SGI_Options.limitLow.texture:Hide() - SGI_Options.limitTooltip:Hide() - end) - - SGI_Options.limitHigh = CreateFrame("Frame","SGI_HighLimit",SGI_Options) - SGI_Options.limitHigh:SetWidth(40) - SGI_Options.limitHigh:SetHeight(40) - SGI_Options.limitHigh:SetPoint("CENTER",SGI_Options,"CENTER",60,80) - SGI_Options.limitHigh.text = SGI_Options.limitHigh:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") - SGI_Options.limitHigh.text:SetPoint("CENTER") - SGI_Options.limitHigh.texture = SGI_Options.limitHigh:CreateTexture() - SGI_Options.limitHigh.texture:SetAllPoints() - SGI_Options.limitHigh.texture:SetTexture(1,1,0,0.2) - SGI_Options.limitHigh.texture:Hide() - - SGI_Options.limitHigh:SetScript("OnEnter",function() - SGI_Options.limitHigh.texture:Show() - SGI_Options.limitTooltip:Show() - end) - SGI_Options.limitHigh:SetScript("OnLeave",function() - SGI_Options.limitHigh.texture:Hide() - SGI_Options.limitTooltip:Hide() - end) - - SGI_Options.limitLow.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.lowLimit.." - ") - SGI_Options.limitLow:SetScript("OnMouseWheel",function(self,delta) - if delta == 1 and SGI_DATA[SGI_DATA_INDEX].settings.lowLimit + 1 <= SGI_DATA[SGI_DATA_INDEX].settings.highLimit then - SGI_DATA[SGI_DATA_INDEX].settings.lowLimit = SGI_DATA[SGI_DATA_INDEX].settings.lowLimit + 1 - SGI_Options.limitLow.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.lowLimit.." - ") - elseif delta == -1 and SGI_DATA[SGI_DATA_INDEX].settings.lowLimit - 1 >= SGI_MIN_LEVEL_SUPER_SCAN then - SGI_DATA[SGI_DATA_INDEX].settings.lowLimit = SGI_DATA[SGI_DATA_INDEX].settings.lowLimit - 1 - SGI_Options.limitLow.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.lowLimit.." - ") - end - end) - - SGI_Options.limitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.highLimit) - SGI_Options.limitHigh:SetScript("OnMouseWheel",function(self,delta) - if delta == 1 and SGI_DATA[SGI_DATA_INDEX].settings.highLimit + 1 <= SGI_MAX_LEVEL_SUPER_SCAN then - SGI_DATA[SGI_DATA_INDEX].settings.highLimit = SGI_DATA[SGI_DATA_INDEX].settings.highLimit + 1 - SGI_Options.limitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.highLimit) - elseif delta == -1 and SGI_DATA[SGI_DATA_INDEX].settings.highLimit > SGI_DATA[SGI_DATA_INDEX].settings.lowLimit then - SGI_DATA[SGI_DATA_INDEX].settings.highLimit = SGI_DATA[SGI_DATA_INDEX].settings.highLimit - 1 - SGI_Options.limitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.highLimit) - end - end) - - SGI_Options.limitText = SGI_Options.limitLow:CreateFontString(nil,"OVERLAY","GameFontNormal") - SGI_Options.limitText:SetPoint("BOTTOM",SGI_Options.limitLow,"TOP",16,3) - SGI_Options.limitText:SetText(SGI.L["Level limits"]) - - SGI_Options.raceLimitHigh = CreateFrame("Frame","SGI_RaceLimitHigh",SGI_Options) - SGI_Options.raceLimitHigh:SetWidth(40) - SGI_Options.raceLimitHigh:SetHeight(40) - SGI_Options.raceLimitHigh:SetPoint("CENTER",SGI_Options,"CENTER",150,80) - SGI_Options.raceLimitHigh.text = SGI_Options.raceLimitHigh:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") - SGI_Options.raceLimitHigh.text:SetPoint("CENTER") - SGI_Options.raceLimitHigh.texture = SGI_Options.raceLimitHigh:CreateTexture() - SGI_Options.raceLimitHigh.texture:SetAllPoints() - SGI_Options.raceLimitHigh.texture:SetTexture(1,1,0,0.2) - SGI_Options.raceLimitHigh.texture:Hide() - SGI_Options.raceTooltip = CreateFrame("Frame","LimitTool",SGI_Options.raceLimitHigh,"GameTooltipTemplate") - - SGI_Options.raceTooltip:SetPoint("TOP",SGI_Options.raceLimitHigh,"BOTTOM") - SGI_Options.raceTooltip.text = SGI_Options.raceTooltip:CreateFontString(nil,"OVERLAY","GameFontNormal") - SGI_Options.raceTooltip.text:SetPoint("LEFT",SGI_Options.raceTooltip,"LEFT",12,0) - SGI_Options.raceTooltip.text:SetJustifyH("LEFT") - SGI_Options.raceTooltip.text:SetText(SGI.L["The level you wish to start dividing the search by race"]) - SGI_Options.raceTooltip.text:SetWidth(110) - SGI_Options.raceTooltip:SetWidth(125) - SGI_Options.raceTooltip:SetHeight(SGI_Options.raceTooltip.text:GetHeight() + 12) - - SGI_Options.raceLimitText = SGI_Options.raceLimitHigh:CreateFontString(nil,"OVERLAY","GameFontNormal") - SGI_Options.raceLimitText:SetPoint("BOTTOM",SGI_Options.raceLimitHigh,"TOP",0,3) - SGI_Options.raceLimitText:SetText(SGI.L["Racefilter Start:"]) - - SGI_Options.raceLimitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.raceStart) - SGI_Options.raceLimitHigh:SetScript("OnMouseWheel",function(self,delta) - if delta == -1 and SGI_DATA[SGI_DATA_INDEX].settings.raceStart > 1 then - SGI_DATA[SGI_DATA_INDEX].settings.raceStart = SGI_DATA[SGI_DATA_INDEX].settings.raceStart - 1 - SGI_Options.raceLimitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.raceStart) - elseif delta == 1 and SGI_DATA[SGI_DATA_INDEX].settings.raceStart < SGI_MAX_LEVEL_SUPER_SCAN + 1 then - SGI_DATA[SGI_DATA_INDEX].settings.raceStart = SGI_DATA[SGI_DATA_INDEX].settings.raceStart + 1 - SGI_Options.raceLimitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.raceStart) - if SGI_DATA[SGI_DATA_INDEX].settings.raceStart > SGI_MAX_LEVEL_SUPER_SCAN then - SGI_Options.raceLimitHigh.text:SetText(SGI.L["OFF"]) - end - end - end) - - SGI_Options.raceLimitHigh:SetScript("OnEnter",function() - SGI_Options.raceLimitHigh.texture:Show() - SGI_Options.raceTooltip:Show() - end) - SGI_Options.raceLimitHigh:SetScript("OnLeave",function() - SGI_Options.raceLimitHigh.texture:Hide() - SGI_Options.raceTooltip:Hide() - end) - - SGI_Options.classLimitHigh = CreateFrame("Frame","SGI_ClassLimitHigh",SGI_Options) - SGI_Options.classLimitHigh:SetWidth(40) - SGI_Options.classLimitHigh:SetHeight(40) - SGI_Options.classLimitHigh:SetPoint("CENTER",SGI_Options,"CENTER",150,10) - SGI_Options.classLimitHigh.text = SGI_Options.classLimitHigh:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") - SGI_Options.classLimitHigh.text:SetPoint("CENTER") - SGI_Options.classLimitHigh.texture = SGI_Options.classLimitHigh:CreateTexture() - SGI_Options.classLimitHigh.texture:SetAllPoints() - SGI_Options.classLimitHigh.texture:SetTexture(1,1,0,0.2) - SGI_Options.classLimitHigh.texture:Hide() - SGI_Options.classTooltip = CreateFrame("Frame","LimitTool",SGI_Options.classLimitHigh,"GameTooltipTemplate") - - SGI_Options.classTooltip:SetPoint("TOP",SGI_Options.classLimitHigh,"BOTTOM") - SGI_Options.classTooltip.text = SGI_Options.classTooltip:CreateFontString(nil,"OVERLAY","GameFontNormal") - SGI_Options.classTooltip.text:SetPoint("LEFT",SGI_Options.classTooltip,"LEFT",12,0) - SGI_Options.classTooltip.text:SetJustifyH("LEFT") - SGI_Options.classTooltip.text:SetText(SGI.L["The level you wish to divide the search by class"]) - SGI_Options.classTooltip.text:SetWidth(110) - - SGI_Options.classTooltip:SetWidth(125) - SGI_Options.classTooltip:SetHeight(SGI_Options.classTooltip.text:GetHeight() + 12) - - SGI_Options.classLimitText = SGI_Options.classLimitHigh:CreateFontString(nil,"OVERLAY","GameFontNormal") - SGI_Options.classLimitText:SetPoint("BOTTOM",SGI_Options.classLimitHigh,"TOP",0,3) - SGI_Options.classLimitText:SetText(SGI.L["Classfilter Start:"]) - - SGI_Options.classLimitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.classStart) - SGI_Options.classLimitHigh:SetScript("OnMouseWheel",function(self,delta) - if delta == -1 and SGI_DATA[SGI_DATA_INDEX].settings.classStart > 1 then - SGI_DATA[SGI_DATA_INDEX].settings.classStart = SGI_DATA[SGI_DATA_INDEX].settings.classStart - 1 - SGI_Options.classLimitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.classStart) - elseif delta == 1 and SGI_DATA[SGI_DATA_INDEX].settings.classStart < SGI_MAX_LEVEL_SUPER_SCAN + 1 then - SGI_DATA[SGI_DATA_INDEX].settings.classStart = SGI_DATA[SGI_DATA_INDEX].settings.classStart + 1 - SGI_Options.classLimitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.classStart) - if SGI_DATA[SGI_DATA_INDEX].settings.classStart > SGI_MAX_LEVEL_SUPER_SCAN then - SGI_Options.classLimitHigh.text:SetText(SGI.L["OFF"]) - end - end - end) - - SGI_Options.classLimitHigh:SetScript("OnEnter",function() - SGI_Options.classLimitHigh.texture:Show() - SGI_Options.classTooltip:Show() - end) - SGI_Options.classLimitHigh:SetScript("OnLeave",function() - SGI_Options.classLimitHigh.texture:Hide() - SGI_Options.classTooltip:Hide() - end) - - SGI_Options.Interval = CreateFrame("Frame","SGI_Interval",SGI_Options) - SGI_Options.Interval:SetWidth(40) - SGI_Options.Interval:SetHeight(40) - SGI_Options.Interval:SetPoint("CENTER",SGI_Options,"CENTER",40,10) - SGI_Options.Interval.text = SGI_Options.Interval:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") - SGI_Options.Interval.text:SetPoint("CENTER") - SGI_Options.Interval.texture = SGI_Options.Interval:CreateTexture() - SGI_Options.Interval.texture:SetAllPoints() - SGI_Options.Interval.texture:SetTexture(1,1,0,0.2) - SGI_Options.Interval.texture:Hide() - SGI_Options.intervalTooltip = CreateFrame("Frame","LimitTool",SGI_Options.Interval,"GameTooltipTemplate") - - SGI_Options.intervalTooltip:SetPoint("TOP",SGI_Options.Interval,"BOTTOM") - SGI_Options.intervalTooltip.text = SGI_Options.intervalTooltip:CreateFontString(nil,"OVERLAY","GameFontNormal") - SGI_Options.intervalTooltip.text:SetPoint("LEFT",SGI_Options.intervalTooltip,"LEFT",12,0) - SGI_Options.intervalTooltip.text:SetJustifyH("LEFT") - SGI_Options.intervalTooltip.text:SetText(SGI.L["Amount of levels to search every 7 seconds (higher numbers increase the risk of capping the search results)"]) - SGI_Options.intervalTooltip.text:SetWidth(130) - SGI_Options.intervalTooltip:SetHeight(120) - SGI_Options.intervalTooltip:SetWidth(135) - SGI_Options.intervalTooltip:SetHeight(SGI_Options.intervalTooltip.text:GetHeight() + 12) - - SGI_Options.intervalText = SGI_Options.Interval:CreateFontString(nil,"OVERLAY","GameFontNormal") - SGI_Options.intervalText:SetPoint("BOTTOM",SGI_Options.Interval,"TOP",0,3) - SGI_Options.intervalText:SetText(SGI.L["Interval:"]) - - SGI_Options.Interval.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.interval) - SGI_Options.Interval:SetScript("OnMouseWheel",function(self,delta) - if delta == -1 and SGI_DATA[SGI_DATA_INDEX].settings.interval > 1 then - SGI_DATA[SGI_DATA_INDEX].settings.interval = SGI_DATA[SGI_DATA_INDEX].settings.interval - 1 - SGI_Options.Interval.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.interval) - elseif delta == 1 and SGI_DATA[SGI_DATA_INDEX].settings.interval < 30 then - SGI_DATA[SGI_DATA_INDEX].settings.interval = SGI_DATA[SGI_DATA_INDEX].settings.interval + 1 - SGI_Options.Interval.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.interval) - end - end) - - SGI_Options.Interval:SetScript("OnEnter",function() - SGI_Options.Interval.texture:Show() - SGI_Options.intervalTooltip:Show() - end) - SGI_Options.Interval:SetScript("OnLeave",function() - SGI_Options.Interval.texture:Hide() - SGI_Options.intervalTooltip:Hide() - end) - - anchor = { - point = "BOTTOMLEFT", - relativePoint = "BOTTOMLEFT", - xOfs = 4, - yOfs = 4, - } - SGI_Options.superScanText = SGI_Options:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); - SGI_Options.superScanText:SetPoint("BOTTOMLEFT", SGI_Options, "BOTTOMLEFT", 35, 10); - SGI_Options.superScanText:SetText("SuperScan"); - SGI_Options.buttonPlayPause = CreateButton("SGI_SUPERSCAN_PLAYPAUSE2", SGI_Options, 40,30,"",anchor,SSBtn3_OnClick); - SGI_SUPERSCAN_PLAYPAUSE2:SetNormalTexture("Interface\\Buttons\\UI-SpellbookIcon-NextPage-Up"); - SGI_SUPERSCAN_PLAYPAUSE2:Hide(); - SGI_Options.superScanText:Hide(); - - SGI_Options.nextUpdate = 0; - SGI_Options:SetScript("OnUpdate", function() - if (SGI_Options.nextUpdate < GetTime()) then - - if SGI_DATA[SGI_DATA_INDEX].settings.classStart > SGI_MAX_LEVEL_SUPER_SCAN then - SGI_Options.classLimitHigh.text:SetText(SGI.L["OFF"]) - end - - if SGI_DATA[SGI_DATA_INDEX].settings.raceStart > SGI_MAX_LEVEL_SUPER_SCAN then - SGI_Options.raceLimitHigh.text:SetText(SGI.L["OFF"]) - end - - if (SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_BACKGROUND_MODE"]) then - SGI_SUPERSCAN_PLAYPAUSE2:Show(); - SGI_Options.superScanText:Show(); - if SuperScanFrame then SuperScanFrame:Hide() end; - else - SGI_SUPERSCAN_PLAYPAUSE2:Hide(); - SGI_Options.superScanText:Hide(); - if (SGI:IsScanning()) then - SGI:ShowSuperScanFrame(); - end - end - - if (SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_ADV_SCAN"]) then - if (not SGI_Options.Interval:IsShown()) then - SGI_Options.Interval:Show(); - end - if (not SGI_Options.classLimitHigh:IsShown()) then - SGI_Options.classLimitHigh:Show(); - end - if (not SGI_Options.raceLimitHigh:IsShown()) then - SGI_Options.raceLimitHigh:Show(); - end - else - SGI_Options.Interval:Hide(); - SGI_Options.classLimitHigh:Hide(); - SGI_Options.raceLimitHigh:Hide(); - end - - BUTTON_INVITE.label:SetText(format(SGI.L["Invite: %d"],SGI:GetNumQueued())); - BUTTON_KEYBIND.label:SetText(SGI.L["Set Keybind ("..(SGI_DATA[SGI_DATA_INDEX].keyBind and SGI_DATA[SGI_DATA_INDEX].keyBind or "NONE")..")"]); - - if (SGI_DATA[SGI_DATA_INDEX].debug) then - SGI_Options.title:SetText("|cffff3300(DEBUG MODE) |rSuperGuildInvite "..SGI.VERSION_MAJOR..SGI.VERSION_MINOR.." Options") - else - SGI_Options.title:SetText("SuperGuildInvite "..SGI.VERSION_MAJOR..SGI.VERSION_MINOR.." Options") - end - - if (not SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_HIDE_MINIMAP"]) then - SGI:ShowMinimapButton(); - else - SGI:HideMinimapButton(); - end - - SGI_Options.nextUpdate = GetTime() + 1; - end - end) - -end - -function SGI:ShowOptions() - if (not SGI_Options) then - CreateOptions(); - end - SGI_Options:Show(); -end - -function SGI:HideOptions() - if (SGI_Options) then - SGI_Options:Hide(); - end -end - - -local function CreateMinimapButton() - local f = CreateFrame("Button","SGI_MiniMapButton",Minimap) - f:SetWidth(32) - f:SetHeight(32) - f:SetFrameStrata("MEDIUM") - f:SetMovable(true) - SetFramePosition(f) - - f:SetNormalTexture("Interface\\AddOns\\SuperGuildInviteReborn\\media\\SGI_MiniMapButton") - f:SetPushedTexture("Interface\\AddOns\\SuperGuildInviteReborn\\media\\SGI_MiniMapButtonPushed") - f:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight") - - local tooltip = CreateFrame("Frame","SGI_TooltTipMini",f,"GameTooltipTemplate") - tooltip:SetPoint("BOTTOMRIGHT",f,"TOPLEFT",0,-3) - local toolstring = tooltip:CreateFontString(nil,"OVERLAY","GameFontNormal") - toolstring:SetPoint("TOPLEFT",tooltip,"TOPLEFT",5,-7) - - local toolstring2 = tooltip:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - local toolstring3 = tooltip:CreateFontString(nil, "OVERLAY", "GameFontNormal"); - toolstring2:SetPoint("TOPLEFT",tooltip,"TOPLEFT",7,-33); - toolstring3:SetPoint("TOPLEFT", tooltip, "TOPLEFT", 7, -46); - toolstring2:SetText(format("ETR: %s",SGI:GetSuperScanTimeLeft())); - toolstring3:SetText(format("%d%% done",floor(SGI:GetPercentageDone()))); - - local tUpdate = 0; - local function UpdateTooltip() - if (tUpdate < GetTime()) then - toolstring:SetText(SGI.LOGO..format("|cff88aaffSuperGuildInvite|r\n|cff16ABB5Queue: %d|r",SGI:GetNumQueued())) - toolstring2:SetText(format("ETR: %s",SGI:GetSuperScanTimeLeft())); - toolstring3:SetText(format("%d%% done",floor(SGI:GetPercentageDone()))); - --SGI:debug(format("ETR: %s",SGI:GetSuperScanETR())); - --SGI:debug(format("%d%% done",floor(SGI:GetPercentageDone()))); - tUpdate = GetTime() + 0.2; - end - end - - toolstring:SetText(SGI.LOGO..format("|cff88aaffSuperGuildInvite|r\n|cff16ABB5Queue: |r|cffffff00%d|r",SGI:GetNumQueued())) - toolstring:SetJustifyH("LEFT"); - tooltip:SetWidth(max(toolstring:GetWidth(),toolstring2:GetWidth(),toolstring3:GetWidth())+ 20) - tooltip:SetHeight(toolstring:GetHeight() + toolstring2:GetHeight() + toolstring3:GetHeight() + 15) - tooltip:Hide() - f:SetScript("OnEnter",function() - toolstring:SetText(SGI.LOGO..format("|cff88aaffSuperGuildInvite|r\n|cff16ABB5Queue: %d|r",SGI:GetNumQueued())) - tooltip:Show() - tooltip:SetScript("OnUpdate",UpdateTooltip); - end) - f:SetScript("OnLeave",function() - tooltip:Hide() - tooltip:SetScript("OnUpdate", nil); - end) - - - local function moveButton(self) - local centerX, centerY = Minimap:GetCenter() - local x, y = GetCursorPosition() - x, y = x / self:GetEffectiveScale() - centerX, y / self:GetEffectiveScale() - centerY - centerX, centerY = math.abs(x), math.abs(y) - centerX, centerY = (centerX / math.sqrt(centerX^2 + centerY^2)) * 85, (centerY / sqrt(centerX^2 + centerY^2)) * 85 - centerX = x < 0 and -centerX or centerX - centerY = y < 0 and -centerY or centerY - self:ClearAllPoints() - self:SetPoint("CENTER", centerX, centerY) - end - - f:SetScript("OnMouseDown",function(self,button) - if button == "RightButton" then - self:SetScript("OnUpdate",moveButton) - end - end) - f:SetScript("OnMouseUp",function(self,button) - self:SetScript("OnUpdate",nil) - SaveFramePosition(self) - end) - f:SetScript("OnClick",function(self,button) - if SGI_Options and SGI_Options:IsShown() then - SGI:HideOptions() - else - SGI:ShowOptions() - end - end) -end - -function SGI:ShowMinimapButton() - if (not SGI_MiniMapButton) then - CreateMinimapButton(); - end - SGI_MiniMapButton:Show(); -end - -function SGI:HideMinimapButton() - if (SGI_MiniMapButton) then - SGI_MiniMapButton:Hide(); - end -end - - - - - - - - -SGI:debug(">> GUI.lua"); + +local function onClickTester(self) + if self then + SGI:print("Click on "..self:GetName()); + end +end + +local function CreateButton(name, parent, width, height, label, anchor, onClick) + local f = CreateFrame("Button", name, parent, "UIPanelButtonTemplate"); + f:SetWidth(width); + f:SetHeight(height); + f.label = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall"); + f.label:SetText(label); + f.label:SetPoint("CENTER"); + f:SetWidth(width - 10); + + if (type(anchor) == "table") then + f:SetPoint(anchor.point,parent,anchor.relativePoint,anchor.xOfs,anchor.yOfs); + end + + f:SetScript("OnClick", onClick); + return f; +end + +local function CreateCheckbox(name, parent, label, anchor) + local f = CreateFrame("CheckButton", name, parent, "ChatConfigCheckButtonTemplate"); --ChatConfigCheckButtonTemplate OptionsBaseCheckButtonTemplate + f.label = f:CreateFontString(nil, "OVERLAY", "GameFontNormal"); + f.label:SetText(label); + f.label:SetPoint("LEFT", f, "RIGHT", 5, 1); + + if (type(anchor) == "table") then + f:SetPoint(anchor.point,parent,anchor.relativePoint,anchor.xOfs,anchor.yOfs); + end + + f:HookScript("OnClick", function(self) + SGI_DATA[SGI_DATA_INDEX].settings.checkBox[name] = self:GetChecked() + end) + if SGI_DATA[SGI_DATA_INDEX].settings.checkBox[name] then + f:SetChecked() + end + return f; +end + +local function CreateDropDown(name, parent, label, items, anchor) + local f = CreateFrame("Button", name, parent, "UIDropDownMenuTemplate"); + f:ClearAllPoints(); + f:SetPoint(anchor.point,parent,anchor.relativePoint,anchor.xOfs,anchor.yOfs) + f:Show() + + f.label = f:CreateFontString(nil, "OVERLAY", "GameFontNormal"); + f.label:SetPoint("BOTTOMLEFT", f, "TOPLEFT", 20, 5); + f.label:SetText(label); + + local function OnClick(self) + UIDropDownMenu_SetSelectedID(f, self:GetID()); + SGI_DATA[SGI_DATA_INDEX].settings.dropDown[name] = self:GetID(); + end + + local function initialize(self, level) + local info = UIDropDownMenu_CreateInfo(); + for k,v in pairs(items) do + info = UIDropDownMenu_CreateInfo(); + info.text = v; + info.value = v; + info.func = OnClick; + UIDropDownMenu_AddButton(info, level); + end + end + + UIDropDownMenu_Initialize(f, initialize) + UIDropDownMenu_SetWidth(f, 100); + UIDropDownMenu_SetButtonWidth(f, 124) + SGI_DATA[SGI_DATA_INDEX].settings.dropDown[name] = SGI_DATA[SGI_DATA_INDEX].settings.dropDown[name] or 1 + UIDropDownMenu_SetSelectedID(f, SGI_DATA[SGI_DATA_INDEX].settings.dropDown[name] or 1) + UIDropDownMenu_JustifyText(f, "LEFT") + return f +end + +local function SetFramePosition(frame) + if (type(SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()]) ~= "table") then + if (frame:GetName() == "SGI_MiniMapButton") then + SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()] = {point = "CENTER", relativePoint = "CENTER", xOfs = -31, yOfs = -31}; + else + frame:SetPoint("CENTER"); + SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()] = {point = "CENTER", relativePoint = "CENTER", xOfs = 0, yOfs = 0}; + return; + end + end + if (frame:GetName() == "SGI_MiniMapButton") then + frame:SetPoint( + SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].point, + Minimap, + SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].relativePoint, + SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].xOfs, + SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].yOfs + ); + else + frame:SetPoint( + SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].point, + UIParent, + SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].relativePoint, + SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].xOfs, + SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()].yOfs + ); + end +end + +local function SaveFramePosition(frame) + if (type(SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()]) ~= "table") then + SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()] = {}; + end + local point, parent, relativePoint, xOfs, yOfs = frame:GetPoint(); + SGI_DATA[SGI_DATA_INDEX].settings.frames[frame:GetName()] = {point = point, relativePoint = relativePoint, xOfs = xOfs, yOfs = yOfs}; +end + + +local function CreateInviteListFrame() + CreateFrame("Frame","SGI_Invites") + local SGI_QUEUE = SGI:GetInviteQueue(); + SGI_Invites:SetWidth(370) + SGI_Invites:SetHeight(20*SGI:CountTable(SGI_QUEUE) + 40) + SGI_Invites:SetMovable(true) + SetFramePosition(SGI_Invites) + SGI_Invites:SetScript("OnMouseDown",function(self) + self:StartMoving() + end) + SGI_Invites:SetScript("OnMouseUp",function(self) + self:StopMovingOrSizing() + SaveFramePosition(SGI_Invites) + end) + local backdrop = + { + bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark", + edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", + tile = true, + tileSize = 16, + edgeSize = 16, + insets = { left = 4, right = 4, top = 4, bottom = 4 } + } + SGI_Invites:SetBackdrop(backdrop) + + SGI_Invites.text = SGI_Invites:CreateFontString(nil,"OVERLAY","GameFontNormal") + SGI_Invites.text:SetPoint("TOP",SGI_Invites,"TOP",-15,-15) + SGI_Invites.text:SetText(SGI.L["Click on the players you wish to invite"]) + SGI_Invites.tooltip = CreateFrame("Frame","InviteTime",SGI_Invites,"GameTooltipTemplate") + + --SGI_Invites.tooltip:SetOwner( WorldFrame, "ANCHOR_NONE" ); + + + SGI_Invites.tooltip.text = SGI_Invites.tooltip:CreateFontString(nil,"OVERLAY","GameFontNormal") + SGI_Invites.tooltip:SetPoint("TOP",SGI_Invites,"BOTTOM",0,-2) + SGI_Invites.tooltip.text:SetText("Unknown") + SGI_Invites.tooltip.text:SetPoint("CENTER") + + local close = CreateFrame("Button",nil,SGI_Invites,"UIPanelCloseButton") + close:SetPoint("TOPRIGHT",SGI_Invites,"TOPRIGHT",-4,-4) + + SGI_Invites.items = {} + local update = 0 + local toolUpdate = 0 + SGI_Invites:SetScript("OnUpdate",function() + if (not SGI_Invites:IsShown() or GetTime() < update) then return end + + SGI_QUEUE = SGI:GetInviteQueue(); + + for k,_ in pairs(SGI_Invites.items) do + SGI_Invites.items[k]:Hide() + end + + local i = 0 + local x,y = 10,-30 + for i = 1,30 do + if not SGI_Invites.items[i] then + SGI_Invites.items[i] = CreateFrame("Button","InviteBar"..i,SGI_Invites) + SGI_Invites.items[i]:SetWidth(350) + SGI_Invites.items[i]:SetHeight(20) + SGI_Invites.items[i]:EnableMouse(true) + SGI_Invites.items[i]:SetPoint("TOP",SGI_Invites,"TOP",0,y) + SGI_Invites.items[i].text = SGI_Invites.items[i]:CreateFontString(nil,"OVERLAY","GameFontNormal") + SGI_Invites.items[i].text:SetPoint("LEFT",SGI_Invites.items[i],"LEFT",3,0) + SGI_Invites.items[i].text:SetJustifyH("LEFT") + SGI_Invites.items[i].text:SetWidth(SGI_Invites.items[i]:GetWidth()-10); + SGI_Invites.items[i].player = "unknown" + SGI_Invites.items[i]:RegisterForClicks("LeftButtonDown","RightButtonDown") + SGI_Invites.items[i]:SetScript("OnClick",SGI.SendGuildInvite) + + SGI_Invites.items[i].highlight = SGI_Invites.items[i]:CreateTexture() + SGI_Invites.items[i].highlight:SetAllPoints() + SGI_Invites.items[i].highlight:SetTexture(1,1,0,0.2) + SGI_Invites.items[i].highlight:Hide() + + SGI_Invites.items[i]:SetScript("OnEnter",function() + SGI_Invites.items[i].highlight:Show() + SGI_Invites.tooltip:Show() + SGI_Invites.items[i]:SetScript("OnUpdate",function() + if GetTime() > toolUpdate and SGI_QUEUE[SGI_Invites.items[i].player] then + SGI_Invites.tooltip.text:SetText("Found |cff"..SGI:GetClassColor(SGI_QUEUE[SGI_Invites.items[i].player].classFile)..SGI_Invites.items[i].player.."|r "..SGI:FormatTime(floor(GetTime()-SGI_QUEUE[SGI_Invites.items[i].player].found)).." ago") + local h,w = SGI_Invites.tooltip.text:GetHeight(),SGI_Invites.tooltip.text:GetWidth() + SGI_Invites.tooltip:SetWidth(w+20) + SGI_Invites.tooltip:SetHeight(h+20) + toolUpdate = GetTime() + 0.1 + end + end) + end) + SGI_Invites.items[i]:SetScript("OnLeave",function() + SGI_Invites.items[i].highlight:Hide() + SGI_Invites.tooltip:Hide() + SGI_Invites.items[i]:SetScript("OnUpdate",nil) + end) + end + y = y - 20 + end + i = 0 + for k,_ in pairs(SGI_QUEUE) do + i = i + 1 + local level,classFile,race,class,found = SGI_QUEUE[k].level, SGI_QUEUE[k].classFile, SGI_QUEUE[k].race, SGI_QUEUE[k].class, SGI_QUEUE[k].found + local Text = i..". |cff"..SGI:GetClassColor(classFile)..k.."|r Lvl "..level.." "..race.." |cff"..SGI:GetClassColor(classFile)..class.."|r" + SGI_Invites.items[i].text:SetText(Text) + SGI_Invites.items[i].player = k + SGI_Invites.items[i]:Show() + if i >= 30 then break end + end + SGI_Invites:SetHeight(i * 20 + 40) + update = GetTime() + 0.5 + end) +end + + +function SGI:ShowInviteList() + if (not SGI_Invites) then + CreateInviteListFrame(); + end + SGI_Invites:Show(); +end + +function SGI:HideInviteList() + if (SGI_Invites) then + SGI_Invites:Hide(); + end +end + + +local function SSBtn3_OnClick(self) + if (SGI:IsScanning()) then + SGI:StopSuperScan(); + self:SetNormalTexture("Interface\\Buttons\\UI-SpellbookIcon-NextPage-Up"); + else + SGI:StartSuperScan(); + self:SetNormalTexture("Interface\\TimeManager\\PauseButton"); + SGI:ShowInviteList(); + end +end + +function SGI:CreateSmallSuperScanFrame() + CreateFrame("Frame", "SuperScanFrame"); + SuperScanFrame:SetWidth(130); + SuperScanFrame:SetHeight(30); + local backdrop = + { + bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark", + edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", + tile = true, + tileSize = 16, + edgeSize = 16, + insets = { left = 4, right = 4, top = 4, bottom = 4 } + } + SetFramePosition(SuperScanFrame) + SuperScanFrame:SetMovable(true) + SuperScanFrame:SetScript("OnMouseDown",function(self) + self:StartMoving() + end) + SuperScanFrame:SetScript("OnMouseUp",function(self) + self:StopMovingOrSizing() + SaveFramePosition(self) + end) + SuperScanFrame:SetBackdrop(backdrop) + + local close = CreateFrame("Button",nil,SuperScanFrame,"UIPanelCloseButton") + close:SetPoint("LEFT",SuperScanFrame,"RIGHT",-5,0) + + SuperScanFrame.time = SuperScanFrame:CreateFontString(nil,"OVERLAY","GameFontNormal") + SuperScanFrame.time:SetPoint("CENTER") + --SuperScanFrame.time:SetText(format("|cff00ff00%d%%|r|cffffff00 %s|r ",0,SGI:GetSuperScanETR())) + + SuperScanFrame.progressTexture = SuperScanFrame:CreateTexture(); + SuperScanFrame.progressTexture:SetPoint("LEFT", 5, 0); + SuperScanFrame.progressTexture:SetHeight(18); + SuperScanFrame.progressTexture:SetWidth(140); +-- SuperScanFrame.progressTexture:SetTexture(1,0.5,0,0.4); + SuperScanFrame.progressTexture:SetTexture(0,0.0,0,0.0); + local anchor = { + point = "TOPLEFT", + relativePoint = "BOTTOMLEFT", + xOfs = 0, + yOfs = 0, + } + + SuperScanFrame.button1 = CreateButton("SGI_INVITE_BUTTON2", SuperScanFrame, 70, 30, format("",SGI:GetNumQueued()), anchor, SGI.SendGuildInvite) + anchor.xOfs = 85; + SuperScanFrame.button2 = CreateButton("SGI_PURGE_QUEUE", SuperScanFrame, 55, 30, "Purge", anchor, SGI.PurgeQueue); + anchor.xOfs = 57; + SuperScanFrame.button2 = CreateButton("SGI_SUPERSCAN_PLAYPAUSE", SuperScanFrame, 40,30,"",anchor,SSBtn3_OnClick); + SGI_SUPERSCAN_PLAYPAUSE:SetNormalTexture("Interface\\TimeManager\\PauseButton"); + + SuperScanFrame.nextUpdate = 0; + SuperScanFrame:SetScript("OnUpdate", function() + if (SuperScanFrame.nextUpdate < GetTime()) then + + SuperScanFrame.button1.label:SetText(format("Invite: %d",SGI:GetNumQueued())); + + if (SGI:IsScanning() and SuperScanFrame.ETR and SuperScanFrame.lastETR) then + local remainingTime = SuperScanFrame.ETR - (GetTime() - SuperScanFrame.lastETR); + local totalScanTime = SGI:GetTotalScanTime(); + local percentageDone = (totalScanTime - remainingTime) / totalScanTime; + SuperScanFrame.time:SetText(format("|cff00ff00%d%%|r|cffffff00 %s|r",100*(percentageDone > 1 and 1 or percentageDone),SGI:FormatTime(remainingTime))) + SuperScanFrame.progressTexture:SetWidth(120 * (percentageDone > 1 and 1 or percentageDone)); + end + + SuperScanFrame.nextUpdate = GetTime() + 0.2; + end + end) + + + SuperScanFrame:Hide(); + -- Interface\Buttons\UI-SpellbookIcon-NextPage-Up + -- Interface\TimeManager\PauseButton +end + +function SGI:GetPercentageDone() + if (SGI:IsScanning() and SuperScanFrame.ETR and SuperScanFrame.lastETR) then + local remainingTime = SuperScanFrame.ETR - (GetTime() - SuperScanFrame.lastETR); + local totalScanTime = SGI:GetTotalScanTime(); + local percentageDone = (totalScanTime - remainingTime) / totalScanTime; + return percentageDone * 100; + end + return 0; +end + +function SGI:GetSuperScanTimeLeft() + if (SGI:IsScanning() and SuperScanFrame.ETR and SuperScanFrame.lastETR) then + return SGI:FormatTime(SuperScanFrame.ETR - (GetTime() - SuperScanFrame.lastETR)); + end + return 0; +end + + +function SGI:ShowSuperScanFrame() + if (SuperScanFrame and not (SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_BACKGROUND_MODE"])) then + SuperScanFrame:Show(); + else + if (SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_BACKGROUND_MODE"]) then + SGI:CreateSmallSuperScanFrame(); + SuperScanFrame:Hide(); + return; + else + SGI:CreateSmallSuperScanFrame(); + SuperScanFrame:Show(); + end + + end +end + +function SGI:HideSuperScanFrame() + if (SuperScanFrame) then + SuperScanFrame:Hide(); + end +end + +local function CreateWhisperDefineFrame() + +end + + + + +--local KeyHarvestFrame = CreateFrame("Frame", "SGI_KeyHarvestFrame"); +--KeyHarvestFrame:SetPoint("CENTER",0,200); +--KeyHarvestFrame:SetWidth(10); +--KeyHarvestFrame:SetHeight(10); +--KeyHarvestFrame.text = KeyHarvestFrame:CreateFontString(nil, "OVERLAY", "MovieSubtitleFont"); +--KeyHarvestFrame.text:SetPoint("CENTER"); +--KeyHarvestFrame.text:SetText("|cff00ff00Press the KEY you wish to bind now!|r"); +--KeyHarvestFrame:Hide(); + +--function KeyHarvestFrame:GetNewKeybindKey() +-- KeyHarvestFrame:Show(); +-- self:SetScript("OnKeyDown", function(self, key) +-- if (SetBindingClick(key, "SGI_INVITE_BUTTON2")) then +-- Alerter:SendAlert("|cff00ff00Successfully bound "..key.." to InviteButton!|r",1.5); +-- SGI:print("Successfully bound "..key.." to InviteButton!"); +-- SGI_DATA[SGI_DATA_INDEX].keyBind = key; +-- BUTTON_KEYBIND.label:SetText("Set Keybind ("..key..")"); +-- else +-- Alerter:SendAlert("|cffff0000Error binding "..key.." to InviteButton!|r",1.5); +-- SGI:print("Error binding "..key.." to InviteButton!"); +-- end +-- self:EnableKeyboard(false); +-- KeyHarvestFrame:Hide(); +-- end) +-- self:EnableKeyboard(true); +-- +--end + +local function CreateWhisperDefineFrame() + CreateFrame("Frame","SGI_Whisper") + local backdrop = + { + bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark", + edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", + tile = true, + tileSize = 16, + edgeSize = 16, + insets = { left = 4, right = 4, top = 4, bottom = 4 } + } + SGI_Whisper:SetWidth(500) + SGI_Whisper:SetHeight(365) + SGI_Whisper:SetBackdrop(backdrop) + SetFramePosition(SGI_Whisper) + SGI_Whisper:SetMovable(true) + SGI_Whisper:SetScript("OnMouseDown",function(self) + self:StartMoving() + end) + SGI_Whisper:SetScript("OnMouseUp",function(self) + self:StopMovingOrSizing() + SaveFramePosition(SGI_Whisper) + end) + + local close = CreateFrame("Button",nil,SGI_Whisper,"UIPanelCloseButton") + close:SetPoint("TOPRIGHT",SGI_Whisper,"TOPRIGHT",-4,-4) + + SGI_Whisper.title = SGI_Whisper:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") + SGI_Whisper.title:SetText(SGI.L["SuperGuildInvite Custom Whisper"]) + SGI_Whisper.title:SetPoint("TOP",SGI_Whisper,"TOP",0,-20) + + SGI_Whisper.info = SGI_Whisper:CreateFontString(nil,"OVERLAY","GameFontNormal") + SGI_Whisper.info:SetPoint("TOPLEFT",SGI_Whisper,"TOPLEFT",33,-55) + SGI_Whisper.info:SetText(SGI.L["WhisperInstructions"]) + SGI_Whisper.info:SetWidth(450) + SGI_Whisper.info:SetJustifyH("LEFT") + + SGI_Whisper.edit = CreateFrame("EditBox",nil,SGI_Whisper) + SGI_Whisper.edit:SetWidth(450) + SGI_Whisper.edit:SetHeight(65) + SGI_Whisper.edit:SetMultiLine(true) + SGI_Whisper.edit:SetPoint("TOPLEFT",SGI_Whisper,"TOPLEFT",35,-110) + SGI_Whisper.edit:SetFontObject("GameFontNormal") + SGI_Whisper.edit:SetTextInsets(10,10,10,10) + SGI_Whisper.edit:SetMaxLetters(256) + SGI_Whisper.edit:SetBackdrop(backdrop) + SGI_Whisper.edit:SetText(SGI_DATA[SGI_DATA_INDEX].settings.whispers[SGI_DATA[SGI_DATA_INDEX].settings.dropDown["SGI_WHISPER_DROP"] or 1] or "") + SGI_Whisper.edit:SetScript("OnHide",function() + SGI_Whisper.edit:SetText(SGI_DATA[SGI_DATA_INDEX].settings.whispers[SGI_DATA[SGI_DATA_INDEX].settings.dropDown["SGI_WHISPER_DROP"] or 1] or "") + end) + SGI_Whisper.edit.text = SGI_Whisper.edit:CreateFontString(nil,"OVERLAY","GameFontNormal") + SGI_Whisper.edit.text:SetPoint("TOPLEFT",SGI_Whisper.edit,"TOPLEFT",10,13) + SGI_Whisper.edit.text:SetText(SGI.L["Enter your whisper"]) + + local yOfs = -20 + SGI_Whisper.status = {} + for i = 1,6 do + SGI_Whisper.status[i] = {} + SGI_Whisper.status[i].box = CreateFrame("Frame",nil,SGI_Whisper) + SGI_Whisper.status[i].box:SetWidth(170) + SGI_Whisper.status[i].box:SetHeight(18) + SGI_Whisper.status[i].box:SetFrameStrata("HIGH") + SGI_Whisper.status[i].box.index = i + SGI_Whisper.status[i].box:SetPoint("LEFT",SGI_Whisper,"CENTER",50,yOfs) + SGI_Whisper.status[i].box:SetScript("OnEnter",function(self) + if SGI_DATA[SGI_DATA_INDEX].settings.whispers[self.index] then + GameTooltip:SetOwner(self,"ANCHOR_CURSOR") + GameTooltip:SetText(SGI:FormatWhisper(SGI_DATA[SGI_DATA_INDEX].settings.whispers[self.index],UnitName("Player"))) + end + end) + SGI_Whisper.status[i].box:SetScript("OnLeave",function(self) + GameTooltip:Hide() + end) + SGI_Whisper.status[i].text = SGI_Whisper:CreateFontString(nil,nil,"GameFontNormal") + SGI_Whisper.status[i].text:SetText("Whisper #"..i.." status: ") + SGI_Whisper.status[i].text:SetWidth(200) + SGI_Whisper.status[i].text:SetJustifyH("LEFT") + SGI_Whisper.status[i].text:SetPoint("LEFT",SGI_Whisper,"CENTER",50,yOfs) + yOfs = yOfs - 18 + end + local whispers = { + "Whisper #1", + "Whisper #2", + "Whisper #3", + "Whisper #4", + "Whisper #5", + "Whisper #6", + } + + anchor = {} + anchor.point = "BOTTOMLEFT" + anchor.relativePoint = "BOTTOMLEFT" + anchor.xOfs = 50 + anchor.yOfs = 120 + + --CreateDropDown(name, parent, label, items, anchor) + SGI_Whisper.drop = CreateDropDown("SGI_WHISPER_DROP",SGI_Whisper,SGI.L["Select whisper"],whispers,anchor) + + anchor.xOfs = 100 + anchor.yOfs = 20 + --CreateButton(name, parent, width, height, label, anchor, onClick) + CreateButton("SGI_SAVEWHISPER",SGI_Whisper,120,30,SGI.L["Save"],anchor,function() + local text = SGI_Whisper.edit:GetText() + local ID = SGI_DATA[SGI_DATA_INDEX].settings.dropDown["SGI_WHISPER_DROP"] + SGI_DATA[SGI_DATA_INDEX].settings.whispers[ID] = text + SGI_Whisper.edit:SetText("") + end) + anchor.xOfs = 280 + CreateButton("SGI_CANCELWHISPER",SGI_Whisper,120,30,SGI.L["Cancel"],anchor,function() + SGI_Whisper:Hide() + end) + + SGI_Whisper.update = 0 + SGI_Whisper.changed = false + SGI_Whisper:SetScript("OnUpdate",function() + if GetTime() > SGI_Whisper.update then + for i = 1,6 do + if type(SGI_DATA[SGI_DATA_INDEX].settings.whispers[i]) == "string" then + SGI_Whisper.status[i].text:SetText("Whisper #"..i.." status: |cff00ff00Good|r") + else + SGI_Whisper.status[i].text:SetText("Whisper #"..i.." status: |cffff0000Undefined|r") + end + end + local ID = SGI_DATA[SGI_DATA_INDEX].settings.dropDown["SGI_WHISPER_DROP"] + SGI_Whisper.status[ID].text:SetText("Whisper #"..ID.." status: |cffff8800Editing...|r") + + if ID ~= SGI_Whisper.changed then + SGI_Whisper.changed = ID + SGI_Whisper.edit:SetText(SGI_DATA[SGI_DATA_INDEX].settings.whispers[SGI_DATA[SGI_DATA_INDEX].settings.dropDown["SGI_WHISPER_DROP"] or 1] or "") + end + + SGI_Whisper.update = GetTime() + 0.5 + end + end) + + SGI_Whisper:HookScript("OnHide", function() if (SGI_Options.showAgain) then SGI:ShowOptions() SGI_Options.showAgain = false end end) +end + +local function ShowWhisperFrame() + if SGI_Whisper then + SGI_Whisper:Show() + else + CreateWhisperDefineFrame() + SGI_Whisper:Show() + end +end + +local function HideWhisperFrame() + if SGI_Whisper then + SGI_Whisper:Hide() + end +end + +local function CreateFilterFrame() + CreateFrame("Frame","SGI_Filters") + SGI_Filters:SetWidth(550) + SGI_Filters:SetHeight(380) + SetFramePosition(SGI_Filters) + SGI_Filters:SetMovable(true) + SGI_Filters:SetScript("OnMouseDown",function(self) + self:StartMoving() + end) + SGI_Filters:SetScript("OnMouseUp",function(self) + self:StopMovingOrSizing() + SaveFramePosition(SGI_Filters) + end) + local backdrop = + { + bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark", + edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", + tile = true, + tileSize = 16, + edgeSize = 16, + insets = { left = 4, right = 4, top = 4, bottom = 4 } + } + SGI_Filters:SetBackdrop(backdrop) + local close = CreateFrame("Button",nil,SGI_Filters,"UIPanelCloseButton") + close:SetPoint("TOPRIGHT",SGI_Filters,"TOPRIGHT",-4,-4) + + SGI_Filters.title = SGI_Filters:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); + SGI_Filters.title:SetPoint("TOP", SGI_Filters, "TOP", 0, -15); + SGI_Filters.title:SetText("Edit filters"); + SGI_Filters.underTitle = SGI_Filters:CreateFontString(nil, "OVERLAY", "GameFontNormal"); + SGI_Filters.underTitle:SetPoint("TOP", SGI_Filters, "TOP", 0, -38); + SGI_Filters.underTitle:SetText("|cffff3300Any textbox left empty, except \"Filter name\" will be excluded from the filter|r"); + SGI_Filters.underTitle:SetWidth(400); + SGI_Filters.bottomText = SGI_Filters:CreateFontString(nil, "OVERLAY", "GameFOntNormal"); + SGI_Filters.bottomText:SetPoint("BOTTOM", SGI_Filters, "BOTTOM", 0, 60); + SGI_Filters.bottomText:SetText("|cff00ff00In order to be filtered, a player has to match |r|cffFF3300ALL|r |cff00ff00criterias|r"); + + SGI_Filters.tooltip = CreateFrame("Frame", "FilterTooltip", SGI_Filters.tooltip, "GameTooltipTemplate"); + + + + + SGI_Filters.tooltip:SetWidth(150); + SGI_Filters.tooltip.text = SGI_Filters.tooltip:CreateFontString(nil, "OVERLAY", "GameFontNormal"); + SGI_Filters.tooltip.text:SetPoint("CENTER", SGI_Filters.tooltip, "CENTER", 0, 0); + SGI_Filters.tooltip.text:SetJustifyH("LEFT"); + + SGI_Filters.editBoxName = CreateFrame("EditBox", "SGI_EditBoxName", SGI_Filters); + SGI_Filters.editBoxName:SetWidth(150); + SGI_Filters.editBoxName:SetHeight(30); + SGI_Filters.editBoxName:SetPoint("TOPRIGHT", SGI_Filters, "TOPRIGHT", -40, -90); + SGI_Filters.editBoxName:SetFontObject("GameFontNormal"); + SGI_Filters.editBoxName:SetMaxLetters(65); + SGI_Filters.editBoxName:SetBackdrop(backdrop); + SGI_Filters.editBoxName:SetText(""); + SGI_Filters.editBoxName:SetTextInsets(10,10,10,10); + SGI_Filters.editBoxName:SetScript("OnHide",function(self) + self:SetText(""); + end) + SGI_Filters.editBoxName.title = SGI_Filters.editBoxName:CreateFontString(nil, "OVERLAY", "GameFontNormal"); + SGI_Filters.editBoxName.title:SetPoint("BOTTOMLEFT", SGI_Filters.editBoxName,"TOPLEFT", 0, 5); + SGI_Filters.editBoxName.title:SetText("Filter name"); + + SGI_Filters.editBoxNameFilter = CreateFrame("EditBox", "SGI_EditBoxNameFilter", SGI_Filters); + SGI_Filters.editBoxNameFilter:SetWidth(150); + SGI_Filters.editBoxNameFilter:SetHeight(30); + SGI_Filters.editBoxNameFilter:SetPoint("TOPRIGHT", SGI_Filters, "TOPRIGHT", -40, -150); + SGI_Filters.editBoxNameFilter:SetFontObject("GameFontNormal"); + SGI_Filters.editBoxNameFilter:SetMaxLetters(65); + SGI_Filters.editBoxNameFilter:SetBackdrop(backdrop); + SGI_Filters.editBoxNameFilter:SetText(""); + SGI_Filters.editBoxNameFilter:SetTextInsets(10,10,10,10); + SGI_Filters.editBoxNameFilter:SetScript("OnHide",function(self) + self:SetText(""); + end) + SGI_Filters.editBoxNameFilter:SetScript("OnEnter", function(self) + SGI_Filters.tooltip.text:SetText(SGI.L["Enter a phrase which you wish to include in the filter. If a player's name contains the phrase, they will not be queued"]); + SGI_Filters.tooltip.text:SetWidth(135); + SGI_Filters.tooltip:SetHeight(SGI_Filters.tooltip.text:GetHeight() + 12); + SGI_Filters.tooltip:SetPoint("TOP", self, "BOTTOM", 0, -5); + SGI_Filters.tooltip:Show(); + end) + SGI_Filters.editBoxNameFilter:SetScript("OnLeave", function() + SGI_Filters.tooltip:Hide() + end) + + SGI_Filters.editBoxNameFilter.title = SGI_Filters.editBoxNameFilter:CreateFontString(nil, "OVERLAY", "GameFontNormal"); + SGI_Filters.editBoxNameFilter.title:SetPoint("BOTTOMLEFT", SGI_Filters.editBoxNameFilter,"TOPLEFT", 0, 5); + SGI_Filters.editBoxNameFilter.title:SetText("Name exceptions"); + + SGI_Filters.editBoxLvl = CreateFrame("EditBox", "SGI_EditBoxLvl", SGI_Filters); + SGI_Filters.editBoxLvl:SetWidth(150); + SGI_Filters.editBoxLvl:SetHeight(30); + SGI_Filters.editBoxLvl:SetPoint("TOPRIGHT", SGI_Filters, "TOPRIGHT", -40, -210); + SGI_Filters.editBoxLvl:SetFontObject("GameFontNormal"); + SGI_Filters.editBoxLvl:SetMaxLetters(65); + SGI_Filters.editBoxLvl:SetBackdrop(backdrop); + SGI_Filters.editBoxLvl:SetText(""); + SGI_Filters.editBoxLvl:SetTextInsets(10,10,10,10); + SGI_Filters.editBoxLvl:SetScript("OnHide",function(self) + self:SetText(""); + end) + SGI_Filters.editBoxLvl:SetScript("OnEnter", function(self) + SGI_Filters.tooltip.text:SetText(SGI.L["Enter the level range for the filter. \n\nExample: |cff00ff0055|r:|cff00A2FF58|r \n\nThis would result in only matching players that range from level |cff00ff0055|r to |cff00A2FF58|r (inclusive)"]); + SGI_Filters.tooltip.text:SetWidth(135); + SGI_Filters.tooltip:SetHeight(SGI_Filters.tooltip.text:GetHeight() + 12); + SGI_Filters.tooltip:SetPoint("TOP", self, "BOTTOM", 0, -5); + SGI_Filters.tooltip:Show(); + end) + SGI_Filters.editBoxLvl:SetScript("OnLeave", function() + SGI_Filters.tooltip:Hide() + end) + + SGI_Filters.editBoxLvl.title = SGI_Filters.editBoxLvl:CreateFontString(nil, "OVERLAY", "GameFontNormal"); + SGI_Filters.editBoxLvl.title:SetPoint("BOTTOMLEFT", SGI_Filters.editBoxLvl,"TOPLEFT", 0, 5); + SGI_Filters.editBoxLvl.title:SetText("Level range (Min:Max)"); + + SGI_Filters.editBoxVC = CreateFrame("EditBox", "SGI_EditBoxVC", SGI_Filters); + SGI_Filters.editBoxVC:SetWidth(150); + SGI_Filters.editBoxVC:SetHeight(30); + SGI_Filters.editBoxVC:SetPoint("TOPRIGHT", SGI_Filters, "TOPRIGHT", -40, -270); + SGI_Filters.editBoxVC:SetFontObject("GameFontNormal"); + SGI_Filters.editBoxVC:SetMaxLetters(65); + SGI_Filters.editBoxVC:SetBackdrop(backdrop); + SGI_Filters.editBoxVC:SetText(""); + SGI_Filters.editBoxVC:SetTextInsets(10,10,10,10); + SGI_Filters.editBoxVC:SetScript("OnHide",function(self) + self:SetText(""); + end) + + SGI_Filters.editBoxVC:SetScript("OnEnter", function(self) + SGI_Filters.tooltip.text:SetText(SGI.L["Enter the maximum amount of consecutive vowels and consonants a player's name can contain.\n\nExample: |cff00ff003|r:|cff00A2FF5|r\n\nThis would cause players with more than |cff00ff003|r vowels in a row or more than |cff00A2FF5|r consonants in a row not to be queued."]); + SGI_Filters.tooltip.text:SetWidth(135); + SGI_Filters.tooltip:SetHeight(SGI_Filters.tooltip.text:GetHeight() + 12); + SGI_Filters.tooltip:SetPoint("TOP", self, "BOTTOM", 0, -5); + SGI_Filters.tooltip:Show(); + end) + SGI_Filters.editBoxVC:SetScript("OnLeave", function() + SGI_Filters.tooltip:Hide() + end) + + SGI_Filters.editBoxVC.title = SGI_Filters.editBoxVC:CreateFontString(nil, "OVERLAY", "GameFontNormal"); + SGI_Filters.editBoxVC.title:SetPoint("BOTTOMLEFT", SGI_Filters.editBoxVC,"TOPLEFT", 0, 5); + SGI_Filters.editBoxVC.title:SetText("Max Vowels/Cons (V:C)"); + + SGI_EditBoxName:SetScript("OnEnterPressed", function() + SGI_EditBoxNameFilter:SetFocus(); + end); + SGI_EditBoxNameFilter:SetScript("OnEnterPressed", function() + SGI_EditBoxLvl:SetFocus(); + end); + SGI_EditBoxLvl:SetScript("OnEnterPressed", function() + SGI_EditBoxVC:SetFocus(); + end); + SGI_EditBoxVC:SetScript("OnEnterPressed", function() + SGI_EditBoxName:SetFocus(); + end); + SGI_EditBoxName:SetScript("OnTabPressed", function() + SGI_EditBoxNameFilter:SetFocus(); + end); + SGI_EditBoxNameFilter:SetScript("OnTabPressed", function() + SGI_EditBoxLvl:SetFocus(); + end); + SGI_EditBoxLvl:SetScript("OnTabPressed", function() + SGI_EditBoxVC:SetFocus(); + end); + SGI_EditBoxVC:SetScript("OnTabPressed", function() + SGI_EditBoxName:SetFocus(); + end); + + local CLASS = { + [SGI.L["Death Knight"]] = "DEATHKNIGHT", + [SGI.L["Demon Hunter"]] = "DEMONHUNTER", + [SGI.L["Druid"]] = "DRUID", + [SGI.L["Hunter"]] = "HUNTER", + [SGI.L["Mage"]] = "MAGE", + [SGI.L["Monk"]] = "MONK", + [SGI.L["Paladin"]] = "PALADIN", + [SGI.L["Priest"]] = "PRIEST", + [SGI.L["Rogue"]] = "ROGUE", + [SGI.L["Shaman"]] = "SHAMAN", + [SGI.L["Warlock"]] = "WARLOCK", + [SGI.L["Warrior"]] = "WARRIOR" + } + local Classes = { + SGI.L["Ignore"], + SGI.L["Death Knight"], + SGI.L["Demon Hunter"], + SGI.L["Druid"], + SGI.L["Hunter"], + SGI.L["Mage"], + SGI.L["Monk"], + SGI.L["Paladin"], + SGI.L["Priest"], + SGI.L["Rogue"], + SGI.L["Shaman"], + SGI.L["Warlock"], + SGI.L["Warrior"], + } + local Races = {} + if UnitFactionGroup("player") == "Horde" then + Races = { + SGI.L["Ignore"], + SGI.L["Orc"], + SGI.L["Blood Elf"], + SGI.L["Undead"], + SGI.L["Troll"], + SGI.L["Goblin"], + SGI.L["Tauren"], + SGI.L["Pandaren"], + SGI.L["Highmountain Tauren"], + SGI.L["Nightborne"], + SGI.L["Mag'har Orc"], + SGI.L["Zandalari Troll"], + } + else + Races = { + SGI.L["Ignore"], + SGI.L["Human"], + SGI.L["Dwarf"], + SGI.L["Worgen"], + SGI.L["Draenei"], + SGI.L["Night Elf"], + SGI.L["Gnome"], + SGI.L["Pandaren"], + SGI.L["Void Elf"], + SGI.L["Lightforged Draenei"], + SGI.L["Dark Iron Dwarf"], + } + end + + SGI_Filters.classText = SGI_Filters:CreateFontString(nil, "OVERLAY", "GameFontNormal"); + SGI_Filters.raceText = SGI_Filters:CreateFontString(nil, "OVERLAY", "GameFontNormal"); + + SGI_Filters.classCheckBoxes = {}; + local anchor = { + point = "TOPLEFT", + relativePoint = "TOPLEFT", + xOfs = 40, + yOfs = -90, + } + for k,_ in pairs(Classes) do + SGI_Filters.classCheckBoxes[k] = CreateCheckbox("CHECKBOX_FILTERS_CLASS_"..Classes[k], SGI_Filters, Classes[k], anchor) + + anchor.yOfs = anchor.yOfs - 18; + end + SGI_Filters.classText:SetPoint("BOTTOM", SGI_Filters.classCheckBoxes[1], "TOP", -5, 3); + SGI_Filters.classText:SetText(SGI.L["Classes:"]); + + if (SGI_Filters.classCheckBoxes[1]:GetChecked()) then + for i = 2,12 do + SGI_Filters.classCheckBoxes[i]:Hide(); + end + else + for i = 2,12 do + SGI_Filters.classCheckBoxes[i]:Show(); + end + end + + SGI_Filters.classCheckBoxes[1]:HookScript("PostClick", function() + if (SGI_Filters.classCheckBoxes[1]:GetChecked()) then + for i = 2,12 do + SGI_Filters.classCheckBoxes[i]:Hide(); + end + else + for i = 2,12 do + SGI_Filters.classCheckBoxes[i]:Show(); + end + end + end) + + + SGI_Filters.raceCheckBoxes = {}; + anchor = { + point = "TOPLEFT", + relativePoint = "TOPLEFT", + xOfs = 160, + yOfs = -90, + } + for k,_ in pairs(Races) do + SGI_Filters.raceCheckBoxes[k] = CreateCheckbox("CHECKBOX_FILTERS_RACE_"..Races[k], SGI_Filters, Races[k], anchor) + anchor.yOfs = anchor.yOfs - 18; + end + + SGI_Filters.raceText:SetPoint("BOTTOM", SGI_Filters.raceCheckBoxes[1], "TOP", -5, 3); + SGI_Filters.raceText:SetText(SGI.L["Races:"]); + + if (SGI_Filters.raceCheckBoxes[1]:GetChecked()) then + for i = 2,8 do + SGI_Filters.raceCheckBoxes[i]:Hide(); + end + else + for i = 2,8 do + SGI_Filters.raceCheckBoxes[i]:Show(); + end + end + + SGI_Filters.raceCheckBoxes[1]:HookScript("PostClick", function() + if (SGI_Filters.raceCheckBoxes[1]:GetChecked()) then + for i = 2,8 do + SGI_Filters.raceCheckBoxes[i]:Hide(); + end + else + for i = 2,8 do + SGI_Filters.raceCheckBoxes[i]:Show(); + end + end + end) + + + local function GetFilterData() + local FilterName = SGI_EditBoxName:GetText(); + SGI_EditBoxName:SetText(""); + if (not FilterName or strlen(FilterName) < 1) then + return; + end + SGI:debug("Filter name: "..FilterName); + local V,C = SGI_EditBoxVC:GetText(); + if (V and strlen(V) > 1) then + V,C = strsplit(":", V); + V = tonumber(V); + C = tonumber(C); + if (V == "") then V = nil end + if (C == "") then C = nil end + SGI:debug("Max Vowels: "..(V or "N/A")..", Max Consonants: "..(C or "N/A")); + end + SGI_EditBoxVC:SetText(""); + local Min,Max = SGI_EditBoxLvl:GetText(); + if (Min and strlen(Min) > 1) then + Min, Max = strsplit(":",Min); + Min = tonumber(Min); + Max = tonumber(Max); + SGI:debug("Level range: "..Min.." - "..Max); + end + SGI_EditBoxLvl:SetText(""); + + local ExceptionName = SGI_EditBoxNameFilter:GetText() + if (ExceptionName == "") then + ExceptionName = nil; + end + SGI_EditBoxNameFilter:SetText(""); + + + + local classes = {}; + if (not SGI_Filters.classCheckBoxes[1]:GetChecked()) then + for k,_ in pairs(SGI_Filters.classCheckBoxes) do + if (SGI_Filters.classCheckBoxes[k]:GetChecked()) then + classes[CLASS[SGI_Filters.classCheckBoxes[k].label:GetText()]] = true; + SGI:debug(CLASS[SGI_Filters.classCheckBoxes[k].label:GetText()]); + SGI_Filters.classCheckBoxes[k]:SetChecked(false); + end + end + end + + local races = {} + if (not SGI_Filters.raceCheckBoxes[1]:GetChecked()) then + for k,_ in pairs(SGI_Filters.raceCheckBoxes) do + if (SGI_Filters.raceCheckBoxes[k]:GetChecked()) then + races[SGI_Filters.raceCheckBoxes[k].label:GetText()] = true; + SGI:debug(SGI_Filters.raceCheckBoxes[k].label:GetText()); + SGI_Filters.raceCheckBoxes[k]:SetChecked(false); + end + end + end + SGI:CreateFilter(FilterName,classes,ExceptionName,Min,Max,races,V,C); + SGI_FilterHandle.needRedraw = true; + return true; + end + + anchor = { + point = "BOTTOM", + relativePoint = "BOTTOM", + xOfs = -60, + yOfs = 20, + } + + + SGI_Filters.button1 = CreateButton("BUTTON_SAVE_FILTER", SGI_Filters, 120, 30, SGI.L["Save"], anchor, GetFilterData); + anchor.xOfs = 60; + SGI_Filters.button2 = CreateButton("BUTTON_CANCEL_FILTER", SGI_Filters, 120, 30, SGI.L["Back"], anchor, function() SGI_Filters:Hide() end); + + SGI_Filters:HookScript("OnHide", function() SGI:ShowFilterHandle() SGI_FilterHandle.showOpt = true end); + +end + +local function ShowFilterFrame() + if (not SGI_Filters) then + CreateFilterFrame(); + end + SGI_Filters:Show(); +end + + +local function CreateFilterHandleFrame() + CreateFrame("Frame","SGI_FilterHandle") + SGI_FilterHandle:SetWidth(450) + SGI_FilterHandle:SetHeight(350) + SetFramePosition(SGI_FilterHandle) + SGI_FilterHandle:SetMovable(true) + SGI_FilterHandle:SetScript("OnMouseDown",function(self) + self:StartMoving() + end) + SGI_FilterHandle:SetScript("OnMouseUp",function(self) + self:StopMovingOrSizing() + SaveFramePosition(SGI_FilterHandle) + end) + local backdrop = + { + bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark", + edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", + tile = true, + tileSize = 16, + edgeSize = 16, + insets = { left = 4, right = 4, top = 4, bottom = 4 } + } + SGI_FilterHandle:SetBackdrop(backdrop) + local close = CreateFrame("Button",nil,SGI_FilterHandle,"UIPanelCloseButton") + close:SetPoint("TOPRIGHT",SGI_FilterHandle,"TOPRIGHT",-4,-4) + + SGI_FilterHandle.title = SGI_FilterHandle:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") + SGI_FilterHandle.title:SetText("Filters") + SGI_FilterHandle.title:SetPoint("TOP",SGI_FilterHandle,"TOP",0,-15) + SGI_FilterHandle.underTitle = SGI_FilterHandle:CreateFontString(nil, "OVERLAY", "GameFontNormal"); + SGI_FilterHandle.underTitle:SetText("Click to toggle"); + SGI_FilterHandle.underTitle:SetPoint("TOP", SGI_FilterHandle, "TOP", 0, -35); + + local anchor = {} + anchor.point = "BOTTOM" + anchor.relativePoint = "BOTTOM" + anchor.xOfs = -60 + anchor.yOfs = 30 + + SGI_FilterHandle.button1 = CreateButton("BUTTON_EDIT_FILTERS", SGI_FilterHandle, 120, 30, SGI.L["Add filters"], anchor, function() ShowFilterFrame() SGI_FilterHandle.showOpt = false SGI_FilterHandle.showSelf = true SGI_FilterHandle:Hide() end); + anchor.xOfs = 60 + SGI_FilterHandle.button2 = CreateButton("BUTTON_EDIT_FILTERS", SGI_FilterHandle, 120, 30, SGI.L["Back"], anchor, function() close:Click() end); + + + SGI_FilterHandle.tooltip = CreateFrame("Frame", "SGI_HandleTooltip", SGI_FilterHandle, "GameTooltipTemplate"); + SGI_FilterHandle.tooltip:SetWidth(150); + SGI_FilterHandle.tooltip.text = SGI_FilterHandle.tooltip:CreateFontString(nil, "OVERLAY", "GameFontNormal"); + SGI_FilterHandle.tooltip.text:SetPoint("CENTER", SGI_FilterHandle.tooltip, "CENTER", 0, 0); + SGI_FilterHandle.tooltip.text:SetJustifyH("LEFT"); + + local function FormatTooltipFilterText(filter) + local text = "Filter name: "..filter.nameOfFilter.."\n"; + + if (filter.active) then + text = text.."|cff00ff00[ACTIVE]|r\n"; + else + text = text.."|cffff0000[INACTIVE]|r\n"; + end + + if (filter.class) then + for k,v in pairs(filter.class) do + text = text.."|cff"..(SGI:GetClassColor(k)..k).."|r\n"; + end + end + + if (filter.race) then + for k,v in pairs(filter.race) do + text = text.."|cff16ABB5"..k.."|r\n"; + end + end + + if (filter.minLvl and filter.minLvl ~= "") then + text = text.."|cff00ff00"..filter.minLvl.."|r - "; + if (filter.maxLvl) then + text = text.."|cffff0000"..filter.maxLvl.."|r\n"; + else + text = text.."\n"; + end + end + + if (filter.maxVowels and filter.maxVowels ~= "") then + text = text.."Vowels: |cff16ABB5"..filter.maxVowels.."|r\n"; + end + + if (filter.maxConsonants and filter.maxVowels ~= "") then + text = text.."Consonants: |cff16ABB5"..filter.maxConsonants.."|r\n"; + end + + if (filter.name and filter.name ~= "") then + text = text.."Name exception: |cff16ABB5"..filter.name.."|r"; + end + + return text; + end + + SGI_FilterHandle.filterFrames = {} + SGI_FilterHandle.update = 0; + SGI_FilterHandle.needRedraw = false; + SGI_FilterHandle:SetScript("OnUpdate", function(self) + if (SGI_FilterHandle.update < GetTime()) then + + local anchor = {} + anchor.xOfs = -175 + anchor.yOfs = 110 + + local F = SGI_DATA[SGI_DATA_INDEX].settings.filters; + + if (SGI_FilterHandle.needRedraw) then + for k,_ in pairs(SGI_FilterHandle.filterFrames) do + SGI_FilterHandle.filterFrames[k]:Hide(); + end + SGI_FilterHandle.filterFrames = {}; + SGI_FilterHandle.needRedraw = false; + end + + for k,_ in pairs(F) do + if (not SGI_FilterHandle.filterFrames[k]) then + SGI_FilterHandle.filterFrames[k] = CreateFrame("Button", "FilterFrame"..k, SGI_FilterHandle); + SGI_FilterHandle.filterFrames[k]:SetWidth(80) + SGI_FilterHandle.filterFrames[k]:SetHeight(25); + SGI_FilterHandle.filterFrames[k]:EnableMouse(true); + SGI_FilterHandle.filterFrames[k]:SetPoint("CENTER", SGI_FilterHandle, "CENTER", anchor.xOfs, anchor.yOfs); + if mod(k,5) == 0 then + anchor.xOfs = -175 + anchor.yOfs = anchor.yOfs - 30 + else + anchor.xOfs = anchor.xOfs + 85 + end + SGI_FilterHandle.filterFrames[k].text = SGI_FilterHandle.filterFrames[k]:CreateFontString(nil, "OVERLAY", "GameFontNormal"); + SGI_FilterHandle.filterFrames[k].text:SetPoint("LEFT", SGI_FilterHandle.filterFrames[k], "LEFT", 3, 0); + SGI_FilterHandle.filterFrames[k].text:SetJustifyH("LEFT"); + SGI_FilterHandle.filterFrames[k].text:SetWidth(75); + SGI_FilterHandle.filterFrames[k]:EnableMouse(true); + SGI_FilterHandle.filterFrames[k]:RegisterForClicks("LeftButtonDown","RightButtonDown"); + SGI_FilterHandle.filterFrames[k].highlight = SGI_FilterHandle.filterFrames[k]:CreateTexture(); + SGI_FilterHandle.filterFrames[k].highlight:SetAllPoints(); + if (SGI_DATA[SGI_DATA_INDEX].settings.filters[k].active) then + SGI_FilterHandle.filterFrames[k].highlight:SetTexture(0,1,0,0.2); + else + SGI_FilterHandle.filterFrames[k].highlight:SetTexture(1,0,0,0.2); + end + SGI_FilterHandle.filterFrames[k]:SetScript("OnEnter", function(self) + self.highlight:SetTexture(1,1,0,0.2); + SGI:debug("Enter: YELLOW"); + + SGI_FilterHandle.tooltip.text:SetText(FormatTooltipFilterText(F[k])); + SGI_FilterHandle.tooltip:SetPoint("TOP", self, "BOTTOM", 0, -3); + SGI_FilterHandle.tooltip:SetHeight(SGI_FilterHandle.tooltip.text:GetHeight() + 12); + SGI_FilterHandle.tooltip:SetWidth(SGI_FilterHandle.tooltip.text:GetWidth() + 10); + SGI_FilterHandle.tooltip:Show(); + end) + SGI_FilterHandle.filterFrames[k]:SetScript("OnLeave", function(self) + if (F[k] and F[k].active) then--SGI_FilterHandle.filterFrames[k].state) then + SGI_FilterHandle.filterFrames[k].highlight:SetTexture(0,1,0,0.2); + SGI:debug("Leave: GREEN"); + + else + SGI_FilterHandle.filterFrames[k].highlight:SetTexture(1,0,0,0.2); + SGI:debug("Leave: RED"); + end + + SGI_FilterHandle.tooltip:Hide(); + end) + end + + SGI_FilterHandle.filterFrames[k].filter = F[k]; + SGI_FilterHandle.filterFrames[k].text:SetText(F[k].nameOfFilter); + SGI_FilterHandle.filterFrames[k]:Show(); + + SGI_FilterHandle.filterFrames[k]:SetScript("OnClick", function(self, button) + SGI:debug(button); + if (button == "LeftButton") then + if (SGI_DATA[SGI_DATA_INDEX].settings.filters[k].active) then + SGI_DATA[SGI_DATA_INDEX].settings.filters[k].active = nil; + SGI_FilterHandle.filterFrames[k].highlight:SetTexture(1,0,0,0.2); + SGI:debug("Click: RED"); + else + SGI_DATA[SGI_DATA_INDEX].settings.filters[k].active = true; + SGI_FilterHandle.filterFrames[k].highlight:SetTexture(0,1,0,0.2); + SGI:debug("Click: GREEN"); + end + + SGI_FilterHandle.tooltip.text:SetText(FormatTooltipFilterText(F[k])); + SGI_FilterHandle.tooltip:SetPoint("TOP", self, "BOTTOM", 0, -3); + SGI_FilterHandle.tooltip:SetHeight(SGI_FilterHandle.tooltip.text:GetHeight() + 12); + SGI_FilterHandle.tooltip:SetWidth(SGI_FilterHandle.tooltip.text:GetWidth() + 10); + SGI_FilterHandle.tooltip:Show(); + else + SGI_DATA[SGI_DATA_INDEX].settings.filters[k] = nil; + SGI_FilterHandle.needRedraw = true; + end + + end) + + end + + SGI_FilterHandle.update = GetTime() + 1; + end + end) + SGI_FilterHandle.showOpt = true; + SGI_FilterHandle:HookScript("OnHide", function() if SGI_FilterHandle.showOpt then SGI:ShowOptions() end end) +end + +function SGI:ShowFilterHandle() + if (not SGI_FilterHandle) then + CreateFilterHandleFrame(); + end + SGI_FilterHandle:Show() +end + +local function ChangeLog() + CreateFrame("Frame","SGI_ChangeLog") + SGI_ChangeLog:SetWidth(550) + SGI_ChangeLog:SetHeight(350) + SGI_ChangeLog:SetBackdrop( + { + bgFile = "Interface/ACHIEVEMENTFRAME/UI-Achievement-Parchment-Horizontal", + edgeFile = "Interface/Tooltips/UI-Tooltip-Border", + tile = false, + tileSize = 16, + edgeSize = 16, + insets = { left = 4, right = 4, top = 4, bottom = 4 } + } + ) + SetFramePosition(SGI_ChangeLog) + + local anchor = {} + anchor.point = "BOTTOMRIGHT" + anchor.relativePoint = "BOTTOMRIGHT" + anchor.xOfs = -210 + anchor.yOfs = 10 + + SGI_ChangeLog.check1 = CreateCheckbox("SGI_CHANGES",SGI_ChangeLog,SGI.L["Don't show this after new updates"],anchor) + anchor.xOfs = -300 + SGI_ChangeLog.button1 = CreateButton("SGI_CLOSE_CHANGES",SGI_ChangeLog,120,30,SGI.L["Close"],anchor,function() SGI_ChangeLog:Hide() SGI_DATA.showChanges = SGI.VERSION_MAJOR end) + + SGI_ChangeLog.title = SGI_ChangeLog:CreateFontString() + SGI_ChangeLog.title:SetFont("Fonts\\FRIZQT__.TTF",22,"OUTLINE") + SGI_ChangeLog.title:SetText("|cffffff00<|r|cff16ABB5SuperGuildInvite|r|cff00ff00 Recent Changes|r|cffffff00>|r|cffffff00") + SGI_ChangeLog.title:SetPoint("TOP",SGI_ChangeLog,"TOP",0,-12) + + SGI_ChangeLog.version = SGI_ChangeLog:CreateFontString() + SGI_ChangeLog.version:SetFont("Fonts\\FRIZQT__.TTF",16,"OUTLINE") + SGI_ChangeLog.version:SetPoint("TOPLEFT",SGI_ChangeLog,"TOPLEFT",15,-40) + SGI_ChangeLog.version:SetText("") + + SGI_ChangeLog.items = {} + local y = -65 + for i = 1,10 do + SGI_ChangeLog.items[i] = SGI_ChangeLog:CreateFontString() + SGI_ChangeLog.items[i]:SetFont("Fonts\\FRIZQT__.TTF",14,"OUTLINE") + SGI_ChangeLog.items[i]:SetPoint("TOPLEFT",SGI_ChangeLog,"TOPLEFT",30,y) + SGI_ChangeLog.items[i]:SetText("") + SGI_ChangeLog.items[i]:SetJustifyH("LEFT") + SGI_ChangeLog.items[i]:SetSpacing(3) + y = y - 17 + end + SGI_ChangeLog.SetChange = function(changes) + local Y = -65 + SGI_ChangeLog.version:SetText("|cff16ABB5"..changes.version.."|r") + for k,_ in pairs(changes.items) do + SGI_ChangeLog.items[k]:SetText("|cffffff00"..changes.items[k].."|r") + SGI_ChangeLog.items[k]:SetWidth(490) + SGI_ChangeLog.items[k]:SetPoint("TOPLEFT",SGI_ChangeLog,"TOPLEFT",30,Y) + Y = Y - SGI_ChangeLog.items[k]:GetHeight() - 5 + end + end +end + +function SGI:ShowChanges() + if ( SGI_ChangeLog ) then + SGI_ChangeLog:Show() + else + ChangeLog() + SGI_ChangeLog:Show() + end + SGI_ChangeLog.SetChange(SGI.versionChanges); +end + + +local function CreateTroubleShooter() + CreateFrame("Frame","SGI_TroubleShooter") + SGI_TroubleShooter:SetWidth(300) + SGI_TroubleShooter:SetHeight(100) + SetFramePosition(SGI_TroubleShooter) + SGI_TroubleShooter:SetMovable(true) + SGI_TroubleShooter:SetScript("OnMouseDown",function(self) + self:StartMoving() + end) + SGI_TroubleShooter:SetScript("OnMouseUp",function(self) + self:StopMovingOrSizing() + SaveFramePosition(SGI_TroubleShooter) + end) + local backdrop = + { + bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark", + edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", + tile = true, + tileSize = 16, + edgeSize = 16, + insets = { left = 4, right = 4, top = 4, bottom = 4 } + } + SGI_TroubleShooter:SetBackdrop(backdrop) + local close = CreateFrame("Button",nil,SGI_TroubleShooter,"UIPanelCloseButton") + close:SetPoint("TOPRIGHT",SGI_TroubleShooter,"TOPRIGHT",-4,-4) + + SGI_TroubleShooter.title = SGI_TroubleShooter:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") + SGI_TroubleShooter.title:SetPoint("TOP",SGI_TroubleShooter,"TOP",0,-10) + SGI_TroubleShooter.title:SetText("Common issues") + + + local update = 0; + + SGI_TroubleShooter.items = {}; + SGI_TroubleShooter:SetScript("OnUpdate", function() + if (update < GetTime()) then + + + + + update = GetTime() + 0.5; + end + end) + + + SGI_TroubleShooter:HookScript("OnHide", function() if (SGI_Options.showAgain) then SGI_Options:Show() SGI_Options.showAgain = false end end); +end + +function SGI:ShowTroubleShooter() + if (not SGI_TroubleShooter) then + CreateTroubleShooter(); + end + SGI_TroubleShooter:Show(); +end + + +local function OptBtn2_OnClick() + SGI:ShowSuperScanFrame(); + SSBtn3_OnClick(SGI_SUPERSCAN_PLAYPAUSE2); +end + + +local function CreateOptions() + CreateFrame("Frame","SGI_Options") + SGI_Options:SetWidth(530) + SGI_Options:SetHeight(280) + SetFramePosition(SGI_Options) + SGI_Options:SetMovable(true) + SGI_Options:SetScript("OnMouseDown",function(self) + self:StartMoving() + end) + SGI_Options:SetScript("OnMouseUp",function(self) + self:StopMovingOrSizing() + SaveFramePosition(SGI_Options) + end) + local backdrop = + { + bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark", + edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", + tile = true, + tileSize = 16, + edgeSize = 16, + insets = { left = 4, right = 4, top = 4, bottom = 4 } + } + SGI_Options:SetBackdrop(backdrop) + local close = CreateFrame("Button",nil,SGI_Options,"UIPanelCloseButton") + close:SetPoint("TOPRIGHT",SGI_Options,"TOPRIGHT",-4,-4) + + SGI_Options.title = SGI_Options:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") + SGI_Options.title:SetText("SuperGuildInvite "..SGI.VERSION_MAJOR..SGI.VERSION_MINOR.." Options") + SGI_Options.title:SetPoint("TOP",SGI_Options,"TOP",0,-15) + SGI_Options.bottom = SGI_Options:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") + SGI_Options.bottom:SetText("Updated by a Fan") + SGI_Options.bottom:SetPoint("BOTTOM",SGI_Options,"BOTTOM",0,5) + + SGI_Options.optionHelpText = SGI_Options:CreateFontString(nil, "OVERLAY","GameFontNormal"); + SGI_Options.optionHelpText:SetText("|cff00D2FFScroll to change levels|r"); + SGI_Options.optionHelpText:SetPoint("TOP",SGI_Options,"TOP",70,-110); + + local anchor = {} + anchor.point = "TOPLEFT" + anchor.relativePoint = "TOPLEFT" + anchor.xOfs = 7 + anchor.yOfs = -50 + + local WhisperMode = { + SGI.L["Invite only"], + SGI.L["Invite, then whisper"], + SGI.L["Whisper only"], + } + + local spacing = 25; + + SGI_Options.dropDown1 = CreateDropDown("DROPDOWN_INVITE_MODE", SGI_Options, SGI.L["Invite Mode"], WhisperMode, anchor); + anchor.yOfs = anchor.yOfs - spacing - 7; + anchor.xOfs = anchor.xOfs + 13; +-- SGI_Options.checkBox1 = CreateCheckbox("CHECKBOX_MUTE_SGI", SGI_Options, SGI.L["Mute SGI"], anchor); +-- anchor.yOfs = anchor.yOfs - spacing; + SGI_Options.checkBox2 = CreateCheckbox("CHECKBOX_ADV_SCAN", SGI_Options, SGI.L["Advanced scan options"], anchor); + anchor.yOfs = anchor.yOfs - spacing; +-- SGI_Options.checkBox3 = CreateCheckbox("CHECKBOX_HIDE_SYSTEM", SGI_Options, SGI.L["Hide system messages"], anchor); +-- anchor.yOfs = anchor.yOfs - spacing; + SGI_Options.checkBox7 = CreateCheckbox("CHECKBOX_HIDE_WHISPER", SGI_Options, SGI.L["Hide outgoing whispers"], anchor); + anchor.yOfs = anchor.yOfs - spacing; + SGI_Options.checkBox4 = CreateCheckbox("CHECKBOX_HIDE_MINIMAP", SGI_Options, SGI.L["Hide minimap button"], anchor); + anchor.yOfs = anchor.yOfs - spacing; + SGI_Options.checkBox5 = CreateCheckbox("CHECKBOX_BACKGROUND_MODE", SGI_Options, SGI.L["Run SuperScan in the background"], anchor); + anchor.yOfs = anchor.yOfs - spacing; + SGI_Options.checkBox6 = CreateCheckbox("CHECKBOX_ENABLE_FILTERS", SGI_Options, SGI.L["Enable filtering"], anchor); + +-- SGI_Options.checkBox3:HookScript("PostClick", function(self) ChatIntercept:StateSystem(self:GetChecked()) end); + SGI_Options.checkBox7:HookScript("PostClick", function(self) ChatIntercept:StateWhisper(self:GetChecked()) end); + + +-- ANchor point for the bottom row of buttons + + anchor.point = "BOTTOMLEFT" + anchor.relativePoint = "BOTTOMLEFT" + anchor.xOfs = 20 + anchor.yOfs = 25 + + --onClickTester + SGI_Options.button1 = CreateButton("BUTTON_CUSTOM_WHISPER", SGI_Options, 120, 30, SGI.L["Edit whisper"], anchor, function(self) ShowWhisperFrame() SGI_Options:Hide() SGI_Options.showAgain = true end); + anchor.xOfs = anchor.xOfs + 125; + SGI_Options.button2 = CreateButton("BUTTON_SUPER_SCAN", SGI_Options, 120, 30, SGI.L["SuperScan"], anchor, OptBtn2_OnClick); + anchor.xOfs = anchor.xOfs + 125; + SGI_Options.button3 = CreateButton("BUTTON_INVITE", SGI_Options, 120, 30, format(SGI.L["Invite: %d"],SGI:GetNumQueued()), anchor, SGI.SendGuildInvite); + anchor.xOfs = anchor.xOfs + 125; + SGI_Options.button4 = CreateButton("BUTTON_CHOOSE_INVITES", SGI_Options, 120, 30, SGI.L["Choose invites"], anchor, SGI.ShowInviteList); + anchor.yOfs = 60; + SGI_Options.button5 = CreateButton("BUTTON_EDIT_FILTERS", SGI_Options, 120, 30, SGI.L["Filters"], anchor, function() SGI:ShowFilterHandle() SGI_Options:Hide() end); + anchor.xOfs = anchor.xOfs - 125; + --SGI_Options.button6 = CreateButton("BUTTON_HELP", SGI_Options, 120, 30, SGI.L["Help"],anchor, function() SGI:ShowTroubleShooter() SGI_Options:Hide() SGI_Options.showAgain = true end); + --anchor.xOfs = anchor.xOfs - 125; + +--Take out keybinding, no way to escape from it once you click it. Very dangerous and poor design. + +-- SGI_Options.button7 = CreateButton("BUTTON_KEYBIND", SGI_Options, 120, 30, SGI.L["Set Keybind ("..(SGI_DATA[SGI_DATA_INDEX].keyBind and SGI_DATA--[SGI_DATA_INDEX].keyBind or "NONE")..")"], anchor, KeyHarvestFrame.GetNewKeybindKey); +-- anchor.xOfs = anchor.xOfs - 125; + --SGI_Options.button8 = CreateButton("BUTTON_FILTER", SGI_Options, 120, 30, SGI.L["Filters"], anchor, onClickTester); + + + SGI_Options.limitLow = CreateFrame("Frame","SGI_LowLimit",SGI_Options) + SGI_Options.limitLow:SetWidth(40) + SGI_Options.limitLow:SetHeight(40) + SGI_Options.limitLow:SetPoint("CENTER",SGI_Options,"CENTER",40,40) + SGI_Options.limitLow.text = SGI_Options.limitLow:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") + SGI_Options.limitLow.text:SetPoint("CENTER") + SGI_Options.limitLow.texture = SGI_Options.limitLow:CreateTexture() + SGI_Options.limitLow.texture:SetAllPoints() + SGI_Options.limitLow.texture:SetTexture(1,1,0,0.2) + SGI_Options.limitLow.texture:Hide() + SGI_Options.limitTooltip = CreateFrame("Frame","LimitTool",SGI_Options.limitLow,"GameTooltipTemplate") + + SGI_Options.limitTooltip:SetPoint("TOP",SGI_Options.limitLow,"BOTTOM") + SGI_Options.limitTooltip.text = SGI_Options.limitTooltip:CreateFontString(nil,"OVERLAY","GameFontNormal") + SGI_Options.limitTooltip.text:SetPoint("LEFT",SGI_Options.limitTooltip,"LEFT",12,0) + SGI_Options.limitTooltip.text:SetJustifyH("LEFT") + SGI_Options.limitTooltip.text:SetText(SGI.L["Highest and lowest level to search for"]) + SGI_Options.limitTooltip.text:SetWidth(115) + SGI_Options.limitTooltip:SetWidth(130) + SGI_Options.limitTooltip:SetHeight(SGI_Options.limitTooltip.text:GetHeight() + 12) + + SGI_Options.limitLow:SetScript("OnEnter",function() + SGI_Options.limitLow.texture:Show() + SGI_Options.limitTooltip:Show() + end) + SGI_Options.limitLow:SetScript("OnLeave",function() + SGI_Options.limitLow.texture:Hide() + SGI_Options.limitTooltip:Hide() + end) + + SGI_Options.limitHigh = CreateFrame("Frame","SGI_HighLimit",SGI_Options) + SGI_Options.limitHigh:SetWidth(40) + SGI_Options.limitHigh:SetHeight(40) + SGI_Options.limitHigh:SetPoint("CENTER",SGI_Options,"CENTER",90,40) + SGI_Options.limitHigh.text = SGI_Options.limitHigh:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") + SGI_Options.limitHigh.text:SetPoint("CENTER") + SGI_Options.limitHigh.texture = SGI_Options.limitHigh:CreateTexture() + SGI_Options.limitHigh.texture:SetAllPoints() + SGI_Options.limitHigh.texture:SetTexture(1,1,0,0.2) + SGI_Options.limitHigh.texture:Hide() + + SGI_Options.limitHigh:SetScript("OnEnter",function() + SGI_Options.limitHigh.texture:Show() + SGI_Options.limitTooltip:Show() + end) + SGI_Options.limitHigh:SetScript("OnLeave",function() + SGI_Options.limitHigh.texture:Hide() + SGI_Options.limitTooltip:Hide() + end) + + SGI_Options.limitLow.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.lowLimit.." - ") + SGI_Options.limitLow:SetScript("OnMouseWheel",function(self,delta) + if delta == 1 and SGI_DATA[SGI_DATA_INDEX].settings.lowLimit + 1 <= SGI_DATA[SGI_DATA_INDEX].settings.highLimit then + SGI_DATA[SGI_DATA_INDEX].settings.lowLimit = SGI_DATA[SGI_DATA_INDEX].settings.lowLimit + 1 + SGI_Options.limitLow.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.lowLimit.." - ") + elseif delta == -1 and SGI_DATA[SGI_DATA_INDEX].settings.lowLimit - 1 >= SGI_MIN_LEVEL_SUPER_SCAN then + SGI_DATA[SGI_DATA_INDEX].settings.lowLimit = SGI_DATA[SGI_DATA_INDEX].settings.lowLimit - 1 + SGI_Options.limitLow.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.lowLimit.." - ") + end + end) + + SGI_Options.limitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.highLimit) + SGI_Options.limitHigh:SetScript("OnMouseWheel",function(self,delta) + if delta == 1 and SGI_DATA[SGI_DATA_INDEX].settings.highLimit + 1 <= SGI_MAX_LEVEL_SUPER_SCAN then + SGI_DATA[SGI_DATA_INDEX].settings.highLimit = SGI_DATA[SGI_DATA_INDEX].settings.highLimit + 1 + SGI_Options.limitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.highLimit) + elseif delta == -1 and SGI_DATA[SGI_DATA_INDEX].settings.highLimit > SGI_DATA[SGI_DATA_INDEX].settings.lowLimit then + SGI_DATA[SGI_DATA_INDEX].settings.highLimit = SGI_DATA[SGI_DATA_INDEX].settings.highLimit - 1 + SGI_Options.limitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.highLimit) + end + end) + + SGI_Options.limitText = SGI_Options.limitLow:CreateFontString(nil,"OVERLAY","GameFontNormal") + SGI_Options.limitText:SetPoint("BOTTOM",SGI_Options.limitLow,"TOP",16,0) + SGI_Options.limitText:SetText(SGI.L["Level limits"]) + + SGI_Options.raceLimitHigh = CreateFrame("Frame","SGI_RaceLimitHigh",SGI_Options) + SGI_Options.raceLimitHigh:SetWidth(40) + SGI_Options.raceLimitHigh:SetHeight(40) + SGI_Options.raceLimitHigh:SetPoint("CENTER",SGI_Options,"CENTER",200,70) + SGI_Options.raceLimitHigh.text = SGI_Options.raceLimitHigh:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") + SGI_Options.raceLimitHigh.text:SetPoint("CENTER") + SGI_Options.raceLimitHigh.texture = SGI_Options.raceLimitHigh:CreateTexture() + SGI_Options.raceLimitHigh.texture:SetAllPoints() + SGI_Options.raceLimitHigh.texture:SetTexture(1,1,0,0.2) + SGI_Options.raceLimitHigh.texture:Hide() + SGI_Options.raceTooltip = CreateFrame("Frame","LimitTool",SGI_Options.raceLimitHigh,"GameTooltipTemplate") + + SGI_Options.raceTooltip:SetPoint("TOP",SGI_Options.raceLimitHigh,"BOTTOM") + SGI_Options.raceTooltip.text = SGI_Options.raceTooltip:CreateFontString(nil,"OVERLAY","GameFontNormal") + SGI_Options.raceTooltip.text:SetPoint("LEFT",SGI_Options.raceTooltip,"LEFT",12,0) + SGI_Options.raceTooltip.text:SetJustifyH("LEFT") + SGI_Options.raceTooltip.text:SetText(SGI.L["The level you wish to start dividing the search by race"]) + SGI_Options.raceTooltip.text:SetWidth(110) + SGI_Options.raceTooltip:SetWidth(125) + SGI_Options.raceTooltip:SetHeight(SGI_Options.raceTooltip.text:GetHeight() + 12) + + SGI_Options.raceLimitText = SGI_Options.raceLimitHigh:CreateFontString(nil,"OVERLAY","GameFontNormal") + SGI_Options.raceLimitText:SetPoint("BOTTOM",SGI_Options.raceLimitHigh,"TOP",0,3) + SGI_Options.raceLimitText:SetText(SGI.L["Racefilter Start:"]) + + SGI_Options.raceLimitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.raceStart) + SGI_Options.raceLimitHigh:SetScript("OnMouseWheel",function(self,delta) + if delta == -1 and SGI_DATA[SGI_DATA_INDEX].settings.raceStart > 1 then + SGI_DATA[SGI_DATA_INDEX].settings.raceStart = SGI_DATA[SGI_DATA_INDEX].settings.raceStart - 1 + SGI_Options.raceLimitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.raceStart) + elseif delta == 1 and SGI_DATA[SGI_DATA_INDEX].settings.raceStart < SGI_MAX_LEVEL_SUPER_SCAN + 1 then + SGI_DATA[SGI_DATA_INDEX].settings.raceStart = SGI_DATA[SGI_DATA_INDEX].settings.raceStart + 1 + SGI_Options.raceLimitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.raceStart) + if SGI_DATA[SGI_DATA_INDEX].settings.raceStart > SGI_MAX_LEVEL_SUPER_SCAN then + SGI_Options.raceLimitHigh.text:SetText(SGI.L["OFF"]) + end + end + end) + + SGI_Options.raceLimitHigh:SetScript("OnEnter",function() + SGI_Options.raceLimitHigh.texture:Show() + SGI_Options.raceTooltip:Show() + end) + SGI_Options.raceLimitHigh:SetScript("OnLeave",function() + SGI_Options.raceLimitHigh.texture:Hide() + SGI_Options.raceTooltip:Hide() + end) + + SGI_Options.classLimitHigh = CreateFrame("Frame","SGI_ClassLimitHigh",SGI_Options) + SGI_Options.classLimitHigh:SetWidth(40) + SGI_Options.classLimitHigh:SetHeight(40) + SGI_Options.classLimitHigh:SetPoint("CENTER",SGI_Options,"CENTER",200,20) + SGI_Options.classLimitHigh.text = SGI_Options.classLimitHigh:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") + SGI_Options.classLimitHigh.text:SetPoint("CENTER") + SGI_Options.classLimitHigh.texture = SGI_Options.classLimitHigh:CreateTexture() + SGI_Options.classLimitHigh.texture:SetAllPoints() + SGI_Options.classLimitHigh.texture:SetTexture(1,1,0,0.2) + SGI_Options.classLimitHigh.texture:Hide() + SGI_Options.classTooltip = CreateFrame("Frame","LimitTool",SGI_Options.classLimitHigh,"GameTooltipTemplate") + + SGI_Options.classTooltip:SetPoint("TOP",SGI_Options.classLimitHigh,"BOTTOM") + SGI_Options.classTooltip.text = SGI_Options.classTooltip:CreateFontString(nil,"OVERLAY","GameFontNormal") + SGI_Options.classTooltip.text:SetPoint("LEFT",SGI_Options.classTooltip,"LEFT",12,0) + SGI_Options.classTooltip.text:SetJustifyH("LEFT") + SGI_Options.classTooltip.text:SetText(SGI.L["The level you wish to divide the search by class"]) + SGI_Options.classTooltip.text:SetWidth(110) + + SGI_Options.classTooltip:SetWidth(125) + SGI_Options.classTooltip:SetHeight(SGI_Options.classTooltip.text:GetHeight() + 12) + + SGI_Options.classLimitText = SGI_Options.classLimitHigh:CreateFontString(nil,"OVERLAY","GameFontNormal") + SGI_Options.classLimitText:SetPoint("BOTTOM",SGI_Options.classLimitHigh,"TOP",0,3) + SGI_Options.classLimitText:SetText(SGI.L["Classfilter Start:"]) + + SGI_Options.classLimitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.classStart) + SGI_Options.classLimitHigh:SetScript("OnMouseWheel",function(self,delta) + if delta == -1 and SGI_DATA[SGI_DATA_INDEX].settings.classStart > 1 then + SGI_DATA[SGI_DATA_INDEX].settings.classStart = SGI_DATA[SGI_DATA_INDEX].settings.classStart - 1 + SGI_Options.classLimitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.classStart) + elseif delta == 1 and SGI_DATA[SGI_DATA_INDEX].settings.classStart < SGI_MAX_LEVEL_SUPER_SCAN + 1 then + SGI_DATA[SGI_DATA_INDEX].settings.classStart = SGI_DATA[SGI_DATA_INDEX].settings.classStart + 1 + SGI_Options.classLimitHigh.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.classStart) + if SGI_DATA[SGI_DATA_INDEX].settings.classStart > SGI_MAX_LEVEL_SUPER_SCAN then + SGI_Options.classLimitHigh.text:SetText(SGI.L["OFF"]) + end + end + end) + + SGI_Options.classLimitHigh:SetScript("OnEnter",function() + SGI_Options.classLimitHigh.texture:Show() + SGI_Options.classTooltip:Show() + end) + SGI_Options.classLimitHigh:SetScript("OnLeave",function() + SGI_Options.classLimitHigh.texture:Hide() + SGI_Options.classTooltip:Hide() + end) + + SGI_Options.Interval = CreateFrame("Frame","SGI_Interval",SGI_Options) + SGI_Options.Interval:SetWidth(40) + SGI_Options.Interval:SetHeight(40) + SGI_Options.Interval:SetPoint("CENTER",SGI_Options,"CENTER",200,-30) + SGI_Options.Interval.text = SGI_Options.Interval:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") + SGI_Options.Interval.text:SetPoint("CENTER") + SGI_Options.Interval.texture = SGI_Options.Interval:CreateTexture() + SGI_Options.Interval.texture:SetAllPoints() + SGI_Options.Interval.texture:SetTexture(1,1,0,0.2) + SGI_Options.Interval.texture:Hide() + SGI_Options.intervalTooltip = CreateFrame("Frame","LimitTool",SGI_Options.Interval,"GameTooltipTemplate") + + SGI_Options.intervalTooltip:SetPoint("TOP",SGI_Options.Interval,"BOTTOM") + SGI_Options.intervalTooltip.text = SGI_Options.intervalTooltip:CreateFontString(nil,"OVERLAY","GameFontNormal") + SGI_Options.intervalTooltip.text:SetPoint("LEFT",SGI_Options.intervalTooltip,"LEFT",12,0) + SGI_Options.intervalTooltip.text:SetJustifyH("LEFT") + SGI_Options.intervalTooltip.text:SetText(SGI.L["Amount of levels to search every 7 seconds (higher numbers increase the risk of capping the search results)"]) + SGI_Options.intervalTooltip.text:SetWidth(130) + SGI_Options.intervalTooltip:SetHeight(120) + SGI_Options.intervalTooltip:SetWidth(135) + SGI_Options.intervalTooltip:SetHeight(SGI_Options.intervalTooltip.text:GetHeight() + 12) + + SGI_Options.intervalText = SGI_Options.Interval:CreateFontString(nil,"OVERLAY","GameFontNormal") + SGI_Options.intervalText:SetPoint("BOTTOM",SGI_Options.Interval,"TOP",0,3) + SGI_Options.intervalText:SetText(SGI.L["Interval:"]) + + SGI_Options.Interval.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.interval) + SGI_Options.Interval:SetScript("OnMouseWheel",function(self,delta) + if delta == -1 and SGI_DATA[SGI_DATA_INDEX].settings.interval > 1 then + SGI_DATA[SGI_DATA_INDEX].settings.interval = SGI_DATA[SGI_DATA_INDEX].settings.interval - 1 + SGI_Options.Interval.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.interval) + elseif delta == 1 and SGI_DATA[SGI_DATA_INDEX].settings.interval < 30 then + SGI_DATA[SGI_DATA_INDEX].settings.interval = SGI_DATA[SGI_DATA_INDEX].settings.interval + 1 + SGI_Options.Interval.text:SetText(SGI_DATA[SGI_DATA_INDEX].settings.interval) + end + end) + + SGI_Options.Interval:SetScript("OnEnter",function() + SGI_Options.Interval.texture:Show() + SGI_Options.intervalTooltip:Show() + end) + SGI_Options.Interval:SetScript("OnLeave",function() + SGI_Options.Interval.texture:Hide() + SGI_Options.intervalTooltip:Hide() + end) + + anchor = { + point = "BOTTOMLEFT", + relativePoint = "BOTTOMLEFT", + xOfs = 4, + yOfs = 4, + } + SGI_Options.superScanText = SGI_Options:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); + SGI_Options.superScanText:SetPoint("BOTTOMLEFT", SGI_Options, "BOTTOMLEFT", 35, 10); + SGI_Options.superScanText:SetText("SuperScan"); + SGI_Options.buttonPlayPause = CreateButton("SGI_SUPERSCAN_PLAYPAUSE2", SGI_Options, 40,30,"",anchor,SSBtn3_OnClick); + SGI_SUPERSCAN_PLAYPAUSE2:SetNormalTexture("Interface\\Buttons\\UI-SpellbookIcon-NextPage-Up"); + SGI_SUPERSCAN_PLAYPAUSE2:Hide(); + SGI_Options.superScanText:Hide(); + + SGI_Options.nextUpdate = GetTime(); + SGI_Options:SetScript("OnUpdate", function() + + if (SGI_Options.nextUpdate < GetTime()) then + + + + if SGI_DATA[SGI_DATA_INDEX].settings.classStart > SGI_MAX_LEVEL_SUPER_SCAN then + SGI_Options.classLimitHigh.text:SetText(SGI.L["OFF"]) + end + + if SGI_DATA[SGI_DATA_INDEX].settings.raceStart > SGI_MAX_LEVEL_SUPER_SCAN then + SGI_Options.raceLimitHigh.text:SetText(SGI.L["OFF"]) + end + + if (SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_BACKGROUND_MODE"]) then + SGI_SUPERSCAN_PLAYPAUSE2:Show(); + SGI_Options.superScanText:Show(); + if SuperScanFrame then SuperScanFrame:Hide() end; + else + SGI_SUPERSCAN_PLAYPAUSE2:Hide(); + SGI_Options.superScanText:Hide(); + if (SGI:IsScanning()) then + SGI:ShowSuperScanFrame(); + end + end + + if (SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_ADV_SCAN"]) then + + + -- print ( SGI_Options.nextUpdate) + + if (not SGI_Options.Interval:IsShown()) then + SGI_Options.Interval:Show(); + end + if (not SGI_Options.classLimitHigh:IsShown()) then + SGI_Options.classLimitHigh:Show(); + end + if (not SGI_Options.raceLimitHigh:IsShown()) then + SGI_Options.raceLimitHigh:Show(); + end + else + SGI_Options.Interval:Hide(); + SGI_Options.classLimitHigh:Hide(); + SGI_Options.raceLimitHigh:Hide(); + end + + --SGI_Options.Interval:Show(); + --SGI_Options.classLimitHigh:Show(); + --SGI_Options.raceLimitHigh:Show(); + + + + BUTTON_INVITE.label:SetText(format(SGI.L["Invite: %d"],SGI:GetNumQueued())); + --BUTTON_KEYBIND.label:SetText(SGI.L["Set Keybind ("..(SGI_DATA[SGI_DATA_INDEX].keyBind and SGI_DATA[SGI_DATA_INDEX].keyBind or "NONE")..")"]); + + if (SGI_DATA[SGI_DATA_INDEX].debug) then + SGI_Options.title:SetText("|cffff3300(DEBUG MODE) |rSuperGuildInvite "..SGI.VERSION_MAJOR..SGI.VERSION_MINOR.." Options") + else + SGI_Options.title:SetText("SuperGuildInvite "..SGI.VERSION_MAJOR..SGI.VERSION_MINOR.." Options") + end + + if (not SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_HIDE_MINIMAP"]) then + SGI:ShowMinimapButton(); + else + SGI:HideMinimapButton(); + end + + SGI_Options.nextUpdate = GetTime() + 1; + end + end) + +end + +function SGI:ShowOptions() + if (not SGI_Options) then + CreateOptions(); + end + SGI_Options:Show(); +end + +function SGI:HideOptions() + if (SGI_Options) then + SGI_Options:Hide(); + end +end + + +local function CreateMinimapButton() + local f = CreateFrame("Button","SGI_MiniMapButton",Minimap) + f:SetWidth(32) + f:SetHeight(32) + f:SetFrameStrata("MEDIUM") + f:SetMovable(true) + SetFramePosition(f) + + f:SetNormalTexture("Interface\\AddOns\\SuperGuildInviteReborn\\media\\SGI_MiniMapButton") + f:SetPushedTexture("Interface\\AddOns\\SuperGuildInviteReborn\\media\\SGI_MiniMapButtonPushed") + f:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight") + +-- local tooltip = CreateFrame("Frame","SGI_TooltTipMini",f,"GameTooltipTemplate") +-- tooltip:SetPoint("BOTTOMRIGHT",f,"TOPLEFT",0,-3) +-- local toolstring = tooltip:CreateFontString(nil,"OVERLAY","GameFontNormal") +-- toolstring:SetPoint("TOPLEFT",tooltip,"TOPLEFT",5,-7) + +-- local toolstring2 = tooltip:CreateFontString(nil, "OVERLAY", "GameFontNormal"); +-- local toolstring3 = tooltip:CreateFontString(nil, "OVERLAY", "GameFontNormal"); +-- toolstring2:SetPoint("TOPLEFT",tooltip,"TOPLEFT",7,-33); +-- toolstring3:SetPoint("TOPLEFT", tooltip, "TOPLEFT", 7, -46); +-- toolstring2:SetText(format("ETR: %s",SGI:GetSuperScanTimeLeft())); +-- toolstring3:SetText(format("%d%% done",floor(SGI:GetPercentageDone()))); + +-- local tUpdate = 0; +-- local function UpdateTooltip() +-- if (tUpdate < GetTime()) then +-- toolstring:SetText(SGI.LOGO..format("|cff88aaffSuperGuildInvite|r\n|cff16ABB5Queue: %d|r",SGI:GetNumQueued())) +-- toolstring2:SetText(format("ETR: %s",SGI:GetSuperScanTimeLeft())); +-- toolstring3:SetText(format("%d%% done",floor(SGI:GetPercentageDone()))); + --SGI:debug(format("ETR: %s",SGI:GetSuperScanETR())); + --SGI:debug(format("%d%% done",floor(SGI:GetPercentageDone()))); +-- tUpdate = GetTime() + 0.2; +-- end +-- end + +-- toolstring:SetText(SGI.LOGO..format("|cff88aaffSuperGuildInvite|r\n|cff16ABB5Queue: |r|cffffff00%d|r",SGI:GetNumQueued())) +-- toolstring:SetJustifyH("LEFT"); +-- tooltip:SetWidth(max(toolstring:GetWidth(),toolstring2:GetWidth(),toolstring3:GetWidth())+ 20) +-- tooltip:SetHeight(toolstring:GetHeight() + toolstring2:GetHeight() + toolstring3:GetHeight() + 15) +-- tooltip:Hide() +-- f:SetScript("OnEnter",function() +-- toolstring:SetText(SGI.LOGO..format("|cff88aaffSuperGuildInvite|r\n|cff16ABB5Queue: %d|r",SGI:GetNumQueued())) +-- tooltip:Show() +-- tooltip:SetScript("OnUpdate",UpdateTooltip); +-- end) +-- f:SetScript("OnLeave",function() +-- tooltip:Hide() +-- tooltip:SetScript("OnUpdate", nil); +-- end) + + + local function moveButton(self) + local centerX, centerY = Minimap:GetCenter() + local x, y = GetCursorPosition() + x, y = x / self:GetEffectiveScale() - centerX, y / self:GetEffectiveScale() - centerY + centerX, centerY = math.abs(x), math.abs(y) + centerX, centerY = (centerX / math.sqrt(centerX^2 + centerY^2)) * 85, (centerY / sqrt(centerX^2 + centerY^2)) * 85 + centerX = x < 0 and -centerX or centerX + centerY = y < 0 and -centerY or centerY + self:ClearAllPoints() + self:SetPoint("CENTER", centerX, centerY) + end + + f:SetScript("OnMouseDown",function(self,button) + if button == "RightButton" then + self:SetScript("OnUpdate",moveButton) + end + end) + f:SetScript("OnMouseUp",function(self,button) + self:SetScript("OnUpdate",nil) + SaveFramePosition(self) + end) + f:SetScript("OnClick",function(self,button) + if SGI_Options and SGI_Options:IsShown() then + SGI:HideOptions() + else + SGI:ShowOptions() + end + end) +end + +function SGI:ShowMinimapButton() + if (not SGI_MiniMapButton) then + CreateMinimapButton(); + end + SGI_MiniMapButton:Show(); +end + +function SGI:HideMinimapButton() + if (SGI_MiniMapButton) then + SGI_MiniMapButton:Hide(); + end +end + + + + + + + + +SGI:debug(">> GUI.lua"); diff --git a/core/SGI_System_Message.lua b/core/SGI_System_Message.lua index 8360690..4981b60 100644 --- a/core/SGI_System_Message.lua +++ b/core/SGI_System_Message.lua @@ -1,134 +1,134 @@ -local function ProcessSystemMsg(msg) - local place = strfind(ERR_GUILD_INVITE_S,"%s",1,true) - if (place) then - local n = strsub(msg,place) - local name = strsub(n,1,(strfind(n,"%s") or 2)-1) - if format(ERR_GUILD_INVITE_S,name) == msg then - return "invite",name - end - end - - place = strfind(ERR_GUILD_DECLINE_S,"%s",1,true) - if (place) then - n = strsub(msg,place) - name = strsub(n,1,(strfind(n,"%s") or 2)-1) - if format(ERR_GUILD_DECLINE_S,name) == msg then - return "decline",name - end - end - - place = strfind(ERR_ALREADY_IN_GUILD_S,"%s",1,true) - if (place) then - n = strsub(msg,place) - name = strsub(n,1,(strfind(n,"%s") or 2)-1) - if format(ERR_ALREADY_IN_GUILD_S,name) == msg then - return "guilded",name - end - end - - place = strfind(ERR_ALREADY_INVITED_TO_GUILD_S,"%s",1,true) - if (place) then - n = strsub(msg,place) - name = strsub(n,1,(strfind(n,"%s") or 2)-1) - if format(ERR_ALREADY_INVITED_TO_GUILD_S,name) == msg then - return "already",name - end - end - - place = strfind(ERR_GUILD_DECLINE_AUTO_S,"%s",1,true) - if (place) then - n = strsub(msg,place) - name = strsub(n,1,(strfind(n,"%s") or 2)-1) - if format(ERR_GUILD_DECLINE_AUTO_S,name) == msg then - return "auto",name - end - end - - place = strfind(ERR_GUILD_JOIN_S,"%s",1,true) - if (place) then - n = strsub(msg,place) - name = strsub(n,1,(strfind(n,"%s") or 2)-1) - if format(ERR_GUILD_JOIN_S,name) == msg then - return "join",name - end - end - - place = strfind(ERR_GUILD_PLAYER_NOT_FOUND_S,"%s",1,true) - if (place) then - n = strsub(msg,place) - name = strsub(n,1,(strfind(n,"%s") or 2)-2) - if format(ERR_GUILD_PLAYER_NOT_FOUND_S,name) == msg then - return "miss",name - end - end - - place = strfind(ERR_CHAT_PLAYER_NOT_FOUND_S,"%s",1,true) - if (place) then - n = strsub(msg,place) - name = strsub(n,1,(strfind(n,"%s") or 2)-2) - if format(ERR_CHAT_PLAYER_NOT_FOUND_S,name) == msg then - return "out",name - end - end - - return "unregistered message", "N/A"; -end - -function SGI:SystemMessage(event,_,message,...) - - local type, name = ProcessSystemMsg(message); - SGI:debug("Type: "..type.." Name: "..name); - - if (type == "invite") then - if (SGI:IsRegisteredForWhisper(name)) then - SGI:SendWhisper(SGI:FormatWhisper(SGI:PickRandomWhisper(), name), name, 1); - end - elseif (type == "decline") then - SGI:UnregisterForWhisper(name); - elseif (type == "auto") then - SGI:LockPlayer(name); - SGI:UnregisterForWhisper(name); - elseif (type == "guilded") then - SGI:LockPlayer(name); - SGI:UnregisterForWhisper(name); - elseif (type == "already") then - SGI:LockPlayer(name); - SGI:UnregisterForWhisper(name); - elseif (type == "join") then - - if (CanEditOfficerNote()) then - for i = 1,GetNumGuildMembers() do - local n = GetGuildRosterInfo(i); - if (n == name) then - GuildRosterSetOfficerNote(i, date()); - end - end - elseif (CanEditPublicNote()) then - for i = 1,GetNumGuildMembers() do - local n = GetGuildRosterInfo(i); - if (n == name) then - GuildRosterSetPublicNote(i, date()); - end - end - end - - elseif (type == "miss") then - if (SGI:IsSharing(name)) then - SGI:StopMassShare(name); - debug("Stopped mass share!"); - end - SGI:print(format(SGI.L["Unable to invite %s. They will not be locked."],name)); - SGI:UnlockPlayer(name); - SGI:UnregisterForWhisper(name); - elseif (type == "out") then - -- hmm... - if (SGI:IsSharing(name)) then - SGI:StopMassShare(name); - debug("Stopped mass share!"); - end - SGI:RemoveQueued(name); - end - -end - -SGI:debug(">> System_Message.lua"); +local function ProcessSystemMsg(msg) + local place = strfind(ERR_GUILD_INVITE_S,"%s",1,true) + if (place) then + local n = strsub(msg,place) + local name = strsub(n,1,(strfind(n,"%s") or 2)-1) + if format(ERR_GUILD_INVITE_S,name) == msg then + return "invite",name + end + end + + place = strfind(ERR_GUILD_DECLINE_S,"%s",1,true) + if (place) then + n = strsub(msg,place) + name = strsub(n,1,(strfind(n,"%s") or 2)-1) + if format(ERR_GUILD_DECLINE_S,name) == msg then + return "decline",name + end + end + + place = strfind(ERR_ALREADY_IN_GUILD_S,"%s",1,true) + if (place) then + n = strsub(msg,place) + name = strsub(n,1,(strfind(n,"%s") or 2)-1) + if format(ERR_ALREADY_IN_GUILD_S,name) == msg then + return "guilded",name + end + end + + place = strfind(ERR_ALREADY_INVITED_TO_GUILD_S,"%s",1,true) + if (place) then + n = strsub(msg,place) + name = strsub(n,1,(strfind(n,"%s") or 2)-1) + if format(ERR_ALREADY_INVITED_TO_GUILD_S,name) == msg then + return "already",name + end + end + + place = strfind(ERR_GUILD_DECLINE_AUTO_S,"%s",1,true) + if (place) then + n = strsub(msg,place) + name = strsub(n,1,(strfind(n,"%s") or 2)-1) + if format(ERR_GUILD_DECLINE_AUTO_S,name) == msg then + return "auto",name + end + end + + place = strfind(ERR_GUILD_JOIN_S,"%s",1,true) + if (place) then + n = strsub(msg,place) + name = strsub(n,1,(strfind(n,"%s") or 2)-1) + if format(ERR_GUILD_JOIN_S,name) == msg then + return "join",name + end + end + + place = strfind(ERR_GUILD_PLAYER_NOT_FOUND_S,"%s",1,true) + if (place) then + n = strsub(msg,place) + name = strsub(n,1,(strfind(n,"%s") or 2)-2) + if format(ERR_GUILD_PLAYER_NOT_FOUND_S,name) == msg then + return "miss",name + end + end + + place = strfind(ERR_CHAT_PLAYER_NOT_FOUND_S,"%s",1,true) + if (place) then + n = strsub(msg,place) + name = strsub(n,1,(strfind(n,"%s") or 2)-2) + if format(ERR_CHAT_PLAYER_NOT_FOUND_S,name) == msg then + return "out",name + end + end + + return "unregistered message", "N/A"; +end + +function SGI:SystemMessage(event,_,message,...) + + local type, name = ProcessSystemMsg(message); + SGI:debug("Type: "..type.." Name: "..name); + + if (type == "invite") then + if (SGI:IsRegisteredForWhisper(name)) then + SGI:SendWhisper(SGI:FormatWhisper(SGI:PickRandomWhisper(), name), name, 1); + end + elseif (type == "decline") then + SGI:UnregisterForWhisper(name); + elseif (type == "auto") then + SGI:LockPlayer(name); + SGI:UnregisterForWhisper(name); + elseif (type == "guilded") then + SGI:LockPlayer(name); + SGI:UnregisterForWhisper(name); + elseif (type == "already") then + SGI:LockPlayer(name); + SGI:UnregisterForWhisper(name); +--[[ elseif (type == "join") then + + if (CanEditOfficerNote()) then + for i = 1,GetNumGuildMembers() do + local n = GetGuildRosterInfo(i); + if (n == name) then + GuildRosterSetOfficerNote(i, date()); + end + end + elseif (CanEditPublicNote()) then + for i = 1,GetNumGuildMembers() do + local n = GetGuildRosterInfo(i); + if (n == name) then + GuildRosterSetPublicNote(i, date()); + end + end + end +]]-- Optional, could cause disconnects if large guild. + elseif (type == "miss") then + if (SGI:IsSharing(name)) then + SGI:StopMassShare(name); + debug("Stopped mass share!"); + end + SGI:print(format(SGI.L["Unable to invite %s. They will not be locked."],name)); + SGI:UnlockPlayer(name); + SGI:UnregisterForWhisper(name); + elseif (type == "out") then + -- hmm... + if (SGI:IsSharing(name)) then + SGI:StopMassShare(name); + debug("Stopped mass share!"); + end + SGI:RemoveQueued(name); + end + +end + +SGI:debug(">> System_Message.lua"); diff --git a/core/SGI_Utils.lua b/core/SGI_Utils.lua index fad7031..701dcf6 100644 --- a/core/SGI_Utils.lua +++ b/core/SGI_Utils.lua @@ -1,59 +1,59 @@ - -function SGI:FormatTime(T) - local R,S,M,H = "" - T = floor(T) - H = floor(T/3600) - M = floor((T-3600*H)/60) - S = T-(3600*H + 60*M) - - if T <= 0 then - return L["less than 1 second"] - end - - if H ~= 0 then - R = R..H..L[" hours "] - end - if M ~= 0 then - R = R..M..L[" minutes "] - end - if S ~= 0 then - R = R..S..L[" seconds"] - end - - return R -end - -function SGI:CountTable(T) - local i = 0 - if type(T) ~= "table" then - return i - end - for k,_ in pairs(T) do - i = i + 1 - end - return i -end - ---[[ -function SGI. - -function SGI. - -function SGI. - -function SGI. - -function SGI. -function SGI. - -function SGI. - -function SGI. -function SGI. -function SGI. -function SGI. -function SGI. -function SGI. -function SGI. -function SGI. -]] \ No newline at end of file + +function SGI:FormatTime(T) + local R,S,M,H = "" + T = floor(T) + H = floor(T/3600) + M = floor((T-3600*H)/60) + S = T-(3600*H + 60*M) + + if T <= 0 then + return L["less than 1 second"] + end + + if H ~= 0 then + R = R..H..L[" hours "] + end + if M ~= 0 then + R = R..M..L[" minutes "] + end + if S ~= 0 then + R = R..S..L[" seconds"] + end + + return R +end + +function SGI:CountTable(T) + local i = 0 + if type(T) ~= "table" then + return i + end + for k,_ in pairs(T) do + i = i + 1 + end + return i +end + +--[[ +function SGI. + +function SGI. + +function SGI. + +function SGI. + +function SGI. +function SGI. + +function SGI. + +function SGI. +function SGI. +function SGI. +function SGI. +function SGI. +function SGI. +function SGI. +function SGI. +]] diff --git a/core/SuperScan.lua b/core/SuperScan.lua index a4347be..948e1bf 100644 --- a/core/SuperScan.lua +++ b/core/SuperScan.lua @@ -1,677 +1,744 @@ -SGI.superScan = {}; -SGI.libWho = {}; - - -CreateFrame("Frame", "SGI_SUPER_SCAN"); -CreateFrame("Frame", "SGI_ANTI_SPAM_FRAME"); -CreateFrame("Frame", "SGI_WHISPER_QUEUE_FRAME"); - -LibStub:GetLibrary("LibWho-2.0"):Embed(SGI.libWho); - -local start-- = SGI_DATA[SGI_DATA_INDEX].settings.lowLimit; -local stop-- = SGI_DATA[SGI_DATA_INDEX].settings.highLimit; -local race-- = SGI_DATA[SGI_DATA_INDEX].settings.raceStart; -local class-- = SGI_DATA[SGI_DATA_INDEX].settings.classStart; -local interval-- = SGI_DATA[SGI_DATA_INDEX].settings.interval; - --- Fix for WhoLib bug -local oldFlags; - -local superScanIntervalTime = 8; -local superScanLast = 0; -local superScanProgress = 1; -local whoQueryList; -local whoSent = false; -local whoMaster = false; -local scanInProgress = false; -local shouldHideFriendsFrame = false; -local SGI_QUEUE = {}; -local SGI_ANTI_SPAM = {}; -local SGI_TEMP_BAN = {}; -local whisperWaiting = {}; -local whisperQueue = {}; -local sessionTotal = 0; -local amountScanned = 0; -local amountGuildless = 0; -local amountQueued = 0; -local superScanLap = 1; - -local raceClassCombos = { - ["Alliance"] = { - ["Human"] = { - "Paladin", - "Hunter", - "Mage", - "Priest", - "Rogue", - "Warrior", - "Warlock", - "Death Knight", - "Monk", - }, - ["Draenei"] = { - "Hunter", - "Mage", - "Paladin", - "Priest", - "Shaman", - "Death Knight", - "Warrior", - "Monk", - }, - ["Gnome"] = { - "Mage", - "Priest", - "Rogue", - "Warlock", - "Warrior", - "Death Knight", - "Monk", - }, - ["Dwarf"] = { - "Hunter", - "Mage", - "Paladin", - "Priest", - "Rogue", - "Shaman", - "Warlock", - "Warrior", - "Death Knight", - "Monk", - }, - ["Night Elf"] = { - "Druid", - "Hunter", - "Mage", - "Priest", - "Rogue", - "Warrior", - "Death Knight", - "Demon Hunter", - "Monk", - }, - ["Worgen"] = { - "Druid", - "Hunter", - "Mage", - "Priest", - "Rogue", - "Warlock", - "Warrior", - "Death Knight", - }, - ["Pandaren"] = { - "Hunter", - "Mage", - "Priest", - "Rogue", - "Shaman", - "Warrior", - "Monk", - }, - }, - ["Horde"] = { - ["Blood Elf"] = { - "Paladin", - "Hunter", - "Mage", - "Priest", - "Rogue", - "Warlock", - "Warrior", - "Death Knight", - "Demon Hunter", - "Monk", - }, - ["Orc"] = { - "Hunter", - "Mage", - "Rogue", - "Shaman", - "Warlock", - "Warrior", - "Death Knight", - "Monk", - }, - ["Goblin"] = { - "Hunter", - "Mage", - "Priest", - "Rogue", - "Shaman", - "Warlock", - "Warrior", - "Death Knight", - }, - ["Tauren"] = { - "Druid", - "Hunter", - "Paladin", - "Priest", - "Shaman", - "Warrior", - "Death Knight", - "Monk", - }, - ["Troll"] = { - "Druid", - "Hunter", - "Mage", - "Priest", - "Rogue", - "Shaman", - "Warlock", - "Warrior", - "Death Knight", - "Monk", - }, - ["Undead"] = { - "Hunter", - "Mage", - "Priest", - "Rogue", - "Warlock", - "Warrior", - "Death Knight", - "Monk", - }, - ["Pandaren"] = { - "Hunter", - "Mage", - "Priest", - "Rogue", - "Shaman", - "Warrior", - "Monk", - }, - }, -} - -local GetTime = GetTime; -local strfind = strfind; -local strsub = strsub; -local tonumber = tonumber; - -local L = SGI.L; - -function SGI:PickRandomWhisper() - local i = 0 - local tbl = {} - for k,_ in pairs(SGI_DATA[SGI_DATA_INDEX].settings.whispers) do - i = i + 1 - tbl[i] = SGI_DATA[SGI_DATA_INDEX].settings.whispers[k] - end - if #tbl == 0 then - return SGI_DATA[SGI_DATA_INDEX].settings.whisper - end - return tbl[random(#tbl)] -end - -function SGI:FormatWhisper(msg, name) - local whisper = msg - if not msg then SGI:print("You have not set your whispers!") msg = "<NO WHISPER SET>" whisper = "<NO WHISPER SET>" end - if not name then name = "ExampleName" end - local guildName,guildLevel = GetGuildInfo(UnitName("Player"))--,GetGuildLevel() - if not guildName then guildName = "<InvalidName>" end - if not guildLevel then guildLevel = "<InvalidLevel>" end - if strfind(msg,"PLAYER") then - whisper = strsub(msg,1,strfind(msg,"PLAYER")-1)..name..strsub(msg,strfind(msg,"PLAYER")+6) - end - if strfind(whisper,"NAME") then - whisper = strsub(whisper,1,strfind(whisper,"NAME")-1)..guildName..strsub(whisper,strfind(whisper,"NAME")+4) - end - if strfind(whisper,"LEVEL") then - whisper = strsub(whisper,1,strfind(whisper,"LEVEL")-1)..guildLevel..strsub(whisper,strfind(whisper,"LEVEL")+5) - end - return whisper -end - -local function QueueInvite(name,level,classFile,race,class,found) - SGI_QUEUE[name] = { - level = level, - class = class, - classFile = classFile, - race = race, - found = found, - } - GuildShield:IsShielded(name) -end - -local function PutOnHold(name,level,classFile,race,class,found) - SGI_ANTI_SPAM[name] = { - level = level, - class = class, - classFile = classFile, - race = race, - found = found, - } - GuildShield:IsShielded(name) -end - -SGI_ANTI_SPAM_FRAME.t = 0; -SGI_ANTI_SPAM_FRAME:SetScript("OnUpdate", function() - if (SGI_ANTI_SPAM_FRAME.t < GetTime()) then - for k,_ in pairs(SGI_ANTI_SPAM) do - if (SGI_ANTI_SPAM[k].found + 4 < GetTime()) then - SGI_QUEUE[k] = SGI_ANTI_SPAM[k]; - SGI_ANTI_SPAM[k] = nil; - amountQueued = amountQueued + 1; - end - end - SGI_ANTI_SPAM_FRAME.t = GetTime() + 0.5; - end -end) - -SGI_WHISPER_QUEUE_FRAME.t = 0; -SGI_WHISPER_QUEUE_FRAME:SetScript("OnUpdate", function() - if (SGI_WHISPER_QUEUE_FRAME.t < GetTime()) then - - for k,_ in pairs(whisperQueue) do - if (whisperQueue[k].t < GetTime()) then - ChatIntercept:InterceptNextWhisper(); - SendChatMessage(whisperQueue[k].msg, "WHISPER", nil, k); - whisperQueue[k] = nil; - end - end - - SGI_WHISPER_QUEUE_FRAME.t = GetTime() + 0.5; - - end -end) - -local function ValidateName(player) - --Check: - -- Lock - -- filter - -- guild list - - if (SGI_DATA.lock[player.name]) then - return false; - end - - if (SGI_DATA.guildList[GetRealmName()][player.name]) then - return false; - end - - if (SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_ENABLE_FILTERS"] and not SGI:FilterPlayer(player)) then - return false; - end - - return true; -end - -local function TrimRealmName(name) - if (type(name) ~= "string") then SGI:debug("TrimRealmName: No name!") return end - - local myRealm = GetRealmName(); - - if (type(myRealm) ~= "string") then SGI:debug("TrimRealmName: No realmName!") return end - - if (strfind(name, myRealm)) then - if (strfind(name, "-")) then - local n = strsub(name,1,strfind(name,"-")-1); - return n; - end - end - return name; -end - -local function WhoResultCallback(query, results, complete) - if (whoSent) then - whoSent = false; - SGI:debug("...got reply"); - - flags = oldFlags; - - superScanProgress = superScanProgress + 1; - local ETR = (#whoQueryList - superScanProgress + 1) * superScanIntervalTime; - if (SuperScanFrame) then - SuperScanFrame.ETR = ETR; - SuperScanFrame.lastETR = GetTime(); - end - - local numResults = 0; - - for _, result in pairs(results) do - amountScanned = amountScanned + 1; - numResults = numResults + 1; - - result.Name = TrimRealmName(result.Name); - - SGI:BroadcastVersion(result.Name) - - if (result.Guild == "") then - local player = { - name = result.Name, - level = result.Level, - race = result.Race, - class = result.NoLocaleClass, - } - amountGuildless = amountGuildless + 1; - if (ValidateName(player)) then - PutOnHold(result.Name, result.Level, result.NoLocaleClass, result.Race, result.Class, GetTime()); - end - end - end - SGI:debug("Scan result: "..numResults); - end -end - -local function SuperScan() - if (GetTime() > superScanLast + superScanIntervalTime) then - if (superScanProgress == (#whoQueryList + 1)) then - superScanProgress = 1; - superScanLast = GetTime(); - amountGuildless = 0; - sessionTotal = sessionTotal + amountScanned; - amountScanned = 0; - else - oldFlags = flags; - flags = nil; - --SendWho(tostring(whoQueryList[superScanProgress])) - SGI.libWho:Who(tostring(whoQueryList[superScanProgress]),{queue = SGI.libWho.WHOLIB_QUERY_QUIET, callback = WhoResultCallback}); - whoSent = true; - superScanLast = GetTime(); - SGI:debug("Sent query: "..whoQueryList[superScanProgress].."..."); - end - end -end - -local function CreateSuperScanQuery(start, stop, interval, class, race) - - if (not SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_ADV_SCAN"]) then - interval = 5; - class = 999; - race = 999; - end - - local SGI_BREAK_POINT_SUPER_SCAN = 90; - - whoQueryList = {}; - local current = start; - local Classes = { - SGI.L["Death Knight"], - SGI.L["Demon Hunter"], - SGI.L["Druid"], - SGI.L["Hunter"], - SGI.L["Mage"], - SGI.L["Monk"], - SGI.L["Paladin"], - SGI.L["Priest"], - SGI.L["Rogue"], - SGI.L["Shaman"], - SGI.L["Warlock"], - SGI.L["Warrior"], - } - local Races = {} - if UnitFactionGroup("player") == "Horde" then - Races = { - SGI.L["Orc"], - SGI.L["Blood Elf"], - SGI.L["Undead"], - SGI.L["Troll"], - SGI.L["Goblin"], - SGI.L["Tauren"], - SGI.L["Pandaren"], - } - else - Races = { - SGI.L["Human"], - SGI.L["Dwarf"], - SGI.L["Worgen"], - SGI.L["Draenei"], - SGI.L["Night Elf"], - SGI.L["Gnome"], - SGI.L["Pandaren"], - } - end - - if (start < SGI_BREAK_POINT_SUPER_SCAN) then - while (current + interval < ( (SGI_BREAK_POINT_SUPER_SCAN > stop) and stop or SGI_BREAK_POINT_SUPER_SCAN)) do - - if (current + interval >= race and current + interval >= class) then - for k,_ in pairs(raceClassCombos[UnitFactionGroup("player")]) do - for j,_ in pairs(raceClassCombos[UnitFactionGroup("player")][k]) do - tinsert(whoQueryList, current.."- -"..(current + interval - 1).." r-"..SGI.L[k].." c-"..SGI.L[raceClassCombos[UnitFactionGroup("player")][k][j]]); - end - end - elseif (current + interval >= race) then - for k, _ in pairs(Races) do - tinsert(whoQueryList, current.."- -"..(current + interval - 1).." r-"..Races[k]); - end - elseif (current + interval >= class) then - for k, _ in pairs(Classes) do - tinsert(whoQueryList, current.."- -"..(current + interval - 1).." c-"..Classes[k]); - end - else - tinsert(whoQueryList, current.."- -"..(current + interval - 1)); - end - - current = current + interval; - end - - if ( current < ( (SGI_BREAK_POINT_SUPER_SCAN > stop) and stop or SGI_BREAK_POINT_SUPER_SCAN ) ) then - local t_stop = (SGI_BREAK_POINT_SUPER_SCAN > stop) and stop or SGI_BREAK_POINT_SUPER_SCAN; - if (t_stop >= race and t_stop >= class) then - for k,_ in pairs(raceClassCombos[UnitFactionGroup("player")]) do - for j,_ in pairs(raceClassCombos[UnitFactionGroup("player")][k]) do - tinsert(whoQueryList, current.."- -"..(t_stop).." r-"..SGI.L[k].." c-"..SGI.L[raceClassCombos[UnitFactionGroup("player")][k][j]]); - end - end - elseif (t_stop >= race) then - for k, _ in pairs(Races) do - tinsert(whoQueryList, current.."- -"..(t_stop).." r-"..Races[k]); - end - elseif (t_stop >= class) then - for k, _ in pairs(Classes) do - tinsert(whoQueryList, current.."- -"..(t_stop).." c-"..Classes[k]); - end - else - tinsert(whoQueryList, current.."- -"..(t_stop)); - end - current = t_stop + 1; - end - end - if (stop < current) then return end; - - while (current <= stop) do - if (current >= race and current >= class) then - for k,_ in pairs(raceClassCombos[UnitFactionGroup("player")]) do - for j,_ in pairs(raceClassCombos[UnitFactionGroup("player")][k]) do - tinsert(whoQueryList, current.." r-"..SGI.L[k].." c-"..SGI.L[raceClassCombos[UnitFactionGroup("player")][k][j]]); - end - end - elseif (current >= race) then - for k,_ in pairs(Races) do - tinsert(whoQueryList, current.." r-"..Races[k]); - end - elseif (current >= class) then - for k,_ in pairs(Classes) do - tinsert(whoQueryList, current.." c-"..Classes[k]); - end - else - tinsert(whoQueryList, current); - end - current = current + 1; - end -end - -local function CanResume() - local s = SGI_DATA[SGI_DATA_INDEX].settings; - return (start == s.lowLimit and stop == s.highLimit and race == s.raceStart and class == s.classStart and interval == s.interval); -end - -local function ResetSuperScan() - start = SGI_DATA[SGI_DATA_INDEX].settings.lowLimit; - stop = SGI_DATA[SGI_DATA_INDEX].settings.highLimit; - race = SGI_DATA[SGI_DATA_INDEX].settings.raceStart; - class = SGI_DATA[SGI_DATA_INDEX].settings.classStart; - interval = SGI_DATA[SGI_DATA_INDEX].settings.interval; - - amountGuildless = 0; - sessionTotal = sessionTotal + amountScanned; - amountScanned = 0; - superScanProgress = 1; - CreateSuperScanQuery(start, stop, interval, class, race); -end - -function SGI:StartSuperScan() - if (not CanResume()) then - ResetSuperScan(); - end - - if (SuperScanFrame) then - SuperScanFrame.lastETR = GetTime(); - end - - scanInProgress = true; - SGI_SUPER_SCAN:SetScript("OnUpdate", SuperScan); -end - -function SGI:StopSuperScan() - - scanInProgress = false; - SGI_SUPER_SCAN:SetScript("OnUpdate", nil); - SGI:debug(FriendsFrame:IsShown()); - --FriendsMicroButton:Click(); - --FriendsFrameCloseButton:Click(); -end - -function SGI:RemoveQueued(name) - SGI:LockPlayer(name); - SGI_QUEUE[name] = nil; - SGI_ANTI_SPAM[name] = nil; - - local nameTrim = TrimRealmName(name); - - SGI_ANTI_SPAM[nameTrim] = nil - SGI_QUEUE[nameTrim] = nil; - - SGI:debug("RemoveQueued(name) removed "..nameTrim); -end - -function SGI:UnregisterForWhisper(name) - whisperWaiting[name] = nil; - whisperQueue[name] = nil; -end - -function SGI:SendWhisper(message, name, delay) - whisperQueue[name] = {msg = message, t = delay + GetTime()}; - whisperWaiting[name] = nil; -end - -function SGI:RegisterForWhisper(name) - whisperWaiting[name] = true; -end - -function SGI:IsRegisteredForWhisper(name) - return whisperWaiting[name]; -end - - - -function SGI:SendGuildInvite(button) - local name = self.player - if not name then name = next(SGI_QUEUE) button = "LeftButton" end - if not name then return end - - if (SGI:IsLocked(name)) then - SGI:RemoveQueued(name); - return; - end - - if (UnitIsInMyGuild(name)) then - SGI:LockPlayer(name); - SGI:RemoveQueued(name); - return; - end - - if (button == "LeftButton") then - - if (SGI_DATA[SGI_DATA_INDEX].settings.dropDown["DROPDOWN_INVITE_MODE"] == 1) then - - GuildInvite(name); - SGI:LockPlayer(name); - --SGI:print("Only Invite: "..name); - - elseif (SGI_DATA[SGI_DATA_INDEX].settings.dropDown["DROPDOWN_INVITE_MODE"] == 2) then - - GuildInvite(name); - SGI:RegisterForWhisper(name); - SGI:LockPlayer(name); - --SGI:print("Invite, then whisper: "..name); - - elseif (SGI_DATA[SGI_DATA_INDEX].settings.dropDown["DROPDOWN_INVITE_MODE"] == 3) then - - SGI:SendWhisper(SGI:FormatWhisper(SGI:PickRandomWhisper(), name), name, 4); - SGI:LockPlayer(name); - --SGI:print("Only whisper: "..name); - - else - SGI:print(SGI.L["You need to specify the mode in which you wish to invite"]) - SGI:print(SGI.L["Go to Options and select your Invite Mode"]) - end - GuildShield:IsShielded(name); - SGI:LiveSync(name) - end - - SGI:RemoveQueued(name); -end - -function SGI:RemoveShielded(player) - SGI:debug(player); - if (not player) then SGI:debug("Error: No player name provided!") return end - - local playerTrim = TrimRealmName(player); - - SGI_ANTI_SPAM[playerTrim] = nil - SGI_QUEUE[playerTrim] = nil; - SGI:LockPlayer(playerTrim); - - SGI_ANTI_SPAM[player] = nil - SGI_QUEUE[player] = nil; - SGI:LockPlayer(player); - SGI:print("|cffffff00Removed |r|cff00A2FF"..player.."|r|cffffff00 because they are shielded.|r") -end - -function SGI:GetNumQueued() - return SGI:CountTable(SGI_QUEUE); -end - -function SGI:PurgeQueue() - SGI_QUEUE = {}; - SGI_ANTI_SPAM = {}; -end - -function SGI:GetSuperScanETR() - if (whoQueryList) then - return SGI:FormatTime((#whoQueryList - superScanProgress + 1) * superScanIntervalTime); - else - return 0; - end -end - -function SGI:GetSuperScanProgress() - return floor((superScanProgress - 1) / #whoQueryList); -end - -function SGI:GetTotalScanTime() - return ((#whoQueryList - 1) * superScanIntervalTime); -end - -function SGI:IsScanning() - return scanInProgress; -end - -function SGI:GetInviteQueue() - return SGI_QUEUE; -end - -function SGI:GetSuperScanStats() - return amountScanned, amountGuildless, amountQueued, sessionTotal; -end - - - -SGI:debug(">> SuperScan.lua"); \ No newline at end of file +SGI.superScan = {}; +SGI.libWho = {}; + + +CreateFrame("Frame", "SGI_SUPER_SCAN"); +CreateFrame("Frame", "SGI_ANTI_SPAM_FRAME"); +CreateFrame("Frame", "SGI_WHISPER_QUEUE_FRAME"); + +LibStub:GetLibrary("LibWho-2.0"):Embed(SGI.libWho); + +local start-- = SGI_DATA[SGI_DATA_INDEX].settings.lowLimit; +local stop-- = SGI_DATA[SGI_DATA_INDEX].settings.highLimit; +local race-- = SGI_DATA[SGI_DATA_INDEX].settings.raceStart; +local class-- = SGI_DATA[SGI_DATA_INDEX].settings.classStart; +local interval-- = SGI_DATA[SGI_DATA_INDEX].settings.interval; + +-- Fix for WhoLib bug +local oldFlags; + +local superScanIntervalTime = 8; +local superScanLast = 0; +local superScanProgress = 1; +local whoQueryList; +local whoSent = false; +local whoMaster = false; +local scanInProgress = false; +local shouldHideFriendsFrame = false; +local SGI_QUEUE = {}; +local SGI_ANTI_SPAM = {}; +local SGI_TEMP_BAN = {}; +local whisperWaiting = {}; +local whisperQueue = {}; +local sessionTotal = 0; +local amountScanned = 0; +local amountGuildless = 0; +local amountQueued = 0; +local superScanLap = 1; + +local raceClassCombos = { + ["Alliance"] = { + ["Human"] = { + "Paladin", + "Hunter", + "Mage", + "Priest", + "Rogue", + "Warrior", + "Warlock", + "Death Knight", + "Monk", + }, + ["Draenei"] = { + "Hunter", + "Mage", + "Paladin", + "Priest", + "Shaman", + "Death Knight", + "Warrior", + "Monk", + }, + ["Gnome"] = { + "Mage", + "Priest", + "Rogue", + "Warlock", + "Warrior", + "Death Knight", + "Monk", + }, + ["Dwarf"] = { + "Hunter", + "Mage", + "Paladin", + "Priest", + "Rogue", + "Shaman", + "Warlock", + "Warrior", + "Death Knight", + "Monk", + }, + ["Night Elf"] = { + "Druid", + "Hunter", + "Mage", + "Priest", + "Rogue", + "Warrior", + "Death Knight", + "Demon Hunter", + "Monk", + }, + ["Worgen"] = { + "Druid", + "Hunter", + "Mage", + "Priest", + "Rogue", + "Warlock", + "Warrior", + "Death Knight", + }, + ["Pandaren"] = { + "Hunter", + "Mage", + "Priest", + "Rogue", + "Shaman", + "Warrior", + "Monk", + }, + ["Void Elf"] = { + "Hunter", + "Mage", + "Monk", + "Priest", + "Rogue", + "Warlock", + "Warrior", + }, + ["Lightforged Draenei"] = { + "Hunter", + "Mage", + "Paladin", + "Priest", + "Warrior", + }, + ["Dark Iron Dwarf"] = { + "Hunter", + "Mage", + "Monk", + "Paladin", + "Priest", + "Rogue", + "Shaman", + "Warlock", + "Warrior", + }, + ["Kul'Tiran Human"] = { --not sure if this is correct naming + "Druid", -- only known class at the moment + }, + }, + ["Horde"] = { + ["Blood Elf"] = { + "Paladin", + "Hunter", + "Mage", + "Priest", + "Rogue", + "Warlock", + "Warrior", + "Death Knight", + "Demon Hunter", + "Monk", + }, + ["Orc"] = { + "Hunter", + "Mage", + "Rogue", + "Shaman", + "Warlock", + "Warrior", + "Death Knight", + "Monk", + }, + ["Goblin"] = { + "Hunter", + "Mage", + "Priest", + "Rogue", + "Shaman", + "Warlock", + "Warrior", + "Death Knight", + }, + ["Tauren"] = { + "Druid", + "Hunter", + "Paladin", + "Priest", + "Shaman", + "Warrior", + "Death Knight", + "Monk", + }, + ["Troll"] = { + "Druid", + "Hunter", + "Mage", + "Priest", + "Rogue", + "Shaman", + "Warlock", + "Warrior", + "Death Knight", + "Monk", + }, + ["Undead"] = { + "Hunter", + "Mage", + "Priest", + "Rogue", + "Warlock", + "Warrior", + "Death Knight", + "Monk", + }, + ["Pandaren"] = { + "Hunter", + "Mage", + "Priest", + "Rogue", + "Shaman", + "Warrior", + "Monk", + }, + ["Highmountain Tauren"] = { + "Druid", + "Hunter", + "Monk", + "Shaman", + "Warrior", + }, + ["Nightborne"] = { + "Hunter", + "Mage", + "Monk", + "Priest", + "Rogue", + "Warlock", + "Warrior", + }, + ["Mag'har Orc"] = { + "Hunter", + "Mage", + "Monk", + "Priest", + "Rogue", + "Shaman", + "Warrior", + }, + ["Zandalari Troll"] = { + "Druid", + "Hunter", + "Mage", + "Priest", + "Rogue", + "Shaman", + "Warlock", + "Warrior", + }, + }, +} + +local GetTime = GetTime; +local strfind = strfind; +local strsub = strsub; +local tonumber = tonumber; + +local L = SGI.L; + +function SGI:PickRandomWhisper() + local i = 0 + local tbl = {} + for k,_ in pairs(SGI_DATA[SGI_DATA_INDEX].settings.whispers) do + i = i + 1 + tbl[i] = SGI_DATA[SGI_DATA_INDEX].settings.whispers[k] + end + if #tbl == 0 then + return SGI_DATA[SGI_DATA_INDEX].settings.whisper + end + return tbl[random(#tbl)] +end + +function SGI:FormatWhisper(msg, name) + local whisper = msg + if not msg then SGI:print("You have not set your whispers!") msg = "<NO WHISPER SET>" whisper = "<NO WHISPER SET>" end + if not name then name = "ExampleName" end + local guildName,guildLevel = GetGuildInfo(UnitName("Player"))--,GetGuildLevel() + if not guildName then guildName = "<InvalidName>" end + if not guildLevel then guildLevel = "<InvalidLevel>" end + if strfind(msg,"PLAYER") then + whisper = strsub(msg,1,strfind(msg,"PLAYER")-1)..name..strsub(msg,strfind(msg,"PLAYER")+6) + end + if strfind(whisper,"NAME") then + whisper = strsub(whisper,1,strfind(whisper,"NAME")-1)..guildName..strsub(whisper,strfind(whisper,"NAME")+4) + end + if strfind(whisper,"LEVEL") then + whisper = strsub(whisper,1,strfind(whisper,"LEVEL")-1)..guildLevel..strsub(whisper,strfind(whisper,"LEVEL")+5) + end + return whisper +end + +local function QueueInvite(name,level,classFile,race,class,found) + SGI_QUEUE[name] = { + level = level, + class = class, + classFile = classFile, + race = race, + found = found, + } + --GuildShield:IsShielded(name) +end + +local function PutOnHold(name,level,classFile,race,class,found) + SGI_ANTI_SPAM[name] = { + level = level, + class = class, + classFile = classFile, + race = race, + found = found, + } + --GuildShield:IsShielded(name) +end + +SGI_ANTI_SPAM_FRAME.t = 0; +SGI_ANTI_SPAM_FRAME:SetScript("OnUpdate", function() + if (SGI_ANTI_SPAM_FRAME.t < GetTime()) then + for k,_ in pairs(SGI_ANTI_SPAM) do + if (SGI_ANTI_SPAM[k].found + 4 < GetTime()) then + SGI_QUEUE[k] = SGI_ANTI_SPAM[k]; + SGI_ANTI_SPAM[k] = nil; + amountQueued = amountQueued + 1; + end + end + SGI_ANTI_SPAM_FRAME.t = GetTime() + 0.5; + end +end) + +SGI_WHISPER_QUEUE_FRAME.t = 0; +SGI_WHISPER_QUEUE_FRAME:SetScript("OnUpdate", function() + if (SGI_WHISPER_QUEUE_FRAME.t < GetTime()) then + + for k,_ in pairs(whisperQueue) do + if (whisperQueue[k].t < GetTime()) then + ChatIntercept:InterceptNextWhisper(); + SendChatMessage(whisperQueue[k].msg, "WHISPER", nil, k); + whisperQueue[k] = nil; + end + end + + SGI_WHISPER_QUEUE_FRAME.t = GetTime() + 0.5; + + end +end) + +local function ValidateName(player) + --Check: + -- Lock + -- filter + -- guild list + + if (SGI_DATA.lock[player.name]) then + return false; + end + + if (SGI_DATA.guildList[GetRealmName()][player.name]) then + return false; + end + + if (SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_ENABLE_FILTERS"] and not SGI:FilterPlayer(player)) then + return false; + end + + return true; +end + +local function TrimRealmName(name) + if (type(name) ~= "string") then SGI:debug("TrimRealmName: No name!") return end + + local myRealm = GetRealmName(); + + if (type(myRealm) ~= "string") then SGI:debug("TrimRealmName: No realmName!") return end + + if (strfind(name, myRealm)) then + if (strfind(name, "-")) then + local n = strsub(name,1,strfind(name,"-")-1); + return n; + end + end + return name; +end + +local function WhoResultCallback(query, results, complete) + if (whoSent) then + whoSent = false; + SGI:debug("...got reply"); + + flags = oldFlags; + + superScanProgress = superScanProgress + 1; + local ETR = (#whoQueryList - superScanProgress + 1) * superScanIntervalTime; + if (SuperScanFrame) then + SuperScanFrame.ETR = ETR; + SuperScanFrame.lastETR = GetTime(); + end + + local numResults = 0; + + for _, result in pairs(results) do + amountScanned = amountScanned + 1; + numResults = numResults + 1; + + result.Name = TrimRealmName(result.Name); + + SGI:BroadcastVersion(result.Name) + + if (result.Guild == "") then + local player = { + name = result.Name, + level = result.Level, + race = result.Race, + class = result.NoLocaleClass, + } + amountGuildless = amountGuildless + 1; + if (ValidateName(player)) then + PutOnHold(result.Name, result.Level, result.NoLocaleClass, result.Race, result.Class, GetTime()); + end + end + end + SGI:debug("Scan result: "..numResults); + end +end + +local function SuperScan() + if (GetTime() > superScanLast + superScanIntervalTime) then + if (superScanProgress == (#whoQueryList + 1)) then + superScanProgress = 1; + superScanLast = GetTime(); + amountGuildless = 0; + sessionTotal = sessionTotal + amountScanned; + amountScanned = 0; + else + oldFlags = flags; + flags = nil; + --SendWho(tostring(whoQueryList[superScanProgress])) + SGI.libWho:Who(tostring(whoQueryList[superScanProgress]),{queue = SGI.libWho.WHOLIB_QUERY_QUIET, callback = WhoResultCallback}); + whoSent = true; + superScanLast = GetTime(); + SGI:debug("Sent query: "..whoQueryList[superScanProgress].."..."); + end + superScanLast = GetTime(); + end + +end + +local function CreateSuperScanQuery(start, stop, interval, class, race) + + if (not SGI_DATA[SGI_DATA_INDEX].settings.checkBox["CHECKBOX_ADV_SCAN"]) then + interval = 5; + class = 999; + race = 999; + end + + local SGI_BREAK_POINT_SUPER_SCAN = 90; + + whoQueryList = {}; + local current = start; + local Classes = { + SGI.L["Death Knight"], + SGI.L["Demon Hunter"], + SGI.L["Druid"], + SGI.L["Hunter"], + SGI.L["Mage"], + SGI.L["Monk"], + SGI.L["Paladin"], + SGI.L["Priest"], + SGI.L["Rogue"], + SGI.L["Shaman"], + SGI.L["Warlock"], + SGI.L["Warrior"], + } + local Races = {} + if UnitFactionGroup("player") == "Horde" then + Races = { + SGI.L["Orc"], + SGI.L["Blood Elf"], + SGI.L["Undead"], + SGI.L["Troll"], + SGI.L["Goblin"], + SGI.L["Tauren"], + SGI.L["Pandaren"], + } + else + Races = { + SGI.L["Human"], + SGI.L["Dwarf"], + SGI.L["Worgen"], + SGI.L["Draenei"], + SGI.L["Night Elf"], + SGI.L["Gnome"], + SGI.L["Pandaren"], + } + end + + if (start < SGI_BREAK_POINT_SUPER_SCAN) then + while (current + interval < ( (SGI_BREAK_POINT_SUPER_SCAN > stop) and stop or SGI_BREAK_POINT_SUPER_SCAN)) do + + if (current + interval >= race and current + interval >= class) then + for k,_ in pairs(raceClassCombos[UnitFactionGroup("player")]) do + for j,_ in pairs(raceClassCombos[UnitFactionGroup("player")][k]) do + tinsert(whoQueryList, current.."- -"..(current + interval - 1).." r-"..SGI.L[k].." c-"..SGI.L[raceClassCombos[UnitFactionGroup("player")][k][j]]); + end + end + elseif (current + interval >= race) then + for k, _ in pairs(Races) do + tinsert(whoQueryList, current.."- -"..(current + interval - 1).." r-"..Races[k]); + end + elseif (current + interval >= class) then + for k, _ in pairs(Classes) do + tinsert(whoQueryList, current.."- -"..(current + interval - 1).." c-"..Classes[k]); + end + else + tinsert(whoQueryList, current.."- -"..(current + interval - 1)); + end + + current = current + interval; + end + + if ( current < ( (SGI_BREAK_POINT_SUPER_SCAN > stop) and stop or SGI_BREAK_POINT_SUPER_SCAN ) ) then + local t_stop = (SGI_BREAK_POINT_SUPER_SCAN > stop) and stop or SGI_BREAK_POINT_SUPER_SCAN; + if (t_stop >= race and t_stop >= class) then + for k,_ in pairs(raceClassCombos[UnitFactionGroup("player")]) do + for j,_ in pairs(raceClassCombos[UnitFactionGroup("player")][k]) do + tinsert(whoQueryList, current.."- -"..(t_stop).." r-"..SGI.L[k].." c-"..SGI.L[raceClassCombos[UnitFactionGroup("player")][k][j]]); + end + end + elseif (t_stop >= race) then + for k, _ in pairs(Races) do + tinsert(whoQueryList, current.."- -"..(t_stop).." r-"..Races[k]); + end + elseif (t_stop >= class) then + for k, _ in pairs(Classes) do + tinsert(whoQueryList, current.."- -"..(t_stop).." c-"..Classes[k]); + end + else + tinsert(whoQueryList, current.."- -"..(t_stop)); + end + current = t_stop + 1; + end + end + if (stop < current) then return end; + + while (current <= stop) do + if (current >= race and current >= class) then + for k,_ in pairs(raceClassCombos[UnitFactionGroup("player")]) do + for j,_ in pairs(raceClassCombos[UnitFactionGroup("player")][k]) do + tinsert(whoQueryList, current.." r-"..SGI.L[k].." c-"..SGI.L[raceClassCombos[UnitFactionGroup("player")][k][j]]); + end + end + elseif (current >= race) then + for k,_ in pairs(Races) do + tinsert(whoQueryList, current.." r-"..Races[k]); + end + elseif (current >= class) then + for k,_ in pairs(Classes) do + tinsert(whoQueryList, current.." c-"..Classes[k]); + end + else + tinsert(whoQueryList, current); + end + current = current + 1; + end +end + +local function CanResume() + local s = SGI_DATA[SGI_DATA_INDEX].settings; + return (start == s.lowLimit and stop == s.highLimit and race == s.raceStart and class == s.classStart and interval == s.interval); +end + +local function ResetSuperScan() + start = SGI_DATA[SGI_DATA_INDEX].settings.lowLimit; + stop = SGI_DATA[SGI_DATA_INDEX].settings.highLimit; + race = SGI_DATA[SGI_DATA_INDEX].settings.raceStart; + class = SGI_DATA[SGI_DATA_INDEX].settings.classStart; + interval = SGI_DATA[SGI_DATA_INDEX].settings.interval; + + amountGuildless = 0; + sessionTotal = sessionTotal + amountScanned; + amountScanned = 0; + superScanProgress = 1; + CreateSuperScanQuery(start, stop, interval, class, race); +end + +function SGI:StartSuperScan() + if (not CanResume()) then + ResetSuperScan(); + end + + if (SuperScanFrame) then + SuperScanFrame.lastETR = GetTime(); + end + + scanInProgress = true; + SGI_SUPER_SCAN:SetScript("OnUpdate", SuperScan); +end + +function SGI:StopSuperScan() + + scanInProgress = false; + SGI_SUPER_SCAN:SetScript("OnUpdate", nil); + SGI:debug(FriendsFrame:IsShown()); + --FriendsMicroButton:Click(); + --FriendsFrameCloseButton:Click(); +end + +function SGI:RemoveQueued(name) + SGI:LockPlayer(name); + SGI_QUEUE[name] = nil; + SGI_ANTI_SPAM[name] = nil; + + local nameTrim = TrimRealmName(name); + + SGI_ANTI_SPAM[nameTrim] = nil + SGI_QUEUE[nameTrim] = nil; + + SGI:debug("RemoveQueued(name) removed "..nameTrim); +end + +function SGI:UnregisterForWhisper(name) + whisperWaiting[name] = nil; + whisperQueue[name] = nil; +end + +function SGI:SendWhisper(message, name, delay) + whisperQueue[name] = {msg = message, t = delay + GetTime()}; + whisperWaiting[name] = nil; +end + +function SGI:RegisterForWhisper(name) + whisperWaiting[name] = true; +end + +function SGI:IsRegisteredForWhisper(name) + return whisperWaiting[name]; +end + + + +function SGI:SendGuildInvite(button) + local name = self.player + if not name then name = next(SGI_QUEUE) button = "LeftButton" end + if not name then return end + + if (SGI:IsLocked(name)) then + SGI:RemoveQueued(name); + return; + end + + if (UnitIsInMyGuild(name)) then + SGI:LockPlayer(name); + SGI:RemoveQueued(name); + return; + end + + if (button == "LeftButton") then + + if (SGI_DATA[SGI_DATA_INDEX].settings.dropDown["DROPDOWN_INVITE_MODE"] == 1) then + + GuildInvite(name); + SGI:LockPlayer(name); + --SGI:print("Only Invite: "..name); + + elseif (SGI_DATA[SGI_DATA_INDEX].settings.dropDown["DROPDOWN_INVITE_MODE"] == 2) then + + GuildInvite(name); + SGI:RegisterForWhisper(name); + SGI:LockPlayer(name); + --SGI:print("Invite, then whisper: "..name); + + elseif (SGI_DATA[SGI_DATA_INDEX].settings.dropDown["DROPDOWN_INVITE_MODE"] == 3) then + + SGI:SendWhisper(SGI:FormatWhisper(SGI:PickRandomWhisper(), name), name, 4); + SGI:LockPlayer(name); + --SGI:print("Only whisper: "..name); + + else + SGI:print(SGI.L["You need to specify the mode in which you wish to invite"]) + SGI:print(SGI.L["Go to Options and select your Invite Mode"]) + end + --GuildShield:IsShielded(name); + SGI:LiveSync(name) + end + + SGI:RemoveQueued(name); +end + +function SGI:RemoveShielded(player) + SGI:debug(player); + if (not player) then SGI:debug("Error: No player name provided!") return end + + local playerTrim = TrimRealmName(player); + + SGI_ANTI_SPAM[playerTrim] = nil + SGI_QUEUE[playerTrim] = nil; + SGI:LockPlayer(playerTrim); + + SGI_ANTI_SPAM[player] = nil + SGI_QUEUE[player] = nil; + SGI:LockPlayer(player); + SGI:print("|cffffff00Removed |r|cff00A2FF"..player.."|r|cffffff00 because they are shielded.|r") +end + +function SGI:GetNumQueued() + return SGI:CountTable(SGI_QUEUE); +end + +function SGI:PurgeQueue() + SGI_QUEUE = {}; + SGI_ANTI_SPAM = {}; +end + +function SGI:GetSuperScanETR() + if (whoQueryList) then + return SGI:FormatTime((#whoQueryList - superScanProgress + 1) * superScanIntervalTime); + else + return 0; + end +end + +function SGI:GetSuperScanProgress() + return floor((superScanProgress - 1) / #whoQueryList); +end + +function SGI:GetTotalScanTime() + return ((#whoQueryList - 1) * superScanIntervalTime); +end + +function SGI:IsScanning() + return scanInProgress; +end + +function SGI:GetInviteQueue() + return SGI_QUEUE; +end + +function SGI:GetSuperScanStats() + return amountScanned, amountGuildless, amountQueued, sessionTotal; +end + + + +SGI:debug(">> SuperScan.lua"); diff --git a/libs/Alerts/Alerts.lua b/libs/Alerts/Alerts.lua index 775b063..1734f97 100644 --- a/libs/Alerts/Alerts.lua +++ b/libs/Alerts/Alerts.lua @@ -1,56 +1,56 @@ -Alerter = CreateFrame("Frame") -Alerter.items = {} -Alerter.update = 0 -Alerter.free = { - [1] = true, - [2] = true, - [3] = true, - [4] = true, - [5] = true, -} -Alerter.wipe = {} - -local Alerts = {} - -do - yOfs = 250 - for i = 1,5 do - Alerter.items[i] = Alerter:CreateFontString() - Alerter.items[i]:SetFont("Fonts\\FRIZQT__.TTF",40,"OUTLINE") - Alerter.items[i]:SetPoint("CENTER",ALERT,"CENTER",0,yOfs) - yOfs = yOfs - 50 - end -end - -function Alerter:SendAlert(msg,duration) - tinsert(Alerts,{m=msg,t=GetTime()+duration}) -end - -Alerter:SetScript("OnUpdate",function() - if Alerter.update < GetTime() then - - for k,_ in pairs(Alerter.wipe) do - if Alerter.wipe[k] < GetTime() then - Alerter.items[k]:SetText("") - Alerter.wipe[k] = nil - Alerter.free[k] = true - end - end - - - for k,_ in pairs(Alerts) do - for j,_ in pairs(Alerter.free) do - if Alerter.free[j] then - Alerter.items[j]:SetText(Alerts[k].m) - Alerter.wipe[j] = Alerts[k].t - Alerter.free[j] = false - Alerts[k] = nil - break - end - end - end - - - Alerter.update = GetTime() + 0.2 - end -end) \ No newline at end of file +Alerter = CreateFrame("Frame") +Alerter.items = {} +Alerter.update = 0 +Alerter.free = { + [1] = true, + [2] = true, + [3] = true, + [4] = true, + [5] = true, +} +Alerter.wipe = {} + +local Alerts = {} + +do + yOfs = 250 + for i = 1,5 do + Alerter.items[i] = Alerter:CreateFontString() + Alerter.items[i]:SetFont("Fonts\\FRIZQT__.TTF",40,"OUTLINE") + Alerter.items[i]:SetPoint("CENTER",ALERT,"CENTER",0,yOfs) + yOfs = yOfs - 50 + end +end + +function Alerter:SendAlert(msg,duration) + tinsert(Alerts,{m=msg,t=GetTime()+duration}) +end + +Alerter:SetScript("OnUpdate",function() + if Alerter.update < GetTime() then + + for k,_ in pairs(Alerter.wipe) do + if Alerter.wipe[k] < GetTime() then + Alerter.items[k]:SetText("") + Alerter.wipe[k] = nil + Alerter.free[k] = true + end + end + + + for k,_ in pairs(Alerts) do + for j,_ in pairs(Alerter.free) do + if Alerter.free[j] then + Alerter.items[j]:SetText(Alerts[k].m) + Alerter.wipe[j] = Alerts[k].t + Alerter.free[j] = false + Alerts[k] = nil + break + end + end + end + + + Alerter.update = GetTime() + 0.2 + end +end) diff --git a/libs/ChatIntercept/ChatIntercept.lua b/libs/ChatIntercept/ChatIntercept.lua index 1022b86..33a53dc 100644 --- a/libs/ChatIntercept/ChatIntercept.lua +++ b/libs/ChatIntercept/ChatIntercept.lua @@ -1,124 +1,127 @@ --- Format: ["SYSTEM"] = { pattern1, pattern2, pattern3, ...} -local messagesToHide = { - ERR_GUILD_INVITE_S, - ERR_GUILD_DECLINE_S, - ERR_ALREADY_IN_GUILD_S, - ERR_ALREADY_INVITED_TO_GUILD_S, - ERR_GUILD_DECLINE_AUTO_S, - ERR_GUILD_PLAYER_NOT_FOUND_S, - ERR_CHAT_PLAYER_NOT_FOUND_S, -} - -local RealmCleanup = { - ERR_CHAT_PLAYER_NOT_FOUND_S, -} - -local chatFilters = {} -local OnInt = {} -local WhisperFilterActive = false; - -local function check(msg) - local place - local n - local name - for k,_ in pairs(messagesToHide) do - place = strfind(messagesToHide[k],"%s",1,true) - if place then - name = strfind(msg," ",place,true) - if name then - n = strsub(msg,place,name-1) - if format(messagesToHide[k],n) == msg then - return true - else - n = strsub(msg,place,name-2) - if format(messagesToHide[k],n) == msg then - return true - end - end - end - end - end -end - -local function check2(msg) - local place - local n - local name - for k,_ in pairs(RealmCleanup) do - place = strfind(RealmCleanup[k],"%s",1,true) - if place then - name = strfind(msg," ",place,true) - if name then - n = strsub(msg,place,name-1) - if format(RealmCleanup[k],n) == msg then - return true - else - n = strsub(msg,place,name-2) - if format(RealmCleanup[k],n) == msg then - return true - end - end - end - end - end -end - -local function HideOutWhispers(self, event, msg, sender) - if (sender == UnitName("player")) then - ChatFrame_RemoveMessageEventFilter("CHAT_MSG_WHISPER_INFORM", HideOutWhispers); - SGI:debug("Blocked outgoing whisper!"); - return true; - end -end - -local function HideSystemMessage(self, event, msg) - if (check(msg)) then - SGI:debug("Blocked message: "..msg); - return true; - end -end - -local function HideRealmConflictMessage(self, event, msg) - if (check2(msg)) then - SGI:debug("Blocked message: "..msg.." from check2()"); - return true; - end -end - -ChatIntercept = {} -function ChatIntercept:StateSystem(on) - if (on) then - ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", HideSystemMessage); - print("|cffffff00ChatIntercept [|r|cff16ABB5System Messages|r|cffffff00] is now |r|cff00ff00ACTIVE|r"); - else - ChatFrame_RemoveMessageEventFilter("CHAT_MSG_SYSTEM", HideSystemMessage); - print("|cffffff00ChatIntercept [|r|cff16ABB5System Messages|r|cffffff00] is now |r|cffff0000INACTIVE|r"); - end -end - -function ChatIntercept:StateRealm(state) - if (state) then - ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", HideRealmConflictMessage); - SGI:debug("Blocking realm conflict messages"); - else - ChatFrame_RemoveMessageEventFilter("CHAT_MSG_SYSTEM",HideRealmConflictMessage); - SGI:debug("Not blocking realm conflict messages"); - end -end - -function ChatIntercept:StateWhisper(on) - WhisperFilterActive = on; - if (on) then - --ChatFrame_AddMessageEventFilter("CHAT_MSG_WHISPER_INFORM", HideOutWhispers); - print("|cffffff00ChatIntercept [|r|cff16ABB5Whispers|r|cffffff00] is now |r|cff00ff00ACTIVE|r"); - else - --ChatFrame_RemoveMessageEventFilter("CHAT_MSG_WHISPER_INFORM", HideOutWhispers); - print("|cffffff00ChatIntercept [|r|cff16ABB5Whispers|r|cffffff00] is now |r|cffff0000INACTIVE|r"); - end -end - -function ChatIntercept:InterceptNextWhisper() - if (WhisperFilterActive) then - ChatFrame_AddMessageEventFilter("CHAT_MSG_WHISPER_INFORM", HideOutWhispers); - end -end \ No newline at end of file +-- Format: ["SYSTEM"] = { pattern1, pattern2, pattern3, ...} +local messagesToHide = { + ERR_GUILD_INVITE_S, + ERR_GUILD_DECLINE_S, + ERR_ALREADY_IN_GUILD_S, + ERR_ALREADY_INVITED_TO_GUILD_S, + ERR_GUILD_DECLINE_AUTO_S, + ERR_GUILD_PLAYER_NOT_FOUND_S, + ERR_CHAT_PLAYER_NOT_FOUND_S, +} + +local RealmCleanup = { + ERR_CHAT_PLAYER_NOT_FOUND_S, +} + +local chatFilters = {} +local OnInt = {} +local WhisperFilterActive = false; + +local function check(msg) + local place + local n + local name + for k,_ in pairs(messagesToHide) do + place = strfind(messagesToHide[k],"%s",1,true) + if place then + name = strfind(msg," ",place,true) + if name then + n = strsub(msg,place,name-1) + if format(messagesToHide[k],n) == msg then + return true + else + n = strsub(msg,place,name-2) + if format(messagesToHide[k],n) == msg then + return true + end + end + end + end + end +end + +local function check2(msg) + local place + local n + local name + for k,_ in pairs(RealmCleanup) do + place = strfind(RealmCleanup[k],"%s",1,true) + if place then + name = strfind(msg," ",place,true) + if name then + n = strsub(msg,place,name-1) + if format(RealmCleanup[k],n) == msg then + return true + else + n = strsub(msg,place,name-2) + if format(RealmCleanup[k],n) == msg then + return true + end + end + end + end + end +end + +local function HideOutWhispers(self, event, msg, sender) + if (sender == UnitName("player")) then + ChatFrame_RemoveMessageEventFilter("CHAT_MSG_WHISPER_INFORM", HideOutWhispers); + SGI:debug("Blocked outgoing whisper!"); + return true; + end +end + +local function HideSystemMessage(self, event, msg) + if (check(msg)) then + SGI:debug("Blocked message: "..msg); + return true; + end +end + +local function HideRealmConflictMessage(self, event, msg) + if (check2(msg)) then + SGI:debug("Blocked message: "..msg.." from check2()"); + return true; + end +end + +ChatIntercept = {} +function ChatIntercept:StateSystem(on) + if (on) then + ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", HideSystemMessage); +-- print("|cffffff00ChatIntercept [|r|cff16ABB5System Messages|r|cffffff00] is now |r|cff00ff00ACTIVE|r"); + else + ChatFrame_RemoveMessageEventFilter("CHAT_MSG_SYSTEM", HideSystemMessage); +-- print("|cffffff00ChatIntercept [|r|cff16ABB5System Messages|r|cffffff00] is now |r|cffff0000INACTIVE|r"); + end +end + +function ChatIntercept:StateRealm(state) + if (state) then + ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", HideRealmConflictMessage); +-- SGI:debug("Blocking realm conflict messages"); + else + ChatFrame_RemoveMessageEventFilter("CHAT_MSG_SYSTEM",HideRealmConflictMessage); +-- SGI:debug("Not blocking realm conflict messages"); + end +end + +function ChatIntercept:StateWhisper(on) + + if (on) then + ChatFrame_AddMessageEventFilter("CHAT_MSG_WHISPER_INFORM", HideOutWhispers); + WhisperFilterActive = on; +-- print("|cffffff00ChatIntercept [|r|cff16ABB5Whispers|r|cffffff00] is now |r|cff00ff00ACTIVE|r"); + else + ChatFrame_RemoveMessageEventFilter("CHAT_MSG_WHISPER_INFORM", HideOutWhispers); + WhisperFilterActive = nill; +-- print("|cffffff00ChatIntercept [|r|cff16ABB5Whispers|r|cffffff00] is now |r|cffff0000INACTIVE|r"); + end +end + +function ChatIntercept:InterceptNextWhisper() + + if (WhisperFilterActive) then + ChatFrame_AddMessageEventFilter("CHAT_MSG_WHISPER_INFORM", HideOutWhispers); + end +end diff --git a/libs/LibWho-2.0/Changelog-LibWho-2.0-2.0.146.txt b/libs/LibWho-2.0/Changelog-LibWho-2.0-2.0.146.txt index 802fe25..9cbfe5b 100644 --- a/libs/LibWho-2.0/Changelog-LibWho-2.0-2.0.146.txt +++ b/libs/LibWho-2.0/Changelog-LibWho-2.0-2.0.146.txt @@ -1,25 +1,25 @@ ------------------------------------------------------------------------- -r146 | mysticalos | 2015-02-24 16:45:37 +0000 (Tue, 24 Feb 2015) | 1 line -Changed paths: - A /tags/2.0.146 (from /trunk:145) - -Tagging as 2.0.146 ------------------------------------------------------------------------- -r145 | MysticalOS | 2015-02-24 16:43:23 +0000 (Tue, 24 Feb 2015) | 1 line -Changed paths: - M /trunk/LibWho-2.0.toc - -ToC ------------------------------------------------------------------------- -r143 | sylvanaar | 2015-02-01 17:28:35 +0000 (Sun, 01 Feb 2015) | 1 line -Changed paths: - M /trunk/LibWho-2.0/LibWho-2.0.lua - -Fix compatibility error with Swatter. Issue #25 ------------------------------------------------------------------------- -r142 | sylvanaar | 2015-02-01 17:26:11 +0000 (Sun, 01 Feb 2015) | 1 line -Changed paths: - M /trunk/LibWho-2.0/LibWho-2.0.lua - -Fix 0/1 false/true errors. Issue #24 ------------------------------------------------------------------------- +------------------------------------------------------------------------ +r146 | mysticalos | 2015-02-24 16:45:37 +0000 (Tue, 24 Feb 2015) | 1 line +Changed paths: + A /tags/2.0.146 (from /trunk:145) + +Tagging as 2.0.146 +------------------------------------------------------------------------ +r145 | MysticalOS | 2015-02-24 16:43:23 +0000 (Tue, 24 Feb 2015) | 1 line +Changed paths: + M /trunk/LibWho-2.0.toc + +ToC +------------------------------------------------------------------------ +r143 | sylvanaar | 2015-02-01 17:28:35 +0000 (Sun, 01 Feb 2015) | 1 line +Changed paths: + M /trunk/LibWho-2.0/LibWho-2.0.lua + +Fix compatibility error with Swatter. Issue #25 +------------------------------------------------------------------------ +r142 | sylvanaar | 2015-02-01 17:26:11 +0000 (Sun, 01 Feb 2015) | 1 line +Changed paths: + M /trunk/LibWho-2.0/LibWho-2.0.lua + +Fix 0/1 false/true errors. Issue #24 +------------------------------------------------------------------------ diff --git a/libs/LibWho-2.0/LibWho-2.0.toc b/libs/LibWho-2.0/LibWho-2.0.toc index 4a2fe9e..0f8ae68 100644 --- a/libs/LibWho-2.0/LibWho-2.0.toc +++ b/libs/LibWho-2.0/LibWho-2.0.toc @@ -1,23 +1,23 @@ -## Interface: 60100 -## X-Curse-Packaged-Version: 2.0.146 -## X-Curse-Project-Name: WhoLib -## X-Curse-Project-ID: wholib -## X-Curse-Repository-ID: wow/wholib/mainline - -## Title: Lib: LibWho-2.0 -## Notes: Queing of /who and SendWho() queries and a much better interface (see docs), with gurantee to be executed & callback. -## Version: 2.0.145 -## Author: ALeX Kazik, Sylvanaar, Pazza -## eMail: wow@kazik.de -## X-Category: Library - -## OptionalDeps: LibStub, CallbackHandler-1.0 - -## LoadOnDemand: 1 - -#@no-lib-strip@ -libs\LibStub\LibStub.lua -libs\CallbackHandler-1.0\CallbackHandler-1.0.lua -#@end-no-lib-strip@ - -LibWho-2.0\LibWho-2.0.lua +## Interface: 60100 +## X-Curse-Packaged-Version: 2.0.146 +## X-Curse-Project-Name: WhoLib +## X-Curse-Project-ID: wholib +## X-Curse-Repository-ID: wow/wholib/mainline + +## Title: Lib: LibWho-2.0 +## Notes: Queing of /who and SendWho() queries and a much better interface (see docs), with gurantee to be executed & callback. +## Version: 2.0.145 +## Author: ALeX Kazik, Sylvanaar, Pazza +## eMail: wow@kazik.de +## X-Category: Library + +## OptionalDeps: LibStub, CallbackHandler-1.0 + +## LoadOnDemand: 1 + +#@no-lib-strip@ +libs\LibStub\LibStub.lua +libs\CallbackHandler-1.0\CallbackHandler-1.0.lua +#@end-no-lib-strip@ + +LibWho-2.0\LibWho-2.0.lua diff --git a/libs/LibWho-2.0/LibWho-2.0/LibWho-2.0.lua b/libs/LibWho-2.0/LibWho-2.0/LibWho-2.0.lua index 64c859b..47d5780 100644 --- a/libs/LibWho-2.0/LibWho-2.0/LibWho-2.0.lua +++ b/libs/LibWho-2.0/LibWho-2.0/LibWho-2.0.lua @@ -1,948 +1,948 @@ ---- ---- check for an already loaded old WhoLib ---- - -if WhoLibByALeX or WhoLib then - -- the WhoLib-1.0 (WhoLibByALeX) or WhoLib (by Malex) is loaded -> fail! - error("an other WhoLib is already running - disable them first!\n") - return -end -- if - ---- ---- check version ---- - -assert(LibStub, "LibWho-2.0 requires LibStub") - - -local major_version = 'LibWho-2.0' -local minor_version = tonumber("145") or 99999 - -local lib = LibStub:NewLibrary(major_version, minor_version) - - -if not lib then - return -- already loaded and no upgrade necessary -end - -lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib) -local callbacks = lib.callbacks - -local am = {} -local om = getmetatable(lib) -if om then - for k, v in pairs(om) do am[k] = v end -end -am.__tostring = function() return major_version end -setmetatable(lib, am) - -local function dbgfunc(...) if lib.Debug then print(...) end end -local function NOP() return end -local dbg = NOP - ---- ---- initalize base ---- - -if type(lib['hooked']) ~= 'table' then - lib['hooked'] = {} -end -- if - -if type(lib['hook']) ~= 'table' then - lib['hook'] = {} -end -- if - -if type(lib['events']) ~= 'table' then - lib['events'] = {} -end -- if - -if type(lib['embeds']) ~= 'table' then - lib['embeds'] = {} -end -- if - -if type(lib['frame']) ~= 'table' then - lib['frame'] = CreateFrame('Frame', major_version); -end -- if -lib['frame']:Hide() - -lib.Queue = {[1]={}, [2]={}, [3]={}} -lib.WhoInProgress = false -lib.Result = nil -lib.Args = nil -lib.Total = nil -lib.Quiet = nil -lib.Debug = false -lib.Cache = {} -lib.CacheQueue = {} -lib.SetWhoToUIState = false - - -lib.MinInterval = 2.5 -lib.MaxInterval = 10 - ---- ---- locale ---- - -if (GetLocale() == "ruRU") then - lib.L = { - ['console_queued'] = 'Добавлено в очередь "/who %s"', - ['console_query'] = 'Результат "/who %s"', - ['gui_wait'] = '- Пожалуйста подождите -', - } -else - -- enUS is the default - lib.L = { - ['console_queued'] = 'Added "/who %s" to queue', - ['console_query'] = 'Result of "/who %s"', - ['gui_wait'] = '- Please Wait -', - } -end -- if - - ---- ---- external functions/constants ---- - -lib['external'] = { - 'WHOLIB_QUEUE_USER', - 'WHOLIB_QUEUE_QUIET', - 'WHOLIB_QUEUE_SCANNING', - 'WHOLIB_FLAG_ALWAYS_CALLBACK', - 'Who', - 'UserInfo', - 'CachedUserInfo', - 'GetWhoLibDebug', - 'SetWhoLibDebug', --- 'RegisterWhoLibEvent', -} - --- queues -lib['WHOLIB_QUEUE_USER'] = 1 -lib['WHOLIB_QUEUE_QUIET'] = 2 -lib['WHOLIB_QUEUE_SCANNING'] = 3 - - - -local queue_all = { - [1] = 'WHOLIB_QUEUE_USER', - [2] = 'WHOLIB_QUEUE_QUIET', - [3] = 'WHOLIB_QUEUE_SCANNING', -} - -local queue_quiet = { - [2] = 'WHOLIB_QUEUE_QUIET', - [3] = 'WHOLIB_QUEUE_SCANNING', -} - --- bit masks! -lib['WHOLIB_FLAG_ALWAYS_CALLBACK'] = 1 - -function lib:Reset() - self.Queue = {[1]={}, [2]={}, [3]={}} - self.Cache = {} - self.CacheQueue = {} -end - -function lib.Who(defhandler, query, opts) - local self, args, usage = lib, {}, 'Who(query, [opts])' - - args.query = self:CheckArgument(usage, 'query', 'string', query) - opts = self:CheckArgument(usage, 'opts', 'table', opts, {}) - args.queue = self:CheckPreset(usage, 'opts.queue', queue_all, opts.queue, self.WHOLIB_QUEUE_SCANNING) - args.flags = self:CheckArgument(usage, 'opts.flags', 'number', opts.flags, 0) - args.callback, args.handler = self:CheckCallback(usage, 'opts.', opts.callback, opts.handler, defhandler) - -- now args - copied and verified from opts - - if args.queue == self.WHOLIB_QUEUE_USER then - if WhoFrame:IsShown() then - self:GuiWho(args.query) - else - self:ConsoleWho(args.query) - end - else - self:AskWho(args) - end -end - -local function ignoreRealm(name) - local _, realm = string.split("-", name) - local connectedServers = GetAutoCompleteRealms() - if connectedServers then - for i = 1, #connectedServers do - if realm == connectedServers[i] then return false end - end - end - return true -end - -function lib.UserInfo(defhandler, name, opts) - local self, args, usage = lib, {}, 'UserInfo(name, [opts])' - local now = time() - - name = self:CheckArgument(usage, 'name', 'string', name) - if name:len() == 0 then return end - - --There is no api to tell connected realms from cross realm by name. As such, we check known connections table before excluding who inquiry - --UnitRealmRelationship and UnitIsSameServer don't work with "name". They require unitID so they are useless here - if name:find("%-") and ignoreRealm(name) then return end - - args.name = self:CapitalizeInitial(name) - opts = self:CheckArgument(usage, 'opts', 'table', opts, {}) - args.queue = self:CheckPreset(usage, 'opts.queue', queue_quiet, opts.queue, self.WHOLIB_QUEUE_SCANNING) - args.flags = self:CheckArgument(usage, 'opts.flags', 'number', opts.flags, 0) - args.timeout = self:CheckArgument(usage, 'opts.timeout', 'number', opts.timeout, 5) - args.callback, args.handler = self:CheckCallback(usage, 'opts.', opts.callback, opts.handler, defhandler) - - -- now args - copied and verified from opts - local cachedName = self.Cache[args.name] - - if(cachedName ~= nil)then - -- user is in cache - if(cachedName.valid == true and (args.timeout < 0 or cachedName.last + args.timeout*60 > now))then - -- cache is valid and timeout is in range - --dbg('Info(' .. args.name ..') returned immedeatly') - if(bit.band(args.flags, self.WHOLIB_FLAG_ALWAYS_CALLBACK) ~= 0)then - self:RaiseCallback(args, cachedName.data) - return false - else - return self:DupAll(self:ReturnUserInfo(args.name)) - end - elseif(cachedName.valid == false)then - -- query is already running (first try) - if(args.callback ~= nil)then - tinsert(cachedName.callback, args) - end - --dbg('Info(' .. args.name ..') returned cause it\'s already searching') - return nil - end - else - self.Cache[args.name] = {valid=false, inqueue=false, callback={}, data={Name = args.name}, last=now } - end - - local cachedName = self.Cache[args.name] - - if(cachedName.inqueue)then - -- query is running! - if(args.callback ~= nil)then - tinsert(cachedName.callback, args) - end - dbg('Info(' .. args.name ..') returned cause it\'s already searching') - return nil - end - if (GetLocale() == "ruRU") then -- in ruRU with n- not show information about player in WIM addon - if args.name and args.name:len() > 0 then - local query = 'и-"' .. args.name .. '"' - cachedName.inqueue = true - if(args.callback ~= nil)then - tinsert(cachedName.callback, args) - end - self.CacheQueue[query] = args.name - dbg('Info(' .. args.name ..') added to queue') - self:AskWho( { query = query, queue = args.queue, flags = 0, info = args.name } ) - end - else - if args.name and args.name:len() > 0 then - local query = 'n-"' .. args.name .. '"' - cachedName.inqueue = true - if(args.callback ~= nil)then - tinsert(cachedName.callback, args) - end - self.CacheQueue[query] = args.name - dbg('Info(' .. args.name ..') added to queue') - self:AskWho( { query = query, queue = args.queue, flags = 0, info = args.name } ) - end - end - return nil -end - -function lib.CachedUserInfo(_, name) - local self, usage = lib, 'CachedUserInfo(name)' - - name = self:CapitalizeInitial(self:CheckArgument(usage, 'name', 'string', name)) - - if self.Cache[name] == nil then - return nil - else - return self:DupAll(self:ReturnUserInfo(name)) - end -end - -function lib.GetWhoLibDebug(_, mode) - return lib.Debug -end - -function lib.SetWhoLibDebug(_, mode) - lib.Debug = mode - dbg = mode and dbgfunc or NOP -end - ---function lib.RegisterWhoLibEvent(defhandler, event, callback, handler) --- local self, usage = lib, 'RegisterWhoLibEvent(event, callback, [handler])' --- --- self:CheckPreset(usage, 'event', self.events, event) --- local callback, handler = self:CheckCallback(usage, '', callback, handler, defhandler, true) --- table.insert(self.events[event], {callback=callback, handler=handler}) ---end - --- non-embedded externals - -function lib.Embed(_, handler) - local self, usage = lib, 'Embed(handler)' - - self:CheckArgument(usage, 'handler', 'table', handler) - - for _,name in pairs(self.external) do - handler[name] = self[name] - end -- do - self['embeds'][handler] = true - - return handler -end - -function lib.Library(_) - local self = lib - - return self:Embed({}) -end - ---- ---- internal functions ---- - -function lib:AllQueuesEmpty() - local queueCount = #self.Queue[1] + #self.Queue[2] + #self.Queue[3] + #self.CacheQueue - - -- Be sure that we have cleared the in-progress status - if self.WhoInProgress then - queueCount = queueCount + 1 - end - - return queueCount == 0 -end - -local queryInterval = 5 - -function lib:GetQueryInterval() return queryInterval end - -function lib:AskWhoNextIn5sec() - if self.frame:IsShown() then return end - - dbg("Waiting to send next who") - self.Timeout_time = queryInterval - self['frame']:Show() -end - -function lib:CancelPendingWhoNext() - lib['frame']:Hide() -end - -lib['frame']:SetScript("OnUpdate", function(frame, elapsed) - lib.Timeout_time = lib.Timeout_time - elapsed - if lib.Timeout_time <= 0 then - lib['frame']:Hide() - lib:AskWhoNext() - end -- if -end); - - --- queue scheduler -local queue_weights = { [1] = 0.6, [2] = 0.2, [3] = 0.2 } -local queue_bounds = { [1] = 0.6, [2] = 0.2, [3] = 0.2 } - --- allow for single queries from the user to get processed faster -local lastInstantQuery = time() -local INSTANT_QUERY_MIN_INTERVAL = 60 -- only once every 1 min - -function lib:UpdateWeights() - local weightsum, sum, count = 0, 0, 0 - for k,v in pairs(queue_weights) do - sum = sum + v - weightsum = weightsum + v * #self.Queue[k] - end - - if weightsum == 0 then - for k,v in pairs(queue_weights) do queue_bounds[k] = v end - return - end - - local adjust = sum / weightsum - - for k,v in pairs(queue_bounds) do - queue_bounds[k] = queue_weights[k] * adjust * #self.Queue[k] - end -end - -function lib:GetNextFromScheduler() - self:UpdateWeights() - - -- Since an addon could just fill up the user q for instant processing - -- we have to limit instants to 1 per INSTANT_QUERY_MIN_INTERVAL - -- and only try instant fulfilment if it will empty the user queue - if #self.Queue[1] == 1 then - if time() - lastInstantQuery > INSTANT_QUERY_MIN_INTERVAL then - dbg("INSTANT") - lastInstantQuery = time() - return 1, self.Queue[1] - end - end - - local n,i = math.random(),0 - repeat - i=i+1 - n = n - queue_bounds[i] - until i>=#self.Queue or n <= 0 - - dbg(("Q=%d, bound=%d"):format(i, queue_bounds[i])) - - if #self.Queue[i] > 0 then - dbg(("Q=%d, bound=%d"):format(i, queue_bounds[i])) - return i, self.Queue[i] - else - dbg("Queues empty, waiting") - end -end - -lib.queue_bounds = queue_bounds - -function lib:AskWhoNext() - if lib.frame:IsShown() then - dbg("Already waiting") - return - end - - self:CancelPendingWhoNext() - - if self.WhoInProgress then - -- if we had a who going, it didnt complete - dbg("TIMEOUT: "..self.Args.query) - local args = self.Args - self.Args = nil --- if args.info and self.CacheQueue[args.query] ~= nil then - dbg("Requeing "..args.query) - tinsert(self.Queue[args.queue], args) - if args.console_show ~= nil then - DEFAULT_CHAT_FRAME:AddMessage(("Timeout on result of '%s' - retrying..."):format(args.query),1,1,0) - args.console_show = true - end --- end - - if queryInterval < lib.MaxInterval then - queryInterval = queryInterval + 0.5 - dbg("--Throttling down to 1 who per " .. queryInterval .. "s") - end - end - - - self.WhoInProgress = false - - local v,k,args = nil - local kludge = 10 - repeat - k,v = self:GetNextFromScheduler() - if not k then break end - if(WhoFrame:IsShown() and k > self.WHOLIB_QUEUE_QUIET)then - break - end - if(#v > 0)then - args = tremove(v, 1) - break - end - kludge = kludge - 1 - until kludge <= 0 - - if args then - self.WhoInProgress = true - self.Result = {} - self.Args = args - self.Total = -1 - if(args.console_show == true)then - DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_query'], args.query), 1, 1, 0) - - end - - if args.queue == self.WHOLIB_QUEUE_USER then - WhoFrameEditBox:SetText(args.query) - self.Quiet = false - - if args.whotoui then - self.hooked.SetWhoToUI(args.whotoui) - else - self.hooked.SetWhoToUI(args.gui and true or false) - end - else - self.hooked.SetWhoToUI(true) - self.Quiet = true - end - - dbg("QUERY: "..args.query) - self.hooked.SendWho(args.query) - else - self.Args = nil - self.WhoInProgress = false - end - - -- Keep processing the who queue if there is more work - if not self:AllQueuesEmpty() then - self:AskWhoNextIn5sec() - else - dbg("*** Done processing requests ***") - end -end - -function lib:AskWho(args) - tinsert(self.Queue[args.queue], args) - dbg('[' .. args.queue .. '] added "' .. args.query .. '", queues=' .. #self.Queue[1] .. '/'.. #self.Queue[2] .. '/'.. #self.Queue[3]) - self:TriggerEvent('WHOLIB_QUERY_ADDED') - - self:AskWhoNext() -end - -function lib:ReturnWho() - if not self.Args then - self.Quiet = nil - return - end - - if(self.Args.queue == self.WHOLIB_QUEUE_QUIET or self.Args.queue == self.WHOLIB_QUEUE_SCANNING)then - self.Quiet = nil - end - - if queryInterval > self.MinInterval then - queryInterval = queryInterval - 0.5 - dbg("--Throttling up to 1 who per " .. queryInterval .. "s") - end - - self.WhoInProgress = false - dbg("RESULT: "..self.Args.query) - dbg('[' .. self.Args.queue .. '] returned "' .. self.Args.query .. '", total=' .. self.Total ..' , queues=' .. #self.Queue[1] .. '/'.. #self.Queue[2] .. '/'.. #self.Queue[3]) - local now = time() - local complete = (self.Total == #self.Result) and (self.Total < MAX_WHOS_FROM_SERVER) - for _,v in pairs(self.Result)do - if(self.Cache[v.Name] == nil)then - self.Cache[v.Name] = { inqueue = false, callback = {} } - end - - local cachedName = self.Cache[v.Name] - - cachedName.valid = true -- is now valid - cachedName.data = v -- update data - cachedName.data.Online = true -- player is online - cachedName.last = now -- update timestamp - if(cachedName.inqueue)then - if(self.Args.info and self.CacheQueue[self.Args.query] == v.Name)then - -- found by the query which was created to -> remove us from query - self.CacheQueue[self.Args.query] = nil - else - -- found by another query - for k2,v2 in pairs(self.CacheQueue) do - if(v2 == v.Name)then - for i=self.WHOLIB_QUEUE_QUIET, self.WHOLIB_QUEUE_SCANNING do - for k3,v3 in pairs(self.Queue[i]) do - if(v3.query == k2 and v3.info)then - -- remove the query which was generated for this user, cause another query was faster... - dbg("Found '"..v.Name.."' early via query '"..self.Args.query.."'") - table.remove(self.Queue[i], k3) - self.CacheQueue[k2] = nil - end - end - end - end - end - end - dbg('Info(' .. v.Name ..') returned: on') - for _,v2 in pairs(cachedName.callback) do - self:RaiseCallback(v2, self:ReturnUserInfo(v.Name)) - end - cachedName.callback = {} - end - cachedName.inqueue = false -- query is done - end - if(self.Args.info and self.CacheQueue[self.Args.query])then - -- the query did not deliver the result => not online! - local name = self.CacheQueue[self.Args.query] - local cachedName = self.Cache[name] - if (cachedName.inqueue)then - -- nothing found (yet) - cachedName.valid = true -- is now valid - cachedName.inqueue = false -- query is done? - cachedName.last = now -- update timestamp - if(complete)then - cachedName.data.Online = false -- player is offline - else - cachedName.data.Online = nil -- player is unknown (more results from who than can be displayed) - end - end - dbg('Info(' .. name ..') returned: ' .. (cachedName.data.Online == false and 'off' or 'unkn')) - for _,v in pairs(cachedName.callback) do - self:RaiseCallback(v, self:ReturnUserInfo(name)) - end - cachedName.callback = {} - self.CacheQueue[self.Args.query] = nil - end - self:RaiseCallback(self.Args, self.Args.query, self.Result, complete, self.Args.info) - self:TriggerEvent('WHOLIB_QUERY_RESULT', self.Args.query, self.Result, complete, self.Args.info) - - if not self:AllQueuesEmpty() then - self:AskWhoNextIn5sec() - end -end - -function lib:GuiWho(msg) - if(msg == self.L['gui_wait'])then - return - end - - for _,v in pairs(self.Queue[self.WHOLIB_QUEUE_USER]) do - if(v.gui == true)then - return - end - end - if(self.WhoInProgress)then - WhoFrameEditBox:SetText(self.L['gui_wait']) - end - self.savedText = msg - self:AskWho({query = msg, queue = self.WHOLIB_QUEUE_USER, flags = 0, gui = true}) - WhoFrameEditBox:ClearFocus(); -end - -function lib:ConsoleWho(msg) - --WhoFrameEditBox:SetText(msg) - local console_show = false - local q1 = self.Queue[self.WHOLIB_QUEUE_USER] - local q1count = #q1 - - if(q1count > 0 and q1[q1count].query == msg)then -- last query is itdenical: drop - return - end - - if(q1count > 0 and q1[q1count].console_show == false)then -- display 'queued' if console and not yet shown - DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_queued'], q1[q1count].query), 1, 1, 0) - q1[q1count].console_show = true - end - if(q1count > 0 or self.WhoInProgress)then - DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_queued'], msg), 1, 1, 0) - console_show = true - end - self:AskWho({query = msg, queue = self.WHOLIB_QUEUE_USER, flags = 0, console_show = console_show}) -end - -function lib:ReturnUserInfo(name) - if(name ~= nil and self ~= nil and self.Cache ~= nil and self.Cache[name] ~= nil) then - return self.Cache[name].data, (time() - self.Cache[name].last) / 60 - end -end - -function lib:RaiseCallback(args, ...) - if type(args.callback) == 'function' then - args.callback(self:DupAll(...)) - elseif args.callback then -- must be a string - args.handler[args.callback](args.handler, self:DupAll(...)) - end -- if -end - --- Argument checking - -function lib:CheckArgument(func, name, argtype, arg, defarg) - if arg == nil and defarg ~= nil then - return defarg - elseif type(arg) == argtype then - return arg - else - error(string.format("%s: '%s' - %s%s expected got %s", func, name, (defarg ~= nil) and 'nil or ' or '', argtype, type(arg)), 3) - end -- if -end - -function lib:CheckPreset(func, name, preset, arg, defarg) - if arg == nil and defarg ~= nil then - return defarg - elseif arg ~= nil and preset[arg] ~= nil then - return arg - else - local p = {} - for k,v in pairs(preset) do - if type(v) ~= 'string' then - table.insert(p, k) - else - table.insert(p, v) - end -- if - end -- for - error(string.format("%s: '%s' - one of %s%s expected got %s", func, name, (defarg ~= nil) and 'nil, ' or '', table.concat(p, ', '), self:simple_dump(arg)), 3) - end -- if -end - -function lib:CheckCallback(func, prefix, callback, handler, defhandler, nonil) - if not nonil and callback == nil then - -- no callback: ignore handler - return nil, nil - elseif type(callback) == 'function' then - -- simple function - if handler ~= nil then - error(string.format("%s: '%shandler' - nil expected got %s", func, prefix, type(arg)), 3) - end -- if - elseif type(callback) == 'string' then - -- method - if handler == nil then - handler = defhandler - end -- if - if type(handler) ~= 'table' or type(handler[callback]) ~= 'function' or handler == self then - error(string.format("%s: '%shandler' - nil or function expected got %s", func, prefix, type(arg)), 3) - end -- if - else - error(string.format("%s: '%scallback' - %sfunction or string expected got %s", func, prefix, nonil and 'nil or ' or '', type(arg)), 3) - end -- if - - return callback, handler -end - --- helpers - -function lib:simple_dump(x) - if type(x) == 'string' then - return 'string \''..x..'\'' - elseif type(x) == 'number' then - return 'number '..x - else - return type(x) - end -end - -function lib:Dup(from) - local to = {} - - for k,v in pairs(from) do - if type(v) == 'table' then - to[k] = self:Dup(v) - else - to[k] = v - end -- if - end -- for - - return to -end - -function lib:DupAll(x, ...) - if type(x) == 'table' then - return self:Dup(x), self:DupAll(...) - elseif x ~= nil then - return x, self:DupAll(...) - else - return nil - end -- if -end - -local MULTIBYTE_FIRST_CHAR = "^([\192-\255]?%a?[\128-\191]*)" - -function lib:CapitalizeInitial(name) - return name:gsub(MULTIBYTE_FIRST_CHAR, string.upper, 1) -end - ---- ---- user events (Using CallbackHandler) ---- - -lib.PossibleEvents = { - 'WHOLIB_QUERY_RESULT', - 'WHOLIB_QUERY_ADDED', -} - -function lib:TriggerEvent(event, ...) - callbacks:Fire(event, ...) -end - ---- ---- slash commands ---- - -SlashCmdList['WHO'] = function(msg) - dbg("console /who: "..msg) - -- new /who function - --local self = lib - - if(msg == '')then - lib:GuiWho(WhoFrame_GetDefaultWhoCommand()) - elseif(WhoFrame:IsVisible())then - lib:GuiWho(msg) - else - lib:ConsoleWho(msg) - end -end - -SlashCmdList['WHOLIB_DEBUG'] = function() - -- /wholibdebug: toggle debug on/off - local self = lib - - self:SetWhoLibDebug(not self.Debug) -end - -SLASH_WHOLIB_DEBUG1 = '/wholibdebug' - - ---- ---- hook activation ---- - --- functions to hook -local hooks = { - 'SendWho', - 'WhoFrameEditBox_OnEnterPressed', --- 'FriendsFrame_OnEvent', - 'SetWhoToUI', -} - --- hook all functions (which are not yet hooked) -for _, name in pairs(hooks) do - if not lib['hooked'][name] then - lib['hooked'][name] = _G[name] - _G[name] = function(...) - lib.hook[name](lib, ...) - end -- function - end -- if -end -- for - --- fake 'WhoFrame:Hide' as hooked -table.insert(hooks, 'WhoFrame_Hide') - --- check for unused hooks -> remove function -for name, _ in pairs(lib['hook']) do - if not hooks[name] then - lib['hook'][name] = function() end - end -- if -end -- for - --- secure hook 'WhoFrame:Hide' -if not lib['hooked']['WhoFrame_Hide'] then - lib['hooked']['WhoFrame_Hide'] = true - hooksecurefunc(WhoFrame, 'Hide', function(...) - lib['hook']['WhoFrame_Hide'](lib, ...) - end -- function - ) -end -- if - - - ------ Coroutine based implementation (future) ---function lib:sendWhoResult(val) --- coroutine.yield(val) ---end --- ---function lib:sendWaitState(val) --- coroutine.yield(val) ---end --- ---function lib:producer() --- return coroutine.create( --- function() --- lib:AskWhoNext() --- lib:sendWaitState(true) --- --- -- Resumed look for data --- --- end) ---end - - - - - ---- ---- hook replacements ---- - -function lib.hook.SendWho(self, msg) - dbg("SendWho: "..msg) - lib.AskWho(self, {query = msg, queue = lib.WHOLIB_QUEUE_USER, whotoui = lib.SetWhoToUIState, flags = 0}) -end - -function lib.hook.WhoFrameEditBox_OnEnterPressed(self) - lib:GuiWho(WhoFrameEditBox:GetText()) -end - ---[[ -function lib.hook.FriendsFrame_OnEvent(self, ...) - if event ~= 'WHO_LIST_UPDATE' or not lib.Quiet then - lib.hooked.FriendsFrame_OnEvent(...) - end -end -]] - -hooksecurefunc(FriendsFrame, 'RegisterEvent', function(self, event) - if(event == "WHO_LIST_UPDATE") then - self:UnregisterEvent("WHO_LIST_UPDATE"); - end - end); - - -function lib.hook.SetWhoToUI(self, state) - lib.SetWhoToUIState = state -end - -function lib.hook.WhoFrame_Hide(self) - if(not lib.WhoInProgress)then - lib:AskWhoNextIn5sec() - end -end - - ---- ---- WoW events ---- - -local who_pattern = string.gsub(WHO_NUM_RESULTS, '%%d', '%%d%+') - - -function lib:CHAT_MSG_SYSTEM(arg1) - if arg1 and arg1:find(who_pattern) then - lib:ProcessWhoResults() - end -end - -FriendsFrame:UnregisterEvent("WHO_LIST_UPDATE") - -function lib:WHO_LIST_UPDATE() - if not lib.Quiet then - WhoList_Update() - FriendsFrame_Update() - end - - lib:ProcessWhoResults() -end - -function lib:ProcessWhoResults() - local num - self.Total, num = GetNumWhoResults() - for i=1, num do - local charname, guildname, level, race, class, zone, nonlocalclass, sex = GetWhoInfo(i) - self.Result[i] = {Name=charname, Guild=guildname, Level=level, Race=race, Class=class, Zone=zone, NoLocaleClass=nonlocalclass, Sex=sex } - end - - self:ReturnWho() -end - ---- ---- event activation ---- - -lib['frame']:UnregisterAllEvents(); - -lib['frame']:SetScript("OnEvent", function(frame, event, ...) - lib[event](lib, ...) -end); - -for _,name in pairs({ - 'CHAT_MSG_SYSTEM', - 'WHO_LIST_UPDATE', -}) do - lib['frame']:RegisterEvent(name); -end -- for - - ---- ---- re-embed ---- - -for target,_ in pairs(lib['embeds']) do - if type(target) == 'table' then - lib:Embed(target) - end -- if -end -- for +--- +--- check for an already loaded old WhoLib +--- + +if WhoLibByALeX or WhoLib then + -- the WhoLib-1.0 (WhoLibByALeX) or WhoLib (by Malex) is loaded -> fail! + error("an other WhoLib is already running - disable them first!\n") + return +end -- if + +--- +--- check version +--- + +assert(LibStub, "LibWho-2.0 requires LibStub") + + +local major_version = 'LibWho-2.0' +local minor_version = tonumber("145") or 99999 + +local lib = LibStub:NewLibrary(major_version, minor_version) + + +if not lib then + return -- already loaded and no upgrade necessary +end + +lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib) +local callbacks = lib.callbacks + +local am = {} +local om = getmetatable(lib) +if om then + for k, v in pairs(om) do am[k] = v end +end +am.__tostring = function() return major_version end +setmetatable(lib, am) + +local function dbgfunc(...) if lib.Debug then print(...) end end +local function NOP() return end +local dbg = NOP + +--- +--- initalize base +--- + +if type(lib['hooked']) ~= 'table' then + lib['hooked'] = {} +end -- if + +if type(lib['hook']) ~= 'table' then + lib['hook'] = {} +end -- if + +if type(lib['events']) ~= 'table' then + lib['events'] = {} +end -- if + +if type(lib['embeds']) ~= 'table' then + lib['embeds'] = {} +end -- if + +if type(lib['frame']) ~= 'table' then + lib['frame'] = CreateFrame('Frame', major_version); +end -- if +lib['frame']:Hide() + +lib.Queue = {[1]={}, [2]={}, [3]={}} +lib.WhoInProgress = false +lib.Result = nil +lib.Args = nil +lib.Total = nil +lib.Quiet = nil +lib.Debug = false +lib.Cache = {} +lib.CacheQueue = {} +lib.SetWhoToUIState = false + + +lib.MinInterval = 2.5 +lib.MaxInterval = 10 + +--- +--- locale +--- + +if (GetLocale() == "ruRU") then + lib.L = { + ['console_queued'] = 'Добавлено в очередь "/who %s"', + ['console_query'] = 'Результат "/who %s"', + ['gui_wait'] = '- Пожалуйста подождите -', + } +else + -- enUS is the default + lib.L = { + ['console_queued'] = 'Added "/who %s" to queue', + ['console_query'] = 'Result of "/who %s"', + ['gui_wait'] = '- Please Wait -', + } +end -- if + + +--- +--- external functions/constants +--- + +lib['external'] = { + 'WHOLIB_QUEUE_USER', + 'WHOLIB_QUEUE_QUIET', + 'WHOLIB_QUEUE_SCANNING', + 'WHOLIB_FLAG_ALWAYS_CALLBACK', + 'Who', + 'UserInfo', + 'CachedUserInfo', + 'GetWhoLibDebug', + 'SetWhoLibDebug', +-- 'RegisterWhoLibEvent', +} + +-- queues +lib['WHOLIB_QUEUE_USER'] = 1 +lib['WHOLIB_QUEUE_QUIET'] = 2 +lib['WHOLIB_QUEUE_SCANNING'] = 3 + + + +local queue_all = { + [1] = 'WHOLIB_QUEUE_USER', + [2] = 'WHOLIB_QUEUE_QUIET', + [3] = 'WHOLIB_QUEUE_SCANNING', +} + +local queue_quiet = { + [2] = 'WHOLIB_QUEUE_QUIET', + [3] = 'WHOLIB_QUEUE_SCANNING', +} + +-- bit masks! +lib['WHOLIB_FLAG_ALWAYS_CALLBACK'] = 1 + +function lib:Reset() + self.Queue = {[1]={}, [2]={}, [3]={}} + self.Cache = {} + self.CacheQueue = {} +end + +function lib.Who(defhandler, query, opts) + local self, args, usage = lib, {}, 'Who(query, [opts])' + + args.query = self:CheckArgument(usage, 'query', 'string', query) + opts = self:CheckArgument(usage, 'opts', 'table', opts, {}) + args.queue = self:CheckPreset(usage, 'opts.queue', queue_all, opts.queue, self.WHOLIB_QUEUE_SCANNING) + args.flags = self:CheckArgument(usage, 'opts.flags', 'number', opts.flags, 0) + args.callback, args.handler = self:CheckCallback(usage, 'opts.', opts.callback, opts.handler, defhandler) + -- now args - copied and verified from opts + + if args.queue == self.WHOLIB_QUEUE_USER then + if WhoFrame:IsShown() then + self:GuiWho(args.query) + else + self:ConsoleWho(args.query) + end + else + self:AskWho(args) + end +end + +local function ignoreRealm(name) + local _, realm = string.split("-", name) + local connectedServers = GetAutoCompleteRealms() + if connectedServers then + for i = 1, #connectedServers do + if realm == connectedServers[i] then return false end + end + end + return true +end + +function lib.UserInfo(defhandler, name, opts) + local self, args, usage = lib, {}, 'UserInfo(name, [opts])' + local now = time() + + name = self:CheckArgument(usage, 'name', 'string', name) + if name:len() == 0 then return end + + --There is no api to tell connected realms from cross realm by name. As such, we check known connections table before excluding who inquiry + --UnitRealmRelationship and UnitIsSameServer don't work with "name". They require unitID so they are useless here + if name:find("%-") and ignoreRealm(name) then return end + + args.name = self:CapitalizeInitial(name) + opts = self:CheckArgument(usage, 'opts', 'table', opts, {}) + args.queue = self:CheckPreset(usage, 'opts.queue', queue_quiet, opts.queue, self.WHOLIB_QUEUE_SCANNING) + args.flags = self:CheckArgument(usage, 'opts.flags', 'number', opts.flags, 0) + args.timeout = self:CheckArgument(usage, 'opts.timeout', 'number', opts.timeout, 5) + args.callback, args.handler = self:CheckCallback(usage, 'opts.', opts.callback, opts.handler, defhandler) + + -- now args - copied and verified from opts + local cachedName = self.Cache[args.name] + + if(cachedName ~= nil)then + -- user is in cache + if(cachedName.valid == true and (args.timeout < 0 or cachedName.last + args.timeout*60 > now))then + -- cache is valid and timeout is in range + --dbg('Info(' .. args.name ..') returned immedeatly') + if(bit.band(args.flags, self.WHOLIB_FLAG_ALWAYS_CALLBACK) ~= 0)then + self:RaiseCallback(args, cachedName.data) + return false + else + return self:DupAll(self:ReturnUserInfo(args.name)) + end + elseif(cachedName.valid == false)then + -- query is already running (first try) + if(args.callback ~= nil)then + tinsert(cachedName.callback, args) + end + --dbg('Info(' .. args.name ..') returned cause it\'s already searching') + return nil + end + else + self.Cache[args.name] = {valid=false, inqueue=false, callback={}, data={Name = args.name}, last=now } + end + + local cachedName = self.Cache[args.name] + + if(cachedName.inqueue)then + -- query is running! + if(args.callback ~= nil)then + tinsert(cachedName.callback, args) + end + dbg('Info(' .. args.name ..') returned cause it\'s already searching') + return nil + end + if (GetLocale() == "ruRU") then -- in ruRU with n- not show information about player in WIM addon + if args.name and args.name:len() > 0 then + local query = 'и-"' .. args.name .. '"' + cachedName.inqueue = true + if(args.callback ~= nil)then + tinsert(cachedName.callback, args) + end + self.CacheQueue[query] = args.name + dbg('Info(' .. args.name ..') added to queue') + self:AskWho( { query = query, queue = args.queue, flags = 0, info = args.name } ) + end + else + if args.name and args.name:len() > 0 then + local query = 'n-"' .. args.name .. '"' + cachedName.inqueue = true + if(args.callback ~= nil)then + tinsert(cachedName.callback, args) + end + self.CacheQueue[query] = args.name + dbg('Info(' .. args.name ..') added to queue') + self:AskWho( { query = query, queue = args.queue, flags = 0, info = args.name } ) + end + end + return nil +end + +function lib.CachedUserInfo(_, name) + local self, usage = lib, 'CachedUserInfo(name)' + + name = self:CapitalizeInitial(self:CheckArgument(usage, 'name', 'string', name)) + + if self.Cache[name] == nil then + return nil + else + return self:DupAll(self:ReturnUserInfo(name)) + end +end + +function lib.GetWhoLibDebug(_, mode) + return lib.Debug +end + +function lib.SetWhoLibDebug(_, mode) + lib.Debug = mode + dbg = mode and dbgfunc or NOP +end + +--function lib.RegisterWhoLibEvent(defhandler, event, callback, handler) +-- local self, usage = lib, 'RegisterWhoLibEvent(event, callback, [handler])' +-- +-- self:CheckPreset(usage, 'event', self.events, event) +-- local callback, handler = self:CheckCallback(usage, '', callback, handler, defhandler, true) +-- table.insert(self.events[event], {callback=callback, handler=handler}) +--end + +-- non-embedded externals + +function lib.Embed(_, handler) + local self, usage = lib, 'Embed(handler)' + + self:CheckArgument(usage, 'handler', 'table', handler) + + for _,name in pairs(self.external) do + handler[name] = self[name] + end -- do + self['embeds'][handler] = true + + return handler +end + +function lib.Library(_) + local self = lib + + return self:Embed({}) +end + +--- +--- internal functions +--- + +function lib:AllQueuesEmpty() + local queueCount = #self.Queue[1] + #self.Queue[2] + #self.Queue[3] + #self.CacheQueue + + -- Be sure that we have cleared the in-progress status + if self.WhoInProgress then + queueCount = queueCount + 1 + end + + return queueCount == 0 +end + +local queryInterval = 5 + +function lib:GetQueryInterval() return queryInterval end + +function lib:AskWhoNextIn5sec() + if self.frame:IsShown() then return end + + dbg("Waiting to send next who") + self.Timeout_time = queryInterval + self['frame']:Show() +end + +function lib:CancelPendingWhoNext() + lib['frame']:Hide() +end + +lib['frame']:SetScript("OnUpdate", function(frame, elapsed) + lib.Timeout_time = lib.Timeout_time - elapsed + if lib.Timeout_time <= 0 then + lib['frame']:Hide() + lib:AskWhoNext() + end -- if +end); + + +-- queue scheduler +local queue_weights = { [1] = 0.6, [2] = 0.2, [3] = 0.2 } +local queue_bounds = { [1] = 0.6, [2] = 0.2, [3] = 0.2 } + +-- allow for single queries from the user to get processed faster +local lastInstantQuery = time() +local INSTANT_QUERY_MIN_INTERVAL = 60 -- only once every 1 min + +function lib:UpdateWeights() + local weightsum, sum, count = 0, 0, 0 + for k,v in pairs(queue_weights) do + sum = sum + v + weightsum = weightsum + v * #self.Queue[k] + end + + if weightsum == 0 then + for k,v in pairs(queue_weights) do queue_bounds[k] = v end + return + end + + local adjust = sum / weightsum + + for k,v in pairs(queue_bounds) do + queue_bounds[k] = queue_weights[k] * adjust * #self.Queue[k] + end +end + +function lib:GetNextFromScheduler() + self:UpdateWeights() + + -- Since an addon could just fill up the user q for instant processing + -- we have to limit instants to 1 per INSTANT_QUERY_MIN_INTERVAL + -- and only try instant fulfilment if it will empty the user queue + if #self.Queue[1] == 1 then + if time() - lastInstantQuery > INSTANT_QUERY_MIN_INTERVAL then + dbg("INSTANT") + lastInstantQuery = time() + return 1, self.Queue[1] + end + end + + local n,i = math.random(),0 + repeat + i=i+1 + n = n - queue_bounds[i] + until i>=#self.Queue or n <= 0 + + dbg(("Q=%d, bound=%d"):format(i, queue_bounds[i])) + + if #self.Queue[i] > 0 then + dbg(("Q=%d, bound=%d"):format(i, queue_bounds[i])) + return i, self.Queue[i] + else + dbg("Queues empty, waiting") + end +end + +lib.queue_bounds = queue_bounds + +function lib:AskWhoNext() + if lib.frame:IsShown() then + dbg("Already waiting") + return + end + + self:CancelPendingWhoNext() + + if self.WhoInProgress then + -- if we had a who going, it didnt complete + dbg("TIMEOUT: "..self.Args.query) + local args = self.Args + self.Args = nil +-- if args.info and self.CacheQueue[args.query] ~= nil then + dbg("Requeing "..args.query) + tinsert(self.Queue[args.queue], args) + if args.console_show ~= nil then + DEFAULT_CHAT_FRAME:AddMessage(("Timeout on result of '%s' - retrying..."):format(args.query),1,1,0) + args.console_show = true + end +-- end + + if queryInterval < lib.MaxInterval then + queryInterval = queryInterval + 0.5 + dbg("--Throttling down to 1 who per " .. queryInterval .. "s") + end + end + + + self.WhoInProgress = false + + local v,k,args = nil + local kludge = 10 + repeat + k,v = self:GetNextFromScheduler() + if not k then break end + if(WhoFrame:IsShown() and k > self.WHOLIB_QUEUE_QUIET)then + break + end + if(#v > 0)then + args = tremove(v, 1) + break + end + kludge = kludge - 1 + until kludge <= 0 + + if args then + self.WhoInProgress = true + self.Result = {} + self.Args = args + self.Total = -1 + if(args.console_show == true)then + DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_query'], args.query), 1, 1, 0) + + end + + if args.queue == self.WHOLIB_QUEUE_USER then + WhoFrameEditBox:SetText(args.query) + self.Quiet = false + + if args.whotoui then + self.hooked.SetWhoToUI(args.whotoui) + else + self.hooked.SetWhoToUI(args.gui and true or false) + end + else + self.hooked.SetWhoToUI(true) + self.Quiet = true + end + + dbg("QUERY: "..args.query) + self.hooked.SendWho(args.query) + else + self.Args = nil + self.WhoInProgress = false + end + + -- Keep processing the who queue if there is more work + if not self:AllQueuesEmpty() then + self:AskWhoNextIn5sec() + else + dbg("*** Done processing requests ***") + end +end + +function lib:AskWho(args) + tinsert(self.Queue[args.queue], args) + dbg('[' .. args.queue .. '] added "' .. args.query .. '", queues=' .. #self.Queue[1] .. '/'.. #self.Queue[2] .. '/'.. #self.Queue[3]) + self:TriggerEvent('WHOLIB_QUERY_ADDED') + + self:AskWhoNext() +end + +function lib:ReturnWho() + if not self.Args then + self.Quiet = nil + return + end + + if(self.Args.queue == self.WHOLIB_QUEUE_QUIET or self.Args.queue == self.WHOLIB_QUEUE_SCANNING)then + self.Quiet = nil + end + + if queryInterval > self.MinInterval then + queryInterval = queryInterval - 0.5 + dbg("--Throttling up to 1 who per " .. queryInterval .. "s") + end + + self.WhoInProgress = false + dbg("RESULT: "..self.Args.query) + dbg('[' .. self.Args.queue .. '] returned "' .. self.Args.query .. '", total=' .. self.Total ..' , queues=' .. #self.Queue[1] .. '/'.. #self.Queue[2] .. '/'.. #self.Queue[3]) + local now = time() + local complete = (self.Total == #self.Result) and (self.Total < MAX_WHOS_FROM_SERVER) + for _,v in pairs(self.Result)do + if(self.Cache[v.Name] == nil)then + self.Cache[v.Name] = { inqueue = false, callback = {} } + end + + local cachedName = self.Cache[v.Name] + + cachedName.valid = true -- is now valid + cachedName.data = v -- update data + cachedName.data.Online = true -- player is online + cachedName.last = now -- update timestamp + if(cachedName.inqueue)then + if(self.Args.info and self.CacheQueue[self.Args.query] == v.Name)then + -- found by the query which was created to -> remove us from query + self.CacheQueue[self.Args.query] = nil + else + -- found by another query + for k2,v2 in pairs(self.CacheQueue) do + if(v2 == v.Name)then + for i=self.WHOLIB_QUEUE_QUIET, self.WHOLIB_QUEUE_SCANNING do + for k3,v3 in pairs(self.Queue[i]) do + if(v3.query == k2 and v3.info)then + -- remove the query which was generated for this user, cause another query was faster... + dbg("Found '"..v.Name.."' early via query '"..self.Args.query.."'") + table.remove(self.Queue[i], k3) + self.CacheQueue[k2] = nil + end + end + end + end + end + end + dbg('Info(' .. v.Name ..') returned: on') + for _,v2 in pairs(cachedName.callback) do + self:RaiseCallback(v2, self:ReturnUserInfo(v.Name)) + end + cachedName.callback = {} + end + cachedName.inqueue = false -- query is done + end + if(self.Args.info and self.CacheQueue[self.Args.query])then + -- the query did not deliver the result => not online! + local name = self.CacheQueue[self.Args.query] + local cachedName = self.Cache[name] + if (cachedName.inqueue)then + -- nothing found (yet) + cachedName.valid = true -- is now valid + cachedName.inqueue = false -- query is done? + cachedName.last = now -- update timestamp + if(complete)then + cachedName.data.Online = false -- player is offline + else + cachedName.data.Online = nil -- player is unknown (more results from who than can be displayed) + end + end + dbg('Info(' .. name ..') returned: ' .. (cachedName.data.Online == false and 'off' or 'unkn')) + for _,v in pairs(cachedName.callback) do + self:RaiseCallback(v, self:ReturnUserInfo(name)) + end + cachedName.callback = {} + self.CacheQueue[self.Args.query] = nil + end + self:RaiseCallback(self.Args, self.Args.query, self.Result, complete, self.Args.info) + self:TriggerEvent('WHOLIB_QUERY_RESULT', self.Args.query, self.Result, complete, self.Args.info) + + if not self:AllQueuesEmpty() then + self:AskWhoNextIn5sec() + end +end + +function lib:GuiWho(msg) + if(msg == self.L['gui_wait'])then + return + end + + for _,v in pairs(self.Queue[self.WHOLIB_QUEUE_USER]) do + if(v.gui == true)then + return + end + end + if(self.WhoInProgress)then + WhoFrameEditBox:SetText(self.L['gui_wait']) + end + self.savedText = msg + self:AskWho({query = msg, queue = self.WHOLIB_QUEUE_USER, flags = 0, gui = true}) + WhoFrameEditBox:ClearFocus(); +end + +function lib:ConsoleWho(msg) + --WhoFrameEditBox:SetText(msg) + local console_show = false + local q1 = self.Queue[self.WHOLIB_QUEUE_USER] + local q1count = #q1 + + if(q1count > 0 and q1[q1count].query == msg)then -- last query is itdenical: drop + return + end + + if(q1count > 0 and q1[q1count].console_show == false)then -- display 'queued' if console and not yet shown + DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_queued'], q1[q1count].query), 1, 1, 0) + q1[q1count].console_show = true + end + if(q1count > 0 or self.WhoInProgress)then + DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_queued'], msg), 1, 1, 0) + console_show = true + end + self:AskWho({query = msg, queue = self.WHOLIB_QUEUE_USER, flags = 0, console_show = console_show}) +end + +function lib:ReturnUserInfo(name) + if(name ~= nil and self ~= nil and self.Cache ~= nil and self.Cache[name] ~= nil) then + return self.Cache[name].data, (time() - self.Cache[name].last) / 60 + end +end + +function lib:RaiseCallback(args, ...) + if type(args.callback) == 'function' then + args.callback(self:DupAll(...)) + elseif args.callback then -- must be a string + args.handler[args.callback](args.handler, self:DupAll(...)) + end -- if +end + +-- Argument checking + +function lib:CheckArgument(func, name, argtype, arg, defarg) + if arg == nil and defarg ~= nil then + return defarg + elseif type(arg) == argtype then + return arg + else + error(string.format("%s: '%s' - %s%s expected got %s", func, name, (defarg ~= nil) and 'nil or ' or '', argtype, type(arg)), 3) + end -- if +end + +function lib:CheckPreset(func, name, preset, arg, defarg) + if arg == nil and defarg ~= nil then + return defarg + elseif arg ~= nil and preset[arg] ~= nil then + return arg + else + local p = {} + for k,v in pairs(preset) do + if type(v) ~= 'string' then + table.insert(p, k) + else + table.insert(p, v) + end -- if + end -- for + error(string.format("%s: '%s' - one of %s%s expected got %s", func, name, (defarg ~= nil) and 'nil, ' or '', table.concat(p, ', '), self:simple_dump(arg)), 3) + end -- if +end + +function lib:CheckCallback(func, prefix, callback, handler, defhandler, nonil) + if not nonil and callback == nil then + -- no callback: ignore handler + return nil, nil + elseif type(callback) == 'function' then + -- simple function + if handler ~= nil then + error(string.format("%s: '%shandler' - nil expected got %s", func, prefix, type(arg)), 3) + end -- if + elseif type(callback) == 'string' then + -- method + if handler == nil then + handler = defhandler + end -- if + if type(handler) ~= 'table' or type(handler[callback]) ~= 'function' or handler == self then + error(string.format("%s: '%shandler' - nil or function expected got %s", func, prefix, type(arg)), 3) + end -- if + else + error(string.format("%s: '%scallback' - %sfunction or string expected got %s", func, prefix, nonil and 'nil or ' or '', type(arg)), 3) + end -- if + + return callback, handler +end + +-- helpers + +function lib:simple_dump(x) + if type(x) == 'string' then + return 'string \''..x..'\'' + elseif type(x) == 'number' then + return 'number '..x + else + return type(x) + end +end + +function lib:Dup(from) + local to = {} + + for k,v in pairs(from) do + if type(v) == 'table' then + to[k] = self:Dup(v) + else + to[k] = v + end -- if + end -- for + + return to +end + +function lib:DupAll(x, ...) + if type(x) == 'table' then + return self:Dup(x), self:DupAll(...) + elseif x ~= nil then + return x, self:DupAll(...) + else + return nil + end -- if +end + +local MULTIBYTE_FIRST_CHAR = "^([\192-\255]?%a?[\128-\191]*)" + +function lib:CapitalizeInitial(name) + return name:gsub(MULTIBYTE_FIRST_CHAR, string.upper, 1) +end + +--- +--- user events (Using CallbackHandler) +--- + +lib.PossibleEvents = { + 'WHOLIB_QUERY_RESULT', + 'WHOLIB_QUERY_ADDED', +} + +function lib:TriggerEvent(event, ...) + callbacks:Fire(event, ...) +end + +--- +--- slash commands +--- + +SlashCmdList['WHO'] = function(msg) + dbg("console /who: "..msg) + -- new /who function + --local self = lib + + if(msg == '')then + lib:GuiWho(WhoFrame_GetDefaultWhoCommand()) + elseif(WhoFrame:IsVisible())then + lib:GuiWho(msg) + else + lib:ConsoleWho(msg) + end +end + +SlashCmdList['WHOLIB_DEBUG'] = function() + -- /wholibdebug: toggle debug on/off + local self = lib + + self:SetWhoLibDebug(not self.Debug) +end + +SLASH_WHOLIB_DEBUG1 = '/wholibdebug' + + +--- +--- hook activation +--- + +-- functions to hook +local hooks = { + 'SendWho', + 'WhoFrameEditBox_OnEnterPressed', +-- 'FriendsFrame_OnEvent', + 'SetWhoToUI', +} + +-- hook all functions (which are not yet hooked) +for _, name in pairs(hooks) do + if not lib['hooked'][name] then + lib['hooked'][name] = _G[name] + _G[name] = function(...) + lib.hook[name](lib, ...) + end -- function + end -- if +end -- for + +-- fake 'WhoFrame:Hide' as hooked +table.insert(hooks, 'WhoFrame_Hide') + +-- check for unused hooks -> remove function +for name, _ in pairs(lib['hook']) do + if not hooks[name] then + lib['hook'][name] = function() end + end -- if +end -- for + +-- secure hook 'WhoFrame:Hide' +if not lib['hooked']['WhoFrame_Hide'] then + lib['hooked']['WhoFrame_Hide'] = true + hooksecurefunc(WhoFrame, 'Hide', function(...) + lib['hook']['WhoFrame_Hide'](lib, ...) + end -- function + ) +end -- if + + + +----- Coroutine based implementation (future) +--function lib:sendWhoResult(val) +-- coroutine.yield(val) +--end +-- +--function lib:sendWaitState(val) +-- coroutine.yield(val) +--end +-- +--function lib:producer() +-- return coroutine.create( +-- function() +-- lib:AskWhoNext() +-- lib:sendWaitState(true) +-- +-- -- Resumed look for data +-- +-- end) +--end + + + + + +--- +--- hook replacements +--- + +function lib.hook.SendWho(self, msg) + dbg("SendWho: "..msg) + lib.AskWho(self, {query = msg, queue = lib.WHOLIB_QUEUE_USER, whotoui = lib.SetWhoToUIState, flags = 0}) +end + +function lib.hook.WhoFrameEditBox_OnEnterPressed(self) + lib:GuiWho(WhoFrameEditBox:GetText()) +end + +--[[ +function lib.hook.FriendsFrame_OnEvent(self, ...) + if event ~= 'WHO_LIST_UPDATE' or not lib.Quiet then + lib.hooked.FriendsFrame_OnEvent(...) + end +end +]] + +hooksecurefunc(FriendsFrame, 'RegisterEvent', function(self, event) + if(event == "WHO_LIST_UPDATE") then + self:UnregisterEvent("WHO_LIST_UPDATE"); + end + end); + + +function lib.hook.SetWhoToUI(self, state) + lib.SetWhoToUIState = state +end + +function lib.hook.WhoFrame_Hide(self) + if(not lib.WhoInProgress)then + lib:AskWhoNextIn5sec() + end +end + + +--- +--- WoW events +--- + +local who_pattern = string.gsub(WHO_NUM_RESULTS, '%%d', '%%d%+') + + +function lib:CHAT_MSG_SYSTEM(arg1) + if arg1 and arg1:find(who_pattern) then + lib:ProcessWhoResults() + end +end + +FriendsFrame:UnregisterEvent("WHO_LIST_UPDATE") + +function lib:WHO_LIST_UPDATE() + if not lib.Quiet then + WhoList_Update() + FriendsFrame_Update() + end + + lib:ProcessWhoResults() +end + +function lib:ProcessWhoResults() + local num + self.Total, num = GetNumWhoResults() + for i=1, num do + local charname, guildname, level, race, class, zone, nonlocalclass, sex = GetWhoInfo(i) + self.Result[i] = {Name=charname, Guild=guildname, Level=level, Race=race, Class=class, Zone=zone, NoLocaleClass=nonlocalclass, Sex=sex } + end + + self:ReturnWho() +end + +--- +--- event activation +--- + +lib['frame']:UnregisterAllEvents(); + +lib['frame']:SetScript("OnEvent", function(frame, event, ...) + lib[event](lib, ...) +end); + +for _,name in pairs({ + 'CHAT_MSG_SYSTEM', + 'WHO_LIST_UPDATE', +}) do + lib['frame']:RegisterEvent(name); +end -- for + + +--- +--- re-embed +--- + +for target,_ in pairs(lib['embeds']) do + if type(target) == 'table' then + lib:Embed(target) + end -- if +end -- for diff --git a/libs/LibWho-2.0/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua b/libs/LibWho-2.0/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua index 2a64013..e0fe1af 100644 --- a/libs/LibWho-2.0/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua +++ b/libs/LibWho-2.0/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua @@ -1,238 +1,240 @@ ---[[ $Id: CallbackHandler-1.0.lua 18 2014-10-16 02:52:20Z mikk $ ]] -local MAJOR, MINOR = "CallbackHandler-1.0", 6 -local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR) - -if not CallbackHandler then return end -- No upgrade needed - -local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end} - --- Lua APIs -local tconcat = table.concat -local assert, error, loadstring = assert, error, loadstring -local setmetatable, rawset, rawget = setmetatable, rawset, rawget -local next, select, pairs, type, tostring = next, select, pairs, type, tostring - --- Global vars/functions that we don't upvalue since they might get hooked, or upgraded --- List them here for Mikk's FindGlobals script --- GLOBALS: geterrorhandler - -local xpcall = xpcall - -local function errorhandler(err) - return geterrorhandler()(err) -end - -local function CreateDispatcher(argCount) - local code = [[ - local next, xpcall, eh = ... - - local method, ARGS - local function call() method(ARGS) end - - local function dispatch(handlers, ...) - local index - index, method = next(handlers) - if not method then return end - local OLD_ARGS = ARGS - ARGS = ... - repeat - xpcall(call, eh) - index, method = next(handlers, index) - until not method - ARGS = OLD_ARGS - end - - return dispatch - ]] - - local ARGS, OLD_ARGS = {}, {} - for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end - code = code:gsub("OLD_ARGS", tconcat(OLD_ARGS, ", ")):gsub("ARGS", tconcat(ARGS, ", ")) - return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler) -end - -local Dispatchers = setmetatable({}, {__index=function(self, argCount) - local dispatcher = CreateDispatcher(argCount) - rawset(self, argCount, dispatcher) - return dispatcher -end}) - --------------------------------------------------------------------------- --- CallbackHandler:New --- --- target - target object to embed public APIs in --- RegisterName - name of the callback registration API, default "RegisterCallback" --- UnregisterName - name of the callback unregistration API, default "UnregisterCallback" --- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API. - -function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName) - - RegisterName = RegisterName or "RegisterCallback" - UnregisterName = UnregisterName or "UnregisterCallback" - if UnregisterAllName==nil then -- false is used to indicate "don't want this method" - UnregisterAllName = "UnregisterAllCallbacks" - end - - -- we declare all objects and exported APIs inside this closure to quickly gain access - -- to e.g. function names, the "target" parameter, etc - - - -- Create the registry object - local events = setmetatable({}, meta) - local registry = { recurse=0, events=events } - - -- registry:Fire() - fires the given event/message into the registry - function registry:Fire(eventname, ...) - if not rawget(events, eventname) or not next(events[eventname]) then return end - local oldrecurse = registry.recurse - registry.recurse = oldrecurse + 1 - - Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...) - - registry.recurse = oldrecurse - - if registry.insertQueue and oldrecurse==0 then - -- Something in one of our callbacks wanted to register more callbacks; they got queued - for eventname,callbacks in pairs(registry.insertQueue) do - local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. - for self,func in pairs(callbacks) do - events[eventname][self] = func - -- fire OnUsed callback? - if first and registry.OnUsed then - registry.OnUsed(registry, target, eventname) - first = nil - end - end - end - registry.insertQueue = nil - end - end - - -- Registration of a callback, handles: - -- self["method"], leads to self["method"](self, ...) - -- self with function ref, leads to functionref(...) - -- "addonId" (instead of self) with function ref, leads to functionref(...) - -- all with an optional arg, which, if present, gets passed as first argument (after self if present) - target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]]) - if type(eventname) ~= "string" then - error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2) - end - - method = method or eventname - - local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. - - if type(method) ~= "string" and type(method) ~= "function" then - error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2) - end - - local regfunc - - if type(method) == "string" then - -- self["method"] calling style - if type(self) ~= "table" then - error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2) - elseif self==target then - error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2) - elseif type(self[method]) ~= "function" then - error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2) - end - - if select("#",...)>=1 then -- this is not the same as testing for arg==nil! - local arg=select(1,...) - regfunc = function(...) self[method](self,arg,...) end - else - regfunc = function(...) self[method](self,...) end - end - else - -- function ref with self=object or self="addonId" or self=thread - if type(self)~="table" and type(self)~="string" and type(self)~="thread" then - error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2) - end - - if select("#",...)>=1 then -- this is not the same as testing for arg==nil! - local arg=select(1,...) - regfunc = function(...) method(arg,...) end - else - regfunc = method - end - end - - - if events[eventname][self] or registry.recurse<1 then - -- if registry.recurse<1 then - -- we're overwriting an existing entry, or not currently recursing. just set it. - events[eventname][self] = regfunc - -- fire OnUsed callback? - if registry.OnUsed and first then - registry.OnUsed(registry, target, eventname) - end - else - -- we're currently processing a callback in this registry, so delay the registration of this new entry! - -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency - registry.insertQueue = registry.insertQueue or setmetatable({},meta) - registry.insertQueue[eventname][self] = regfunc - end - end - - -- Unregister a callback - target[UnregisterName] = function(self, eventname) - if not self or self==target then - error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2) - end - if type(eventname) ~= "string" then - error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2) - end - if rawget(events, eventname) and events[eventname][self] then - events[eventname][self] = nil - -- Fire OnUnused callback? - if registry.OnUnused and not next(events[eventname]) then - registry.OnUnused(registry, target, eventname) - end - end - if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then - registry.insertQueue[eventname][self] = nil - end - end - - -- OPTIONAL: Unregister all callbacks for given selfs/addonIds - if UnregisterAllName then - target[UnregisterAllName] = function(...) - if select("#",...)<1 then - error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2) - end - if select("#",...)==1 and ...==target then - error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2) - end - - - for i=1,select("#",...) do - local self = select(i,...) - if registry.insertQueue then - for eventname, callbacks in pairs(registry.insertQueue) do - if callbacks[self] then - callbacks[self] = nil - end - end - end - for eventname, callbacks in pairs(events) do - if callbacks[self] then - callbacks[self] = nil - -- Fire OnUnused callback? - if registry.OnUnused and not next(callbacks) then - registry.OnUnused(registry, target, eventname) - end - end - end - end - end - end - - return registry -end - - --- CallbackHandler purposefully does NOT do explicit embedding. Nor does it --- try to upgrade old implicit embeds since the system is selfcontained and --- relies on closures to work. - +--[[ $Id: CallbackHandler-1.0.lua 14 2010-08-09 00:43:38Z mikk $ ]] +local MAJOR, MINOR = "CallbackHandler-1.0", 6 +local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR) + +if not CallbackHandler then return end -- No upgrade needed + +local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end} + +-- Lua APIs +local tconcat = table.concat +local assert, error, loadstring = assert, error, loadstring +local setmetatable, rawset, rawget = setmetatable, rawset, rawget +local next, select, pairs, type, tostring = next, select, pairs, type, tostring + +-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded +-- List them here for Mikk's FindGlobals script +-- GLOBALS: geterrorhandler + +local xpcall = xpcall + +local function errorhandler(err) + return geterrorhandler()(err) +end + +local function CreateDispatcher(argCount) + local code = [[ + local next, xpcall, eh = ... + + local method, ARGS + local function call() method(ARGS) end + + local function dispatch(handlers, ...) + local index + index, method = next(handlers) + if not method then return end + local OLD_ARGS = ARGS + ARGS = ... + repeat + xpcall(call, eh) + index, method = next(handlers, index) + until not method + ARGS = OLD_ARGS + end + + return dispatch + ]] + + local ARGS, OLD_ARGS = {}, {} + for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end + code = code:gsub("OLD_ARGS", tconcat(OLD_ARGS, ", ")):gsub("ARGS", tconcat(ARGS, ", ")) + return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler) +end + +local Dispatchers = setmetatable({}, {__index=function(self, argCount) + local dispatcher = CreateDispatcher(argCount) + rawset(self, argCount, dispatcher) + return dispatcher +end}) + +-------------------------------------------------------------------------- +-- CallbackHandler:New +-- +-- target - target object to embed public APIs in +-- RegisterName - name of the callback registration API, default "RegisterCallback" +-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback" +-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API. + +function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused) + -- TODO: Remove this after beta has gone out + assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused") + + RegisterName = RegisterName or "RegisterCallback" + UnregisterName = UnregisterName or "UnregisterCallback" + if UnregisterAllName==nil then -- false is used to indicate "don't want this method" + UnregisterAllName = "UnregisterAllCallbacks" + end + + -- we declare all objects and exported APIs inside this closure to quickly gain access + -- to e.g. function names, the "target" parameter, etc + + + -- Create the registry object + local events = setmetatable({}, meta) + local registry = { recurse=0, events=events } + + -- registry:Fire() - fires the given event/message into the registry + function registry:Fire(eventname, ...) + if not rawget(events, eventname) or not next(events[eventname]) then return end + local oldrecurse = registry.recurse + registry.recurse = oldrecurse + 1 + + Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...) + + registry.recurse = oldrecurse + + if registry.insertQueue and oldrecurse==0 then + -- Something in one of our callbacks wanted to register more callbacks; they got queued + for eventname,callbacks in pairs(registry.insertQueue) do + local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. + for self,func in pairs(callbacks) do + events[eventname][self] = func + -- fire OnUsed callback? + if first and registry.OnUsed then + registry.OnUsed(registry, target, eventname) + first = nil + end + end + end + registry.insertQueue = nil + end + end + + -- Registration of a callback, handles: + -- self["method"], leads to self["method"](self, ...) + -- self with function ref, leads to functionref(...) + -- "addonId" (instead of self) with function ref, leads to functionref(...) + -- all with an optional arg, which, if present, gets passed as first argument (after self if present) + target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]]) + if type(eventname) ~= "string" then + error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2) + end + + method = method or eventname + + local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. + + if type(method) ~= "string" and type(method) ~= "function" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2) + end + + local regfunc + + if type(method) == "string" then + -- self["method"] calling style + if type(self) ~= "table" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2) + elseif self==target then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2) + elseif type(self[method]) ~= "function" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2) + end + + if select("#",...)>=1 then -- this is not the same as testing for arg==nil! + local arg=select(1,...) + regfunc = function(...) self[method](self,arg,...) end + else + regfunc = function(...) self[method](self,...) end + end + else + -- function ref with self=object or self="addonId" or self=thread + if type(self)~="table" and type(self)~="string" and type(self)~="thread" then + error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2) + end + + if select("#",...)>=1 then -- this is not the same as testing for arg==nil! + local arg=select(1,...) + regfunc = function(...) method(arg,...) end + else + regfunc = method + end + end + + + if events[eventname][self] or registry.recurse<1 then + -- if registry.recurse<1 then + -- we're overwriting an existing entry, or not currently recursing. just set it. + events[eventname][self] = regfunc + -- fire OnUsed callback? + if registry.OnUsed and first then + registry.OnUsed(registry, target, eventname) + end + else + -- we're currently processing a callback in this registry, so delay the registration of this new entry! + -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency + registry.insertQueue = registry.insertQueue or setmetatable({},meta) + registry.insertQueue[eventname][self] = regfunc + end + end + + -- Unregister a callback + target[UnregisterName] = function(self, eventname) + if not self or self==target then + error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2) + end + if type(eventname) ~= "string" then + error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2) + end + if rawget(events, eventname) and events[eventname][self] then + events[eventname][self] = nil + -- Fire OnUnused callback? + if registry.OnUnused and not next(events[eventname]) then + registry.OnUnused(registry, target, eventname) + end + end + if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then + registry.insertQueue[eventname][self] = nil + end + end + + -- OPTIONAL: Unregister all callbacks for given selfs/addonIds + if UnregisterAllName then + target[UnregisterAllName] = function(...) + if select("#",...)<1 then + error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2) + end + if select("#",...)==1 and ...==target then + error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2) + end + + + for i=1,select("#",...) do + local self = select(i,...) + if registry.insertQueue then + for eventname, callbacks in pairs(registry.insertQueue) do + if callbacks[self] then + callbacks[self] = nil + end + end + end + for eventname, callbacks in pairs(events) do + if callbacks[self] then + callbacks[self] = nil + -- Fire OnUnused callback? + if registry.OnUnused and not next(callbacks) then + registry.OnUnused(registry, target, eventname) + end + end + end + end + end + end + + return registry +end + + +-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it +-- try to upgrade old implicit embeds since the system is selfcontained and +-- relies on closures to work. + diff --git a/libs/LibWho-2.0/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml b/libs/LibWho-2.0/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml index 876df83..a5b22a7 100644 --- a/libs/LibWho-2.0/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml +++ b/libs/LibWho-2.0/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml @@ -1,4 +1,4 @@ -<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ -..\FrameXML\UI.xsd"> - <Script file="CallbackHandler-1.0.lua"/> -</Ui> \ No newline at end of file +<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ +..\FrameXML\UI.xsd"> + <Script file="CallbackHandler-1.0.lua"/> +</Ui> diff --git a/libs/LibWho-2.0/libs/LibStub/LibStub.lua b/libs/LibWho-2.0/libs/LibStub/LibStub.lua index 7e9b5cd..7e7b76d 100644 --- a/libs/LibWho-2.0/libs/LibStub/LibStub.lua +++ b/libs/LibWho-2.0/libs/LibStub/LibStub.lua @@ -1,51 +1,51 @@ --- $Id: LibStub.lua 103 2014-10-16 03:02:50Z mikk $ --- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/addons/libstub/ for more info --- LibStub is hereby placed in the Public Domain --- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke -local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! -local LibStub = _G[LIBSTUB_MAJOR] - --- Check to see is this version of the stub is obsolete -if not LibStub or LibStub.minor < LIBSTUB_MINOR then - LibStub = LibStub or {libs = {}, minors = {} } - _G[LIBSTUB_MAJOR] = LibStub - LibStub.minor = LIBSTUB_MINOR - - -- LibStub:NewLibrary(major, minor) - -- major (string) - the major version of the library - -- minor (string or number ) - the minor version of the library - -- - -- returns nil if a newer or same version of the lib is already present - -- returns empty library object or old library object if upgrade is needed - function LibStub:NewLibrary(major, minor) - assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") - minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") - - local oldminor = self.minors[major] - if oldminor and oldminor >= minor then return nil end - self.minors[major], self.libs[major] = minor, self.libs[major] or {} - return self.libs[major], oldminor - end - - -- LibStub:GetLibrary(major, [silent]) - -- major (string) - the major version of the library - -- silent (boolean) - if true, library is optional, silently return nil if its not found - -- - -- throws an error if the library can not be found (except silent is set) - -- returns the library object if found - function LibStub:GetLibrary(major, silent) - if not self.libs[major] and not silent then - error(("Cannot find a library instance of %q."):format(tostring(major)), 2) - end - return self.libs[major], self.minors[major] - end - - -- LibStub:IterateLibraries() - -- - -- Returns an iterator for the currently registered libraries - function LibStub:IterateLibraries() - return pairs(self.libs) - end - - setmetatable(LibStub, { __call = LibStub.GetLibrary }) -end +-- $Id: LibStub.lua 103 2014-10-16 03:02:50Z mikk $ +-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/addons/libstub/ for more info +-- LibStub is hereby placed in the Public Domain +-- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! +local LibStub = _G[LIBSTUB_MAJOR] + +-- Check to see is this version of the stub is obsolete +if not LibStub or LibStub.minor < LIBSTUB_MINOR then + LibStub = LibStub or {libs = {}, minors = {} } + _G[LIBSTUB_MAJOR] = LibStub + LibStub.minor = LIBSTUB_MINOR + + -- LibStub:NewLibrary(major, minor) + -- major (string) - the major version of the library + -- minor (string or number ) - the minor version of the library + -- + -- returns nil if a newer or same version of the lib is already present + -- returns empty library object or old library object if upgrade is needed + function LibStub:NewLibrary(major, minor) + assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") + minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") + + local oldminor = self.minors[major] + if oldminor and oldminor >= minor then return nil end + self.minors[major], self.libs[major] = minor, self.libs[major] or {} + return self.libs[major], oldminor + end + + -- LibStub:GetLibrary(major, [silent]) + -- major (string) - the major version of the library + -- silent (boolean) - if true, library is optional, silently return nil if its not found + -- + -- throws an error if the library can not be found (except silent is set) + -- returns the library object if found + function LibStub:GetLibrary(major, silent) + if not self.libs[major] and not silent then + error(("Cannot find a library instance of %q."):format(tostring(major)), 2) + end + return self.libs[major], self.minors[major] + end + + -- LibStub:IterateLibraries() + -- + -- Returns an iterator for the currently registered libraries + function LibStub:IterateLibraries() + return pairs(self.libs) + end + + setmetatable(LibStub, { __call = LibStub.GetLibrary }) +end diff --git a/libs/LibWho-2.0/libs/LibStub/LibStub.toc b/libs/LibWho-2.0/libs/LibStub/LibStub.toc index ac4a1c4..12077be 100644 --- a/libs/LibWho-2.0/libs/LibStub/LibStub.toc +++ b/libs/LibWho-2.0/libs/LibStub/LibStub.toc @@ -1,13 +1,13 @@ -## Interface: 60000 -## Title: Lib: LibStub -## Notes: Universal Library Stub -## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel -## X-Website: http://www.wowace.com/addons/libstub/ -## X-Category: Library -## X-License: Public Domain -## X-Curse-Packaged-Version: 1.0.2.60000 -## X-Curse-Project-Name: LibStub -## X-Curse-Project-ID: libstub -## X-Curse-Repository-ID: wow/libstub/mainline - -LibStub.lua +## Interface: 60000 +## Title: Lib: LibStub +## Notes: Universal Library Stub +## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel +## X-Website: http://www.wowace.com/addons/libstub/ +## X-Category: Library +## X-License: Public Domain +## X-Curse-Packaged-Version: 1.0.2.60000 +## X-Curse-Project-Name: LibStub +## X-Curse-Project-ID: libstub +## X-Curse-Repository-ID: wow/libstub/mainline + +LibStub.lua diff --git a/libs/LibWho-2.0/libs/LibStub/tests/test.lua b/libs/LibWho-2.0/libs/LibStub/tests/test.lua index 276ddab..fb3bcbd 100644 --- a/libs/LibWho-2.0/libs/LibStub/tests/test.lua +++ b/libs/LibWho-2.0/libs/LibStub/tests/test.lua @@ -1,41 +1,41 @@ -debugstack = debug.traceback -strmatch = string.match - -loadfile("../LibStub.lua")() - -local lib, oldMinor = LibStub:NewLibrary("Pants", 1) -- make a new thingy -assert(lib) -- should return the library table -assert(not oldMinor) -- should not return the old minor, since it didn't exist - --- the following is to create data and then be able to check if the same data exists after the fact -function lib:MyMethod() -end -local MyMethod = lib.MyMethod -lib.MyTable = {} -local MyTable = lib.MyTable - -local newLib, newOldMinor = LibStub:NewLibrary("Pants", 1) -- try to register a library with the same version, should silently fail -assert(not newLib) -- should not return since out of date - -local newLib, newOldMinor = LibStub:NewLibrary("Pants", 0) -- try to register a library with a previous, should silently fail -assert(not newLib) -- should not return since out of date - -local newLib, newOldMinor = LibStub:NewLibrary("Pants", 2) -- register a new version -assert(newLib) -- library table -assert(rawequal(newLib, lib)) -- should be the same reference as the previous -assert(newOldMinor == 1) -- should return the minor version of the previous version - -assert(rawequal(lib.MyMethod, MyMethod)) -- verify that values were saved -assert(rawequal(lib.MyTable, MyTable)) -- verify that values were saved - -local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 3 Blah") -- register a new version with a string minor version (instead of a number) -assert(newLib) -- library table -assert(newOldMinor == 2) -- previous version was 2 - -local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 4 and please ignore 15 Blah") -- register a new version with a string minor version (instead of a number) -assert(newLib) -assert(newOldMinor == 3) -- previous version was 3 (even though it gave a string) - -local newLib, newOldMinor = LibStub:NewLibrary("Pants", 5) -- register a new library, using a normal number instead of a string -assert(newLib) -assert(newOldMinor == 4) -- previous version was 4 (even though it gave a string) \ No newline at end of file +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + +local lib, oldMinor = LibStub:NewLibrary("Pants", 1) -- make a new thingy +assert(lib) -- should return the library table +assert(not oldMinor) -- should not return the old minor, since it didn't exist + +-- the following is to create data and then be able to check if the same data exists after the fact +function lib:MyMethod() +end +local MyMethod = lib.MyMethod +lib.MyTable = {} +local MyTable = lib.MyTable + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 1) -- try to register a library with the same version, should silently fail +assert(not newLib) -- should not return since out of date + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 0) -- try to register a library with a previous, should silently fail +assert(not newLib) -- should not return since out of date + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 2) -- register a new version +assert(newLib) -- library table +assert(rawequal(newLib, lib)) -- should be the same reference as the previous +assert(newOldMinor == 1) -- should return the minor version of the previous version + +assert(rawequal(lib.MyMethod, MyMethod)) -- verify that values were saved +assert(rawequal(lib.MyTable, MyTable)) -- verify that values were saved + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 3 Blah") -- register a new version with a string minor version (instead of a number) +assert(newLib) -- library table +assert(newOldMinor == 2) -- previous version was 2 + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 4 and please ignore 15 Blah") -- register a new version with a string minor version (instead of a number) +assert(newLib) +assert(newOldMinor == 3) -- previous version was 3 (even though it gave a string) + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 5) -- register a new library, using a normal number instead of a string +assert(newLib) +assert(newOldMinor == 4) -- previous version was 4 (even though it gave a string) diff --git a/libs/LibWho-2.0/libs/LibStub/tests/test2.lua b/libs/LibWho-2.0/libs/LibStub/tests/test2.lua index eae7172..af431dd 100644 --- a/libs/LibWho-2.0/libs/LibStub/tests/test2.lua +++ b/libs/LibWho-2.0/libs/LibStub/tests/test2.lua @@ -1,27 +1,27 @@ -debugstack = debug.traceback -strmatch = string.match - -loadfile("../LibStub.lua")() - -for major, library in LibStub:IterateLibraries() do - -- check that MyLib doesn't exist yet, by iterating through all the libraries - assert(major ~= "MyLib") -end - -assert(not LibStub:GetLibrary("MyLib", true)) -- check that MyLib doesn't exist yet by direct checking -assert(not pcall(LibStub.GetLibrary, LibStub, "MyLib")) -- don't silently fail, thus it should raise an error. -local lib = LibStub:NewLibrary("MyLib", 1) -- create the lib -assert(lib) -- check it exists -assert(rawequal(LibStub:GetLibrary("MyLib"), lib)) -- verify that :GetLibrary("MyLib") properly equals the lib reference - -assert(LibStub:NewLibrary("MyLib", 2)) -- create a new version - -local count=0 -for major, library in LibStub:IterateLibraries() do - -- check that MyLib exists somewhere in the libraries, by iterating through all the libraries - if major == "MyLib" then -- we found it! - count = count +1 - assert(rawequal(library, lib)) -- verify that the references are equal - end -end -assert(count == 1) -- verify that we actually found it, and only once +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + +for major, library in LibStub:IterateLibraries() do + -- check that MyLib doesn't exist yet, by iterating through all the libraries + assert(major ~= "MyLib") +end + +assert(not LibStub:GetLibrary("MyLib", true)) -- check that MyLib doesn't exist yet by direct checking +assert(not pcall(LibStub.GetLibrary, LibStub, "MyLib")) -- don't silently fail, thus it should raise an error. +local lib = LibStub:NewLibrary("MyLib", 1) -- create the lib +assert(lib) -- check it exists +assert(rawequal(LibStub:GetLibrary("MyLib"), lib)) -- verify that :GetLibrary("MyLib") properly equals the lib reference + +assert(LibStub:NewLibrary("MyLib", 2)) -- create a new version + +local count=0 +for major, library in LibStub:IterateLibraries() do + -- check that MyLib exists somewhere in the libraries, by iterating through all the libraries + if major == "MyLib" then -- we found it! + count = count +1 + assert(rawequal(library, lib)) -- verify that the references are equal + end +end +assert(count == 1) -- verify that we actually found it, and only once diff --git a/libs/LibWho-2.0/libs/LibStub/tests/test3.lua b/libs/LibWho-2.0/libs/LibStub/tests/test3.lua index 30f7b94..3c06002 100644 --- a/libs/LibWho-2.0/libs/LibStub/tests/test3.lua +++ b/libs/LibWho-2.0/libs/LibStub/tests/test3.lua @@ -1,14 +1,14 @@ -debugstack = debug.traceback -strmatch = string.match - -loadfile("../LibStub.lua")() - -local proxy = newproxy() -- non-string - -assert(not pcall(LibStub.NewLibrary, LibStub, proxy, 1)) -- should error, proxy is not a string, it's userdata -local success, ret = pcall(LibStub.GetLibrary, proxy, true) -assert(not success or not ret) -- either error because proxy is not a string or because it's not actually registered. - -assert(not pcall(LibStub.NewLibrary, LibStub, "Something", "No number in here")) -- should error, minor has no string in it. - -assert(not LibStub:GetLibrary("Something", true)) -- shouldn't've created it from the above statement \ No newline at end of file +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + +local proxy = newproxy() -- non-string + +assert(not pcall(LibStub.NewLibrary, LibStub, proxy, 1)) -- should error, proxy is not a string, it's userdata +local success, ret = pcall(LibStub.GetLibrary, proxy, true) +assert(not success or not ret) -- either error because proxy is not a string or because it's not actually registered. + +assert(not pcall(LibStub.NewLibrary, LibStub, "Something", "No number in here")) -- should error, minor has no string in it. + +assert(not LibStub:GetLibrary("Something", true)) -- shouldn't've created it from the above statement diff --git a/libs/LibWho-2.0/libs/LibStub/tests/test4.lua b/libs/LibWho-2.0/libs/LibStub/tests/test4.lua index 43eb338..294623b 100644 --- a/libs/LibWho-2.0/libs/LibStub/tests/test4.lua +++ b/libs/LibWho-2.0/libs/LibStub/tests/test4.lua @@ -1,41 +1,41 @@ -debugstack = debug.traceback -strmatch = string.match - -loadfile("../LibStub.lua")() - - --- Pretend like loaded libstub is old and doesn't have :IterateLibraries -assert(LibStub.minor) -LibStub.minor = LibStub.minor - 0.0001 -LibStub.IterateLibraries = nil - -loadfile("../LibStub.lua")() - -assert(type(LibStub.IterateLibraries)=="function") - - --- Now pretend that we're the same version -- :IterateLibraries should NOT be re-created -LibStub.IterateLibraries = 123 - -loadfile("../LibStub.lua")() - -assert(LibStub.IterateLibraries == 123) - - --- Now pretend that a newer version is loaded -- :IterateLibraries should NOT be re-created -LibStub.minor = LibStub.minor + 0.0001 - -loadfile("../LibStub.lua")() - -assert(LibStub.IterateLibraries == 123) - - --- Again with a huge number -LibStub.minor = LibStub.minor + 1234567890 - -loadfile("../LibStub.lua")() - -assert(LibStub.IterateLibraries == 123) - - -print("OK") \ No newline at end of file +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + + +-- Pretend like loaded libstub is old and doesn't have :IterateLibraries +assert(LibStub.minor) +LibStub.minor = LibStub.minor - 0.0001 +LibStub.IterateLibraries = nil + +loadfile("../LibStub.lua")() + +assert(type(LibStub.IterateLibraries)=="function") + + +-- Now pretend that we're the same version -- :IterateLibraries should NOT be re-created +LibStub.IterateLibraries = 123 + +loadfile("../LibStub.lua")() + +assert(LibStub.IterateLibraries == 123) + + +-- Now pretend that a newer version is loaded -- :IterateLibraries should NOT be re-created +LibStub.minor = LibStub.minor + 0.0001 + +loadfile("../LibStub.lua")() + +assert(LibStub.IterateLibraries == 123) + + +-- Again with a huge number +LibStub.minor = LibStub.minor + 1234567890 + +loadfile("../LibStub.lua")() + +assert(LibStub.IterateLibraries == 123) + + +print("OK") diff --git a/libs/LibWho-2.0XX/LibWho-2.0.lua b/libs/LibWho-2.0XX/LibWho-2.0.lua index 7abeb6c..30cf02a 100644 --- a/libs/LibWho-2.0XX/LibWho-2.0.lua +++ b/libs/LibWho-2.0XX/LibWho-2.0.lua @@ -1,948 +1,948 @@ ---- ---- check for an already loaded old WhoLib ---- - -if WhoLibByALeX or WhoLib then - -- the WhoLib-1.0 (WhoLibByALeX) or WhoLib (by Malex) is loaded -> fail! - error("an other WhoLib is already running - disable them first!\n") - return -end -- if - ---- ---- check version ---- - -assert(LibStub, "LibWho-2.0 requires LibStub") - - -local major_version = 'LibWho-2.0' -local minor_version = tonumber("136") or 99999 - -local lib = LibStub:NewLibrary(major_version, minor_version) - - -if not lib then - return -- already loaded and no upgrade necessary -end - -lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib) -local callbacks = lib.callbacks - -local am = {} -local om = getmetatable(lib) -if om then - for k, v in pairs(om) do am[k] = v end -end -am.__tostring = function() return major_version end -setmetatable(lib, am) - -local function dbgfunc(...) if lib.Debug then print(...) end end -local function NOP() return end -local dbg = NOP - ---- ---- initalize base ---- - -if type(lib['hooked']) ~= 'table' then - lib['hooked'] = {} -end -- if - -if type(lib['hook']) ~= 'table' then - lib['hook'] = {} -end -- if - -if type(lib['events']) ~= 'table' then - lib['events'] = {} -end -- if - -if type(lib['embeds']) ~= 'table' then - lib['embeds'] = {} -end -- if - -if type(lib['frame']) ~= 'table' then - lib['frame'] = CreateFrame('Frame', major_version); -end -- if -lib['frame']:Hide() - -lib.Queue = {[1]={}, [2]={}, [3]={}} -lib.WhoInProgress = false -lib.Result = nil -lib.Args = nil -lib.Total = nil -lib.Quiet = nil -lib.Debug = false -lib.Cache = {} -lib.CacheQueue = {} -lib.SetWhoToUIState = 0 - - -lib.MinInterval = 2.5 -lib.MaxInterval = 10 - ---- ---- locale ---- - -if (GetLocale() == "ruRU") then - lib.L = { - ['console_queued'] = 'Добавлено в очередь "/who %s"', - ['console_query'] = 'Результат "/who %s"', - ['gui_wait'] = '- Пожалуйста подождите -', - } -else - -- enUS is the default - lib.L = { - ['console_queued'] = 'Added "/who %s" to queue', - ['console_query'] = 'Result of "/who %s"', - ['gui_wait'] = '- Please Wait -', - } -end -- if - - ---- ---- external functions/constants ---- - -lib['external'] = { - 'WHOLIB_QUEUE_USER', - 'WHOLIB_QUEUE_QUIET', - 'WHOLIB_QUEUE_SCANNING', - 'WHOLIB_FLAG_ALWAYS_CALLBACK', - 'Who', - 'UserInfo', - 'CachedUserInfo', - 'GetWhoLibDebug', - 'SetWhoLibDebug', --- 'RegisterWhoLibEvent', -} - --- queues -lib['WHOLIB_QUEUE_USER'] = 1 -lib['WHOLIB_QUEUE_QUIET'] = 2 -lib['WHOLIB_QUEUE_SCANNING'] = 3 - - - -local queue_all = { - [1] = 'WHOLIB_QUEUE_USER', - [2] = 'WHOLIB_QUEUE_QUIET', - [3] = 'WHOLIB_QUEUE_SCANNING', -} - -local queue_quiet = { - [2] = 'WHOLIB_QUEUE_QUIET', - [3] = 'WHOLIB_QUEUE_SCANNING', -} - --- bit masks! -lib['WHOLIB_FLAG_ALWAYS_CALLBACK'] = 1 - -function lib:Reset() - self.Queue = {[1]={}, [2]={}, [3]={}} - self.Cache = {} - self.CacheQueue = {} -end - -function lib.Who(defhandler, query, opts) - local self, args, usage = lib, {}, 'Who(query, [opts])' - - args.query = self:CheckArgument(usage, 'query', 'string', query) - opts = self:CheckArgument(usage, 'opts', 'table', opts, {}) - args.queue = self:CheckPreset(usage, 'opts.queue', queue_all, opts.queue, self.WHOLIB_QUEUE_SCANNING) - args.flags = self:CheckArgument(usage, 'opts.flags', 'number', flags, 0) - args.callback, args.handler = self:CheckCallback(usage, 'opts.', opts.callback, opts.handler, defhandler) - -- now args - copied and verified from opts - - if args.queue == self.WHOLIB_QUEUE_USER then - if WhoFrame:IsShown() then - self:GuiWho(args.query) - else - self:ConsoleWho(args.query) - end - else - self:AskWho(args) - end -end - -local function ignoreRealm(name) - local _, realm = string.split("-", name) - local connectedServers = GetAutoCompleteRealms() - if connectedServers then - for i = 1, #connectedServers do - if realm == connectedServers[i] then return false end - end - end - return true -end - -function lib.UserInfo(defhandler, name, opts) - local self, args, usage = lib, {}, 'UserInfo(name, [opts])' - local now = time() - - name = self:CheckArgument(usage, 'name', 'string', name) - if name:len() == 0 then return end - - --There is no api to tell connected realms from cross realm by name. As such, we check known connections table before excluding who inquiry - --UnitRealmRelationship and UnitIsSameServer don't work with "name". They require unitID so they are useless here - if name:find("%-") and ignoreRealm(name) then return end - - args.name = self:CapitalizeInitial(name) - opts = self:CheckArgument(usage, 'opts', 'table', opts, {}) - args.queue = self:CheckPreset(usage, 'opts.queue', queue_quiet, opts.queue, self.WHOLIB_QUEUE_SCANNING) - args.flags = self:CheckArgument(usage, 'opts.flags', 'number', opts.flags, 0) - args.timeout = self:CheckArgument(usage, 'opts.timeout', 'number', opts.timeout, 5) - args.callback, args.handler = self:CheckCallback(usage, 'opts.', opts.callback, opts.handler, defhandler) - - -- now args - copied and verified from opts - local cachedName = self.Cache[args.name] - - if(cachedName ~= nil)then - -- user is in cache - if(cachedName.valid == true and (args.timeout < 0 or cachedName.last + args.timeout*60 > now))then - -- cache is valid and timeout is in range - --dbg('Info(' .. args.name ..') returned immedeatly') - if(bit.band(args.flags, self.WHOLIB_FLAG_ALWAYS_CALLBACK) ~= 0)then - self:RaiseCallback(args, cachedName.data) - return false - else - return self:DupAll(self:ReturnUserInfo(args.name)) - end - elseif(cachedName.valid == false)then - -- query is already running (first try) - if(args.callback ~= nil)then - tinsert(cachedName.callback, args) - end - --dbg('Info(' .. args.name ..') returned cause it\'s already searching') - return nil - end - else - self.Cache[args.name] = {valid=false, inqueue=false, callback={}, data={Name = args.name}, last=now } - end - - local cachedName = self.Cache[args.name] - - if(cachedName.inqueue)then - -- query is running! - if(args.callback ~= nil)then - tinsert(cachedName.callback, args) - end - dbg('Info(' .. args.name ..') returned cause it\'s already searching') - return nil - end - if (GetLocale() == "ruRU") then -- in ruRU with n- not show information about player in WIM addon - if args.name and args.name:len() > 0 then - local query = 'и-"' .. args.name .. '"' - cachedName.inqueue = true - if(args.callback ~= nil)then - tinsert(cachedName.callback, args) - end - self.CacheQueue[query] = args.name - dbg('Info(' .. args.name ..') added to queue') - self:AskWho( { query = query, queue = args.queue, flags = 0, info = args.name } ) - end - else - if args.name and args.name:len() > 0 then - local query = 'n-"' .. args.name .. '"' - cachedName.inqueue = true - if(args.callback ~= nil)then - tinsert(cachedName.callback, args) - end - self.CacheQueue[query] = args.name - dbg('Info(' .. args.name ..') added to queue') - self:AskWho( { query = query, queue = args.queue, flags = 0, info = args.name } ) - end - end - return nil -end - -function lib.CachedUserInfo(_, name) - local self, usage = lib, 'CachedUserInfo(name)' - - name = self:CapitalizeInitial(self:CheckArgument(usage, 'name', 'string', name)) - - if self.Cache[name] == nil then - return nil - else - return self:DupAll(self:ReturnUserInfo(name)) - end -end - -function lib.GetWhoLibDebug(_, mode) - return lib.Debug -end - -function lib.SetWhoLibDebug(_, mode) - lib.Debug = mode - dbg = mode and dbgfunc or NOP -end - ---function lib.RegisterWhoLibEvent(defhandler, event, callback, handler) --- local self, usage = lib, 'RegisterWhoLibEvent(event, callback, [handler])' --- --- self:CheckPreset(usage, 'event', self.events, event) --- local callback, handler = self:CheckCallback(usage, '', callback, handler, defhandler, true) --- table.insert(self.events[event], {callback=callback, handler=handler}) ---end - --- non-embedded externals - -function lib.Embed(_, handler) - local self, usage = lib, 'Embed(handler)' - - self:CheckArgument(usage, 'handler', 'table', handler) - - for _,name in pairs(self.external) do - handler[name] = self[name] - end -- do - self['embeds'][handler] = true - - return handler -end - -function lib.Library(_) - local self = lib - - return self:Embed({}) -end - ---- ---- internal functions ---- - -function lib:AllQueuesEmpty() - local queueCount = #self.Queue[1] + #self.Queue[2] + #self.Queue[3] + #self.CacheQueue - - -- Be sure that we have cleared the in-progress status - if self.WhoInProgress then - queueCount = queueCount + 1 - end - - return queueCount == 0 -end - -local queryInterval = 5 - -function lib:GetQueryInterval() return queryInterval end - -function lib:AskWhoNextIn5sec() - if self.frame:IsShown() then return end - - dbg("Waiting to send next who") - self.Timeout_time = queryInterval - self['frame']:Show() -end - -function lib:CancelPendingWhoNext() - lib['frame']:Hide() -end - -lib['frame']:SetScript("OnUpdate", function(frame, elapsed) - lib.Timeout_time = lib.Timeout_time - elapsed - if lib.Timeout_time <= 0 then - lib['frame']:Hide() - lib:AskWhoNext() - end -- if -end); - - --- queue scheduler -local queue_weights = { [1] = 0.6, [2] = 0.2, [3] = 0.2 } -local queue_bounds = { [1] = 0.6, [2] = 0.2, [3] = 0.2 } - --- allow for single queries from the user to get processed faster -local lastInstantQuery = time() -local INSTANT_QUERY_MIN_INTERVAL = 60 -- only once every 1 min - -function lib:UpdateWeights() - local weightsum, sum, count = 0, 0, 0 - for k,v in pairs(queue_weights) do - sum = sum + v - weightsum = weightsum + v * #self.Queue[k] - end - - if weightsum == 0 then - for k,v in pairs(queue_weights) do queue_bounds[k] = v end - return - end - - local adjust = sum / weightsum - - for k,v in pairs(queue_bounds) do - queue_bounds[k] = queue_weights[k] * adjust * #self.Queue[k] - end -end - -function lib:GetNextFromScheduler() - self:UpdateWeights() - - -- Since an addon could just fill up the user q for instant processing - -- we have to limit instants to 1 per INSTANT_QUERY_MIN_INTERVAL - -- and only try instant fulfilment if it will empty the user queue - if #self.Queue[1] == 1 then - if time() - lastInstantQuery > INSTANT_QUERY_MIN_INTERVAL then - dbg("INSTANT") - lastInstantQuery = time() - return 1, self.Queue[1] - end - end - - local n,i = math.random(),0 - repeat - i=i+1 - n = n - queue_bounds[i] - until i>=#self.Queue or n <= 0 - - dbg(("Q=%d, bound=%d"):format(i, queue_bounds[i])) - - if #self.Queue[i] > 0 then - dbg(("Q=%d, bound=%d"):format(i, queue_bounds[i])) - return i, self.Queue[i] - else - dbg("Queues empty, waiting") - end -end - -lib.queue_bounds = queue_bounds - -function lib:AskWhoNext() - if lib.frame:IsShown() then - dbg("Already waiting") - return - end - - self:CancelPendingWhoNext() - - if self.WhoInProgress then - -- if we had a who going, it didnt complete - dbg("TIMEOUT: "..self.Args.query) - local args = self.Args - self.Args = nil --- if args.info and self.CacheQueue[args.query] ~= nil then - dbg("Requeing "..args.query) - tinsert(self.Queue[args.queue], args) - if args.console_show ~= nil then - DEFAULT_CHAT_FRAME:AddMessage(("Timeout on result of '%s' - retrying..."):format(args.query),1,1,0) - args.console_show = true - end --- end - - if queryInterval < lib.MaxInterval then - queryInterval = queryInterval + 0.5 - dbg("--Throttling down to 1 who per " .. queryInterval .. "s") - end - end - - - self.WhoInProgress = false - - local v,k,args = nil - local kludge = 10 - repeat - k,v = self:GetNextFromScheduler() - if not k then break end - if(WhoFrame:IsShown() and k > self.WHOLIB_QUEUE_QUIET)then - break - end - if(#v > 0)then - args = tremove(v, 1) - break - end - kludge = kludge - 1 - until kludge <= 0 - - if args then - self.WhoInProgress = true - self.Result = {} - self.Args = args - self.Total = -1 - if(args.console_show == true)then - DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_query'], args.query), 1, 1, 0) - - end - - if args.queue == self.WHOLIB_QUEUE_USER then - WhoFrameEditBox:SetText(args.query) - self.Quiet = false - - if args.whotoui then - self.hooked.SetWhoToUI(args.whotoui) - else - self.hooked.SetWhoToUI(args.gui and 1 or 0) - end - else - self.hooked.SetWhoToUI(1) - self.Quiet = true - end - - dbg("QUERY: "..args.query) - self.hooked.SendWho(args.query) - else - self.Args = nil - self.WhoInProgress = false - end - - -- Keep processing the who queue if there is more work - if not self:AllQueuesEmpty() then - self:AskWhoNextIn5sec() - else - dbg("*** Done processing requests ***") - end -end - -function lib:AskWho(args) - tinsert(self.Queue[args.queue], args) - dbg('[' .. args.queue .. '] added "' .. args.query .. '", queues=' .. #self.Queue[1] .. '/'.. #self.Queue[2] .. '/'.. #self.Queue[3]) - self:TriggerEvent('WHOLIB_QUERY_ADDED') - - self:AskWhoNext() -end - -function lib:ReturnWho() - if not self.Args then - self.Quiet = nil - return - end - - if(self.Args.queue == self.WHOLIB_QUEUE_QUIET or self.Args.queue == self.WHOLIB_QUEUE_SCANNING)then - self.Quiet = nil - end - - if queryInterval > self.MinInterval then - queryInterval = queryInterval - 0.5 - dbg("--Throttling up to 1 who per " .. queryInterval .. "s") - end - - self.WhoInProgress = false - dbg("RESULT: "..self.Args.query) - dbg('[' .. self.Args.queue .. '] returned "' .. self.Args.query .. '", total=' .. self.Total ..' , queues=' .. #self.Queue[1] .. '/'.. #self.Queue[2] .. '/'.. #self.Queue[3]) - local now = time() - local complete = (self.Total == #self.Result) and (self.Total < MAX_WHOS_FROM_SERVER) - for _,v in pairs(self.Result)do - if(self.Cache[v.Name] == nil)then - self.Cache[v.Name] = { inqueue = false, callback = {} } - end - - local cachedName = self.Cache[v.Name] - - cachedName.valid = true -- is now valid - cachedName.data = v -- update data - cachedName.data.Online = true -- player is online - cachedName.last = now -- update timestamp - if(cachedName.inqueue)then - if(self.Args.info and self.CacheQueue[self.Args.query] == v.Name)then - -- found by the query which was created to -> remove us from query - self.CacheQueue[self.Args.query] = nil - else - -- found by another query - for k2,v2 in pairs(self.CacheQueue) do - if(v2 == v.Name)then - for i=self.WHOLIB_QUEUE_QUIET, self.WHOLIB_QUEUE_SCANNING do - for k3,v3 in pairs(self.Queue[i]) do - if(v3.query == k2 and v3.info)then - -- remove the query which was generated for this user, cause another query was faster... - dbg("Found '"..v.Name.."' early via query '"..self.Args.query.."'") - table.remove(self.Queue[i], k3) - self.CacheQueue[k2] = nil - end - end - end - end - end - end - dbg('Info(' .. v.Name ..') returned: on') - for _,v2 in pairs(cachedName.callback) do - self:RaiseCallback(v2, self:ReturnUserInfo(v.Name)) - end - cachedName.callback = {} - end - cachedName.inqueue = false -- query is done - end - if(self.Args.info and self.CacheQueue[self.Args.query])then - -- the query did not deliver the result => not online! - local name = self.CacheQueue[self.Args.query] - local cachedName = self.Cache[name] - if (cachedName.inqueue)then - -- nothing found (yet) - cachedName.valid = true -- is now valid - cachedName.inqueue = false -- query is done? - cachedName.last = now -- update timestamp - if(complete)then - cachedName.data.Online = false -- player is offline - else - cachedName.data.Online = nil -- player is unknown (more results from who than can be displayed) - end - end - dbg('Info(' .. name ..') returned: ' .. (cachedName.data.Online == false and 'off' or 'unkn')) - for _,v in pairs(cachedName.callback) do - self:RaiseCallback(v, self:ReturnUserInfo(name)) - end - cachedName.callback = {} - self.CacheQueue[self.Args.query] = nil - end - self:RaiseCallback(self.Args, self.Args.query, self.Result, complete, self.Args.info) - self:TriggerEvent('WHOLIB_QUERY_RESULT', self.Args.query, self.Result, complete, self.Args.info) - - if not self:AllQueuesEmpty() then - self:AskWhoNextIn5sec() - end -end - -function lib:GuiWho(msg) - if(msg == self.L['gui_wait'])then - return - end - - for _,v in pairs(self.Queue[self.WHOLIB_QUEUE_USER]) do - if(v.gui == true)then - return - end - end - if(self.WhoInProgress)then - WhoFrameEditBox:SetText(self.L['gui_wait']) - end - self.savedText = msg - self:AskWho({query = msg, queue = self.WHOLIB_QUEUE_USER, flags = 0, gui = true}) - WhoFrameEditBox:ClearFocus(); -end - -function lib:ConsoleWho(msg) - --WhoFrameEditBox:SetText(msg) - local console_show = false - local q1 = self.Queue[self.WHOLIB_QUEUE_USER] - local q1count = #q1 - - if(q1count > 0 and q1[q1count].query == msg)then -- last query is itdenical: drop - return - end - - if(q1count > 0 and q1[q1count].console_show == false)then -- display 'queued' if console and not yet shown - DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_queued'], q1[q1count].query), 1, 1, 0) - q1[q1count].console_show = true - end - if(q1count > 0 or self.WhoInProgress)then - DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_queued'], msg), 1, 1, 0) - console_show = true - end - self:AskWho({query = msg, queue = self.WHOLIB_QUEUE_USER, flags = 0, console_show = console_show}) -end - -function lib:ReturnUserInfo(name) - if(name ~= nil and self ~= nil and self.Cache ~= nil and self.Cache[name] ~= nil) then - return self.Cache[name].data, (time() - self.Cache[name].last) / 60 - end -end - -function lib:RaiseCallback(args, ...) - if type(args.callback) == 'function' then - args.callback(self:DupAll(...)) - elseif args.callback then -- must be a string - args.handler[args.callback](args.handler, self:DupAll(...)) - end -- if -end - --- Argument checking - -function lib:CheckArgument(func, name, argtype, arg, defarg) - if arg == nil and defarg ~= nil then - return defarg - elseif type(arg) == argtype then - return arg - else - error(string.format("%s: '%s' - %s%s expected got %s", func, name, (defarg ~= nil) and 'nil or ' or '', argtype, type(arg)), 3) - end -- if -end - -function lib:CheckPreset(func, name, preset, arg, defarg) - if arg == nil and defarg ~= nil then - return defarg - elseif arg ~= nil and preset[arg] ~= nil then - return arg - else - local p = {} - for k,v in pairs(preset) do - if type(v) ~= 'string' then - table.insert(p, k) - else - table.insert(p, v) - end -- if - end -- for - error(string.format("%s: '%s' - one of %s%s expected got %s", func, name, (defarg ~= nil) and 'nil, ' or '', table.concat(p, ', '), self:simple_dump(arg)), 3) - end -- if -end - -function lib:CheckCallback(func, prefix, callback, handler, defhandler, nonil) - if not nonil and callback == nil then - -- no callback: ignore handler - return nil, nil - elseif type(callback) == 'function' then - -- simple function - if handler ~= nil then - error(string.format("%s: '%shandler' - nil expected got %s", func, prefix, type(arg)), 3) - end -- if - elseif type(callback) == 'string' then - -- method - if handler == nil then - handler = defhandler - end -- if - if type(handler) ~= 'table' or type(handler[callback]) ~= 'function' or handler == self then - error(string.format("%s: '%shandler' - nil or function expected got %s", func, prefix, type(arg)), 3) - end -- if - else - error(string.format("%s: '%scallback' - %sfunction or string expected got %s", func, prefix, nonil and 'nil or ' or '', type(arg)), 3) - end -- if - - return callback, handler -end - --- helpers - -function lib:simple_dump(x) - if type(x) == 'string' then - return 'string \''..x..'\'' - elseif type(x) == 'number' then - return 'number '..x - else - return type(x) - end -end - -function lib:Dup(from) - local to = {} - - for k,v in pairs(from) do - if type(v) == 'table' then - to[k] = self:Dup(v) - else - to[k] = v - end -- if - end -- for - - return to -end - -function lib:DupAll(x, ...) - if type(x) == 'table' then - return self:Dup(x), self:DupAll(...) - elseif x ~= nil then - return x, self:DupAll(...) - else - return nil - end -- if -end - -local MULTIBYTE_FIRST_CHAR = "^([\192-\255]?%a?[\128-\191]*)" - -function lib:CapitalizeInitial(name) - return name:gsub(MULTIBYTE_FIRST_CHAR, string.upper, 1) -end - ---- ---- user events (Using CallbackHandler) ---- - -lib.PossibleEvents = { - 'WHOLIB_QUERY_RESULT', - 'WHOLIB_QUERY_ADDED', -} - -function lib:TriggerEvent(event, ...) - callbacks:Fire(event, ...) -end - ---- ---- slash commands ---- - -SlashCmdList['WHO'] = function(msg) - dbg("console /who: "..msg) - -- new /who function - --local self = lib - - if(msg == '')then - lib:GuiWho(WhoFrame_GetDefaultWhoCommand()) - elseif(WhoFrame:IsVisible())then - lib:GuiWho(msg) - else - lib:ConsoleWho(msg) - end -end - -SlashCmdList['WHOLIB_DEBUG'] = function() - -- /wholibdebug: toggle debug on/off - local self = lib - - self:SetWhoLibDebug(not self.Debug) -end - -SLASH_WHOLIB_DEBUG1 = '/wholibdebug' - - ---- ---- hook activation ---- - --- functions to hook -local hooks = { - 'SendWho', - 'WhoFrameEditBox_OnEnterPressed', --- 'FriendsFrame_OnEvent', - 'SetWhoToUI', -} - --- hook all functions (which are not yet hooked) -for _, name in pairs(hooks) do - if not lib['hooked'][name] then - lib['hooked'][name] = _G[name] - _G[name] = function(...) - lib.hook[name](lib, ...) - end -- function - end -- if -end -- for - --- fake 'WhoFrame:Hide' as hooked -table.insert(hooks, 'WhoFrame_Hide') - --- check for unused hooks -> remove function -for name, _ in pairs(lib['hook']) do - if not hooks[name] then - lib['hook'][name] = function() end - end -- if -end -- for - --- secure hook 'WhoFrame:Hide' -if not lib['hooked']['WhoFrame_Hide'] then - lib['hooked']['WhoFrame_Hide'] = true - hooksecurefunc(WhoFrame, 'Hide', function(...) - lib['hook']['WhoFrame_Hide'](lib, ...) - end -- function - ) -end -- if - - - ------ Coroutine based implementation (future) ---function lib:sendWhoResult(val) --- coroutine.yield(val) ---end --- ---function lib:sendWaitState(val) --- coroutine.yield(val) ---end --- ---function lib:producer() --- return coroutine.create( --- function() --- lib:AskWhoNext() --- lib:sendWaitState(true) --- --- -- Resumed look for data --- --- end) ---end - - - - - ---- ---- hook replacements ---- - -function lib.hook.SendWho(self, msg) - dbg("SendWho: "..msg) - lib.AskWho(self, {query = msg, queue = lib.WHOLIB_QUEUE_USER, whotoui = lib.SetWhoToUIState, flags = 0}) -end - -function lib.hook.WhoFrameEditBox_OnEnterPressed(self) - lib:GuiWho(WhoFrameEditBox:GetText()) -end - ---[[ -function lib.hook.FriendsFrame_OnEvent(self, ...) - if event ~= 'WHO_LIST_UPDATE' or not lib.Quiet then - lib.hooked.FriendsFrame_OnEvent(...) - end -end -]] - -hooksecurefunc(FriendsFrame, 'RegisterEvent', function(self, event) - if(event == "WHO_LIST_UPDATE") then - self:UnregisterEvent("WHO_LIST_UPDATE"); - end - end); - - -function lib.hook.SetWhoToUI(self, state) - lib.SetWhoToUIState = state -end - -function lib.hook.WhoFrame_Hide(self) - if(not lib.WhoInProgress)then - lib:AskWhoNextIn5sec() - end -end - - ---- ---- WoW events ---- - -local who_pattern = string.gsub(WHO_NUM_RESULTS, '%%d', '%%d%+') - - -function lib:CHAT_MSG_SYSTEM(arg1) - if arg1 and arg1:find(who_pattern) then - lib:ProcessWhoResults() - end -end - -FriendsFrame:UnregisterEvent("WHO_LIST_UPDATE") - -function lib:WHO_LIST_UPDATE() - if not lib.Quiet then - WhoList_Update() - FriendsFrame_Update() - end - - lib:ProcessWhoResults() -end - -function lib:ProcessWhoResults() - local num - self.Total, num = GetNumWhoResults() - for i=1, num do - local charname, guildname, level, race, class, zone, nonlocalclass, sex = GetWhoInfo(i) - self.Result[i] = {Name=charname, Guild=guildname, Level=level, Race=race, Class=class, Zone=zone, NoLocaleClass=nonlocalclass, Sex=sex } - end - - self:ReturnWho() -end - ---- ---- event activation ---- - -lib['frame']:UnregisterAllEvents(); - -lib['frame']:SetScript("OnEvent", function(frame, event, ...) - lib[event](lib, ...) -end); - -for _,name in pairs({ - 'CHAT_MSG_SYSTEM', - 'WHO_LIST_UPDATE', -}) do - lib['frame']:RegisterEvent(name); -end -- for - - ---- ---- re-embed ---- - -for target,_ in pairs(lib['embeds']) do - if type(target) == 'table' then - lib:Embed(target) - end -- if -end -- for +--- +--- check for an already loaded old WhoLib +--- + +if WhoLibByALeX or WhoLib then + -- the WhoLib-1.0 (WhoLibByALeX) or WhoLib (by Malex) is loaded -> fail! + error("an other WhoLib is already running - disable them first!\n") + return +end -- if + +--- +--- check version +--- + +assert(LibStub, "LibWho-2.0 requires LibStub") + + +local major_version = 'LibWho-2.0' +local minor_version = tonumber("136") or 99999 + +local lib = LibStub:NewLibrary(major_version, minor_version) + + +if not lib then + return -- already loaded and no upgrade necessary +end + +lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib) +local callbacks = lib.callbacks + +local am = {} +local om = getmetatable(lib) +if om then + for k, v in pairs(om) do am[k] = v end +end +am.__tostring = function() return major_version end +setmetatable(lib, am) + +local function dbgfunc(...) if lib.Debug then print(...) end end +local function NOP() return end +local dbg = NOP + +--- +--- initalize base +--- + +if type(lib['hooked']) ~= 'table' then + lib['hooked'] = {} +end -- if + +if type(lib['hook']) ~= 'table' then + lib['hook'] = {} +end -- if + +if type(lib['events']) ~= 'table' then + lib['events'] = {} +end -- if + +if type(lib['embeds']) ~= 'table' then + lib['embeds'] = {} +end -- if + +if type(lib['frame']) ~= 'table' then + lib['frame'] = CreateFrame('Frame', major_version); +end -- if +lib['frame']:Hide() + +lib.Queue = {[1]={}, [2]={}, [3]={}} +lib.WhoInProgress = false +lib.Result = nil +lib.Args = nil +lib.Total = nil +lib.Quiet = nil +lib.Debug = false +lib.Cache = {} +lib.CacheQueue = {} +lib.SetWhoToUIState = 0 + + +lib.MinInterval = 2.5 +lib.MaxInterval = 10 + +--- +--- locale +--- + +if (GetLocale() == "ruRU") then + lib.L = { + ['console_queued'] = 'Добавлено в очередь "/who %s"', + ['console_query'] = 'Результат "/who %s"', + ['gui_wait'] = '- Пожалуйста подождите -', + } +else + -- enUS is the default + lib.L = { + ['console_queued'] = 'Added "/who %s" to queue', + ['console_query'] = 'Result of "/who %s"', + ['gui_wait'] = '- Please Wait -', + } +end -- if + + +--- +--- external functions/constants +--- + +lib['external'] = { + 'WHOLIB_QUEUE_USER', + 'WHOLIB_QUEUE_QUIET', + 'WHOLIB_QUEUE_SCANNING', + 'WHOLIB_FLAG_ALWAYS_CALLBACK', + 'Who', + 'UserInfo', + 'CachedUserInfo', + 'GetWhoLibDebug', + 'SetWhoLibDebug', +-- 'RegisterWhoLibEvent', +} + +-- queues +lib['WHOLIB_QUEUE_USER'] = 1 +lib['WHOLIB_QUEUE_QUIET'] = 2 +lib['WHOLIB_QUEUE_SCANNING'] = 3 + + + +local queue_all = { + [1] = 'WHOLIB_QUEUE_USER', + [2] = 'WHOLIB_QUEUE_QUIET', + [3] = 'WHOLIB_QUEUE_SCANNING', +} + +local queue_quiet = { + [2] = 'WHOLIB_QUEUE_QUIET', + [3] = 'WHOLIB_QUEUE_SCANNING', +} + +-- bit masks! +lib['WHOLIB_FLAG_ALWAYS_CALLBACK'] = 1 + +function lib:Reset() + self.Queue = {[1]={}, [2]={}, [3]={}} + self.Cache = {} + self.CacheQueue = {} +end + +function lib.Who(defhandler, query, opts) + local self, args, usage = lib, {}, 'Who(query, [opts])' + + args.query = self:CheckArgument(usage, 'query', 'string', query) + opts = self:CheckArgument(usage, 'opts', 'table', opts, {}) + args.queue = self:CheckPreset(usage, 'opts.queue', queue_all, opts.queue, self.WHOLIB_QUEUE_SCANNING) + args.flags = self:CheckArgument(usage, 'opts.flags', 'number', flags, 0) + args.callback, args.handler = self:CheckCallback(usage, 'opts.', opts.callback, opts.handler, defhandler) + -- now args - copied and verified from opts + + if args.queue == self.WHOLIB_QUEUE_USER then + if WhoFrame:IsShown() then + self:GuiWho(args.query) + else + self:ConsoleWho(args.query) + end + else + self:AskWho(args) + end +end + +local function ignoreRealm(name) + local _, realm = string.split("-", name) + local connectedServers = GetAutoCompleteRealms() + if connectedServers then + for i = 1, #connectedServers do + if realm == connectedServers[i] then return false end + end + end + return true +end + +function lib.UserInfo(defhandler, name, opts) + local self, args, usage = lib, {}, 'UserInfo(name, [opts])' + local now = time() + + name = self:CheckArgument(usage, 'name', 'string', name) + if name:len() == 0 then return end + + --There is no api to tell connected realms from cross realm by name. As such, we check known connections table before excluding who inquiry + --UnitRealmRelationship and UnitIsSameServer don't work with "name". They require unitID so they are useless here + if name:find("%-") and ignoreRealm(name) then return end + + args.name = self:CapitalizeInitial(name) + opts = self:CheckArgument(usage, 'opts', 'table', opts, {}) + args.queue = self:CheckPreset(usage, 'opts.queue', queue_quiet, opts.queue, self.WHOLIB_QUEUE_SCANNING) + args.flags = self:CheckArgument(usage, 'opts.flags', 'number', opts.flags, 0) + args.timeout = self:CheckArgument(usage, 'opts.timeout', 'number', opts.timeout, 5) + args.callback, args.handler = self:CheckCallback(usage, 'opts.', opts.callback, opts.handler, defhandler) + + -- now args - copied and verified from opts + local cachedName = self.Cache[args.name] + + if(cachedName ~= nil)then + -- user is in cache + if(cachedName.valid == true and (args.timeout < 0 or cachedName.last + args.timeout*60 > now))then + -- cache is valid and timeout is in range + --dbg('Info(' .. args.name ..') returned immedeatly') + if(bit.band(args.flags, self.WHOLIB_FLAG_ALWAYS_CALLBACK) ~= 0)then + self:RaiseCallback(args, cachedName.data) + return false + else + return self:DupAll(self:ReturnUserInfo(args.name)) + end + elseif(cachedName.valid == false)then + -- query is already running (first try) + if(args.callback ~= nil)then + tinsert(cachedName.callback, args) + end + --dbg('Info(' .. args.name ..') returned cause it\'s already searching') + return nil + end + else + self.Cache[args.name] = {valid=false, inqueue=false, callback={}, data={Name = args.name}, last=now } + end + + local cachedName = self.Cache[args.name] + + if(cachedName.inqueue)then + -- query is running! + if(args.callback ~= nil)then + tinsert(cachedName.callback, args) + end + dbg('Info(' .. args.name ..') returned cause it\'s already searching') + return nil + end + if (GetLocale() == "ruRU") then -- in ruRU with n- not show information about player in WIM addon + if args.name and args.name:len() > 0 then + local query = 'и-"' .. args.name .. '"' + cachedName.inqueue = true + if(args.callback ~= nil)then + tinsert(cachedName.callback, args) + end + self.CacheQueue[query] = args.name + dbg('Info(' .. args.name ..') added to queue') + self:AskWho( { query = query, queue = args.queue, flags = 0, info = args.name } ) + end + else + if args.name and args.name:len() > 0 then + local query = 'n-"' .. args.name .. '"' + cachedName.inqueue = true + if(args.callback ~= nil)then + tinsert(cachedName.callback, args) + end + self.CacheQueue[query] = args.name + dbg('Info(' .. args.name ..') added to queue') + self:AskWho( { query = query, queue = args.queue, flags = 0, info = args.name } ) + end + end + return nil +end + +function lib.CachedUserInfo(_, name) + local self, usage = lib, 'CachedUserInfo(name)' + + name = self:CapitalizeInitial(self:CheckArgument(usage, 'name', 'string', name)) + + if self.Cache[name] == nil then + return nil + else + return self:DupAll(self:ReturnUserInfo(name)) + end +end + +function lib.GetWhoLibDebug(_, mode) + return lib.Debug +end + +function lib.SetWhoLibDebug(_, mode) + lib.Debug = mode + dbg = mode and dbgfunc or NOP +end + +--function lib.RegisterWhoLibEvent(defhandler, event, callback, handler) +-- local self, usage = lib, 'RegisterWhoLibEvent(event, callback, [handler])' +-- +-- self:CheckPreset(usage, 'event', self.events, event) +-- local callback, handler = self:CheckCallback(usage, '', callback, handler, defhandler, true) +-- table.insert(self.events[event], {callback=callback, handler=handler}) +--end + +-- non-embedded externals + +function lib.Embed(_, handler) + local self, usage = lib, 'Embed(handler)' + + self:CheckArgument(usage, 'handler', 'table', handler) + + for _,name in pairs(self.external) do + handler[name] = self[name] + end -- do + self['embeds'][handler] = true + + return handler +end + +function lib.Library(_) + local self = lib + + return self:Embed({}) +end + +--- +--- internal functions +--- + +function lib:AllQueuesEmpty() + local queueCount = #self.Queue[1] + #self.Queue[2] + #self.Queue[3] + #self.CacheQueue + + -- Be sure that we have cleared the in-progress status + if self.WhoInProgress then + queueCount = queueCount + 1 + end + + return queueCount == 0 +end + +local queryInterval = 5 + +function lib:GetQueryInterval() return queryInterval end + +function lib:AskWhoNextIn5sec() + if self.frame:IsShown() then return end + + dbg("Waiting to send next who") + self.Timeout_time = queryInterval + self['frame']:Show() +end + +function lib:CancelPendingWhoNext() + lib['frame']:Hide() +end + +lib['frame']:SetScript("OnUpdate", function(frame, elapsed) + lib.Timeout_time = lib.Timeout_time - elapsed + if lib.Timeout_time <= 0 then + lib['frame']:Hide() + lib:AskWhoNext() + end -- if +end); + + +-- queue scheduler +local queue_weights = { [1] = 0.6, [2] = 0.2, [3] = 0.2 } +local queue_bounds = { [1] = 0.6, [2] = 0.2, [3] = 0.2 } + +-- allow for single queries from the user to get processed faster +local lastInstantQuery = time() +local INSTANT_QUERY_MIN_INTERVAL = 60 -- only once every 1 min + +function lib:UpdateWeights() + local weightsum, sum, count = 0, 0, 0 + for k,v in pairs(queue_weights) do + sum = sum + v + weightsum = weightsum + v * #self.Queue[k] + end + + if weightsum == 0 then + for k,v in pairs(queue_weights) do queue_bounds[k] = v end + return + end + + local adjust = sum / weightsum + + for k,v in pairs(queue_bounds) do + queue_bounds[k] = queue_weights[k] * adjust * #self.Queue[k] + end +end + +function lib:GetNextFromScheduler() + self:UpdateWeights() + + -- Since an addon could just fill up the user q for instant processing + -- we have to limit instants to 1 per INSTANT_QUERY_MIN_INTERVAL + -- and only try instant fulfilment if it will empty the user queue + if #self.Queue[1] == 1 then + if time() - lastInstantQuery > INSTANT_QUERY_MIN_INTERVAL then + dbg("INSTANT") + lastInstantQuery = time() + return 1, self.Queue[1] + end + end + + local n,i = math.random(),0 + repeat + i=i+1 + n = n - queue_bounds[i] + until i>=#self.Queue or n <= 0 + + dbg(("Q=%d, bound=%d"):format(i, queue_bounds[i])) + + if #self.Queue[i] > 0 then + dbg(("Q=%d, bound=%d"):format(i, queue_bounds[i])) + return i, self.Queue[i] + else + dbg("Queues empty, waiting") + end +end + +lib.queue_bounds = queue_bounds + +function lib:AskWhoNext() + if lib.frame:IsShown() then + dbg("Already waiting") + return + end + + self:CancelPendingWhoNext() + + if self.WhoInProgress then + -- if we had a who going, it didnt complete + dbg("TIMEOUT: "..self.Args.query) + local args = self.Args + self.Args = nil +-- if args.info and self.CacheQueue[args.query] ~= nil then + dbg("Requeing "..args.query) + tinsert(self.Queue[args.queue], args) + if args.console_show ~= nil then + DEFAULT_CHAT_FRAME:AddMessage(("Timeout on result of '%s' - retrying..."):format(args.query),1,1,0) + args.console_show = true + end +-- end + + if queryInterval < lib.MaxInterval then + queryInterval = queryInterval + 0.5 + dbg("--Throttling down to 1 who per " .. queryInterval .. "s") + end + end + + + self.WhoInProgress = false + + local v,k,args = nil + local kludge = 10 + repeat + k,v = self:GetNextFromScheduler() + if not k then break end + if(WhoFrame:IsShown() and k > self.WHOLIB_QUEUE_QUIET)then + break + end + if(#v > 0)then + args = tremove(v, 1) + break + end + kludge = kludge - 1 + until kludge <= 0 + + if args then + self.WhoInProgress = true + self.Result = {} + self.Args = args + self.Total = -1 + if(args.console_show == true)then + DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_query'], args.query), 1, 1, 0) + + end + + if args.queue == self.WHOLIB_QUEUE_USER then + WhoFrameEditBox:SetText(args.query) + self.Quiet = false + + if args.whotoui then + self.hooked.SetWhoToUI(args.whotoui) + else + self.hooked.SetWhoToUI(args.gui and 1 or 0) + end + else + self.hooked.SetWhoToUI(1) + self.Quiet = true + end + + dbg("QUERY: "..args.query) + self.hooked.SendWho(args.query) + else + self.Args = nil + self.WhoInProgress = false + end + + -- Keep processing the who queue if there is more work + if not self:AllQueuesEmpty() then + self:AskWhoNextIn5sec() + else + dbg("*** Done processing requests ***") + end +end + +function lib:AskWho(args) + tinsert(self.Queue[args.queue], args) + dbg('[' .. args.queue .. '] added "' .. args.query .. '", queues=' .. #self.Queue[1] .. '/'.. #self.Queue[2] .. '/'.. #self.Queue[3]) + self:TriggerEvent('WHOLIB_QUERY_ADDED') + + self:AskWhoNext() +end + +function lib:ReturnWho() + if not self.Args then + self.Quiet = nil + return + end + + if(self.Args.queue == self.WHOLIB_QUEUE_QUIET or self.Args.queue == self.WHOLIB_QUEUE_SCANNING)then + self.Quiet = nil + end + + if queryInterval > self.MinInterval then + queryInterval = queryInterval - 0.5 + dbg("--Throttling up to 1 who per " .. queryInterval .. "s") + end + + self.WhoInProgress = false + dbg("RESULT: "..self.Args.query) + dbg('[' .. self.Args.queue .. '] returned "' .. self.Args.query .. '", total=' .. self.Total ..' , queues=' .. #self.Queue[1] .. '/'.. #self.Queue[2] .. '/'.. #self.Queue[3]) + local now = time() + local complete = (self.Total == #self.Result) and (self.Total < MAX_WHOS_FROM_SERVER) + for _,v in pairs(self.Result)do + if(self.Cache[v.Name] == nil)then + self.Cache[v.Name] = { inqueue = false, callback = {} } + end + + local cachedName = self.Cache[v.Name] + + cachedName.valid = true -- is now valid + cachedName.data = v -- update data + cachedName.data.Online = true -- player is online + cachedName.last = now -- update timestamp + if(cachedName.inqueue)then + if(self.Args.info and self.CacheQueue[self.Args.query] == v.Name)then + -- found by the query which was created to -> remove us from query + self.CacheQueue[self.Args.query] = nil + else + -- found by another query + for k2,v2 in pairs(self.CacheQueue) do + if(v2 == v.Name)then + for i=self.WHOLIB_QUEUE_QUIET, self.WHOLIB_QUEUE_SCANNING do + for k3,v3 in pairs(self.Queue[i]) do + if(v3.query == k2 and v3.info)then + -- remove the query which was generated for this user, cause another query was faster... + dbg("Found '"..v.Name.."' early via query '"..self.Args.query.."'") + table.remove(self.Queue[i], k3) + self.CacheQueue[k2] = nil + end + end + end + end + end + end + dbg('Info(' .. v.Name ..') returned: on') + for _,v2 in pairs(cachedName.callback) do + self:RaiseCallback(v2, self:ReturnUserInfo(v.Name)) + end + cachedName.callback = {} + end + cachedName.inqueue = false -- query is done + end + if(self.Args.info and self.CacheQueue[self.Args.query])then + -- the query did not deliver the result => not online! + local name = self.CacheQueue[self.Args.query] + local cachedName = self.Cache[name] + if (cachedName.inqueue)then + -- nothing found (yet) + cachedName.valid = true -- is now valid + cachedName.inqueue = false -- query is done? + cachedName.last = now -- update timestamp + if(complete)then + cachedName.data.Online = false -- player is offline + else + cachedName.data.Online = nil -- player is unknown (more results from who than can be displayed) + end + end + dbg('Info(' .. name ..') returned: ' .. (cachedName.data.Online == false and 'off' or 'unkn')) + for _,v in pairs(cachedName.callback) do + self:RaiseCallback(v, self:ReturnUserInfo(name)) + end + cachedName.callback = {} + self.CacheQueue[self.Args.query] = nil + end + self:RaiseCallback(self.Args, self.Args.query, self.Result, complete, self.Args.info) + self:TriggerEvent('WHOLIB_QUERY_RESULT', self.Args.query, self.Result, complete, self.Args.info) + + if not self:AllQueuesEmpty() then + self:AskWhoNextIn5sec() + end +end + +function lib:GuiWho(msg) + if(msg == self.L['gui_wait'])then + return + end + + for _,v in pairs(self.Queue[self.WHOLIB_QUEUE_USER]) do + if(v.gui == true)then + return + end + end + if(self.WhoInProgress)then + WhoFrameEditBox:SetText(self.L['gui_wait']) + end + self.savedText = msg + self:AskWho({query = msg, queue = self.WHOLIB_QUEUE_USER, flags = 0, gui = true}) + WhoFrameEditBox:ClearFocus(); +end + +function lib:ConsoleWho(msg) + --WhoFrameEditBox:SetText(msg) + local console_show = false + local q1 = self.Queue[self.WHOLIB_QUEUE_USER] + local q1count = #q1 + + if(q1count > 0 and q1[q1count].query == msg)then -- last query is itdenical: drop + return + end + + if(q1count > 0 and q1[q1count].console_show == false)then -- display 'queued' if console and not yet shown + DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_queued'], q1[q1count].query), 1, 1, 0) + q1[q1count].console_show = true + end + if(q1count > 0 or self.WhoInProgress)then + DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_queued'], msg), 1, 1, 0) + console_show = true + end + self:AskWho({query = msg, queue = self.WHOLIB_QUEUE_USER, flags = 0, console_show = console_show}) +end + +function lib:ReturnUserInfo(name) + if(name ~= nil and self ~= nil and self.Cache ~= nil and self.Cache[name] ~= nil) then + return self.Cache[name].data, (time() - self.Cache[name].last) / 60 + end +end + +function lib:RaiseCallback(args, ...) + if type(args.callback) == 'function' then + args.callback(self:DupAll(...)) + elseif args.callback then -- must be a string + args.handler[args.callback](args.handler, self:DupAll(...)) + end -- if +end + +-- Argument checking + +function lib:CheckArgument(func, name, argtype, arg, defarg) + if arg == nil and defarg ~= nil then + return defarg + elseif type(arg) == argtype then + return arg + else + error(string.format("%s: '%s' - %s%s expected got %s", func, name, (defarg ~= nil) and 'nil or ' or '', argtype, type(arg)), 3) + end -- if +end + +function lib:CheckPreset(func, name, preset, arg, defarg) + if arg == nil and defarg ~= nil then + return defarg + elseif arg ~= nil and preset[arg] ~= nil then + return arg + else + local p = {} + for k,v in pairs(preset) do + if type(v) ~= 'string' then + table.insert(p, k) + else + table.insert(p, v) + end -- if + end -- for + error(string.format("%s: '%s' - one of %s%s expected got %s", func, name, (defarg ~= nil) and 'nil, ' or '', table.concat(p, ', '), self:simple_dump(arg)), 3) + end -- if +end + +function lib:CheckCallback(func, prefix, callback, handler, defhandler, nonil) + if not nonil and callback == nil then + -- no callback: ignore handler + return nil, nil + elseif type(callback) == 'function' then + -- simple function + if handler ~= nil then + error(string.format("%s: '%shandler' - nil expected got %s", func, prefix, type(arg)), 3) + end -- if + elseif type(callback) == 'string' then + -- method + if handler == nil then + handler = defhandler + end -- if + if type(handler) ~= 'table' or type(handler[callback]) ~= 'function' or handler == self then + error(string.format("%s: '%shandler' - nil or function expected got %s", func, prefix, type(arg)), 3) + end -- if + else + error(string.format("%s: '%scallback' - %sfunction or string expected got %s", func, prefix, nonil and 'nil or ' or '', type(arg)), 3) + end -- if + + return callback, handler +end + +-- helpers + +function lib:simple_dump(x) + if type(x) == 'string' then + return 'string \''..x..'\'' + elseif type(x) == 'number' then + return 'number '..x + else + return type(x) + end +end + +function lib:Dup(from) + local to = {} + + for k,v in pairs(from) do + if type(v) == 'table' then + to[k] = self:Dup(v) + else + to[k] = v + end -- if + end -- for + + return to +end + +function lib:DupAll(x, ...) + if type(x) == 'table' then + return self:Dup(x), self:DupAll(...) + elseif x ~= nil then + return x, self:DupAll(...) + else + return nil + end -- if +end + +local MULTIBYTE_FIRST_CHAR = "^([\192-\255]?%a?[\128-\191]*)" + +function lib:CapitalizeInitial(name) + return name:gsub(MULTIBYTE_FIRST_CHAR, string.upper, 1) +end + +--- +--- user events (Using CallbackHandler) +--- + +lib.PossibleEvents = { + 'WHOLIB_QUERY_RESULT', + 'WHOLIB_QUERY_ADDED', +} + +function lib:TriggerEvent(event, ...) + callbacks:Fire(event, ...) +end + +--- +--- slash commands +--- + +SlashCmdList['WHO'] = function(msg) + dbg("console /who: "..msg) + -- new /who function + --local self = lib + + if(msg == '')then + lib:GuiWho(WhoFrame_GetDefaultWhoCommand()) + elseif(WhoFrame:IsVisible())then + lib:GuiWho(msg) + else + lib:ConsoleWho(msg) + end +end + +SlashCmdList['WHOLIB_DEBUG'] = function() + -- /wholibdebug: toggle debug on/off + local self = lib + + self:SetWhoLibDebug(not self.Debug) +end + +SLASH_WHOLIB_DEBUG1 = '/wholibdebug' + + +--- +--- hook activation +--- + +-- functions to hook +local hooks = { + 'SendWho', + 'WhoFrameEditBox_OnEnterPressed', +-- 'FriendsFrame_OnEvent', + 'SetWhoToUI', +} + +-- hook all functions (which are not yet hooked) +for _, name in pairs(hooks) do + if not lib['hooked'][name] then + lib['hooked'][name] = _G[name] + _G[name] = function(...) + lib.hook[name](lib, ...) + end -- function + end -- if +end -- for + +-- fake 'WhoFrame:Hide' as hooked +table.insert(hooks, 'WhoFrame_Hide') + +-- check for unused hooks -> remove function +for name, _ in pairs(lib['hook']) do + if not hooks[name] then + lib['hook'][name] = function() end + end -- if +end -- for + +-- secure hook 'WhoFrame:Hide' +if not lib['hooked']['WhoFrame_Hide'] then + lib['hooked']['WhoFrame_Hide'] = true + hooksecurefunc(WhoFrame, 'Hide', function(...) + lib['hook']['WhoFrame_Hide'](lib, ...) + end -- function + ) +end -- if + + + +----- Coroutine based implementation (future) +--function lib:sendWhoResult(val) +-- coroutine.yield(val) +--end +-- +--function lib:sendWaitState(val) +-- coroutine.yield(val) +--end +-- +--function lib:producer() +-- return coroutine.create( +-- function() +-- lib:AskWhoNext() +-- lib:sendWaitState(true) +-- +-- -- Resumed look for data +-- +-- end) +--end + + + + + +--- +--- hook replacements +--- + +function lib.hook.SendWho(self, msg) + dbg("SendWho: "..msg) + lib.AskWho(self, {query = msg, queue = lib.WHOLIB_QUEUE_USER, whotoui = lib.SetWhoToUIState, flags = 0}) +end + +function lib.hook.WhoFrameEditBox_OnEnterPressed(self) + lib:GuiWho(WhoFrameEditBox:GetText()) +end + +--[[ +function lib.hook.FriendsFrame_OnEvent(self, ...) + if event ~= 'WHO_LIST_UPDATE' or not lib.Quiet then + lib.hooked.FriendsFrame_OnEvent(...) + end +end +]] + +hooksecurefunc(FriendsFrame, 'RegisterEvent', function(self, event) + if(event == "WHO_LIST_UPDATE") then + self:UnregisterEvent("WHO_LIST_UPDATE"); + end + end); + + +function lib.hook.SetWhoToUI(self, state) + lib.SetWhoToUIState = state +end + +function lib.hook.WhoFrame_Hide(self) + if(not lib.WhoInProgress)then + lib:AskWhoNextIn5sec() + end +end + + +--- +--- WoW events +--- + +local who_pattern = string.gsub(WHO_NUM_RESULTS, '%%d', '%%d%+') + + +function lib:CHAT_MSG_SYSTEM(arg1) + if arg1 and arg1:find(who_pattern) then + lib:ProcessWhoResults() + end +end + +FriendsFrame:UnregisterEvent("WHO_LIST_UPDATE") + +function lib:WHO_LIST_UPDATE() + if not lib.Quiet then + WhoList_Update() + FriendsFrame_Update() + end + + lib:ProcessWhoResults() +end + +function lib:ProcessWhoResults() + local num + self.Total, num = GetNumWhoResults() + for i=1, num do + local charname, guildname, level, race, class, zone, nonlocalclass, sex = GetWhoInfo(i) + self.Result[i] = {Name=charname, Guild=guildname, Level=level, Race=race, Class=class, Zone=zone, NoLocaleClass=nonlocalclass, Sex=sex } + end + + self:ReturnWho() +end + +--- +--- event activation +--- + +lib['frame']:UnregisterAllEvents(); + +lib['frame']:SetScript("OnEvent", function(frame, event, ...) + lib[event](lib, ...) +end); + +for _,name in pairs({ + 'CHAT_MSG_SYSTEM', + 'WHO_LIST_UPDATE', +}) do + lib['frame']:RegisterEvent(name); +end -- for + + +--- +--- re-embed +--- + +for target,_ in pairs(lib['embeds']) do + if type(target) == 'table' then + lib:Embed(target) + end -- if +end -- for diff --git a/libs/LibWho-2.0XX/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua b/libs/LibWho-2.0XX/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua index 274016c..e0fe1af 100644 --- a/libs/LibWho-2.0XX/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua +++ b/libs/LibWho-2.0XX/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua @@ -1,240 +1,240 @@ ---[[ $Id: CallbackHandler-1.0.lua 14 2010-08-09 00:43:38Z mikk $ ]] -local MAJOR, MINOR = "CallbackHandler-1.0", 6 -local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR) - -if not CallbackHandler then return end -- No upgrade needed - -local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end} - --- Lua APIs -local tconcat = table.concat -local assert, error, loadstring = assert, error, loadstring -local setmetatable, rawset, rawget = setmetatable, rawset, rawget -local next, select, pairs, type, tostring = next, select, pairs, type, tostring - --- Global vars/functions that we don't upvalue since they might get hooked, or upgraded --- List them here for Mikk's FindGlobals script --- GLOBALS: geterrorhandler - -local xpcall = xpcall - -local function errorhandler(err) - return geterrorhandler()(err) -end - -local function CreateDispatcher(argCount) - local code = [[ - local next, xpcall, eh = ... - - local method, ARGS - local function call() method(ARGS) end - - local function dispatch(handlers, ...) - local index - index, method = next(handlers) - if not method then return end - local OLD_ARGS = ARGS - ARGS = ... - repeat - xpcall(call, eh) - index, method = next(handlers, index) - until not method - ARGS = OLD_ARGS - end - - return dispatch - ]] - - local ARGS, OLD_ARGS = {}, {} - for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end - code = code:gsub("OLD_ARGS", tconcat(OLD_ARGS, ", ")):gsub("ARGS", tconcat(ARGS, ", ")) - return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler) -end - -local Dispatchers = setmetatable({}, {__index=function(self, argCount) - local dispatcher = CreateDispatcher(argCount) - rawset(self, argCount, dispatcher) - return dispatcher -end}) - --------------------------------------------------------------------------- --- CallbackHandler:New --- --- target - target object to embed public APIs in --- RegisterName - name of the callback registration API, default "RegisterCallback" --- UnregisterName - name of the callback unregistration API, default "UnregisterCallback" --- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API. - -function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused) - -- TODO: Remove this after beta has gone out - assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused") - - RegisterName = RegisterName or "RegisterCallback" - UnregisterName = UnregisterName or "UnregisterCallback" - if UnregisterAllName==nil then -- false is used to indicate "don't want this method" - UnregisterAllName = "UnregisterAllCallbacks" - end - - -- we declare all objects and exported APIs inside this closure to quickly gain access - -- to e.g. function names, the "target" parameter, etc - - - -- Create the registry object - local events = setmetatable({}, meta) - local registry = { recurse=0, events=events } - - -- registry:Fire() - fires the given event/message into the registry - function registry:Fire(eventname, ...) - if not rawget(events, eventname) or not next(events[eventname]) then return end - local oldrecurse = registry.recurse - registry.recurse = oldrecurse + 1 - - Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...) - - registry.recurse = oldrecurse - - if registry.insertQueue and oldrecurse==0 then - -- Something in one of our callbacks wanted to register more callbacks; they got queued - for eventname,callbacks in pairs(registry.insertQueue) do - local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. - for self,func in pairs(callbacks) do - events[eventname][self] = func - -- fire OnUsed callback? - if first and registry.OnUsed then - registry.OnUsed(registry, target, eventname) - first = nil - end - end - end - registry.insertQueue = nil - end - end - - -- Registration of a callback, handles: - -- self["method"], leads to self["method"](self, ...) - -- self with function ref, leads to functionref(...) - -- "addonId" (instead of self) with function ref, leads to functionref(...) - -- all with an optional arg, which, if present, gets passed as first argument (after self if present) - target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]]) - if type(eventname) ~= "string" then - error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2) - end - - method = method or eventname - - local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. - - if type(method) ~= "string" and type(method) ~= "function" then - error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2) - end - - local regfunc - - if type(method) == "string" then - -- self["method"] calling style - if type(self) ~= "table" then - error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2) - elseif self==target then - error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2) - elseif type(self[method]) ~= "function" then - error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2) - end - - if select("#",...)>=1 then -- this is not the same as testing for arg==nil! - local arg=select(1,...) - regfunc = function(...) self[method](self,arg,...) end - else - regfunc = function(...) self[method](self,...) end - end - else - -- function ref with self=object or self="addonId" or self=thread - if type(self)~="table" and type(self)~="string" and type(self)~="thread" then - error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2) - end - - if select("#",...)>=1 then -- this is not the same as testing for arg==nil! - local arg=select(1,...) - regfunc = function(...) method(arg,...) end - else - regfunc = method - end - end - - - if events[eventname][self] or registry.recurse<1 then - -- if registry.recurse<1 then - -- we're overwriting an existing entry, or not currently recursing. just set it. - events[eventname][self] = regfunc - -- fire OnUsed callback? - if registry.OnUsed and first then - registry.OnUsed(registry, target, eventname) - end - else - -- we're currently processing a callback in this registry, so delay the registration of this new entry! - -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency - registry.insertQueue = registry.insertQueue or setmetatable({},meta) - registry.insertQueue[eventname][self] = regfunc - end - end - - -- Unregister a callback - target[UnregisterName] = function(self, eventname) - if not self or self==target then - error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2) - end - if type(eventname) ~= "string" then - error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2) - end - if rawget(events, eventname) and events[eventname][self] then - events[eventname][self] = nil - -- Fire OnUnused callback? - if registry.OnUnused and not next(events[eventname]) then - registry.OnUnused(registry, target, eventname) - end - end - if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then - registry.insertQueue[eventname][self] = nil - end - end - - -- OPTIONAL: Unregister all callbacks for given selfs/addonIds - if UnregisterAllName then - target[UnregisterAllName] = function(...) - if select("#",...)<1 then - error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2) - end - if select("#",...)==1 and ...==target then - error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2) - end - - - for i=1,select("#",...) do - local self = select(i,...) - if registry.insertQueue then - for eventname, callbacks in pairs(registry.insertQueue) do - if callbacks[self] then - callbacks[self] = nil - end - end - end - for eventname, callbacks in pairs(events) do - if callbacks[self] then - callbacks[self] = nil - -- Fire OnUnused callback? - if registry.OnUnused and not next(callbacks) then - registry.OnUnused(registry, target, eventname) - end - end - end - end - end - end - - return registry -end - - --- CallbackHandler purposefully does NOT do explicit embedding. Nor does it --- try to upgrade old implicit embeds since the system is selfcontained and --- relies on closures to work. - +--[[ $Id: CallbackHandler-1.0.lua 14 2010-08-09 00:43:38Z mikk $ ]] +local MAJOR, MINOR = "CallbackHandler-1.0", 6 +local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR) + +if not CallbackHandler then return end -- No upgrade needed + +local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end} + +-- Lua APIs +local tconcat = table.concat +local assert, error, loadstring = assert, error, loadstring +local setmetatable, rawset, rawget = setmetatable, rawset, rawget +local next, select, pairs, type, tostring = next, select, pairs, type, tostring + +-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded +-- List them here for Mikk's FindGlobals script +-- GLOBALS: geterrorhandler + +local xpcall = xpcall + +local function errorhandler(err) + return geterrorhandler()(err) +end + +local function CreateDispatcher(argCount) + local code = [[ + local next, xpcall, eh = ... + + local method, ARGS + local function call() method(ARGS) end + + local function dispatch(handlers, ...) + local index + index, method = next(handlers) + if not method then return end + local OLD_ARGS = ARGS + ARGS = ... + repeat + xpcall(call, eh) + index, method = next(handlers, index) + until not method + ARGS = OLD_ARGS + end + + return dispatch + ]] + + local ARGS, OLD_ARGS = {}, {} + for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end + code = code:gsub("OLD_ARGS", tconcat(OLD_ARGS, ", ")):gsub("ARGS", tconcat(ARGS, ", ")) + return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler) +end + +local Dispatchers = setmetatable({}, {__index=function(self, argCount) + local dispatcher = CreateDispatcher(argCount) + rawset(self, argCount, dispatcher) + return dispatcher +end}) + +-------------------------------------------------------------------------- +-- CallbackHandler:New +-- +-- target - target object to embed public APIs in +-- RegisterName - name of the callback registration API, default "RegisterCallback" +-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback" +-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API. + +function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused) + -- TODO: Remove this after beta has gone out + assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused") + + RegisterName = RegisterName or "RegisterCallback" + UnregisterName = UnregisterName or "UnregisterCallback" + if UnregisterAllName==nil then -- false is used to indicate "don't want this method" + UnregisterAllName = "UnregisterAllCallbacks" + end + + -- we declare all objects and exported APIs inside this closure to quickly gain access + -- to e.g. function names, the "target" parameter, etc + + + -- Create the registry object + local events = setmetatable({}, meta) + local registry = { recurse=0, events=events } + + -- registry:Fire() - fires the given event/message into the registry + function registry:Fire(eventname, ...) + if not rawget(events, eventname) or not next(events[eventname]) then return end + local oldrecurse = registry.recurse + registry.recurse = oldrecurse + 1 + + Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...) + + registry.recurse = oldrecurse + + if registry.insertQueue and oldrecurse==0 then + -- Something in one of our callbacks wanted to register more callbacks; they got queued + for eventname,callbacks in pairs(registry.insertQueue) do + local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. + for self,func in pairs(callbacks) do + events[eventname][self] = func + -- fire OnUsed callback? + if first and registry.OnUsed then + registry.OnUsed(registry, target, eventname) + first = nil + end + end + end + registry.insertQueue = nil + end + end + + -- Registration of a callback, handles: + -- self["method"], leads to self["method"](self, ...) + -- self with function ref, leads to functionref(...) + -- "addonId" (instead of self) with function ref, leads to functionref(...) + -- all with an optional arg, which, if present, gets passed as first argument (after self if present) + target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]]) + if type(eventname) ~= "string" then + error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2) + end + + method = method or eventname + + local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. + + if type(method) ~= "string" and type(method) ~= "function" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2) + end + + local regfunc + + if type(method) == "string" then + -- self["method"] calling style + if type(self) ~= "table" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2) + elseif self==target then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2) + elseif type(self[method]) ~= "function" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2) + end + + if select("#",...)>=1 then -- this is not the same as testing for arg==nil! + local arg=select(1,...) + regfunc = function(...) self[method](self,arg,...) end + else + regfunc = function(...) self[method](self,...) end + end + else + -- function ref with self=object or self="addonId" or self=thread + if type(self)~="table" and type(self)~="string" and type(self)~="thread" then + error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2) + end + + if select("#",...)>=1 then -- this is not the same as testing for arg==nil! + local arg=select(1,...) + regfunc = function(...) method(arg,...) end + else + regfunc = method + end + end + + + if events[eventname][self] or registry.recurse<1 then + -- if registry.recurse<1 then + -- we're overwriting an existing entry, or not currently recursing. just set it. + events[eventname][self] = regfunc + -- fire OnUsed callback? + if registry.OnUsed and first then + registry.OnUsed(registry, target, eventname) + end + else + -- we're currently processing a callback in this registry, so delay the registration of this new entry! + -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency + registry.insertQueue = registry.insertQueue or setmetatable({},meta) + registry.insertQueue[eventname][self] = regfunc + end + end + + -- Unregister a callback + target[UnregisterName] = function(self, eventname) + if not self or self==target then + error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2) + end + if type(eventname) ~= "string" then + error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2) + end + if rawget(events, eventname) and events[eventname][self] then + events[eventname][self] = nil + -- Fire OnUnused callback? + if registry.OnUnused and not next(events[eventname]) then + registry.OnUnused(registry, target, eventname) + end + end + if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then + registry.insertQueue[eventname][self] = nil + end + end + + -- OPTIONAL: Unregister all callbacks for given selfs/addonIds + if UnregisterAllName then + target[UnregisterAllName] = function(...) + if select("#",...)<1 then + error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2) + end + if select("#",...)==1 and ...==target then + error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2) + end + + + for i=1,select("#",...) do + local self = select(i,...) + if registry.insertQueue then + for eventname, callbacks in pairs(registry.insertQueue) do + if callbacks[self] then + callbacks[self] = nil + end + end + end + for eventname, callbacks in pairs(events) do + if callbacks[self] then + callbacks[self] = nil + -- Fire OnUnused callback? + if registry.OnUnused and not next(callbacks) then + registry.OnUnused(registry, target, eventname) + end + end + end + end + end + end + + return registry +end + + +-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it +-- try to upgrade old implicit embeds since the system is selfcontained and +-- relies on closures to work. + diff --git a/libs/LibWho-2.0XX/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml b/libs/LibWho-2.0XX/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml index 876df83..a5b22a7 100644 --- a/libs/LibWho-2.0XX/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml +++ b/libs/LibWho-2.0XX/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml @@ -1,4 +1,4 @@ -<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ -..\FrameXML\UI.xsd"> - <Script file="CallbackHandler-1.0.lua"/> -</Ui> \ No newline at end of file +<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ +..\FrameXML\UI.xsd"> + <Script file="CallbackHandler-1.0.lua"/> +</Ui> diff --git a/libs/LibWho-2.0XX/libs/LibStub/LibStub.lua b/libs/LibWho-2.0XX/libs/LibStub/LibStub.lua index ae1900e..f5fc919 100644 --- a/libs/LibWho-2.0XX/libs/LibStub/LibStub.lua +++ b/libs/LibWho-2.0XX/libs/LibStub/LibStub.lua @@ -1,51 +1,51 @@ --- $Id: LibStub.lua 76 2007-09-03 01:50:17Z mikk $ --- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info --- LibStub is hereby placed in the Public Domain --- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke -local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! -local LibStub = _G[LIBSTUB_MAJOR] - --- Check to see is this version of the stub is obsolete -if not LibStub or LibStub.minor < LIBSTUB_MINOR then - LibStub = LibStub or {libs = {}, minors = {} } - _G[LIBSTUB_MAJOR] = LibStub - LibStub.minor = LIBSTUB_MINOR - - -- LibStub:NewLibrary(major, minor) - -- major (string) - the major version of the library - -- minor (string or number ) - the minor version of the library - -- - -- returns nil if a newer or same version of the lib is already present - -- returns empty library object or old library object if upgrade is needed - function LibStub:NewLibrary(major, minor) - assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") - minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") - - local oldminor = self.minors[major] - if oldminor and oldminor >= minor then return nil end - self.minors[major], self.libs[major] = minor, self.libs[major] or {} - return self.libs[major], oldminor - end - - -- LibStub:GetLibrary(major, [silent]) - -- major (string) - the major version of the library - -- silent (boolean) - if true, library is optional, silently return nil if its not found - -- - -- throws an error if the library can not be found (except silent is set) - -- returns the library object if found - function LibStub:GetLibrary(major, silent) - if not self.libs[major] and not silent then - error(("Cannot find a library instance of %q."):format(tostring(major)), 2) - end - return self.libs[major], self.minors[major] - end - - -- LibStub:IterateLibraries() - -- - -- Returns an iterator for the currently registered libraries - function LibStub:IterateLibraries() - return pairs(self.libs) - end - - setmetatable(LibStub, { __call = LibStub.GetLibrary }) -end +-- $Id: LibStub.lua 76 2007-09-03 01:50:17Z mikk $ +-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info +-- LibStub is hereby placed in the Public Domain +-- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! +local LibStub = _G[LIBSTUB_MAJOR] + +-- Check to see is this version of the stub is obsolete +if not LibStub or LibStub.minor < LIBSTUB_MINOR then + LibStub = LibStub or {libs = {}, minors = {} } + _G[LIBSTUB_MAJOR] = LibStub + LibStub.minor = LIBSTUB_MINOR + + -- LibStub:NewLibrary(major, minor) + -- major (string) - the major version of the library + -- minor (string or number ) - the minor version of the library + -- + -- returns nil if a newer or same version of the lib is already present + -- returns empty library object or old library object if upgrade is needed + function LibStub:NewLibrary(major, minor) + assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") + minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") + + local oldminor = self.minors[major] + if oldminor and oldminor >= minor then return nil end + self.minors[major], self.libs[major] = minor, self.libs[major] or {} + return self.libs[major], oldminor + end + + -- LibStub:GetLibrary(major, [silent]) + -- major (string) - the major version of the library + -- silent (boolean) - if true, library is optional, silently return nil if its not found + -- + -- throws an error if the library can not be found (except silent is set) + -- returns the library object if found + function LibStub:GetLibrary(major, silent) + if not self.libs[major] and not silent then + error(("Cannot find a library instance of %q."):format(tostring(major)), 2) + end + return self.libs[major], self.minors[major] + end + + -- LibStub:IterateLibraries() + -- + -- Returns an iterator for the currently registered libraries + function LibStub:IterateLibraries() + return pairs(self.libs) + end + + setmetatable(LibStub, { __call = LibStub.GetLibrary }) +end diff --git a/libs/LibWho-2.0XX/libs/LibStub/LibStub.toc b/libs/LibWho-2.0XX/libs/LibStub/LibStub.toc index e39aa26..f798fbc 100644 --- a/libs/LibWho-2.0XX/libs/LibStub/LibStub.toc +++ b/libs/LibWho-2.0XX/libs/LibStub/LibStub.toc @@ -1,13 +1,13 @@ -## Interface: 50001 -## Title: Lib: LibStub -## Notes: Universal Library Stub -## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel -## X-Website: http://www.wowace.com/addons/libstub/ -## X-Category: Library -## X-License: Public Domain -## X-Curse-Packaged-Version: 1.0.3-50001 -## X-Curse-Project-Name: LibStub -## X-Curse-Project-ID: libstub -## X-Curse-Repository-ID: wow/libstub/mainline - -LibStub.lua +## Interface: 50001 +## Title: Lib: LibStub +## Notes: Universal Library Stub +## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel +## X-Website: http://www.wowace.com/addons/libstub/ +## X-Category: Library +## X-License: Public Domain +## X-Curse-Packaged-Version: 1.0.3-50001 +## X-Curse-Project-Name: LibStub +## X-Curse-Project-ID: libstub +## X-Curse-Repository-ID: wow/libstub/mainline + +LibStub.lua diff --git a/libs/LibWho-2.0XX/libs/LibStub/tests/test.lua b/libs/LibWho-2.0XX/libs/LibStub/tests/test.lua index 276ddab..fb3bcbd 100644 --- a/libs/LibWho-2.0XX/libs/LibStub/tests/test.lua +++ b/libs/LibWho-2.0XX/libs/LibStub/tests/test.lua @@ -1,41 +1,41 @@ -debugstack = debug.traceback -strmatch = string.match - -loadfile("../LibStub.lua")() - -local lib, oldMinor = LibStub:NewLibrary("Pants", 1) -- make a new thingy -assert(lib) -- should return the library table -assert(not oldMinor) -- should not return the old minor, since it didn't exist - --- the following is to create data and then be able to check if the same data exists after the fact -function lib:MyMethod() -end -local MyMethod = lib.MyMethod -lib.MyTable = {} -local MyTable = lib.MyTable - -local newLib, newOldMinor = LibStub:NewLibrary("Pants", 1) -- try to register a library with the same version, should silently fail -assert(not newLib) -- should not return since out of date - -local newLib, newOldMinor = LibStub:NewLibrary("Pants", 0) -- try to register a library with a previous, should silently fail -assert(not newLib) -- should not return since out of date - -local newLib, newOldMinor = LibStub:NewLibrary("Pants", 2) -- register a new version -assert(newLib) -- library table -assert(rawequal(newLib, lib)) -- should be the same reference as the previous -assert(newOldMinor == 1) -- should return the minor version of the previous version - -assert(rawequal(lib.MyMethod, MyMethod)) -- verify that values were saved -assert(rawequal(lib.MyTable, MyTable)) -- verify that values were saved - -local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 3 Blah") -- register a new version with a string minor version (instead of a number) -assert(newLib) -- library table -assert(newOldMinor == 2) -- previous version was 2 - -local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 4 and please ignore 15 Blah") -- register a new version with a string minor version (instead of a number) -assert(newLib) -assert(newOldMinor == 3) -- previous version was 3 (even though it gave a string) - -local newLib, newOldMinor = LibStub:NewLibrary("Pants", 5) -- register a new library, using a normal number instead of a string -assert(newLib) -assert(newOldMinor == 4) -- previous version was 4 (even though it gave a string) \ No newline at end of file +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + +local lib, oldMinor = LibStub:NewLibrary("Pants", 1) -- make a new thingy +assert(lib) -- should return the library table +assert(not oldMinor) -- should not return the old minor, since it didn't exist + +-- the following is to create data and then be able to check if the same data exists after the fact +function lib:MyMethod() +end +local MyMethod = lib.MyMethod +lib.MyTable = {} +local MyTable = lib.MyTable + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 1) -- try to register a library with the same version, should silently fail +assert(not newLib) -- should not return since out of date + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 0) -- try to register a library with a previous, should silently fail +assert(not newLib) -- should not return since out of date + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 2) -- register a new version +assert(newLib) -- library table +assert(rawequal(newLib, lib)) -- should be the same reference as the previous +assert(newOldMinor == 1) -- should return the minor version of the previous version + +assert(rawequal(lib.MyMethod, MyMethod)) -- verify that values were saved +assert(rawequal(lib.MyTable, MyTable)) -- verify that values were saved + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 3 Blah") -- register a new version with a string minor version (instead of a number) +assert(newLib) -- library table +assert(newOldMinor == 2) -- previous version was 2 + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 4 and please ignore 15 Blah") -- register a new version with a string minor version (instead of a number) +assert(newLib) +assert(newOldMinor == 3) -- previous version was 3 (even though it gave a string) + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 5) -- register a new library, using a normal number instead of a string +assert(newLib) +assert(newOldMinor == 4) -- previous version was 4 (even though it gave a string) diff --git a/libs/LibWho-2.0XX/libs/LibStub/tests/test2.lua b/libs/LibWho-2.0XX/libs/LibStub/tests/test2.lua index eae7172..af431dd 100644 --- a/libs/LibWho-2.0XX/libs/LibStub/tests/test2.lua +++ b/libs/LibWho-2.0XX/libs/LibStub/tests/test2.lua @@ -1,27 +1,27 @@ -debugstack = debug.traceback -strmatch = string.match - -loadfile("../LibStub.lua")() - -for major, library in LibStub:IterateLibraries() do - -- check that MyLib doesn't exist yet, by iterating through all the libraries - assert(major ~= "MyLib") -end - -assert(not LibStub:GetLibrary("MyLib", true)) -- check that MyLib doesn't exist yet by direct checking -assert(not pcall(LibStub.GetLibrary, LibStub, "MyLib")) -- don't silently fail, thus it should raise an error. -local lib = LibStub:NewLibrary("MyLib", 1) -- create the lib -assert(lib) -- check it exists -assert(rawequal(LibStub:GetLibrary("MyLib"), lib)) -- verify that :GetLibrary("MyLib") properly equals the lib reference - -assert(LibStub:NewLibrary("MyLib", 2)) -- create a new version - -local count=0 -for major, library in LibStub:IterateLibraries() do - -- check that MyLib exists somewhere in the libraries, by iterating through all the libraries - if major == "MyLib" then -- we found it! - count = count +1 - assert(rawequal(library, lib)) -- verify that the references are equal - end -end -assert(count == 1) -- verify that we actually found it, and only once +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + +for major, library in LibStub:IterateLibraries() do + -- check that MyLib doesn't exist yet, by iterating through all the libraries + assert(major ~= "MyLib") +end + +assert(not LibStub:GetLibrary("MyLib", true)) -- check that MyLib doesn't exist yet by direct checking +assert(not pcall(LibStub.GetLibrary, LibStub, "MyLib")) -- don't silently fail, thus it should raise an error. +local lib = LibStub:NewLibrary("MyLib", 1) -- create the lib +assert(lib) -- check it exists +assert(rawequal(LibStub:GetLibrary("MyLib"), lib)) -- verify that :GetLibrary("MyLib") properly equals the lib reference + +assert(LibStub:NewLibrary("MyLib", 2)) -- create a new version + +local count=0 +for major, library in LibStub:IterateLibraries() do + -- check that MyLib exists somewhere in the libraries, by iterating through all the libraries + if major == "MyLib" then -- we found it! + count = count +1 + assert(rawequal(library, lib)) -- verify that the references are equal + end +end +assert(count == 1) -- verify that we actually found it, and only once diff --git a/libs/LibWho-2.0XX/libs/LibStub/tests/test3.lua b/libs/LibWho-2.0XX/libs/LibStub/tests/test3.lua index 30f7b94..3c06002 100644 --- a/libs/LibWho-2.0XX/libs/LibStub/tests/test3.lua +++ b/libs/LibWho-2.0XX/libs/LibStub/tests/test3.lua @@ -1,14 +1,14 @@ -debugstack = debug.traceback -strmatch = string.match - -loadfile("../LibStub.lua")() - -local proxy = newproxy() -- non-string - -assert(not pcall(LibStub.NewLibrary, LibStub, proxy, 1)) -- should error, proxy is not a string, it's userdata -local success, ret = pcall(LibStub.GetLibrary, proxy, true) -assert(not success or not ret) -- either error because proxy is not a string or because it's not actually registered. - -assert(not pcall(LibStub.NewLibrary, LibStub, "Something", "No number in here")) -- should error, minor has no string in it. - -assert(not LibStub:GetLibrary("Something", true)) -- shouldn't've created it from the above statement \ No newline at end of file +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + +local proxy = newproxy() -- non-string + +assert(not pcall(LibStub.NewLibrary, LibStub, proxy, 1)) -- should error, proxy is not a string, it's userdata +local success, ret = pcall(LibStub.GetLibrary, proxy, true) +assert(not success or not ret) -- either error because proxy is not a string or because it's not actually registered. + +assert(not pcall(LibStub.NewLibrary, LibStub, "Something", "No number in here")) -- should error, minor has no string in it. + +assert(not LibStub:GetLibrary("Something", true)) -- shouldn't've created it from the above statement diff --git a/libs/LibWho-2.0XX/libs/LibStub/tests/test4.lua b/libs/LibWho-2.0XX/libs/LibStub/tests/test4.lua index 43eb338..294623b 100644 --- a/libs/LibWho-2.0XX/libs/LibStub/tests/test4.lua +++ b/libs/LibWho-2.0XX/libs/LibStub/tests/test4.lua @@ -1,41 +1,41 @@ -debugstack = debug.traceback -strmatch = string.match - -loadfile("../LibStub.lua")() - - --- Pretend like loaded libstub is old and doesn't have :IterateLibraries -assert(LibStub.minor) -LibStub.minor = LibStub.minor - 0.0001 -LibStub.IterateLibraries = nil - -loadfile("../LibStub.lua")() - -assert(type(LibStub.IterateLibraries)=="function") - - --- Now pretend that we're the same version -- :IterateLibraries should NOT be re-created -LibStub.IterateLibraries = 123 - -loadfile("../LibStub.lua")() - -assert(LibStub.IterateLibraries == 123) - - --- Now pretend that a newer version is loaded -- :IterateLibraries should NOT be re-created -LibStub.minor = LibStub.minor + 0.0001 - -loadfile("../LibStub.lua")() - -assert(LibStub.IterateLibraries == 123) - - --- Again with a huge number -LibStub.minor = LibStub.minor + 1234567890 - -loadfile("../LibStub.lua")() - -assert(LibStub.IterateLibraries == 123) - - -print("OK") \ No newline at end of file +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + + +-- Pretend like loaded libstub is old and doesn't have :IterateLibraries +assert(LibStub.minor) +LibStub.minor = LibStub.minor - 0.0001 +LibStub.IterateLibraries = nil + +loadfile("../LibStub.lua")() + +assert(type(LibStub.IterateLibraries)=="function") + + +-- Now pretend that we're the same version -- :IterateLibraries should NOT be re-created +LibStub.IterateLibraries = 123 + +loadfile("../LibStub.lua")() + +assert(LibStub.IterateLibraries == 123) + + +-- Now pretend that a newer version is loaded -- :IterateLibraries should NOT be re-created +LibStub.minor = LibStub.minor + 0.0001 + +loadfile("../LibStub.lua")() + +assert(LibStub.IterateLibraries == 123) + + +-- Again with a huge number +LibStub.minor = LibStub.minor + 1234567890 + +loadfile("../LibStub.lua")() + +assert(LibStub.IterateLibraries == 123) + + +print("OK") diff --git a/locale/localization.lua b/locale/localization.lua index cda79f9..c8c46a7 100644 --- a/locale/localization.lua +++ b/locale/localization.lua @@ -1,452 +1,463 @@ -SGI_Locale = {} - -local function defaultFunc(L,key) - return key -end - -local English = setmetatable({}, {__index=defaultFunc}) - English["English Locale loaded"] = "English Locale loaded" - English["Enable whispers"] = "Enable whispers" - English["Level limits"] = nil - English["Invite Mode"] = nil - English["Whisper only"] = nil - English["Invite and whisper"] = nil - English["Invite only"] = nil - English["Mute SGI"] = nil - English["Filter 55-58 Death Knights"] = nil - English["Do a more thorough search"] = nil - English["Customize whisper"] = nil - English["SuperScan"] = nil - English["Invite: %d"] = nil - English["Choose Invites"] = nil - English["Exceptions"] = nil - English["Help"] = nil - English["The level you wish to start dividing the search by race"] = nil - English["Racefilter Start:"] = nil - English["The level you wish to divide the search by class"] = nil - English["Classfilter Start:"] = nil - English["Amount of levels to search every ~7 seconds (higher numbers increase the risk of capping the search results)"] = nil - English["Interval:"] = nil - English["SuperGuildInvite Custom Whisper"] = nil - English["WhisperInstructions"] = "Create a customized whisper to send people you invite! If you enter the words (must be caps) |cff00ff00NAME|r, |cff0000ffLEVEL|r or |cffff0000PLAYER|r these will be replaced by your Guildname, Guildlevel and the recieving players name" - English["Enter your whisper"] = nil - English["Save"] = nil - English["Cancel"] = nil - English["less than 1 second"] = nil - English[" hours "] = nil - English[" minutes "] = nil - English[" seconds"] = nil - English[" remaining"] = nil - English["Purge Queue"] = nil - English["Click to toggle SuperScan"] = nil - English["Click on the players you wish to invite"] = nil - English["Scan Completed"] = nil - English["Who sent: "] = nil - English["SuperScan was started"] = nil - English["SuperScan was stopped"] = nil - English["PlayersScanned"] = "Players Scanned: |cff44FF44%d|r |cffffff00(Total: |r|cff44FF44%d|r)" - English["PlayersGuildLess"] = "Guildless Players: |cff44FF44%d|r (|cff44FF44%d%%|r)" - English["InvitesQueued"] = "Invites Queued: |cff44FF44%d|r" - English["ExceptionsInstructions"] = "You can add exception phrases that when found in a name will cause the player to be ignore by SuperGuildInvite. You can add several exceptions at once, seperated by a comma (,)." - English["SGI Exceptions"] = nil - English["Enter exceptions"] = nil - English["Go to Options and select your Invite Mode"] = nil - English["You need to specify the mode in which you wish to invite"] = nil - English["Unable to invite %s. They are already in a guild."] = nil - English["Unable to invite %s. They will not be blacklisted."] = nil - - --Trouble shooter-- - English["not sending"] = "|cffff8800Why am I not sending any whispers?|r |cff00A2FFPossibly because you have not checked the checkbox.|r|cff00ff00 Click on this message to fix.|r" - English["to specify"] = "|cffff8800I am getting a message telling me to specify my invite mode when I try to invite!|r|cff00A2FF This happens when you have not used the dropdown menu in the options to pick how to invite people.|r|cff00ff00 Click to fix.|r" - English["I checked the box"] = "|cffff8800I am not sending any whispers when I invite and I checked the box!|r|cff00A2FF This is because you have selected only to invite with the dropdown menu in the options.|r|cff00ff00 Click to fix|r" - English["whisper to everyone"] = "|cffff8800I keep sending a whisper to everyone I invite, OR I just want to send whispers and not invite, but your AddOn does both!|r|cff00A2FF This is because you specified to both invite and whisper on the dropdown menu in options.|r|cff00ff00 Click to fix|r" - English["can't get SGI to invite"] = "|cffff8800I can't get SGI to invite people, all it does is sending whispers.|r|cff00A2FF This is because you picked that option in the dropdown menu.|r|cff00ff00 Click to fix|r" - English["can't see any messages"] = "|cffff8800I can't see any messages from SGI at all!|r|cff00A2FF This is because you have muted SGI in the options.|r|cff00ff00 Click to fix|r" - English["None of the above"] = "|cffff8800None of the above solved my problem!|r|cff00A2FF There might be an issue with the localization (language) you are using. You can try to load your locale manually: /sgi locale:deDE loads German (frFR for french). Please contact me at:|r|cff00ff00 SuperGuildInvite@gmail.com|r" - English["Enabled whispers"] = nil - English['Changed invite mode to "Invite and Whisper"'] = nil - English["Mute has been turned off"] = nil - English['Changed invite mode to "Only Invite". If you wanted "Only Whisper" go to Options and change.'] = nil - - - - English["Shaman"] = nil - English["Death Knight"] = nil - English["Mage"] = nil - English["Priest"] = nil - English["Rogue"] = nil - English["Paladin"] = nil - English["Warlock"] = nil - English["Druid"] = nil - English["Warrior"] = nil - English["Hunter"] = nil - English["Monk"] = nil - - English["Human"] = nil - English["Gnome"] = nil - English["Dwarf"] = nil - English["NightElf"] = nil - English["Draenei"] = nil - English["Worgen"] = nil - English["Pandaren"] = nil - English["Undead"] = nil - English["Orc"] = nil - English["Troll"] = nil - English["Tauren"] = nil - English["BloodElf"] = nil - English["Goblin"] = nil - - English["Author"] = "|cff00A2FF Written by Janniie - Stormreaver EU.|r" - -German = setmetatable({}, {__index=defaultFunc}) - German["English Locale loaded"] = "German Locale loaded" - German["Enable whispers"] = "aktivieren Sie flüstert" - German["Level limits"] = "Levelbeschränkungen" - German["Invite Mode"] = "Einladungsart" - German["Whisper only"] = "Nur anflüstern" - German["Invite and whisper"] = "Einladen und anflüstern" - German["Invite only"] = "Nur einladen" - German["Mute SGI"] = "SGI stummschalten" - German["Filter 55-58 Death Knights"] = "Level 55-58 Todesritter filtern" - German["Do a more thorough search"] = "Gründlichere Suche ausführen" - German["Customize whisper"] = "Flüsternachricht anpassen" - German["SuperScan"] = "SuperScan" - German["Invite: %d"] = "Einladen: %d" - German["Choose Invites"] = "einladungen auswählen" - German["Exceptions"] = "Ausnahmen" - German["Help"] = "Hilfe" - German["SuperGuildInvite Custom Whisper"] = "SuperGuildInvite eigene Flüsternachricht" - German["WhisperInstructions"] = "Erstelle eine eigene Flüsternachricht, die an die Leute gesendet wird, die du einlädst! Wenn du die worte |cff00ff00NAME|r, |cff0000ffLEVEL|r oder |cffff0000PLAYER|r (in Großbuchstaben) benutzt werden diese durch Gildenname, Gildenlevel und den Namen des Empfängers ersetzt." - German["Enter your whisper"] = "Flüsternachricht eingeben" - German["Save"] = "Speichern" - German["Cancel"] = "Abbrechen" - German["less than 1 second"] = "weniger als 1 Sekunden verbleibend" - German[" hours "] = " Stunden " - German[" minutes "] = " minute " - German[" seconds"] = " Sekunden" - German[" remaining"] = " verbleibend" - German["Purge Queue"] = "Warteschlange leeren" - German["Click to toggle SuperScan"] = "Klicken um SuperScan zu beenden" - German["Click on the players you wish to invite"] = "Klicke die Spieler an, die du einladen willst" - German["Scan Completed"] = "Suchlauf beendet" - German["Who sent: "] = "Wer-Abfrage gesendet: " - German["SuperScan was started"] = "SuperScan wurde gestartet" - German["SuperScan was stopped"] = "SuperScan wurde gestoppt" - German["PlayersScanned"] = "Spieler durchsucht: |cff44FF44%d|r (Insgesamt: |cff44FF44%d|r)" - German["PlayersGuildLess"] = "gildenlose Spieler: |cff44FF44%d|r" - German["InvitesQueued"] = "Einladungen in Warteschlange: |cff44FF44%d|r" - German["ExceptionsInstructions"] = "Hier kannst du Ausnahmen eingeben, die, wenn sie in einem Namen gefunden werden, dazu führen daß SGI diesen Spieler ignoriert. Du kannst mehrere Ausnahmen durch ein Komma (,) getrennt eingeben." - German["SGI Exceptions"] = "SGI Ausnahmen" - German["Go to Options and select your Invite Mode"] = "Gehen Sie auf Optionen und wählen Sie Einladungsart" - German["You need to specify the mode in which you wish to invite"] = "Sie müssen den Modus, in dem Sie einladen möchten festlegen" - German["Amount of levels to search every ~7 seconds (higher numbers increase the risk of capping the search results)"] = "Anzahl der Level nach denen etwa alle 7 Sekunden gesucht wird (höhere Zahlen erhöhen das Risiko, daß nicht alle Suchergebnisse bearbeitet werden)." - German["The level you wish to divide the search by class"] = "Level ab dem nach Klasse gesucht wird." - German["The level you wish to divide the search by race"] = "Level ab dem nach Rasse gesucht wird." - - German["not sending"] = "|cffff8800Warum verschicke ich keine Flüsternachrichten?|r |cff00A2FFMöglicherweise hast du das Kästchen nicht angekreuzt.|r|cff00ff00 Klicke auf diese Nachricht um das Problem zu beheben.|r" - German["to specify"] = "|cffff8800Ich bekomme eine Nachricht, daß ich die Einladungsart auswählen soll wenn ich jemanden einladen möchte.|r|cff00A2FF Das passiert wenn du nicht das Auswahlmenü in den Optionen benutzt hast um auszuwählen wie du Leute einlädst.|r|cff00ff00 Klicke auf diese Nachricht um das Problem zu beheben.|r" - German["I checked the box"] = "|cffff8800Ich verschicke keine Flüsternachrichten beim Einladen, obwohl ich das Kästchen angekreuzt habe.|r|cff00A2FF Das passiert wenn du nur einladen im Auswahlmenü ausgewählt hast.|r|cff00ff00 Klicke auf diese Nachricht um das Problem zu beheben.|r" - German["whisper to everyone"] = "|cffff8800Ich verschicke Flüsternachrichten an jeden den ich einlade ODER ich möchte nur Flüsternachrichten senden aber das AddOn macht beides!|r|cff00A2FF Das passiert weil du einladen und anflüstern im Auswahlmenü ausgewählt hast.|r|cff00ff00 Klicke auf diese Nachricht um das Problem zu beheben.|r" - German["can't get SGI to invite"] = "|cffff8800SGI lädt keine Leute ein und schickt ausschließlich Flüsternachrichten.|r|cff00A2FF DU hast nur diese Option im Auswahlmenü ausgewählt.|r|cff00ff00 Klicke auf diese Nachricht um das Problem zu beheben.|r" - German["can't see any messages"] = "|cffff8800Ich sehe keinerlei Ausgabe von SGI.|r|cff00A2FF Du hast SGI in den Optionen stummgeschaltet.|r|cff00ff00 Klicke auf diese Nachricht um das Problem zu beheben.|r" - German["None of the above"] = "|cffff8800Keine der obenstehenden Lösungen löst mein Problem!|r|cff00A2FF Es könnte ein Problem mit der Lokalisation (Sprache) geben, die du benutzt. Du kannst versuchen mit /sgi locale:deDE die deutschen Sprachoptionen zu laden (frFR für Französisch). Bitte schick mir eine Nachricht an:|r|cff00ff00 SuperGuildInvite@gmail.com|r" - German["Enabled whispers"] = "Flüsternachrichten eingeschaltet" - German['Changed invite mode to "Invite and Whisper"'] = "Einladungsart auf einladen und anflüstern geändert" - German["Mute has been turned off"] = "Stummschaltung wurde ausgeschaltet" - German['Changed invite mode to "Only Invite". If you wanted "Only Whisper" go to Options and change.'] = "Einladungsmodus auf nur einladen geändert. Wenn du nur anflüstern wolltest, gehe in die Optionen und ändere es dort." - German["Enter exceptions"] = "Ausnahmen eingeben" - German["Highest and lowest level to search for"] = "Höchster und niedrigster Level nach dem gesucht wird" - - - German["Shaman"] = "Schamane" - German["Death Knight"] = "Todesritter" - German["Mage"] = "Magier" - German["Priest"] = "Priester" - German["Rogue"] = "Schurke" - German["Paladin"] = "Paladin" - German["Warlock"] = "Hexenmeister" - German["Druid"] = "Druide" - German["Warrior"] = "Krieger" - German["Hunter"] = "Jäger" - German["Monk"] = "Mönch" - - German["Human"] = "Mensch" - German["Gnome"] = "Gnom" - German["Dwarf"] = "Zwerg" - German["NightElf"] = "Nachtelf" - German["Draenei"] = "Draenei" - German["Worgen"] = "Worgen" - German["Pandaren"] = "Pandaren" - German["Undead"] = "Untoter" - German["Orc"] = "Ork" - German["Troll"] = "Troll" - German["Tauren"] = "Taure" - German["BloodElf"] = "Blutelf" - German["Goblin"] = "Goblin" - - German["Author"] = "|cff00A2FF Translated by Nephthis - Durotan (EU).|r" - -local French = setmetatable({}, {__index=defaultFunc}) - French["English Locale loaded"] = "French Locale loaded" - French["Enable whispers"] = "Activer les chuchotements" - French["Level limits"] = "Limites de niveau" - French["Invite Mode"] = "Mode d'invitation" - French["Whisper only"] = "Message seulement" - French["Invite and whisper"] = "Invitation et message" - French["Invite only"] = "Invitation seulement" - French["Mute SGI"] = "Mute SGI" - French["Filter 55-58 Death Knights"] = "Filtrer les Chevaliers de la mort 55-58" - French["Do a more thorough search"] = "Faire une recherche plus minutieuse" - French["Customize whisper"] = "Personnaliser le message" - French["SuperScan"] = "SuperScan" - French["Invite: %d"] = "Inviter: %d" - French["Choose Invites"] = "Choisir les invitations" - French["Exceptions"] = "Exceptions" - French["Help"] = "Aide" - French["SuperGuildInvite Custom Whisper"] = "SuperGuildInvite message personnalisé" - French["WhisperInstructions"] = "Créé un message personnalisé à envoyer aux personne que vous invitez ! Si vous entrez les mots (doivent être en majuscule) |cff00ff00NAME|r, |cff0000ffLEVEL|r ou |cffff0000PLAYER|r ils seront remplacés par le NomDeLaGuilde, NiveauDeLaGuilde et NomDuJoueurInvité." - French["Enter your whisper"] = "Entrez votre message" - French["Save"] = "Sauvegarder" - French["Cancel"] = "Annuler" - French["less than 1 second"] = "moins d'1 seconde" - French[" hours "] = " heures " - French[" minutes "] = " minutes " - French[" seconds"] = " secondes " - French[" remaining"] = " restante(s)" - French["Purge Queue"] = "Vider la liste" - French["Click to toggle SuperScan"] = "Cliquez pour afficher SuperScan" - French["Click on the players you wish to invite"] = "Cliquez sur les joueurs que vous souhaitez inviter" - French["Scan Completed"] = "Scan terminé" - French["Who sent: "] = "Qui envoyé: " - French["SuperScan was started"] = "SuperScan démarré" - French["SuperScan was stopped"] = "SuperScan arrêté" - French["PlayersScanned"] = "Joueurs scannés: |cff44FF44%d|r |cffffff00(Total: |r|cff44FF44%d|r)" - French["PlayersGuildLess"] = "Joueurs sans guilde: |cff44FF44%d|r (|cff44FF44%d%%|r)" - French["InvitesQueued"] = "Invitations listées: |cff44FF44%d|r" - French["ExceptionsInstructions"] = "Vous pouvez ajouter des exceptions, si le nom d'un joueur correspond à l'une d'elles, SuperGuildInvite l'ignorera. Vous pouvez ajouter plusieurs exceptions à la fois, pour cela séparez les par une virgule (,)." - French["SGI Exceptions"] = "SGI Exceptions" - French["Author"] = "|cff00A2FF Translated by Anonymous, you know who you are and thank you :)|r" - French["Go to Options and select your Invite Mode"] = "Allez dans Options et sélectionnez votre Mode d'invitation." - French["You need to specify the mode in which you wish to invite"] = "Vous devez spécifier le mode dans lequel vous souhaitez inviter." - French["not sending"] = "|cffff8800Pourquoi je n'envoie aucun message ?|r |cff00A2FFPeut-être parce que vous n'avez pas coché l'option.|r|cff00ff00 Cliquez sur ce message pour corriger.|r" - French["to specify"] = "|cffff8800J'ai un message m'indiquant que je dois spécifier le mode d'invitation quand j'essaye d'inviter !|r|cff00A2FF Ceci arrive quand vous n'avez pas utilisé le menu déroulant dans les options pour choisir votre mode d'invitation.|r|cff00ff00 Cliquez pour corriger.|r" - French["I checked the box"] = "|cffff8800Je n'envoie aucun message lorsque j'invite alors que j'ai coché la case !|r|cff00A2FF C'est parce que vous avez choisi \"Invitation seulement\" comme mode d'invitation.|r|cff00ff00 Cliquez pour corriger.|r" - French["whisper to everyone"] = "|cffff8800Je continue d'envoyer des invitations, or je veux seulement envoyer un message et ne pas inviter !|r|cff00A2FF C'est parce que vous avez choisi \"Invitation et message\" comme mode d'invitation.|r|cff00ff00 Cliquez pour corriger.|r" - French["can't get SGI to invite"] = "|cffff8800SGI n'invite personne, il envoie seulement des message.|r|cff00A2FF C'est parce que vous avez choisi \"Message seulement\" comme mode d'invitation.|r|cff00ff00 Cliquez pour corriger.|r" - French["can't see any messages"] = "|cffff8800Je ne vois plus aucun message de SGI !|r|cff00A2FF C'est parce que vous avez muté SGI dans les options.|r|cff00ff00 Cliquez pour corriger.|r" - French["None of the above"] = "|cffff8800Aucune des solutions n'a corrigé mon problème !|r|cff00A2FF Il peut y avoir une erreur avec le langage que vous utilisez. Vous pouvez essayer de charger votre langue manuellement : /sgi locale:frFR charge la langue française (deDE pour allemande). Merci de me contacter à :|r|cff00ff00 SuperGuildInvite@gmail.com|r" - French["Enabled whispers"] = "Cuchotements activés." - French['Changed invite mode to "Invite and Whisper"'] = 'Mode d\'invitation changé en "Invitation et message".' - French["Mute has been turned off"] = 'Mute désactivé.' - French['Changed invite mode to "Only Invite". If you wanted "Only Whisper" go to Options and change.'] = 'Mode d\'invitation changé en "Inviter seulement". Si vous voulez envoyer un "Message seulement" choisissez-le dans les options.' - French["Enter exceptions"] = 'Entrez les exceptions' - - French["Shaman"] = "Chaman" - French["Death Knight"] = "Chevalier de la mort" - French["Mage"] = "Mage" - French["Priest"] = "Prêtre" - French["Rogue"] = "Voleur" - French["Paladin"] = "Paladin" - French["Warlock"] = "Démoniste" - French["Druid"] = "Druide" - French["Warrior"] = "Guerrier" - French["Hunter"] = "Chasseur" - French["Monk"] = "Moine" - - French["Human"] = "Humain" - French["Gnome"] = "Gnome" - French["Dwarf"] = "Nain" - French["NightElf"] = "Elfe de la nuit" - French["Draenei"] = "Draeneï" - French["Worgen"] = "Worgen" - French["Pandaren"] = "Pandaren" - French["Undead"] = "Mort-vivant" - French["Orc"] = "Orc" - French["Troll"] = "Troll" - French["Tauren"] = "Tauren" - French["BloodElf"] = "Elfe de sang" - French["Goblin"] = "Gobelin" - -local Spanish = setmetatable({}, {__index=defaultFunc}) - Spanish["English Locale loaded"] = "Spanish Locale loaded" - Spanish["Enable whispers"] = nil - Spanish["Level limits"] = nil - Spanish["Invite Mode"] = nil - Spanish["Whisper only"] = nil - Spanish["Invite and whisper"] = nil - Spanish["Invite only"] = nil - Spanish["Mute SGI"] = nil - Spanish["Filter 55-58 Death Knights"] = nil - Spanish["Do a more thorough search"] = nil - Spanish["Customize whisper"] = nil - Spanish["SuperScan"] = nil - Spanish["Invite: %d"] = nil - Spanish["Choose Invites"] = nil - Spanish["Exceptions"] = nil - Spanish["Help"] = nil - Spanish["SuperGuildInvite Custom Whisper"] = nil - Spanish["WhisperInstructions"] = nil - Spanish["Enter your whisper"] = nil - Spanish["Save"] = nil - Spanish["Cancel"] = nil - Spanish["less than 1 second"] = nil - Spanish[" hours "] = nil - Spanish[" minutes "] = nil - Spanish[" seconds"] = nil - Spanish[" remaining"] = nil - Spanish["Purge Queue"] = nil - Spanish["Click to toggle SuperScan"] = nil - Spanish["Click on the players you wish to invite"] = nil - Spanish["Scan Completed"] = nil - Spanish["Who sent: "] = nil - Spanish["SuperScan was started"] = nil - Spanish["SuperScan was stopped"] = nil - Spanish["PlayersScanned"] = nil - Spanish["PlayersGuildLess"] = nil - Spanish["InvitesQueued"] = nil - Spanish["ExceptionsInstructions"] = nil - Spanish["SGI Exceptions"] = nil - Spanish["Author"] = nil - Spanish["Go to Options and select your Invite Mode"] = nil - Spanish["You need to specify the mode in which you wish to invite"] = nil - Spanish["not sending"] = "|cffff8800Why am I not sending any whispers?|r |cff00A2FFPossibly because you have not checked the checkbox.|r|cff00ff00 Click on this message to fix.|r" - Spanish["to specify"] = "|cffff8800I am getting a message telling me to specify my invite mode when I try to invite!|r|cff00A2FF This happens when you have not used the dropdown menu in the options to pick how to invite people.|r|cff00ff00 Click to fix.|r" - Spanish["I checked the box"] = "|cffff8800I am not sending any whispers when I invite and I checked the box!|r|cff00A2FF This is because you have selected only to invite with the dropdown menu in the options.|r|cff00ff00 Click to fix|r" - Spanish["whisper to everyone"] = "|cffff8800I keep sending a whisper to everyone I invite, OR I just want to send whispers and not invite, but your AddOn does both!|r|cff00A2FF This is because you specified to both invite and whisper on the dropdown menu in options.|r|cff00ff00 Click to fix|r" - Spanish["can't get SGI to invite"] = "|cffff8800I can't get SGI to invite people, all it does is sending whispers.|r|cff00A2FF This is because you picked that option in the dropdown menu.|r|cff00ff00 Click to fix|r" - Spanish["can't see any messages"] = "|cffff8800I can't see any messages from SGI at all!|r|cff00A2FF This is because you have muted SGI in the options.|r|cff00ff00 Click to fix|r" - Spanish["None of the above"] = "|cffff8800None of the above solved my problem!|r|cff00A2FF There might be an issue with the localization (language) you are using. You can try to load your locale manually: /sgi locale:deDE loads German (frFR for french). Please contact me at:|r|cff00ff00 SuperGuildInvite@gmail.com|r" - Spanish["Enabled whispers"] = nil - Spanish['Changed invite mode to "Invite and Whisper"'] = nil - Spanish["Mute has been turned off"] = nil - Spanish['Changed invite mode to "Only Invite". If you wanted "Only Whisper" go to Options and change.'] = nil - Spanish["Enter exceptions"] = nil - - Spanish["Shaman"] = nil - Spanish["Death Knight"] = nil - Spanish["Mage"] = nil - Spanish["Priest"] = nil - Spanish["Rogue"] = nil - Spanish["Paladin"] = nil - Spanish["Warlock"] = nil - Spanish["Druid"] = nil - Spanish["Warrior"] = nil - Spanish["Hunter"] = nil - Spanish["Monk"] = nil - - Spanish["Human"] = nil - Spanish["Gnome"] = nil - Spanish["Dwarf"] = nil - Spanish["NightElf"] = nil - Spanish["Draenei"] = nil - Spanish["Worgen"] = nil - Spanish["Pandaren"] = nil - Spanish["Undead"] = nil - Spanish["Orc"] = nil - Spanish["Troll"] = nil - Spanish["Tauren"] = nil - Spanish["BloodElf"] = nil - Spanish["Goblin"] = nil - -local Russian = setmetatable({}, {__index=defaultFunc}) - Russian["Russian Locale loaded"] = "Russian Locale loaded" - Russian["Enable whispers"] = "Разрешить сообщения" - Russian["Level limits"] = "Лимит уровней" - Russian["Invite Mode"] = "Режим приглашения" - Russian["Whisper only"] = "Только сообщение" - Russian["Invite and whisper"] = "Приглашение и сообщение" - Russian["Invite only"] = "Только приглашение" - Russian["Mute SGI"] = "Мут SGI" - Russian["Filter 55-58 Death Knights"] = "Фильтровать Рыцарей Смерти 55-58 уровня" - Russian["Do a more thorough search"] = "Глубокий поиск" - Russian["Customize whisper"] = "Настроить Сообщение" - Russian["SuperScan"] = "СуперСканирование" - Russian["Invite: %d"] = "Пригласить: %d" - Russian["Choose Invites"] = "Выбрать Приглашения" - Russian["Exceptions"] = "Исключения" - Russian["Help"] = "Помощь" - Russian["The level you wish to start dividing the search by race"] = "Уровень, с которого включается рассовый фильтр" - Russian["Racefilter Start:"] = "Рассовый Фильтр" - Russian["The level you wish to divide the search by class"] = "Уровень, с которого включается классовый фильтр" - Russian["Classfilter Start:"] = "Классовый Фильтр" - Russian["Amount of levels to search every ~7 seconds (higher numbers increase the risk of capping the search results)"] = "Интервал уровней для поиска каждые ~7 секунд (больший интервал приводит к риску достигнуть лимита поиска в 49 человек)" - Russian["Interval:"] = "Интервал" - Russian["SuperGuildInvite Custom Whisper"] = "сообщение по умолчанию SGI" - Russian["WhisperInstructions"] = "Create a customized whisper to send people you invite! If you enter the words (must be caps) |cff00ff00NAME|r, |cff0000ffLEVEL|r or |cffff0000PLAYER|r these will be replaced by your Guildname, Guildlevel and the recieving players name" - Russian["Enter your whisper"] = "Введите свое сообщение" - Russian["Save"] = "Сохранить" - Russian["Cancel"] = "Отмена" - Russian["less than 1 second"] = "Менее 1 секунды" - Russian[" hours "] = " Часов " - Russian[" minutes "] = " Минут " - Russian[" seconds"] = " Секунд " - Russian[" remaining"] = "осталось" - Russian["Purge Queue"] = "Очистить Очередь" - Russian["Click to toggle SuperScan"] = "Нажмите чтобы переключить СуперСкан" - Russian["Click on the players you wish to invite"] = "Нажмите на игроков которых хотите пригласить" - Russian["Scan Completed"] = "Сканирование завершено" - Russian["Who sent: "] = "Кто отправлено: " - Russian["SuperScan was started"] = "СуперСканирование началось" - Russian["SuperScan was stopped"] = "Суперсканирование остановлено" - Russian["PlayersScanned"] = "Players Scanned: |cff44FF44%d|r |cffffff00(Total: |r|cff44FF44%d|r)" - Russian["PlayersGuildLess"] = "Guildless Players: |cff44FF44%d|r (|cff44FF44%d%%|r)" - Russian["InvitesQueued"] = "Invites Queued: |cff44FF44%d|r" - Russian["ExceptionsInstructions"] = "You can add exception phrases that when found in a name will cause the player to be ignore by SuperGuildInvite. You can add several exceptions at once, seperated by a comma (,)." - Russian["SGI Exceptions"] = "Исключения SGI" - Russian["Enter exceptions"] = "Ввести исключения" - Russian["Go to Options and select your Invite Mode"] = "Откройте настройки и выберите режим приглашения" - Russian["You need to specify the mode in which you wish to invite"] = "Вы должны выбрать режим приглашения" - Russian["Unable to invite %s. They are already in a guild."] = "Невозможно пришласить %s. Он уже в гильдии" - Russian["Unable to invite %s. They will not be blacklisted."] = "Невозможно пришласить %s. Он не будет занесен в черный список" - - --Trouble shooter-- - Russian["not sending"] = "|cffff8800Why am I not sending any whispers?|r |cff00A2FFPossibly because you have not checked the checkbox.|r|cff00ff00 Click on this message to fix.|r" - Russian["to specify"] = "|cffff8800I am getting a message telling me to specify my invite mode when I try to invite!|r|cff00A2FF This happens when you have not used the dropdown menu in the options to pick how to invite people.|r|cff00ff00 Click to fix.|r" - Russian["I checked the box"] = "|cffff8800I am not sending any whispers when I invite and I checked the box!|r|cff00A2FF This is because you have selected only to invite with the dropdown menu in the options.|r|cff00ff00 Click to fix|r" - Russian["whisper to everyone"] = "|cffff8800I keep sending a whisper to everyone I invite, OR I just want to send whispers and not invite, but your AddOn does both!|r|cff00A2FF This is because you specified to both invite and whisper on the dropdown menu in options.|r|cff00ff00 Click to fix|r" - Russian["can't get SGI to invite"] = "|cffff8800I can't get SGI to invite people, all it does is sending whispers.|r|cff00A2FF This is because you picked that option in the dropdown menu.|r|cff00ff00 Click to fix|r" - Russian["can't see any messages"] = "|cffff8800I can't see any messages from SGI at all!|r|cff00A2FF This is because you have muted SGI in the options.|r|cff00ff00 Click to fix|r" - Russian["None of the above"] = "|cffff8800None of the above solved my problem!|r|cff00A2FF There might be an issue with the localization (language) you are using. You can try to load your locale manually: /sgi locale:deDE loads German (frFR for french). Please contact me at:|r|cff00ff00 SuperGuildInvite@gmail.com|r" - Russian["Enabled whispers"] = "Разрешить сообщения" - Russian['Changed invite mode to "Invite and Whisper"'] = "Режим приглашения изменен на 'приглашение и сообщение'" - Russian["Mute has been turned off"] = "Мут был выключен" - Russian['Changed invite mode to "Only Invite". If you wanted "Only Whisper" go to Options and change.'] = "Режим приглашения изменен на 'только' пригласить. Если вы хотите приглашать людей, смените режим" - - - - Russian["Shaman"] = "Шаман" - Russian["Death Knight"] = "Рыцарь Смерти" - Russian["Mage"] = "Маг" - Russian["Priest"] = "Жрец" - Russian["Rogue"] = "Разбойник" - Russian["Paladin"] = "Паладин" - Russian["Warlock"] = "Чернокнижник" - Russian["Druid"] = "Друид" - Russian["Warrior"] = "Воин" - Russian["Hunter"] = "Охотник" - Russian["Monk"] = "Монах" - - Russian["Human"] = "Человек" - Russian["Gnome"] = "Гном" - Russian["Dwarf"] = "Дворф" - Russian["NightElf"] = "Ночной Эльф" - Russian["Draenei"] = "Дреней" - Russian["Worgen"] = "Ворген" - Russian["Pandaren"] = "Пандарен" - Russian["Undead"] = "Нежить" - Russian["Orc"] = "Орк" - Russian["Troll"] = "Тролль" - Russian["Tauren"] = "Таурен" - Russian["BloodElf"] = "Эльф Крови" - Russian["Goblin"] = "Гоблин" - - Russian["Author"] = "|cff00A2FF Переведено игроком Вовочкин - Гордунни.|r" - - -SGI_Locale["enGB"] = English -SGI_Locale["enUS"] = English -SGI_Locale["deDE"] = German -SGI_Locale["frFR"] = French ---SGI_Locale["ruRU"] = Russian Can't be added because of client issues. ---SGI_Locale["esES"] = Spanish ---SGI_Locale["esMX"] = Spanish +SGI_Locale = {} + +local function defaultFunc(L,key) + return key +end + +local English = setmetatable({}, {__index=defaultFunc}) + English["English Locale loaded"] = "English Locale loaded" + English["Enable whispers"] = "Enable whispers" + English["Level limits"] = nil + English["Invite Mode"] = nil + English["Whisper only"] = nil + English["Invite and whisper"] = nil + English["Invite only"] = nil + English["Mute SGI"] = nil + English["Filter 55-58 Death Knights"] = nil + English["Do a more thorough search"] = nil + English["Customize whisper"] = nil + English["SuperScan"] = nil + English["Invite: %d"] = nil + English["Choose Invites"] = nil + English["Exceptions"] = nil + English["Help"] = nil + English["The level you wish to start dividing the search by race"] = nil + English["Racefilter Start:"] = nil + English["The level you wish to divide the search by class"] = nil + English["Classfilter Start:"] = nil + English["Amount of levels to search every ~7 seconds (higher numbers increase the risk of capping the search results)"] = nil + English["Interval:"] = nil + English["SuperGuildInvite Custom Whisper"] = nil + English["WhisperInstructions"] = "Create a customized whisper to send people you invite! If you enter the words (must be caps) |cff00ff00NAME|r, |cff0000ffLEVEL|r or |cffff0000PLAYER|r these will be replaced by your Guildname, Guildlevel and the recieving players name" + English["Enter your whisper"] = nil + English["Save"] = nil + English["Cancel"] = nil + English["less than 1 second"] = nil + English[" hours "] = nil + English[" minutes "] = nil + English[" seconds"] = nil + English[" remaining"] = nil + English["Purge Queue"] = nil + English["Click to toggle SuperScan"] = nil + English["Click on the players you wish to invite"] = nil + English["Scan Completed"] = nil + English["Who sent: "] = nil + English["SuperScan was started"] = nil + English["SuperScan was stopped"] = nil + English["PlayersScanned"] = "Players Scanned: |cff44FF44%d|r |cffffff00(Total: |r|cff44FF44%d|r)" + English["PlayersGuildLess"] = "Guildless Players: |cff44FF44%d|r (|cff44FF44%d%%|r)" + English["InvitesQueued"] = "Invites Queued: |cff44FF44%d|r" + English["ExceptionsInstructions"] = "You can add exception phrases that when found in a name will cause the player to be ignore by SuperGuildInvite. You can add several exceptions at once, seperated by a comma (,)." + English["SGI Exceptions"] = nil + English["Enter exceptions"] = nil + English["Go to Options and select your Invite Mode"] = nil + English["You need to specify the mode in which you wish to invite"] = nil + English["Unable to invite %s. They are already in a guild."] = nil + English["Unable to invite %s. They will not be blacklisted."] = nil + + --Trouble shooter-- + English["not sending"] = "|cffff8800Why am I not sending any whispers?|r |cff00A2FFPossibly because you have not checked the checkbox.|r|cff00ff00 Click on this message to fix.|r" + English["to specify"] = "|cffff8800I am getting a message telling me to specify my invite mode when I try to invite!|r|cff00A2FF This happens when you have not used the dropdown menu in the options to pick how to invite people.|r|cff00ff00 Click to fix.|r" + English["I checked the box"] = "|cffff8800I am not sending any whispers when I invite and I checked the box!|r|cff00A2FF This is because you have selected only to invite with the dropdown menu in the options.|r|cff00ff00 Click to fix|r" + English["whisper to everyone"] = "|cffff8800I keep sending a whisper to everyone I invite, OR I just want to send whispers and not invite, but your AddOn does both!|r|cff00A2FF This is because you specified to both invite and whisper on the dropdown menu in options.|r|cff00ff00 Click to fix|r" + English["can't get SGI to invite"] = "|cffff8800I can't get SGI to invite people, all it does is sending whispers.|r|cff00A2FF This is because you picked that option in the dropdown menu.|r|cff00ff00 Click to fix|r" + English["can't see any messages"] = "|cffff8800I can't see any messages from SGI at all!|r|cff00A2FF This is because you have muted SGI in the options.|r|cff00ff00 Click to fix|r" + English["None of the above"] = "|cffff8800None of the above solved my problem!|r|cff00A2FF There might be an issue with the localization (language) you are using. You can try to load your locale manually: /sgi locale:deDE loads German (frFR for french). Please contact me at:|r|cff00ff00 SuperGuildInvite@gmail.com|r" + English["Enabled whispers"] = nil + English['Changed invite mode to "Invite and Whisper"'] = nil + English["Mute has been turned off"] = nil + English['Changed invite mode to "Only Invite". If you wanted "Only Whisper" go to Options and change.'] = nil + + + + English["Shaman"] = nil + English["Death Knight"] = nil + English["Mage"] = nil + English["Priest"] = nil + English["Rogue"] = nil + English["Paladin"] = nil + English["Warlock"] = nil + English["Druid"] = nil + English["Warrior"] = nil + English["Hunter"] = nil + English["Monk"] = nil + English["Demon Hunter"] = nil + + English["Human"] = nil + English["Gnome"] = nil + English["Dwarf"] = nil + English["NightElf"] = nil + English["Draenei"] = nil + English["Worgen"] = nil + English["Pandaren"] = nil + English["Undead"] = nil + English["Orc"] = nil + English["Troll"] = nil + English["Tauren"] = nil + English["BloodElf"] = nil + English["Goblin"] = nil + English["Nightborne"] = nil + English["VoidElf"] = nil + English["LightforgedDraenei"] = nil + English["HighmountainTauren"] = nil + English["Mag'harOrc"] = nil + English["Kul'TiranHuman"] = nil + English["ZandalariTroll"] = nil + English["DarkIronDwarf"] = nil + + English["Author"] = "|cff00A2FF Written by Janniie - Stormreaver EU.|r" + +German = setmetatable({}, {__index=defaultFunc}) + German["English Locale loaded"] = "German Locale loaded" + German["Enable whispers"] = "aktivieren Sie flüstert" + German["Level limits"] = "Levelbeschränkungen" + German["Invite Mode"] = "Einladungsart" + German["Whisper only"] = "Nur anflüstern" + German["Invite and whisper"] = "Einladen und anflüstern" + German["Invite only"] = "Nur einladen" + German["Mute SGI"] = "SGI stummschalten" + German["Filter 55-58 Death Knights"] = "Level 55-58 Todesritter filtern" + German["Do a more thorough search"] = "Gründlichere Suche ausführen" + German["Customize whisper"] = "Flüsternachricht anpassen" + German["SuperScan"] = "SuperScan" + German["Invite: %d"] = "Einladen: %d" + German["Choose Invites"] = "einladungen auswählen" + German["Exceptions"] = "Ausnahmen" + German["Help"] = "Hilfe" + German["SuperGuildInvite Custom Whisper"] = "SuperGuildInvite eigene Flüsternachricht" + German["WhisperInstructions"] = "Erstelle eine eigene Flüsternachricht, die an die Leute gesendet wird, die du einlädst! Wenn du die worte |cff00ff00NAME|r, |cff0000ffLEVEL|r oder |cffff0000PLAYER|r (in Großbuchstaben) benutzt werden diese durch Gildenname, Gildenlevel und den Namen des Empfängers ersetzt." + German["Enter your whisper"] = "Flüsternachricht eingeben" + German["Save"] = "Speichern" + German["Cancel"] = "Abbrechen" + German["less than 1 second"] = "weniger als 1 Sekunden verbleibend" + German[" hours "] = " Stunden " + German[" minutes "] = " minute " + German[" seconds"] = " Sekunden" + German[" remaining"] = " verbleibend" + German["Purge Queue"] = "Warteschlange leeren" + German["Click to toggle SuperScan"] = "Klicken um SuperScan zu beenden" + German["Click on the players you wish to invite"] = "Klicke die Spieler an, die du einladen willst" + German["Scan Completed"] = "Suchlauf beendet" + German["Who sent: "] = "Wer-Abfrage gesendet: " + German["SuperScan was started"] = "SuperScan wurde gestartet" + German["SuperScan was stopped"] = "SuperScan wurde gestoppt" + German["PlayersScanned"] = "Spieler durchsucht: |cff44FF44%d|r (Insgesamt: |cff44FF44%d|r)" + German["PlayersGuildLess"] = "gildenlose Spieler: |cff44FF44%d|r" + German["InvitesQueued"] = "Einladungen in Warteschlange: |cff44FF44%d|r" + German["ExceptionsInstructions"] = "Hier kannst du Ausnahmen eingeben, die, wenn sie in einem Namen gefunden werden, dazu führen daß SGI diesen Spieler ignoriert. Du kannst mehrere Ausnahmen durch ein Komma (,) getrennt eingeben." + German["SGI Exceptions"] = "SGI Ausnahmen" + German["Go to Options and select your Invite Mode"] = "Gehen Sie auf Optionen und wählen Sie Einladungsart" + German["You need to specify the mode in which you wish to invite"] = "Sie müssen den Modus, in dem Sie einladen möchten festlegen" + German["Amount of levels to search every ~7 seconds (higher numbers increase the risk of capping the search results)"] = "Anzahl der Level nach denen etwa alle 7 Sekunden gesucht wird (höhere Zahlen erhöhen das Risiko, daß nicht alle Suchergebnisse bearbeitet werden)." + German["The level you wish to divide the search by class"] = "Level ab dem nach Klasse gesucht wird." + German["The level you wish to divide the search by race"] = "Level ab dem nach Rasse gesucht wird." + + German["not sending"] = "|cffff8800Warum verschicke ich keine Flüsternachrichten?|r |cff00A2FFMöglicherweise hast du das Kästchen nicht angekreuzt.|r|cff00ff00 Klicke auf diese Nachricht um das Problem zu beheben.|r" + German["to specify"] = "|cffff8800Ich bekomme eine Nachricht, daß ich die Einladungsart auswählen soll wenn ich jemanden einladen möchte.|r|cff00A2FF Das passiert wenn du nicht das Auswahlmenü in den Optionen benutzt hast um auszuwählen wie du Leute einlädst.|r|cff00ff00 Klicke auf diese Nachricht um das Problem zu beheben.|r" + German["I checked the box"] = "|cffff8800Ich verschicke keine Flüsternachrichten beim Einladen, obwohl ich das Kästchen angekreuzt habe.|r|cff00A2FF Das passiert wenn du nur einladen im Auswahlmenü ausgewählt hast.|r|cff00ff00 Klicke auf diese Nachricht um das Problem zu beheben.|r" + German["whisper to everyone"] = "|cffff8800Ich verschicke Flüsternachrichten an jeden den ich einlade ODER ich möchte nur Flüsternachrichten senden aber das AddOn macht beides!|r|cff00A2FF Das passiert weil du einladen und anflüstern im Auswahlmenü ausgewählt hast.|r|cff00ff00 Klicke auf diese Nachricht um das Problem zu beheben.|r" + German["can't get SGI to invite"] = "|cffff8800SGI lädt keine Leute ein und schickt ausschließlich Flüsternachrichten.|r|cff00A2FF DU hast nur diese Option im Auswahlmenü ausgewählt.|r|cff00ff00 Klicke auf diese Nachricht um das Problem zu beheben.|r" + German["can't see any messages"] = "|cffff8800Ich sehe keinerlei Ausgabe von SGI.|r|cff00A2FF Du hast SGI in den Optionen stummgeschaltet.|r|cff00ff00 Klicke auf diese Nachricht um das Problem zu beheben.|r" + German["None of the above"] = "|cffff8800Keine der obenstehenden Lösungen löst mein Problem!|r|cff00A2FF Es könnte ein Problem mit der Lokalisation (Sprache) geben, die du benutzt. Du kannst versuchen mit /sgi locale:deDE die deutschen Sprachoptionen zu laden (frFR für Französisch). Bitte schick mir eine Nachricht an:|r|cff00ff00 SuperGuildInvite@gmail.com|r" + German["Enabled whispers"] = "Flüsternachrichten eingeschaltet" + German['Changed invite mode to "Invite and Whisper"'] = "Einladungsart auf einladen und anflüstern geändert" + German["Mute has been turned off"] = "Stummschaltung wurde ausgeschaltet" + German['Changed invite mode to "Only Invite". If you wanted "Only Whisper" go to Options and change.'] = "Einladungsmodus auf nur einladen geändert. Wenn du nur anflüstern wolltest, gehe in die Optionen und ändere es dort." + German["Enter exceptions"] = "Ausnahmen eingeben" + German["Highest and lowest level to search for"] = "Höchster und niedrigster Level nach dem gesucht wird" + + + German["Shaman"] = "Schamane" + German["Death Knight"] = "Todesritter" + German["Mage"] = "Magier" + German["Priest"] = "Priester" + German["Rogue"] = "Schurke" + German["Paladin"] = "Paladin" + German["Warlock"] = "Hexenmeister" + German["Druid"] = "Druide" + German["Warrior"] = "Krieger" + German["Hunter"] = "Jäger" + German["Monk"] = "Mönch" + German["Demon Hunter"] = "Dämonenjäger" + + German["Human"] = "Mensch" + German["Gnome"] = "Gnom" + German["Dwarf"] = "Zwerg" + German["NightElf"] = "Nachtelf" + German["Draenei"] = "Draenei" + German["Worgen"] = "Worgen" + German["Pandaren"] = "Pandaren" + German["Undead"] = "Untoter" + German["Orc"] = "Ork" + German["Troll"] = "Troll" + German["Tauren"] = "Taure" + German["BloodElf"] = "Blutelf" + German["Goblin"] = "Goblin" + + German["Author"] = "|cff00A2FF Translated by Nephthis - Durotan (EU).|r" + +local French = setmetatable({}, {__index=defaultFunc}) + French["English Locale loaded"] = "French Locale loaded" + French["Enable whispers"] = "Activer les chuchotements" + French["Level limits"] = "Limites de niveau" + French["Invite Mode"] = "Mode d'invitation" + French["Whisper only"] = "Message seulement" + French["Invite and whisper"] = "Invitation et message" + French["Invite only"] = "Invitation seulement" + French["Mute SGI"] = "Mute SGI" + French["Filter 55-58 Death Knights"] = "Filtrer les Chevaliers de la mort 55-58" + French["Do a more thorough search"] = "Faire une recherche plus minutieuse" + French["Customize whisper"] = "Personnaliser le message" + French["SuperScan"] = "SuperScan" + French["Invite: %d"] = "Inviter: %d" + French["Choose Invites"] = "Choisir les invitations" + French["Exceptions"] = "Exceptions" + French["Help"] = "Aide" + French["SuperGuildInvite Custom Whisper"] = "SuperGuildInvite message personnalisé" + French["WhisperInstructions"] = "Créé un message personnalisé à envoyer aux personne que vous invitez ! Si vous entrez les mots (doivent être en majuscule) |cff00ff00NAME|r, |cff0000ffLEVEL|r ou |cffff0000PLAYER|r ils seront remplacés par le NomDeLaGuilde, NiveauDeLaGuilde et NomDuJoueurInvité." + French["Enter your whisper"] = "Entrez votre message" + French["Save"] = "Sauvegarder" + French["Cancel"] = "Annuler" + French["less than 1 second"] = "moins d'1 seconde" + French[" hours "] = " heures " + French[" minutes "] = " minutes " + French[" seconds"] = " secondes " + French[" remaining"] = " restante(s)" + French["Purge Queue"] = "Vider la liste" + French["Click to toggle SuperScan"] = "Cliquez pour afficher SuperScan" + French["Click on the players you wish to invite"] = "Cliquez sur les joueurs que vous souhaitez inviter" + French["Scan Completed"] = "Scan terminé" + French["Who sent: "] = "Qui envoyé: " + French["SuperScan was started"] = "SuperScan démarré" + French["SuperScan was stopped"] = "SuperScan arrêté" + French["PlayersScanned"] = "Joueurs scannés: |cff44FF44%d|r |cffffff00(Total: |r|cff44FF44%d|r)" + French["PlayersGuildLess"] = "Joueurs sans guilde: |cff44FF44%d|r (|cff44FF44%d%%|r)" + French["InvitesQueued"] = "Invitations listées: |cff44FF44%d|r" + French["ExceptionsInstructions"] = "Vous pouvez ajouter des exceptions, si le nom d'un joueur correspond à l'une d'elles, SuperGuildInvite l'ignorera. Vous pouvez ajouter plusieurs exceptions à la fois, pour cela séparez les par une virgule (,)." + French["SGI Exceptions"] = "SGI Exceptions" + French["Author"] = "|cff00A2FF Translated by Anonymous, you know who you are and thank you :)|r" + French["Go to Options and select your Invite Mode"] = "Allez dans Options et sélectionnez votre Mode d'invitation." + French["You need to specify the mode in which you wish to invite"] = "Vous devez spécifier le mode dans lequel vous souhaitez inviter." + French["not sending"] = "|cffff8800Pourquoi je n'envoie aucun message ?|r |cff00A2FFPeut-être parce que vous n'avez pas coché l'option.|r|cff00ff00 Cliquez sur ce message pour corriger.|r" + French["to specify"] = "|cffff8800J'ai un message m'indiquant que je dois spécifier le mode d'invitation quand j'essaye d'inviter !|r|cff00A2FF Ceci arrive quand vous n'avez pas utilisé le menu déroulant dans les options pour choisir votre mode d'invitation.|r|cff00ff00 Cliquez pour corriger.|r" + French["I checked the box"] = "|cffff8800Je n'envoie aucun message lorsque j'invite alors que j'ai coché la case !|r|cff00A2FF C'est parce que vous avez choisi \"Invitation seulement\" comme mode d'invitation.|r|cff00ff00 Cliquez pour corriger.|r" + French["whisper to everyone"] = "|cffff8800Je continue d'envoyer des invitations, or je veux seulement envoyer un message et ne pas inviter !|r|cff00A2FF C'est parce que vous avez choisi \"Invitation et message\" comme mode d'invitation.|r|cff00ff00 Cliquez pour corriger.|r" + French["can't get SGI to invite"] = "|cffff8800SGI n'invite personne, il envoie seulement des message.|r|cff00A2FF C'est parce que vous avez choisi \"Message seulement\" comme mode d'invitation.|r|cff00ff00 Cliquez pour corriger.|r" + French["can't see any messages"] = "|cffff8800Je ne vois plus aucun message de SGI !|r|cff00A2FF C'est parce que vous avez muté SGI dans les options.|r|cff00ff00 Cliquez pour corriger.|r" + French["None of the above"] = "|cffff8800Aucune des solutions n'a corrigé mon problème !|r|cff00A2FF Il peut y avoir une erreur avec le langage que vous utilisez. Vous pouvez essayer de charger votre langue manuellement : /sgi locale:frFR charge la langue française (deDE pour allemande). Merci de me contacter à :|r|cff00ff00 SuperGuildInvite@gmail.com|r" + French["Enabled whispers"] = "Cuchotements activés." + French['Changed invite mode to "Invite and Whisper"'] = 'Mode d\'invitation changé en "Invitation et message".' + French["Mute has been turned off"] = 'Mute désactivé.' + French['Changed invite mode to "Only Invite". If you wanted "Only Whisper" go to Options and change.'] = 'Mode d\'invitation changé en "Inviter seulement". Si vous voulez envoyer un "Message seulement" choisissez-le dans les options.' + French["Enter exceptions"] = 'Entrez les exceptions' + + French["Shaman"] = "Chaman" + French["Death Knight"] = "Chevalier de la mort" + French["Mage"] = "Mage" + French["Priest"] = "Prêtre" + French["Rogue"] = "Voleur" + French["Paladin"] = "Paladin" + French["Warlock"] = "Démoniste" + French["Druid"] = "Druide" + French["Warrior"] = "Guerrier" + French["Hunter"] = "Chasseur" + French["Monk"] = "Moine" + French["Demon Hunter"] = "Chasseur de démons" + + French["Human"] = "Humain" + French["Gnome"] = "Gnome" + French["Dwarf"] = "Nain" + French["NightElf"] = "Elfe de la nuit" + French["Draenei"] = "Draeneï" + French["Worgen"] = "Worgen" + French["Pandaren"] = "Pandaren" + French["Undead"] = "Mort-vivant" + French["Orc"] = "Orc" + French["Troll"] = "Troll" + French["Tauren"] = "Tauren" + French["BloodElf"] = "Elfe de sang" + French["Goblin"] = "Gobelin" + +local Spanish = setmetatable({}, {__index=defaultFunc}) + Spanish["English Locale loaded"] = "Spanish Locale loaded" + Spanish["Enable whispers"] = nil + Spanish["Level limits"] = nil + Spanish["Invite Mode"] = nil + Spanish["Whisper only"] = nil + Spanish["Invite and whisper"] = nil + Spanish["Invite only"] = nil + Spanish["Mute SGI"] = nil + Spanish["Filter 55-58 Death Knights"] = nil + Spanish["Do a more thorough search"] = nil + Spanish["Customize whisper"] = nil + Spanish["SuperScan"] = nil + Spanish["Invite: %d"] = nil + Spanish["Choose Invites"] = nil + Spanish["Exceptions"] = nil + Spanish["Help"] = nil + Spanish["SuperGuildInvite Custom Whisper"] = nil + Spanish["WhisperInstructions"] = nil + Spanish["Enter your whisper"] = nil + Spanish["Save"] = nil + Spanish["Cancel"] = nil + Spanish["less than 1 second"] = nil + Spanish[" hours "] = nil + Spanish[" minutes "] = nil + Spanish[" seconds"] = nil + Spanish[" remaining"] = nil + Spanish["Purge Queue"] = nil + Spanish["Click to toggle SuperScan"] = nil + Spanish["Click on the players you wish to invite"] = nil + Spanish["Scan Completed"] = nil + Spanish["Who sent: "] = nil + Spanish["SuperScan was started"] = nil + Spanish["SuperScan was stopped"] = nil + Spanish["PlayersScanned"] = nil + Spanish["PlayersGuildLess"] = nil + Spanish["InvitesQueued"] = nil + Spanish["ExceptionsInstructions"] = nil + Spanish["SGI Exceptions"] = nil + Spanish["Author"] = nil + Spanish["Go to Options and select your Invite Mode"] = nil + Spanish["You need to specify the mode in which you wish to invite"] = nil + Spanish["not sending"] = "|cffff8800Why am I not sending any whispers?|r |cff00A2FFPossibly because you have not checked the checkbox.|r|cff00ff00 Click on this message to fix.|r" + Spanish["to specify"] = "|cffff8800I am getting a message telling me to specify my invite mode when I try to invite!|r|cff00A2FF This happens when you have not used the dropdown menu in the options to pick how to invite people.|r|cff00ff00 Click to fix.|r" + Spanish["I checked the box"] = "|cffff8800I am not sending any whispers when I invite and I checked the box!|r|cff00A2FF This is because you have selected only to invite with the dropdown menu in the options.|r|cff00ff00 Click to fix|r" + Spanish["whisper to everyone"] = "|cffff8800I keep sending a whisper to everyone I invite, OR I just want to send whispers and not invite, but your AddOn does both!|r|cff00A2FF This is because you specified to both invite and whisper on the dropdown menu in options.|r|cff00ff00 Click to fix|r" + Spanish["can't get SGI to invite"] = "|cffff8800I can't get SGI to invite people, all it does is sending whispers.|r|cff00A2FF This is because you picked that option in the dropdown menu.|r|cff00ff00 Click to fix|r" + Spanish["can't see any messages"] = "|cffff8800I can't see any messages from SGI at all!|r|cff00A2FF This is because you have muted SGI in the options.|r|cff00ff00 Click to fix|r" + Spanish["None of the above"] = "|cffff8800None of the above solved my problem!|r|cff00A2FF There might be an issue with the localization (language) you are using. You can try to load your locale manually: /sgi locale:deDE loads German (frFR for french). Please contact me at:|r|cff00ff00 SuperGuildInvite@gmail.com|r" + Spanish["Enabled whispers"] = nil + Spanish['Changed invite mode to "Invite and Whisper"'] = nil + Spanish["Mute has been turned off"] = nil + Spanish['Changed invite mode to "Only Invite". If you wanted "Only Whisper" go to Options and change.'] = nil + Spanish["Enter exceptions"] = nil + + Spanish["Shaman"] = nil + Spanish["Death Knight"] = nil + Spanish["Mage"] = nil + Spanish["Priest"] = nil + Spanish["Rogue"] = nil + Spanish["Paladin"] = nil + Spanish["Warlock"] = nil + Spanish["Druid"] = nil + Spanish["Warrior"] = nil + Spanish["Hunter"] = nil + Spanish["Monk"] = nil + + Spanish["Human"] = nil + Spanish["Gnome"] = nil + Spanish["Dwarf"] = nil + Spanish["NightElf"] = nil + Spanish["Draenei"] = nil + Spanish["Worgen"] = nil + Spanish["Pandaren"] = nil + Spanish["Undead"] = nil + Spanish["Orc"] = nil + Spanish["Troll"] = nil + Spanish["Tauren"] = nil + Spanish["BloodElf"] = nil + Spanish["Goblin"] = nil + +local Russian = setmetatable({}, {__index=defaultFunc}) + Russian["Russian Locale loaded"] = "Russian Locale loaded" + Russian["Enable whispers"] = "Разрешить сообщения" + Russian["Level limits"] = "Лимит уровней" + Russian["Invite Mode"] = "Режим приглашения" + Russian["Whisper only"] = "Только сообщение" + Russian["Invite and whisper"] = "Приглашение и сообщение" + Russian["Invite only"] = "Только приглашение" + Russian["Mute SGI"] = "Мут SGI" + Russian["Filter 55-58 Death Knights"] = "Фильтровать Рыцарей Смерти 55-58 уровня" + Russian["Do a more thorough search"] = "Глубокий поиск" + Russian["Customize whisper"] = "Настроить Сообщение" + Russian["SuperScan"] = "СуперСканирование" + Russian["Invite: %d"] = "Пригласить: %d" + Russian["Choose Invites"] = "Выбрать Приглашения" + Russian["Exceptions"] = "Исключения" + Russian["Help"] = "Помощь" + Russian["The level you wish to start dividing the search by race"] = "Уровень, с которого включается рассовый фильтр" + Russian["Racefilter Start:"] = "Рассовый Фильтр" + Russian["The level you wish to divide the search by class"] = "Уровень, с которого включается классовый фильтр" + Russian["Classfilter Start:"] = "Классовый Фильтр" + Russian["Amount of levels to search every ~7 seconds (higher numbers increase the risk of capping the search results)"] = "Интервал уровней для поиска каждые ~7 секунд (больший интервал приводит к риску достигнуть лимита поиска в 49 человек)" + Russian["Interval:"] = "Интервал" + Russian["SuperGuildInvite Custom Whisper"] = "сообщение по умолчанию SGI" + Russian["WhisperInstructions"] = "Create a customized whisper to send people you invite! If you enter the words (must be caps) |cff00ff00NAME|r, |cff0000ffLEVEL|r or |cffff0000PLAYER|r these will be replaced by your Guildname, Guildlevel and the recieving players name" + Russian["Enter your whisper"] = "Введите свое сообщение" + Russian["Save"] = "Сохранить" + Russian["Cancel"] = "Отмена" + Russian["less than 1 second"] = "Менее 1 секунды" + Russian[" hours "] = " Часов " + Russian[" minutes "] = " Минут " + Russian[" seconds"] = " Секунд " + Russian[" remaining"] = "осталось" + Russian["Purge Queue"] = "Очистить Очередь" + Russian["Click to toggle SuperScan"] = "Нажмите чтобы переключить СуперСкан" + Russian["Click on the players you wish to invite"] = "Нажмите на игроков которых хотите пригласить" + Russian["Scan Completed"] = "Сканирование завершено" + Russian["Who sent: "] = "Кто отправлено: " + Russian["SuperScan was started"] = "СуперСканирование началось" + Russian["SuperScan was stopped"] = "Суперсканирование остановлено" + Russian["PlayersScanned"] = "Players Scanned: |cff44FF44%d|r |cffffff00(Total: |r|cff44FF44%d|r)" + Russian["PlayersGuildLess"] = "Guildless Players: |cff44FF44%d|r (|cff44FF44%d%%|r)" + Russian["InvitesQueued"] = "Invites Queued: |cff44FF44%d|r" + Russian["ExceptionsInstructions"] = "You can add exception phrases that when found in a name will cause the player to be ignore by SuperGuildInvite. You can add several exceptions at once, seperated by a comma (,)." + Russian["SGI Exceptions"] = "Исключения SGI" + Russian["Enter exceptions"] = "Ввести исключения" + Russian["Go to Options and select your Invite Mode"] = "Откройте настройки и выберите режим приглашения" + Russian["You need to specify the mode in which you wish to invite"] = "Вы должны выбрать режим приглашения" + Russian["Unable to invite %s. They are already in a guild."] = "Невозможно пришласить %s. Он уже в гильдии" + Russian["Unable to invite %s. They will not be blacklisted."] = "Невозможно пришласить %s. Он не будет занесен в черный список" + + --Trouble shooter-- + Russian["not sending"] = "|cffff8800Why am I not sending any whispers?|r |cff00A2FFPossibly because you have not checked the checkbox.|r|cff00ff00 Click on this message to fix.|r" + Russian["to specify"] = "|cffff8800I am getting a message telling me to specify my invite mode when I try to invite!|r|cff00A2FF This happens when you have not used the dropdown menu in the options to pick how to invite people.|r|cff00ff00 Click to fix.|r" + Russian["I checked the box"] = "|cffff8800I am not sending any whispers when I invite and I checked the box!|r|cff00A2FF This is because you have selected only to invite with the dropdown menu in the options.|r|cff00ff00 Click to fix|r" + Russian["whisper to everyone"] = "|cffff8800I keep sending a whisper to everyone I invite, OR I just want to send whispers and not invite, but your AddOn does both!|r|cff00A2FF This is because you specified to both invite and whisper on the dropdown menu in options.|r|cff00ff00 Click to fix|r" + Russian["can't get SGI to invite"] = "|cffff8800I can't get SGI to invite people, all it does is sending whispers.|r|cff00A2FF This is because you picked that option in the dropdown menu.|r|cff00ff00 Click to fix|r" + Russian["can't see any messages"] = "|cffff8800I can't see any messages from SGI at all!|r|cff00A2FF This is because you have muted SGI in the options.|r|cff00ff00 Click to fix|r" + Russian["None of the above"] = "|cffff8800None of the above solved my problem!|r|cff00A2FF There might be an issue with the localization (language) you are using. You can try to load your locale manually: /sgi locale:deDE loads German (frFR for french). Please contact me at:|r|cff00ff00 SuperGuildInvite@gmail.com|r" + Russian["Enabled whispers"] = "Разрешить сообщения" + Russian['Changed invite mode to "Invite and Whisper"'] = "Режим приглашения изменен на 'приглашение и сообщение'" + Russian["Mute has been turned off"] = "Мут был выключен" + Russian['Changed invite mode to "Only Invite". If you wanted "Only Whisper" go to Options and change.'] = "Режим приглашения изменен на 'только' пригласить. Если вы хотите приглашать людей, смените режим" + + + + Russian["Shaman"] = "Шаман" + Russian["Death Knight"] = "Рыцарь Смерти" + Russian["Mage"] = "Маг" + Russian["Priest"] = "Жрец" + Russian["Rogue"] = "Разбойник" + Russian["Paladin"] = "Паладин" + Russian["Warlock"] = "Чернокнижник" + Russian["Druid"] = "Друид" + Russian["Warrior"] = "Воин" + Russian["Hunter"] = "Охотник" + Russian["Monk"] = "Монах" + + Russian["Human"] = "Человек" + Russian["Gnome"] = "Гном" + Russian["Dwarf"] = "Дворф" + Russian["NightElf"] = "Ночной Эльф" + Russian["Draenei"] = "Дреней" + Russian["Worgen"] = "Ворген" + Russian["Pandaren"] = "Пандарен" + Russian["Undead"] = "Нежить" + Russian["Orc"] = "Орк" + Russian["Troll"] = "Тролль" + Russian["Tauren"] = "Таурен" + Russian["BloodElf"] = "Эльф Крови" + Russian["Goblin"] = "Гоблин" + + Russian["Author"] = "|cff00A2FF Переведено игроком Вовочкин - Гордунни.|r" + + +SGI_Locale["enGB"] = English +SGI_Locale["enUS"] = English +SGI_Locale["deDE"] = German +SGI_Locale["frFR"] = French +--SGI_Locale["ruRU"] = Russian Can't be added because of client issues. +--SGI_Locale["esES"] = Spanish +--SGI_Locale["esMX"] = Spanish