-- upvalue the globals -------------------------------------------------------- local _G = getfenv(0) local LibStub = _G.LibStub local ENABLE = _G.ENABLE local CHANNEL_CATEGORY_GROUP = _G.CHANNEL_CATEGORY_GROUP local CHAT_CHANNELS = _G.CHAT_CHANNELS local CHAT_MSG_GUILD = _G.CHAT_MSG_GUILD local CHAT_MSG_PARTY = _G.CHAT_MSG_PARTY local CHAT_MSG_RAID = _G.CHAT_MSG_RAID local CHAT_MSG_SAY = _G.CHAT_MSG_SAY local CHAT_MSG_WHISPER_INFORM = _G.CHAT_MSG_WHISPER_INFORM local CHAT_MSG_YELL = _G.CHAT_MSG_YELL local CHAT_OPTIONS_LABEL = _G.CHAT_OPTIONS_LABEL local format = _G.format local GetPlayerInfoByGUID = _G.GetPlayerInfoByGUID local gsub = _G.gsub local INSTANCE_CHAT = _G.INSTANCE_CHAT local IsInGroup = _G.IsInGroup local IsInInstance = _G.IsInInstance local IsInRaid = _G.IsInRaid local LE_PARTY_CATEGORY_INSTANCE = _G.LE_PARTY_CATEGORY_INSTANCE local MISCELLANEOUS = _G.MISCELLANEOUS local OFF = _G.OFF local random = _G.random local SendChatMessage = _G.SendChatMessage local strmatch = _G.strmatch local strlen = _G.strlen local strtrim = _G.strtrim local tinsert = _G.tinsert local tostring = _G.tostring local ipairs = _G.ipairs -- declare our module --------------------------------------------------------- local modname = "Chat" local SmartRes2 = LibStub("AceAddon-3.0"):GetAddon("SmartRes2") local Chat = SmartRes2:NewModule(modname, "AceConsole-3.0", "AceEvent-3.0") local L = LibStub("AceLocale-3.0"):GetLocale("SmartRes2") -- update localization table -------------------------------------------------- SmartRes2.L = L -- get LibResInfo-1.0 --------------------------------------------------------- local LRI = LibStub("LibResInfo-1.0") -- declare variables ---------------------------------------------------------- local playerGUID = UnitGUID("player") local _, currentRealm = UnitFullName("player") local singleRndMsg = {} local massRndMsg = {} local alreadyNotified = {} local massStarted = {} local db -- defaults table ------------------------------------------------------------- local defaults = { profile = { chatType = "GROUP", massResMessage = { "I am casting Mass Resurrection.", "Mass resurrection for you! And you! And you! For everybody!", "All your mass resurrections are belong to me!", "I am in your graves, casting Mass Resurrection.", "Free mass resurrections for all of you!", "You are all getting mass resurrected. However, I do not guarantee all your parts are intact." }, notifyCollision = "WHISPER", notifyExpired = true, notifyCancelled = true, notifyEnded = true, notifySelf = true, notifyStarted = true, randChatTbl = { "%p is bringing %t back to life!", "Filthy peon! %p has to resurrect %t!", "%p has to wake %t from eternal slumber.", "%p is ending %t's dirt nap.", "No fallen heroes! %p needs %t to march forward to victory!", "%p doesn't think %t is immortal, but after this res cast, it is close enough.", "Sleeping on the job? %p is disappointed in %t.", "%p knew %t couldn't stay out of the fire. *Sigh*", "Once again, %p pulls %t and their bacon out of the fire.", "%p thinks %t should work on their Dodge skill.", "%p refuses to accept blame for %t's death, but kindly undoes the damage.", "%p grabs a stick. A-ha! %t was only temporarily dead.", "%p is ressing %t", "%p knows %t is faking. It was only a flesh wound!", "Oh. My. God. %p has to breathe life back into %t AGAIN?!?", "%p knows that %t dying was just an excuse to see another silly random res message.", "Think that was bad? %p proudly shows %t the scar tissue caused by Hogger.", "Just to be silly, %p tickles %t until they get back up.", "FOR THE HORDE! FOR THE ALLIANCE! %p thinks %t should be more concerned about yelling FOR THE LICH KING! and prevents that from happening.", "And you thought the Scourge looked bad. In about 10 seconds, %p knows %t will want a comb, some soap, and a mirror.", "Somewhere, the Lich King is laughing at %p, because he knows %t will just die again eventually. More meat for the grinder!!", "%p doesn't want the Lich King to get another soldier, so is bringing %t back to life.", "%p wonders about these stupid res messages. %t should just be happy to be alive.", "%p prays over the corpse of %t, and a miracle happens!", "In a world of resurrection spells, why are NPC deaths permanent? It doesn't matter, since %p is making sure %t's death isn't permanent.", "%p performs a series of lewd acts on %t's still warm corpse. Ew." }, ["*"] = { ["*"] = true } } } -- options table -------------------------------------------------------------- local options local function getOptions() if not options then options = { type = "group", childGroups = "tab", name = CHAT_OPTIONS_LABEL, arg = modname, args = { enabled = { name = ENABLE, desc = L["Toggle module on/off."], descStyle = "inline", type = "toggle", order = 10, get = function() return SmartRes2:GetModuleEnabled(modname) end, set = function(info, value) SmartRes2:SetModuleEnabled(modname, value) end }, selfNotification = { name = L["Self Notification"], desc = L["This tab controls messages only you can see."], type = "group", order = 20, args = { expired = { name = L["Victim Resurrected Expiration"], desc = L["Lets you know the victim did not accept their resurrection and can be resurrected again."], descStyle = "inline", type = "toggle", order = 10, get = function() return db.notifyExpired end, set = function(info, value) db.notifyExpired = value end }, cancelled = { name = L["Caster Cancelled Resurrection"], desc = L["Another caster (not you) cancelled their resurrection."], descStyle = "inline", type = "toggle", order = 20, get = function() return db.notifyCancelled end, set = function(info, value) db.notifyCancelled = value end }, ended = { name = L["Caster Finished Cast"], desc = L["Another caster (not you) completed casting their spell."], descStyle = "inline", type = "toggle", order = 30, get = function() return db.notifyEnded end, set = function(info, value) db.notifyEnded = value end }, myCasts = { name = L["My Resurrections"], desc = L["Tells you whom you are resurrecting, or casting a mass resurrection, or raising the Creator from the dead."], descStyle = "inline", type = "toggle", order = 40, get = function() return db.notifySelf end, set = function(info, value) db.notifySelf = value end }, started = { name = L["Caster Started"], desc = L["Another caster (not you) started a resurrection."], descStyle = "inline", type = "toggle", order = 50, get = function() return db.notifyStarted end, set = function(info, value) db.notifyStarted = value end } } }, single = { name = L["Single Target Messages"], desc = L["Messages about single target casts you send to chat."], type = "group", order = 30, args = { singleStatic = { name = L["Static Message"], desc = L["Enter a static message for resurrections. This will print instead of random messages. Use %p (optional) for yourself, and %t (mandatory) for your target."], type = "input", order = 10, width = "full", validate = function(info, value) value = strtrim(value) value = strlen(value) > 0 and value or nil if value and not strmatch(value, "%%t") then SmartRes2:Print(L["You need a target. Use %t somewhere in your phrase."]) return false else return true end end, get = function() return db.singleMsg end, set = function(info, value) value = strtrim(value) db.singleMsg = strlen(value) > 0 and value or nil end }, --@debug@ addRandomMsg = { name = L["Add Random Message"], desc = L["Add a random message to the table. Use %p (optional) for yourself, and %t (mandatory) for your target."], type = "input", order = 20, width = "full", validate = function(info, value) if value and not strmatch(value, "%%t") then SmartRes2:Print(L["You need a target. Use %t somewhere in your phrase."]) return false else return true end end, get = function() return "" end, set = function(info, value) -- Insert non-empty values into the table value = strtrim(value) value = strlen(value) > 0 and value or nil if value then tinsert(db.randChatTbl, value) end end }, --@end-debug@ randomSingle = { name = L["Random Messages"], desc = L["Select the messages you want to use."], type = "multiselect", order = 30, width = "full", dialogControl = "Dropdown", arg = "single random", values = function() return db.randChatTbl end, get = function(info, index) local value = db[info.arg][db.randChatTbl[index]] local strname = db.randChatTbl[index] singleRndMsg[strname] = singleRndMsg[strname] or strname return db[info.arg][db.randChatTbl[index]] and value end, set = function(info, index, value) local strname = db.randChatTbl[index] db[info.arg][db.randChatTbl[index]] = value if db[info.arg][db.randChatTbl[index]] then singleRndMsg[strname] = strname else singleRndMsg[strname] = nil end end } } }, mass = { name = L["Mass Resurrections"], desc = L["Mass resurrection chat messages."], type = "group", order = 40, args = { massMessage = { name = L["Static Message"], desc = L["Enter a static message for mass resurrections. This will print instead of random messages."], type = "input", order = 10, width = "full", validate = function(info, value) if value and strmatch(value, "%%t") then SmartRes2:Print(L["You cannot specify a target (%t) for mass resurrections."]) return false else return true end end, get = function() return db.massMsg end, set = function(info, value) db.massMsg = value end }, --@debug@ addRandomMassMsg = { name = L["Add Random Message"], desc = L["Add a message to the table. You may optionally specify %p for your name."], type = "input", order = 20, width = "full", validate = function(info, value) if value and strmatch(value, "%%t") then SmartRes2:Print(L["You cannot specify a target (%t) for mass resurrections."]) return false else return true end end, get = function() return "" end, set = function(info, value) value = strtrim(value) value = strlen(value) > 0 and value or nil if value then tinsert(db.massResMessage, value) end end }, --@end-debug@ randomMassMsg = { name = L["Random Messages"], desc = L["Select the messages you want to use."], type = "multiselect", order = 30, width = "full", dialogControl = "Dropdown", arg = "mass random", values = function() return db.massResMessage end, get = function(info, index) local value = db[info.arg][db.massResMessage[index]] local strname = db.massResMessage[index] massRndMsg[strname] = massRndMsg[index] or strname return db[info.arg][db.massResMessage[index]] and value end, set = function(info, index, value) local strname = db.massResMessage[index] db[info.arg][db.massResMessage[index]] = value if db[info.arg][db.massResMessage[index]] then massRndMsg[strname] = strname else massRndMsg[strname] = nil end end } } }, miscellaneous = { name = MISCELLANEOUS, desc = L["Settings that don't fit into other tabs."], type = "group", order = 50, args = { notifyCollision = { name = L["Collision Casts"], desc = L["Notify a caster their spell is a duplicate."], type = "select", order = 10, values = { GROUP = CHANNEL_CATEGORY_GROUP, GUILD = CHAT_MSG_GUILD, INSTANCE = INSTANCE_CHAT, PARTY = CHAT_MSG_PARTY, RAID = CHAT_MSG_RAID, SAY = CHAT_MSG_SAY, WHISPER = CHAT_MSG_WHISPER_INFORM, YELL = CHAT_MSG_YELL, OFF = OFF }, get = function() return db.notifyCollision end, set = function(info, value) db.notifyCollision = value end }, chatType = { name = CHAT_CHANNELS, desc = L["Where to print your resurrection message. Group is smart, and will send to the appropriate channel."], type = "select", order = 20, values = { GROUP = CHANNEL_CATEGORY_GROUP, GUILD = CHAT_MSG_GUILD, INSTANCE = INSTANCE_CHAT, PARTY = CHAT_MSG_PARTY, RAID = CHAT_MSG_RAID, SAY = CHAT_MSG_SAY, WHISPER = CHAT_MSG_WHISPER_INFORM, YELL = CHAT_MSG_YELL, OFF = OFF }, get = function() return db.chatType end, set = function(info, value) db.chatType = value end } } } } } end return options end -- copy original SmartRes2 random res messages to Chat SV and delete original - local function CopyTable(source) local dest = db.randChatTbl for si, sv in ipairs(source) do -- Using ipairs here mostly as an example of usage. local hasMatch for ci, cv in ipairs(dest) do if strmatch(cv, sv) then hasMatch = true break -- We found a dupe, no need to go farther end end if not hasMatch then if strmatch(sv, "%%t") then tinsert(dest, sv) else SmartRes2:Print(L["The random message %s is missing target %t, skipping backup from old saved variables."], tostring(sv)) end end end end function Chat:OnInitialize() self.db = SmartRes2.db:RegisterNamespace(modname, defaults) db = self.db.profile if SmartRes2.db.profile.randChatTbl then CopyTable(SmartRes2.db.profile.randChatTbl) SmartRes2.db.profile.randChatTbl = nil SmartRes2.db.profile.singleMsg = nil SmartRes2.db.profile.notifySelf = nil SmartRes2.db.profile.notifyCollision = nil end self:SetEnabledState(SmartRes2:GetModuleEnabled(modname)) SmartRes2:RegisterModuleOptions(modname, getOptions, CHAT_OPTIONS_LABEL) end function Chat:OnEnable() LRI.RegisterCallback(self, "LibResInfo_ResCastStarted", "CastStarted") LRI.RegisterCallback(self, "LibResInfo_MassResStarted", "CastStarted") LRI.RegisterCallback(self, "LibResInfo_ResCastFinished", "CastFinished") LRI.RegisterCallback(self, "LibResInfo_MassResFinished", "CastFinished") LRI.RegisterCallback(self, "LibResInfo_MassResCancelled", "CastCancelled") LRI.RegisterCallback(self, "LibResInfo_ResCastCancelled", "CastCancelled") alreadyNotified = alreadyNotified or {} massStarted = massStarted or {} end function Chat:OnDisable() LRI.UnregisterAllCallbacks(self) alreadyNotified = nil massStarted = nil end function Chat:Refresh() db = self.db.profile end -- return correct chat type, if set to "GROUP" -------------------------------- local return_chat = { ["GUILD"] = true, ["SAY"] = true, ["YELL"] = true, ["WHISPER"] = true, ["OFF"] = true } local function ChatType(chatType) if return_chat[chatType] then return chatType elseif IsInGroup(LE_PARTY_CATEGORY_INSTANCE) then chatType = "INSTANCE_CHAT" elseif IsInRaid() then if chatType ~= "PARTY" then chatType = "RAID" end elseif IsInGroup() then chatType = "PARTY" end return chatType end -- creator character list (easter eggs!) -------------------------------------- local creatorNames = { ["Myrroddin"] = true, ["Jelia"] = true, ["Badash"] = true, ["Vanhoeffen"] = true, ["Sygon"] = true, ["Selkei"] = true, ["Uthartian"] = true, ["Kadil"] = true } -- handle LibResInfo callbacks ------------------------------------------------ function Chat:CastStarted(callback, targetID, targetGUID, casterID, casterGUID, endTime) -- local variables local _, targetName, targetRealm, casterName, casterRealm, resTargetGUID, isFirst, firstCasterGUID, firstCasterName, resType, firstCasterNameForTarget local isMassRes = callback == "LibResInfo_MassResStarted" if isMassRes then targetID, targetGUID, casterID, casterGUID, endTime = nil, nil, targetID, targetGUID, casterID, casterGUID, endTime else _, _, _, _, _, targetName, targetRealm = GetPlayerInfoByGUID(targetGUID) end _, _, _, _, _, casterName, casterRealm = GetPlayerInfoByGUID(casterGUID) -- get the caster info, resTargetGUID is nil for mass resses _, _, resTargetGUID, isFirst = LRI:UnitIsCastingRes(casterGUID) if isFirst then _, _, _, _, _, firstCasterName = GetPlayerInfoByGUID(casterGUID) end -- get the target info, if targetGUID exists resType, _, _, firstCasterGUID = LRI:UnitHasIncomingRes(targetGUID) if firstCasterGUID then _, _, _, _, _, firstCasterNameForTarget = GetPlayerInfoByGUID(firstCasterGUID) end local chat_type = ChatType(db.chatType) local msg -- what will the message to chat say? if casterGUID == playerGUID then -- process messages to the player if resTargetGUID then -- single target cast -- will the player's cast be first? if isFirst then if targetRealm == "Llane" and creatorNames[targetName] then SmartRes2:Print(L["You are resurrecting the Creator!!"]) elseif db.notifySelf then SmartRes2:Printf(L["You are resurrecting %s"], targetName) end else -- it isn't first SmartRes2:Printf(L["Your resurrection of %s is not the first that will finish. %s has that honour; you should cancel your cast."], targetName, firstCasterNameForTarget) end else -- mass resurrection if not isFirst then SmartRes2:Printf(L["Your mass resurrection spell will not finish first. %s has that honour; you should cancel your cast."], firstCasterName) end end -- process player messages to chat if chat_type ~= "OFF" then if resTargetGUID then -- single target cast if chat_type ~= "OFF" then if db.singleMsg then msg = db.singleMsg else if #singleRndMsg > 0 then msg = singleRndMsg[random(#singleRndMsg)] end end end else -- mass resses if chat_type ~= "OFF" then if db.massMsg then msg = db.massMsg else if #massRndMsg > 0 then msg = massRndMsg[random(#massRndMsg)] end end end end -- replace "%p" and "%t" with caster's name and target's name, respectively msg = gsub(msg, "%%p", casterName) msg = gsub(msg, "%%t", targetName) if chat_type == "WHISPER" then local whisperTarget = format("%s-%s", targetName, targetRealm or currentRealm) SendChatMessage(msg, chat_type, nil, whisperTarget) else SendChatMessage(msg, chat_type) end end elseif casterGUID ~= playerGUID then -- caster is not player if isFirst then if db.notifyStarted then if resTargetGUID then SmartRes2:Printf(L["%s is resurrecting %s."], casterName, targetName) else if not massStarted[casterGUID] then -- mass res callback fires for multiple casts, only send one message SmartRes2:Printf(L["%s is resurrecting everybody."], casterName) massStarted[casterGUID] = true end end end else -- send collision cast messages if alreadyNotified[casterGUID] then return -- don't spam end alreadyNotified[casterGUID] = true chat_type = ChatType(db.notifyCollision) if chat_type ~= "OFF" then if resTargetGUID then -- single target cast if resType == "PENDING" or resType == "CANRES" then msg = format(L["%s already has a resurrection pending; they have not accepted yet."], targetName) else msg = format(L["%s is already being resurrected by %s."], targetName, firstCasterNameForTarget) end else -- mass resses msg = format(L["SmartRes2 would like you to know that %s is already resurrecting everybody."], firstCasterName) end if chat_type == "WHISPER" then local whisperTarget = format("%s-%s", casterName, casterRealm or currentRealm) SendChatMessage(msg, chat_type, nil, whisperTarget) else SendChatMessage(msg, chat_type) end end end end end function Chat:CastFinished(callback, targetID, targetGUID, casterID, casterGUID) local _, casterName, targetName local isMassRes = callback == "LibResInfo_MassResFinished" if isMassRes then targetID, targetGUID, casterID, casterGUID = nil, nil, targetID, targetGUID, casterID, casterGUID else _, _, _, _, _, targetName = GetPlayerInfoByGUID(targetGUID) end _, _, _, _, _, casterName = GetPlayerInfoByGUID(casterGUID) alreadyNotified[casterGUID] = nil massStarted[casterGUID] = nil if db.notifyEnded and casterGUID ~= playerGUID then if targetName then SmartRes2:Printf(L["%s has finished their resurrection cast on %s."], casterName, targetName) else SmartRes2:Printf(L["%s has finished their mass resurection cast."], casterName) end end end function Chat:CastCancelled(callback, targetID, targetGUID, casterID, casterGUID) local _, casterName, targetName local isMassRes = callback == "LibResInfo_MassResCancelled" if isMassRes then targetID, targetGUID, casterID, casterGUID = nil, nil, targetID, targetGUID, casterID, casterGUID else _, _, _, _, _, targetName = GetPlayerInfoByGUID(targetGUID) end _, _, _, _, _, casterName = GetPlayerInfoByGUID(casterGUID) alreadyNotified[casterGUID] = nil massStarted[casterGUID] = nil if db.notifyCancelled and casterGUID ~= playerGUID then if targetName then SmartRes2:Printf(L["%s has cancelled their cast on %s."], casterName, targetName) else SmartRes2:Printf(L["%s has cancelled their mass resurrection."], casterName) end end end