WoWInterface SVN AutoReply

[/] [trunk/] [Core.lua] - Rev 16

Compare with Previous | Blame | View Log

----------------------------------------
-- Addon name   : Animor's AutoReply
-- Author       : Animor
-- Create Date  : 12/1/2011
-- File                 : Core.lua
----------------------------------------

----------------------------------------
-- Libs
----------------------------------------
AutoReply                               = LibStub("AceAddon-3.0"):NewAddon("AutoReply", "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0")
local L                                 = LibStub("AceLocale-3.0"):GetLocale("AutoReply")
local AceConfigDialog   = LibStub("AceConfigDialog-3.0")
local LDBIcon                   = LibStub("LibDBIcon-1.0", true)
local ldb                               = LibStub:GetLibrary("LibDataBroker-1.1")

----------------------------------------
-- Local variables for upavlue
----------------------------------------
local db
local dbChar

----------------------------------------
-- Local variables
----------------------------------------

-- PvP status for reply message
local myBGFaction               = nil
local myBGName                  = ""
local BGWinner                  = nil
local BGArenaActivity   = 0             -- Current PvP activity: 0 - BG, 1 - Arena

-- Matching strings for BG score. BG IDs are according to GetCurrentMapAreaID()
local BGMatchStrings = {
        -- BGs in which score format is ####/####
        [461]   = "(%d+)/",     -- Arathi Basin
        [736]   = "(%d+)/", -- Battle for Gilneas
        [482]   = "(%d+)/",     -- Eye of the Storm
        [813]   = "(%d+)/",     -- Rated Eye of the Storm
        -- BGs in which score format is ##
        [401]   = "(%d+)",      -- Alterac Valley
        [540]   = "(%d+)",      -- Isle of Conquest
        [626]   = "(%d+)",      -- Twin Peaks
        [443]   = "(%d+)",      -- Warsong Gulch
}

-- faction score line according to GetWorldStateUIInfo(). BG IDs are according to GetCurrentMapAreaID()
local BGFirstScoreLineArray = {
        -- BGs in which the first info line is faction score
        [401]   = 1,    -- Alterac Valley
        [461]   = 1,    -- Arathi Basin
        [736]   = 1,    -- Battle for Gilneas
        [540]   = 1,    -- Isle of Conquest
        -- BGs in which the first info line is global (not faction score)
        [482]   = 2,    -- Eye of the Storm
        [626]   = 2,    -- Twin Peaks
        [443]   = 2,    -- Warsong Gulch         
}

-- 512 Strand of the Ancients
        
----------------------------------------
-- Configuration defaults
----------------------------------------
local defaults = {
    profile = {
                -- Global
        globalEn                                = true,
        replyOnce                               = false,
                groupMembersEn                  = false,                
                replyWhisperersEn               = true,
                hideReply                               = false,
                
                -- Global combat
                combatEn                                = true,
                combatText                              = L["%PN (%PHP) is busy in combat in %LOC. Target: %TN (%THP)."],
                        
                -- Away(AFK)
                awayHistoryEn                   = true,
                replyAwayWhisperersEn   = true,
                
                -- Death
                deadEn                                  = true,
                deadText                                = L["%PN is dead now, and the dead can't talk."],
                
                -- History              
                numHistoryEntries               = 100,
                
                -- Raid
                raidEn                                  = true,
                raidText                                = L["%PN (%PHP) is busy raiding %LOC. Progress: %PRG."],                
                raidCombatEn                    = false,
                raidMembersEn                   = false,
                raidBossEn                              = false,
                raidBossText                    = L["%PN (%PHP) is busy raiding %LOC, now fighting boss %BN (%BHP)."],
                
                -- Dungeon
                dungeonEn                               = true,
                dungeonText                             = L["%PN (%PHP) is busy in %LOC dungeon. Progress: %PRG."],
                dungeonCombatEn                 = false,
                dungeonPartyMembersEn   = false,
                dungeonBossEn                   = false,
                dungeonBossText                 = L["%PN (%PHP) is busy in %LOC dungeon, now fighting boss %BN (%BHP)."],
                
                -- Battleground
                bgEn                                    = true,
                bgText                                  = L["%PN (%PHP) is busy in %LOC BG for %TIM now. %SCR."],
                bgCombatEn                              = false,
                bgPrepareEn                             = true,
                bgRaidMembersEn                 = false,
                
                -- Arena
                arenaEn                                 = true,
                arenaText                               = L["%PN (%PHP) is busy in %LOC for %TIM now. %SCR."],
                arenaPrepareEn                  = true,
                arenaRaidMembersEn              = false,                
    },
        
        char = {
                -- Missed whispers history table
                msgHistory                              = {},
                
                -- LDB icon storage
                minimapIcon                     = {
                        hide            = false,
                },
        },
}

--======================================
--======================================
-- CHECK PLAYER STATE: MAIN FUNCTION
--======================================
--======================================
function AutoReply:CheckPlayerState (msg, sender)
        local replyWhisper      = false
        local replyMsg          = ""
        local locationName      = ""
        local instanceType      = ""
        
        -- Check that message doesn't start with addons prefix.
        if not (msg:find("^<.*>") or msg:find("^%[.*%]")) then  
                locationName, instanceType = GetInstanceInfo()
                -- Open world location
                if  instanceType == "none" then
                        locationName = GetZoneText()
                else
                        -- Save instance name
                        self.locationName = locationName
                end             
                
                local playerInCombat = UnitAffectingCombat("player")
                
                -- Raid
                if (instanceType == "raid" and db.raidEn) then
                        if playerInCombat or (not db.raidCombatEn) then -- Combat
                                if (db.raidMembersEn or (not UnitInRaid(sender))) then -- Raid member
                                        if (not self.bossEngaged) then                          -- Non-boss fight
                                                replyMsg                = db.raidText
                                                replyWhisper    = true
                                        elseif (db.raidBossEn)  then                            -- Boss fight
                                                replyMsg                = db.raidBossText
                                                replyWhisper    = true
                                        end                                     
                                end
                        end
                        
                -- 5men dungeon
                elseif (instanceType == "party" and db.dungeonEn) then
                        if playerInCombat or (not db.dungeonCombatEn) then -- Combat
                                if (db.dungeonPartyMembersEn or (not UnitInParty(sender))) then -- Party member
                                        if (not self.bossEngaged) then                                                          -- Non-boss fight
                                                replyMsg                = db.dungeonText
                                                replyWhisper    = true
                                        elseif (db.dungeonBossEn) then                                                          -- Boss fight
                                                replyMsg                = db.dungeonBossText
                                                replyWhisper    = true
                                        end                                     
                                end
                        end
                        
                -- BG
                elseif (instanceType == "pvp" and db.bgEn) then -- BG enable
                        if playerInCombat or (not db.bgCombatEn) then -- Combat
                                if (not UnitBuff("player", "Preparation") or db.bgPrepareEn) then -- Preparation
                                        if (db.bgRaidMembersEn or (not UnitInRaid(sender))) then -- Raid member
                                                replyMsg                = db.bgText
                                                -- Do only on real whisper, not on status check.
                                                -- Do if BGWinner is nil, to handle whisper after PvP activity end
                                                if sender ~= "" and BGWinner == nil then 
                                                        BGWinner = GetBattlefieldWinner()
                                                        -- If no winner data, register event to get winner
                                                        if not BGWinner then self:RegisterEvent("UPDATE_BATTLEFIELD_STATUS") end
                                                end                                                     
                                                BGArenaActivity = 0     -- Mark BG
                                                myBGName        = locationName
                                                replyWhisper    = true
                                        end
                                end
                        end     
                        
                -- Arena
                elseif (instanceType == "arena" and db.arenaEn) then -- Arena enable
                        if (not UnitBuff("player", "Arena Preparation") or db.arenaPrepareEn) then -- Preparation
                                if (db.arenaPartyMembersEn or (not UnitInParty(sender))) then -- Party member
                                        replyMsg                = db.arenaText
                                        -- Do only on real whisper, not on status check.
                                        -- Do if BGWinner is nil, to handle whisper after PvP activity end                                      
                                        if sender ~= "" and BGWinner == nil then 
                                                BGWinner = GetBattlefieldWinner()
                                                -- If no winner data, register event to get winner
                                                if not BGWinner then self:RegisterEvent("UPDATE_BATTLEFIELD_STATUS") end
                                        end                                                     
                                        BGArenaActivity = 1 -- Mark Arena
                                        replyWhisper    = true
                                        if not locationName:find("Arena") then locationName = locationName.." Arena" end
                                end
                        end
                        
                -- Global combat
                elseif instanceType == "none" and db.combatEn and playerInCombat then
                        if (db.groupMembersEn or not (UnitInParty(sender) or UnitInRaid(sender))) then -- Party/raid member
                                replyMsg                = db.combatText                                         
                                replyWhisper    = true                          
                        end
                
                -- Death
                elseif UnitIsDeadOrGhost("player") and db.deadEn then
                        if (db.groupMembersEn or not (UnitInParty(sender) or UnitInRaid(sender))) then -- Party/raid member
                                replyMsg                = db.deadText
                                replyWhisper    = true
                                self:RegisterEvent("PLAYER_ALIVE", "BackToLife")
                                self:RegisterEvent("PLAYER_UNGHOST", "BackToLife")
                        end
                end
                
        end -- addons prefix
        
        return replyWhisper, replyMsg, instanceType, locationName
end

--======================================
--======================================
-- WHISPER HANDLING
--======================================
--======================================

----------------------------------------
-- Recieve whisper event
----------------------------------------
function AutoReply:CHAT_MSG_WHISPER(_, msg, sender, _, _, _, status)    
        -- Do nothing with whispers from GM
        if status ~= "GM" then 
                self:HandleWhisper(msg, sender)
        end
end

----------------------------------------
-- Recieve BN whisper event
----------------------------------------
function AutoReply:CHAT_MSG_BN_WHISPER(_, msg, ...)
        -- Get BN presenceId
        local BNpresenceId      = select(12, ...)               
        self:HandleWhisper(msg, BNpresenceId)
end

----------------------------------------
-- Reply to all away missed whisperers
----------------------------------------
function AutoReply:PLAYER_FLAGS_CHANGED()       
        -- Reply whispers to all missed away senders
        if (not UnitIsAFK("player")) then
                self:ReplyAllAwayMissed()
        end
end

-----------------------------------------------
-- Compose reply message according to template
-----------------------------------------------
function AutoReply:ComposeMsg(msg, instanceType, locationName)
        msg = msg:gsub("%%PN", UnitName("player"))
        msg = msg:gsub("%%PHP", math.floor(UnitHealth("player")/UnitHealthMax("player")*100).."%%")
        msg = msg:gsub("%%LOC", locationName)
        
        if (instanceType == "arena") then
                msg = msg:gsub("%%SCR", self:GetArenaStatus())
                msg = msg:gsub("%%TIM", self:GetPVPTime())
        elseif (instanceType == "pvp") then
                msg = msg:gsub("%%SCR", self:GetBGScore())
                msg = msg:gsub("%%TIM", self:GetPVPTime())
        elseif (instanceType == "raid" or instanceType == "party") then
                msg = msg:gsub("%%PRG", self:GetInstanceProgress(locationName))
        end
        
        -- Target
        if GetUnitName("target", true) then             
                msg = msg:gsub("%%TN", GetUnitName("target", true))
                msg = msg:gsub("%%THP", math.floor(UnitHealth("target")/UnitHealthMax("target")*100).."%%")
        else
                msg = msg:gsub("%%TN", L["Unknown"])
                msg = msg:gsub("%s*%(?%%BHP%)?", "")
        end
        
        -- Boss 
        if self.bossEngaged then
                msg = msg:gsub("%%BN", self.bossName)
                if self.bossNum and (UnitName(self.bossNum) == self.bossName) then
                        -- Set boss health only if boss frame shows the correct boss name
                        msg = msg:gsub("%%BHP", math.floor(UnitHealth(self.bossNum)/UnitHealthMax(self.bossNum)*100).."%%")
                else
                        msg = msg:gsub("%s*%(?%%BHP%)?", "")
                end
        end
        
        msg = self.msgPrefix..msg
        return msg      
end

----------------------------------------
-- Send reply
----------------------------------------
function AutoReply:SendReply(replyMsg, target)
        if type(target) == "number" and select(7, BNGetFriendInfoByID(target)) then     -- check if BN friend is online 
                BNSendWhisper(target, replyMsg)                 
        elseif type(target) == "string" then
                target = target:gsub(" ", "") -- remove space in realm name, if any
                SendChatMessage(replyMsg, "WHISPER", nil, target)               
        end
end

----------------------------------------
-- Handle whisper event
----------------------------------------
function AutoReply:HandleWhisper(msg, sender)
        local replyWhisper, replyMsg, instanceType, locationName = self:CheckPlayerState(msg, sender)
        if replyWhisper then
                -- If busy, according to configuration
                if not ( db.replyOnce and ((self.missedSenders[sender] and not self.bossEngaged) or (self.missedBossSenders[sender] and self.bossEngaged)) ) then -- check reply once
                        replyMsg = self:ComposeMsg(replyMsg, instanceType, locationName)
                        self:SendReply(replyMsg, sender)
                end
                self:AddToHistory(sender, msg, false)
        elseif db.awayHistoryEn and UnitIsAFK("player") then
                -- AFK 
                self:AddToHistory(sender, msg, true)
        end
end

----------------------------------------
-- Hide reply from chatframe
----------------------------------------
function AutoReply.filterReplyMsg(chatFrame, event, msg, ...)   
        if (db.hideReply and msg:find("^"..AutoReply.self.msgPrefix)) then      
                return true
        else
                return false
        end
end

--======================================
--======================================
-- LDB
--======================================
--======================================

----------------------------------------
-- LDB object
----------------------------------------
AutoReply.LDBobject = {
        type    = "data source",
        text    = "AutoReply",
        value   = "",
        icon    = "Interface\\Icons\\Inv_bijou_green",
        label   = "AutoReply",  
        OnClick = function(self, button)
                if button == "RightButton" then
                        AutoReply:ToggleConfigWindow()
                else
                        AutoReply:ToggleHistoryWindow()
                end
        end,
        OnTooltipShow = function(tooltip)
                tooltip:AddLine("|cffffffffAnimor's AutoReply|r")
                tooltip:AddLine(L["Click to show missed whispers history"])
                tooltip:AddLine(L["Right-click to open configuration panel"])
        end,
}

----------------------------------------
-- Show minimap icon (LDB)
----------------------------------------
function AutoReply:ToggleMinimapIcon()  
        if (db.globalEn and not dbChar.minimapIcon.hide) then
                LDBIcon:Show("AutoReplyLDB")
        else
                LDBIcon:Hide("AutoReplyLDB")
        end
end

--======================================
--======================================
-- HISTORY MANAGEMENT 
--======================================
--======================================

----------------------------------------
-- Add a seperator to history on logout
---------------------------------------- 
function AutoReply:PLAYER_LOGOUT()      
        -- Add a seperator to history DB if logging out without cheking missed history.
        -- This is done in order to have a seperator for next session.  
        if (dbChar.msgHistory[#dbChar.msgHistory].sender ~= "_") then
                table.insert(dbChar.msgHistory, {date = "", sender = "_", msg = ""})
        end
end

----------------------------------------
-- Toggle history window
----------------------------------------
function AutoReply:ToggleHistoryWindow()        
        
        if AutoReplyHistory:IsShown() then
                -- If already shown, then hide
                AutoReplyHistory:Hide()
                AutoReplyHistory.messageFrame:Clear()
        else
                -- Add messages from DB in history window                       
                for idx, value in pairs(dbChar.msgHistory) do
                        if (value.sender == "_") then
                                AutoReplyHistory.messageFrame:AddMessage(string.rep("_", 30))
                        elseif (value.date and value.sender and value.msg) then
                                AutoReplyHistory.messageFrame:AddMessage("|cffffff00"..value.date.."|r ".."|cffF58CBA|Hplayer:"..value.sender.."|h["..value.sender.."]|h|r"..": "..value.msg)
                        end
                end     
                
                -- Show frame
                AutoReplyHistory:Show()
                
                -- Check for there are new missed whisper
                if self.missed then
                        -- Set icon to green to indicate missed history was read
                        self.LDBobject.icon     = "Interface\\Icons\\Inv_bijou_green"
                        -- Add seperator to read read history
                        table.insert(dbChar.msgHistory, {date = "", sender = "_", msg = ""})    
                        -- Indicate that there are no missed whispers in history
                        self.missed = false
                end
        end
                
        local newMax = AutoReplyHistory.messageFrame:GetNumMessages() - AutoReplyHistory.messageFrame:GetNumLinesDisplayed()
        AutoReplyHistory.scrollBar:SetMinMaxValues(0, newMax)
        AutoReplyHistory.scrollBar:SetValue(newMax)
                
        if (hebChatDB) then
                AutoReplyHistory.messageFrame:SetFont(hebChat.fonts[hebChatDB.currentFont][2], hebChatDB.currentFontSize)               
        end
        
end

----------------------------------------
-- Clear missed whispers history
----------------------------------------
function AutoReply:ClearHistory()
        wipe (dbChar.msgHistory)
        AutoReplyHistory.messageFrame:Clear()
        self:Print(L["Missed whispers history was cleared."])   
end

----------------------------------------
-- Add a missed whisper to history
----------------------------------------
function AutoReply:AddToHistory(sender, msg, awayWhisper)       
        local senderName = ""
        
        if type(sender) == "number" then        
                -- Extrach realID BN toon name
                senderName = select(4, BNGetFriendInfoByID(sender))             
                -- senderName =  BNTokenCombineGivenAndSurname(select(2, BNGetFriendInfoByID(sender))..select(3, BNGetFriendInfoByID(sender)))
        else
                -- Non-BN sender
                senderName = sender
        end
                
        -- Add new element to history DB
        table.insert(dbChar.msgHistory, {date = date("%d/%m %H:%M"), sender = senderName, msg = msg})
        
        -- If exceeded quota, remove first element      
        while (#dbChar.msgHistory >= db.numHistoryEntries) do
                table.remove(dbChar.msgHistory, 1)
        end
                
        -- Add new senders to missed whispers list (for later reply when done being busy)
        if not awayWhisper then
                if self.bossEngaged then
                        -- Senders during boss fight
                        if not self.missedBossSenders[sender] then self.missedBossSenders[sender] = true end
                else
                        -- Senders during non-boss fight
                        if not self.missedSenders[sender] then self.missedSenders[sender] = true end
                end
        else
                -- Add new senders to missed away whispers list
                self.missedAwaySenders[sender] = true
        end
                
        -- Check for new missed whispers indication
        if not self.missed then
                -- Set Icon to red to indicate new missed history
                self.LDBobject.icon     = "Interface\\Icons\\Inv_bijou_red"
                -- Indicate that there are new missed whispers in history
                self.missed = true
        end
end

--======================================
--======================================
-- PVP DATA
--======================================
--======================================

----------------------------------------
-- Get BG score
----------------------------------------
function AutoReply:GetBGScore()
        
        -- Get player faction for cross-faction RBG: 0 = Horde, 1 = Alliance
        myBGFaction     = GetBattlefieldArenaFaction()
        
        -- If on preparation, the data is not valid yet
        if UnitBuff("player", "Preparation") then
                return L["Status: on preparation"]
        end
        
        -- BG IDs according to GetCurrentMapAreaID()
        -- 401 Alterac Valley,
        -- 461 Arathi Basin,
        -- 482 Eye of the Storm,
        -- 540 Isle of Conquest,
        -- 512 Strand of the Ancients,
        -- 736 The Battle for Gilneas,
        -- 626 Twin Peaks,
        -- 443 Warsong Gulch
        
        local BGID                      = GetCurrentMapAreaID()
        
        -- No score in Strand of the Ancients, report instead end of round timer.
        if BGID == 512 then                                             -- Strand of the Ancients
                if UnitBuff("player", "Preparation") then
                        return L["Status: on preparation"]
                else 
                        local _, _, _, endTime = GetWorldStateUIInfo(8)
                        return endTime or ""
                end
        end     
        -- self:Print(BGID)
        local matchString               = BGMatchStrings[BGID] or "(%d+)"       
        local firstScoreLine    = BGFirstScoreLineArray[BGID] or 1
        local BGstatus                  = ""
                
        -- Get factions score from the lines that appear top-middle of the screen
        local _, _, _, text1, icon1 = GetWorldStateUIInfo(firstScoreLine)
        local _, _, _, text2, icon2 = GetWorldStateUIInfo(firstScoreLine+1)
        -- self:Print(select(4, GetWorldStateUIInfo(firstScoreLine)))
        local allianceScore     = tonumber((text1 or ""):match(matchString)) or "0"
        local hordeScore        = tonumber((text2 or ""):match(matchString)) or "0"
        
        -- Switch if first line is Horde and not Alliance
        if icon1:lower():match("horde") then    
                allianceScore, hordeScore = hordeScore, allianceScore
        end
        
        -- Check if leading or losing
        if allianceScore == hordeScore then
                BGstatus = L["Score: draw"]
        elseif (allianceScore > hordeScore and myBGFaction == 1) or (hordeScore > allianceScore and myBGFaction == 0) then
                BGstatus = L["Leading"]
        else
                BGstatus = L["Losing"]
        end

        if myBGFaction == 1 then
                return format(L["%s %d - %d"], BGstatus, allianceScore, hordeScore) -- Player is Alliance
        else
                return format(L["%s %d - %d"], BGstatus, hordeScore, allianceScore)     -- Player is Horde
        end
        
end

----------------------------------------
-- BG winner/loser
----------------------------------------
function AutoReply:UPDATE_BATTLEFIELD_STATUS()
        BGWinner = GetBattlefieldWinner()
        if BGWinner ~= nil then
                self:UnregisterEvent("UPDATE_BATTLEFIELD_STATUS")
        end
end

----------------------------------------
-- Get BG/Arena time
----------------------------------------
function AutoReply:GetPVPTime()
        
        local timeInPvP = SecondsToTime((GetBattlefieldInstanceRunTime() or 0)/1000, true)
        if (timeInPvP == "") then 
                timeInPvP = L["<1 min"]
        else
                timeInPvP = timeInPvP:gsub("|4(.-):.-;", "%1")  
        end
        
        return timeInPvP
end

----------------------------------------
-- Get arena status
----------------------------------------
function AutoReply:GetArenaStatus()
        
        -- Get player arena team: 0 = Green, 1 = Gold
        myBGFaction     = GetBattlefieldArenaFaction()
        
        -- If on preparation, the data is not valid yet
        if UnitBuff("player", "Arena Preparation") then
                return L["Status: on preparation"]
        end
        
        local myArenaFaction    = ""
        local numTeam                   = GetRealNumPartyMembers() + 1
        
        local _, _, _, team1Remain      = GetWorldStateUIInfo(1)
        local _, _, _, team2Remain      = GetWorldStateUIInfo(2)
        
        local numTeamRemain     = tonumber((team1Remain or ""):match("(%d+)")) or 0
        local numEnemyRemain    = tonumber((team2Remain or ""):match("(%d+)")) or 0
        
        if myBGFaction == 1 then
                myArenaFaction   = L["Gold"]
        else
                myArenaFaction   = L["Green"]
        end
        
        if team2Remain:match(myArenaFaction) then
                numTeamRemain, numEnemyRemain   = numEnemyRemain, numTeamRemain 
        end
        
        return format(L["Status: team: %d/%d, enemy: %d/%d"], numTeamRemain, numTeam, numEnemyRemain, numTeam)
end

--======================================
--======================================
-- INSTANCE DATA
--======================================
--======================================

----------------------------------------
-- Get current instance progress
----------------------------------------
function AutoReply:GetInstanceProgress(locationName)
        
                local numBosses         = 0
                local deadBosses        = 0
                local dungeonID
                                
                if (IsInLFGDungeon()) then
                        -- LFG instance                 
                        dungeonID       = GetPartyLFGID()
                        -- self:Print(dungeonID)
                        if dungeonID == 416 or dungeonID == 417 then
                                numBosses       = 4
                        else
                                numBosses       = GetLFGDungeonNumEncounters(dungeonID)
                        end
                        deadBosses      = self.numKilledBosses          
                else
                        -- Normal instance                      
                        for i = 1, GetNumSavedInstances() do
                                local instanceName, _, _, _, locked, _, _, _, _, _, maxBosses, defeatedBosses = GetSavedInstanceInfo(i)                         
                                if (instanceName == locationName) then                                  
                                        numBosses       = maxBosses
                                        if (locked) then
                                                deadBosses      = defeatedBosses
                                        else
                                                deadBosses      = 0
                                        end
                                        break
                                else
                                        -- dungeon without lockout
                                        deadBosses      = self.numKilledBosses
                                end
                        end
                end
                
                if numBosses == 0 then
                        return deadBosses
                else
                        return (deadBosses.."/"..numBosses)
                end
end

----------------------------------------
-- Get initial dungeon progress
----------------------------------------
function AutoReply:LFG_PROPOSAL_SHOW()
        local _, id, _, _, instanceName, _, _, _, _, completedEncounters = GetLFGProposal()     
        self.numKilledBosses    = completedEncounters
        if id == 416 or id == 417 then -- Siege of Wyrmrest Temple or Fall of Deathwing
                self.locationName       = L["Dragon Soul"] -- preset self.locationName in order to maintain self.numKilledBosses when changing zone.
        else
                self.locationName       = instanceName
        end
end

--======================================
--======================================
-- REPLY TO MISSED SENDERS
--======================================
--======================================

----------------------------------------
-- Out of combat event:
-- 1) Reply to all missed whisperers
-- 2) Check for boss kill
----------------------------------------
function AutoReply:PLAYER_REGEN_ENABLED()
        self:CheckBossKill("PLAYER_REGEN_ENABLED")
        if not self:CheckPlayerState ("", "") and not UnitIsDeadOrGhost("player") then          
                -- Reply whispers to all missed senders
                self:ReplyAllMissed()
        end
end

----------------------------------------
-- Zone Change event:
-- 1) Reset numKilledBosses on new instance
-- 2) Reply to all missed whisperers
----------------------------------------
function AutoReply:ZONE_CHANGED_NEW_AREA()
                
        -- If new instance, reset numKilledBosses
        if db.raidEn or db.dungeonEn then
                local locationName, instanceType = GetInstanceInfo()
                if instanceType ~= "none" and  self.locationName ~= locationName then
                        self.numKilledBosses    = 0
                end
        end

        -- Reply whispers to all missed senders
        if not self:CheckPlayerState ("", "") and not UnitIsDeadOrGhost("player") then
                self:ReplyAllMissed()
        end
        
        -- Clear PvP status for next time
        myBGFaction     = nil
        myBGName        = ""
        BGWinner        = nil
end

----------------------------------------
-- Back to life event:
----------------------------------------
function AutoReply:BackToLife()
        if not self:CheckPlayerState ("", "") and not UnitIsDeadOrGhost("player") then          
                -- Reply whispers to all missed senders
                self:ReplyAllMissed()
                self:UnregisterEvent("PLAYER_ALIVE")
                self:UnregisterEvent("PLAYER_UNGHOST")
        end
end

------------------------------------------------
-- Reply to all missed when becoming available
------------------------------------------------
function AutoReply:ReplyAllMissed()
        local winString = ""
        -- Check if enabled
        if next(self.missedSenders) ~= nil and db.replyWhisperersEn then 
                -- Compose done/available message
                local replyMsg = ""     
                
                if BGWinner and myBGFaction then
                        -- BG/Arena activity ended with winner                          
                        if BGWinner == 255 then
                                winString = L["resulted draw on"]
                        elseif BGWinner == myBGFaction then
                                winString = L["has won"]
                        else
                                winString = L["has lost"]
                        end
                        
                        if BGArenaActivity == 0 then
                                -- BG
                                replyMsg = format(L["%s%s %s %s BG!"], self.msgPrefix, UnitName("player"), winString, myBGName)
                        else
                                -- Arena
                                replyMsg = format(L["%s%s %s the Arena match!"], self.msgPrefix, UnitName("player"), winString)
                        end
                                                                                
                else                            
                        -- Not in BG/Arena
                        replyMsg = self.msgPrefix..UnitName("player")..L[" is available now."]
                end
                
                -- Send to missed senders list
                for sender in pairs(self.missedSenders) do              
                        if type(sender) == "number" or IsInInstance() or not sender:find("-") then -- Do not reply cross-realm whisperers when out of instance
                                self:SendReply(replyMsg, sender)
                        end
                end     
        end
        
        -- Always clear missed whisperers table
        wipe(self.missedSenders)
        
        -- Always clear PvP status for next time
        myBGFaction     = nil
        myBGName        = ""
        BGWinner        = nil   
end

---------------------------------------------------
-- Reply to all away missed when becoming not-away
---------------------------------------------------
function AutoReply:ReplyAllAwayMissed()
        
        -- Check if enabled
        if db.replyAwayWhisperersEn then 
                -- Compose done/available message
                local replyMsg = self.msgPrefix..UnitName("player")..L[" is no longer AFK."]    
                        
                -- Send to all missed whisperers
                for sender in pairs(self.missedAwaySenders) do          
                        self:SendReply(replyMsg, sender)
                end             
        end
                
        wipe(self.missedAwaySenders)
end

--======================================
--======================================
-- ADDON INITIALIZATION FUNCTIONS
--======================================
--======================================

----------------------------------------
-- Addon initializion
----------------------------------------
function AutoReply:OnInitialize()
    -- Called when the addon is loaded
        -----------------------------------
        
        -- Save configuration defaults in the addon's DB
        self.db = LibStub("AceDB-3.0"):New("AutoReplyDB", defaults, true)
        self.db.RegisterCallback(self, "OnProfileChanged", "RefreshConfig")
        self.db.RegisterCallback(self, "OnProfileCopied", "RefreshConfig")
        self.db.RegisterCallback(self, "OnProfileReset", "RefreshConfig")
        db              = self.db.profile
        dbChar  = self.db.char
        
        -- lib DataBroker
        ldb:NewDataObject("AutoReplyLDB", self.LDBobject)               
        
        -- LDB icon
        if not LDBIcon:IsRegistered("AutoReplyLDB") then 
                LDBIcon:Register("AutoReplyLDB", self.LDBobject, dbChar.minimapIcon) 
        end     
        
        -- Profile management
        self.profileOptions = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db)
        
        -- Register configuration options to Ace3
        LibStub("AceConfig-3.0"):RegisterOptionsTable("AutoReply", self.options)
        LibStub("AceConfig-3.0"):RegisterOptionsTable("AutoReplyProfiles", self.profileOptions)
        
        -- Add Configuration options to blizzard UI
        self.configPanel = AceConfigDialog:AddToBlizOptions("AutoReply", "AutoReply")
        self.configPanel.profilePanel = AceConfigDialog:AddToBlizOptions("AutoReplyProfiles", "Profiles", "AutoReply")
        AceConfigDialog:SetDefaultSize("AutoReply", 630, 620)
        
        -- Filter reply to hide it from chat frame
        ChatFrame_AddMessageEventFilter("CHAT_MSG_WHISPER_INFORM", self.filterReplyMsg)
        ChatFrame_AddMessageEventFilter("CHAT_MSG_BN_WHISPER_INFORM", self.filterReplyMsg)
        
        -- Slash commands
        self:RegisterChatCommand("aar", "SlashCommand")
    self:RegisterChatCommand("autoreply", "SlashCommand")
        
        -- Init missed whispers senders for LDB button color
        self.missed                             = false

        -- Addon message prefix
        self.msgPrefix  = "<AutoReply> "        
        
end

----------------------------------------
-- Slash commands
----------------------------------------
function AutoReply:ToggleConfigWindow()
        if ( InterfaceOptionsFrame:IsShown() ) then
        InterfaceOptionsFrame:Hide()
    else
        InterfaceOptionsFrame_OpenToCategory(self.configPanel.profilePanel)
                InterfaceOptionsFrame_OpenToCategory(self.configPanel)
    end 
end

function AutoReply:SlashCommand(input)
        if (input == "") then
                -- Open config panel
                self:ToggleConfigWindow()       
        elseif (input == "his") then
                -- Show history
                self:ToggleHistoryWindow()
        else
                self:Print([[Usage: "/aar" or "/aar his"]])             
        end
end

----------------------------------------
-- Refresh config
----------------------------------------
function AutoReply:RefreshConfig()
        db = self.db.profile
        -- LDBIcon:Refresh("AutoReplyLDB", dbChar.minimapIcon)
end

----------------------------------------
-- Addon enable/disable
----------------------------------------
function AutoReply:OnEnable()
        
        -- Init missed whispers senders
        if self.missedSenders           then wipe (self.missedSenders)          else self.missedSenders         = {} end
        if self.missedBossSenders       then wipe (self.missedBossSenders)      else self.missedBossSenders = {} end
        if self.missedAwaySenders       then wipe (self.missedAwaySenders)      else self.missedAwaySenders = {} end
                
        -- Init LFG instance progress
        self.numKilledBosses    = 0
        
        -- Init boss fight trakcing
        self.bossEngaged                = false
        self.bossName                   = L["Unknown"]
        self.bossNum                    = nil
        self.locationName               = ""
        self.checkBossKillTimer = nil
        
        -- Init PvP status for reply message
        myBGFaction                             = nil
        myBGName                                = ""
        BGWinner                                = nil
        BGArenaActivity                 = 0
        
        -- Register events
        self:RegisterEvent("CHAT_MSG_WHISPER")
        self:RegisterEvent("CHAT_MSG_BN_WHISPER")               
        self:RegisterEvent("LFG_PROPOSAL_SHOW")
        self:RegisterEvent("PLAYER_REGEN_DISABLED")
        self:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT")
        self:RegisterEvent("PLAYER_REGEN_ENABLED")
        self:RegisterEvent("ZONE_CHANGED_NEW_AREA")
        self:RegisterEvent("PLAYER_LOGOUT")
        self:RegisterEvent("PLAYER_FLAGS_CHANGED")      
end

function AutoReply:OnDisable()
    -- Unregister events
        self:UnregisterEvent("CHAT_MSG_WHISPER")
        self:UnregisterEvent("CHAT_MSG_BN_WHISPER")             
        self:UnregisterEvent("LFG_PROPOSAL_SHOW")
        self:UnregisterEvent("PLAYER_REGEN_DISABLED")
        self:UnregisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT")
        self:UnregisterEvent("PLAYER_REGEN_ENABLED")
        self:UnregisterEvent("ZONE_CHANGED_NEW_AREA")
        self:UnregisterEvent("PLAYER_LOGOUT")
        self:UnregisterEvent("PLAYER_FLAGS_CHANGED")
        self:UnregisterEvent("UPDATE_BATTLEFIELD_STATUS")
        self:UnregisterEvent("PLAYER_ALIVE")
        self:UnregisterEvent("PLAYER_UNGHOST")
        self:HandleBossFightEnd()       -- unregister boss fight events, cancel all timers
end

Compare with Previous | Blame