WoWInterface SVN AutoReply

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 16 to Rev 15
    Reverse comparison

Rev 16 → Rev 15

trunk/HistoryFrame.lua
8,8 → 8,7
----------------------------------------
-- Libs
----------------------------------------
local AutoReply = LibStub("AceAddon-3.0"):GetAddon("AutoReply")
local L = LibStub("AceLocale-3.0"):GetLocale("AutoReply")
local L = LibStub("AceLocale-3.0"):GetLocale("AutoReply")
 
----------------------------------------
-- Backdrop templates
106,44 → 105,6
frame.closeButton = closeButton
 
----------------------------------------
-- Clear history button
----------------------------------------
local clearButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
 
clearButton.buttonUpTexture = clearButton:CreateTexture(nil, nil, "UIPanelButtonUpTexture")
clearButton.buttonUpTexture:SetAlpha(0.7)
clearButton:SetNormalTexture(clearButton.buttonUpTexture)
 
clearButton.buttonDownTexture = clearButton:CreateTexture(nil, nil, "UIPanelButtonDownTexture")
clearButton.buttonDownTexture:SetAlpha(0.7)
clearButton:SetPushedTexture(clearButton.buttonDownTexture)
 
clearButton:SetNormalFontObject("GameFontDisable")
-- clearButton:SetHighlightFontObject("GameFontHighlight")
 
clearButton:SetPoint("BOTTOMLEFT", 15, 15)
clearButton:SetHeight(22)
clearButton:SetWidth(95)
clearButton:SetText(L["Clear History"])
clearButton:SetScript("OnClick", function(self)
StaticPopupDialogs["AutoReply clear history"] = {
text = L["Are you sure you want to clear the history?"],
button1 = ACCEPT,
button2 = CANCEL,
timeout = 0,
whileDead = true,
hideOnEscape= true,
OnAccept = function()
AutoReply:ClearHistory()
end,
}
AutoReplyHistoryDialog = StaticPopup_Show("AutoReply clear history")
AutoReplyHistoryDialog:SetFrameStrata("TOOLTIP")
end)
 
frame.clearButton = clearButton
 
----------------------------------------
-- Inner frame
----------------------------------------
local innerFRame = CreateFrame("Frame", nil, frame)
trunk/Locales/enUS.lua
25,8 → 25,8
L["Auto reply same whisperer only once per busy session"] = true
L["Also to party/raid members"] = true
L["Auto reply also to party/raid members"] = true
L["Notify missed whisperers when available"] = true
L["Notify missed whisperers when becoming available (except for AFK)."]= true
L["Notify missed whisperes when available"] = true
L["Notify missed whisperes when becoming available (except for AFK)."]= true
L["Hide minimap icon"] = true
L["Hide auto reply from chat"] = true
L["Hide auto reply from the player's chat frame"] = true
35,7 → 35,7
L["AFK"] = true
L["Save missed whispers also when AFK"] = true
L["Save missed whispers also when away/AFK"] = true
L["Notify missed whisperers when no longer AFK"] = true
L["Notify missed whisperes when no longer AFK"] = true
L[" is no longer AFK."] = true
 
-- Death
82,11 → 82,6
L["Uncheck this if you run Boss mods and want to avoid double auto replies"]= true
L["Reply message during raid boss fights:"] = true
L["%PN (%PHP) is busy raiding %LOC, now fighting boss %BN (%BHP)."]= true
L["Unknown"] = true
L["Dragon Soul"] = true -- raid name
L["Warmaster Blackhorn"] = true
L["Spine of Deathwing"] = true
L["Madness of Deathwing"] = true
 
-- 5men Dungeons
L["Dungeons"] = true
134,8 → 129,6
L["Status: on preparation"] = true
L["Status: team: %d/%d, enemy: %d/%d"] = true
L["%s%s %s the Arena match!"] = true
L["Gold"] = true -- arend team color
L["Green"] = true -- arena team color
 
-- Done messages
L[" has been defeated by "] = true
trunk/AutoReply.toc
1,7 → 1,7
## Interface: 40300
## Author: Animor
## Title: Animor's AutoReply
## Version: 1.0
## Version: 0.9.04
## Notes: Auto reply whispers in specific combat related situations.
## OptionalDeps: Ace3, Recount, LibDataBroker-1.1
## X-Embeds: Ace3, LibDataBroker-1.1
trunk/BossFight.lua
14,10 → 14,6
----------------------------------------
-- Local variables
----------------------------------------
 
-- Debug messages
local debug = nil
 
-- Boss IDs (for encounters without INSTANCE_ENCOUNTER_ENGAGE_UNIT)
local bossIDList = {
54431, -- Echo of Baine
36,21 → 32,6
46254, -- Hogger
}
 
-- Extract encounter name from mobs names that appear in boss frame
local bossMobs = {
-- Warmaster Blackhorn
[56598] = L["Warmaster Blackhorn"], -- The Skyfire
 
-- Spine of Deathwing
[53879] = L["Spine of Deathwing"], -- Deathwing
 
-- Madness of Deathwing
[56846] = L["Madness of Deathwing"], -- Arm Tentacle
[56167] = L["Madness of Deathwing"], -- Arm Tentacle
[56471] = L["Madness of Deathwing"], -- Mutated Corruption
[56168] = L["Madness of Deathwing"], -- Wing Tentacle
}
 
--======================================
--======================================
-- BOSS FIGHT FUNCTIONS
61,6 → 42,7
-- Unit died or distroyed
----------------------------------------
function AutoReply:COMBAT_LOG_EVENT_UNFILTERED(_, _, subevent, ...)
-- self:Print(subevent)
if subevent == "UNIT_DIED" or subevent == "UNIT_DESTROYED" then
self:CheckBossKill(subevent)
end
95,42 → 77,39
-- Check if boss fight started
----------------------------------------
function AutoReply:CheckBossFightStart()
if not self.bossEngaged then
local bossEngaged, targetInCombat = self:BossEngaged()
if bossEngaged then
-- Boss fight start
if debug then self:Print("boss fight start") end
self.bossEngaged = true
self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
self:RegisterEvent("CHAT_MSG_MONSTER_YELL", "CheckBossKill")
self:RegisterEvent("CHAT_MSG_MONSTER_EMOTE", "CheckBossKill")
self:RegisterEvent("RAID_BOSS_EMOTE", "CheckBossKill")
self:RegisterEvent("CHAT_MSG_MONSTER_SAY", "CheckBossKill")
-- self:Print("ScheduleTimer CheckBossWipe - first")
self:ScheduleTimer("CheckBossWipe", 3)
elseif (not targetInCombat) and UnitAffectingCombat("player") then
-- If boss encounter starts before the boss was targetted or before the boss is in combat, schedule boss fight check again.
-- self:Print("ScheduleTimer CheckBossFightStart")
self:ScheduleTimer("CheckBossFightStart", 3)
end
local bossAlive, targetExist = self:BossAlive()
if bossAlive then
-- Boss fight start
-- self:Print("boss fight start")
self.bossEngaged = true
self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
self:RegisterEvent("CHAT_MSG_MONSTER_YELL", "CheckBossKill")
self:RegisterEvent("CHAT_MSG_MONSTER_EMOTE", "CheckBossKill")
self:RegisterEvent("RAID_BOSS_EMOTE", "CheckBossKill")
self:RegisterEvent("CHAT_MSG_MONSTER_SAY", "CheckBossKill")
 
-- self:Print("ScheduleTimer CheckBossWipe - first")
self:ScheduleTimer("CheckBossWipe", 3)
elseif (not targetExist) and UnitAffectingCombat("player") then
-- If boss encounter starts before the boss was targetted, schedule boss fight check again.
-- self:Print("ScheduleTimer CheckBossFightStart")
self:ScheduleTimer("CheckBossFightStart", 3)
end
end
 
----------------------------------------
-- Check for boss fight wipe
----------------------------------------
function AutoReply:CheckBossWipe(confirm)
function AutoReply:CheckBossWipe(confirm)
 
if self.bossEngaged then
local allBossesDead, bossFound = self:AllBossesDead()
if self:GroupInCombat() or (bossFound and not allBossesDead) then
-- No wipe (schedule wipe check again) if:
-- 1) Still in combat.
-- 2) Encountered started and Boss appeared, but out of combat yet.
if self:GroupInCombat() then
-- Still in combat, schedule check again
-- self:Print("ScheduleTimer CheckBossWipe")
self:ScheduleTimer("CheckBossWipe", 3)
elseif confirm then
-- Boss fight wipe
if debug then self:Print("boss fight: wipe") end
-- self:Print("boss fight: wipe")
self:ReplyAllMissedBoss("wipe")
self:HandleBossFightEnd()
else
145,11 → 124,9
-- Perform when boss fight ends (wipe/kill)
--------------------------------------------
function AutoReply:HandleBossFightEnd()
self.bossEngaged = false
self.bossNum = nil
self.bossName = L["Unknown"]
self:CancelAllTimers()
self.checkBossKillTimer = nil
self.bossEngaged = false
self.bossID = nil
self.bossName = "Unknown"
self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
self:UnregisterEvent("CHAT_MSG_MONSTER_YELL")
self:UnregisterEvent("CHAT_MSG_MONSTER_EMOTE")
160,43 → 137,27
----------------------------------------
-- Check if boss is alive
----------------------------------------
function AutoReply:BossEngaged()
local bossEngaged = false
local targetInCombat = false
local bossNum = ""
local bossID = ""
 
function AutoReply:BossAlive()
local bossAlive = false
local targetExist = false
 
-- Check for boss frame
for i = 1, MAX_BOSS_FRAMES do
bossNum = "boss"..i
if UnitExists(bossNum) and not UnitIsDead(bossNum) then -- no need to check UnitAffectingCombat for boss frames (some of them may be friendly).
bossEngaged = true
if UnitAffectingCombat(bossNum) then
targetInCombat = true
end
self.bossNum = bossNum
 
-- Try to match mob name to real boss name
bossID = self:GetUnitId(bossNum)
for mobID, bossName in pairs(bossMobs) do
if mobID == bossID then
self.bossName = bossName
break
end
end
 
-- If mob name wasn't matched, use unit name.
if self.bossName == L["Unknown"] then self.bossName = UnitName(bossNum) end
if (UnitExists("boss"..i) and not UnitIsDead("boss"..i)) then
bossAlive = true
targetExist = true
self.bossID = "boss"..i
self.bossName = UnitName("boss"..i)
break
end
end
 
-- Manual check targets, for bosses without boss frame
if not bossEngaged then
bossEngaged, targetInCombat = self:CheckTargetBoss()
if not bossAlive then
bossAlive, targetExist = self:CheckTargetBoss()
end
 
return bossEngaged, targetInCombat
return bossAlive, targetExist
end
 
----------------------------------------
206,6 → 167,7
local allBossesDead = true
local bossFound = false
local bossAlive = false
local targetExist = false
 
-- Check for boss frame
for i = 1, MAX_BOSS_FRAMES do
219,8 → 181,8
 
-- Manual check targets, for bosses without boss frame
if not bossFound then
_, _, bossFound, bossAlive = self:CheckTargetBoss()
if bossAlive or not bossFound then
bossAlive, targetExist, bossFound = self:CheckTargetBoss()
if bossAlive or (not bossFound) then
allBossesDead = false
end
end
228,80 → 190,21
return allBossesDead, bossFound
end
 
---------------------------------------------
-- Manual check targets for boss
-- Returns bossEngaged, targetInCombat, bossFound, bossAlive
---------------------------------------------
function AutoReply:CheckTargetBoss()
local targetInCombat = false
local bossFound = false
local bossAlive = false
local unitId = ((GetNumRaidMembers() == 0) and "party") or "raid"
local target = nil
local targetUnitID = nil
 
for i = 0, math.max(GetNumRaidMembers(), GetNumPartyMembers()) do
target = (i == 0 and "playertarget") or unitId..i.."target"
if UnitExists(target) and not UnitIsPlayer(target) then
if UnitAffectingCombat(target) then
targetInCombat = true
end
if UnitClassification(target) == "worldboss" then
-- worldboss
bossFound = true -- boss found (dead/alive/in combat)
if not UnitIsDead(target) then
bossAlive = true -- boss is alive
end
if UnitAffectingCombat(target) then -- boss is in combat
if self.bossName == L["Unknown"] then self.bossName = UnitName(target) end
return true, targetInCombat, bossFound, bossAlive
end
else
-- check against boss ID list
targetUnitID = self:GetUnitId(target)
-- for _, bossID in pairs(bossIDList) do
for i = 1, #bossIDList do
if targetUnitID == bossIDList[i] then
bossFound = true -- boss found (dead/alive/in combat)
if not UnitIsDead(target) then
bossAlive = true -- boss is alive
end
if UnitAffectingCombat(target) then -- boss is in combat
if self.bossName == L["Unknown"] then self.bossName = UnitName(target) end
return true, targetInCombat, bossFound, bossAlive
end
end
end
end
end
end
 
return false, targetInCombat, bossFound, bossAlive
end
 
----------------------------------------
-- Check for boss fight end
----------------------------------------
function AutoReply:CheckBossKill(eventname)
if debug then self:Print(eventname) end
-- self:Print(eventname)
if self.bossEngaged and (not UnitAffectingCombat("player")) and (self.db.profile.raidEn or self.db.profile.dungeonEn) then
if debug then self:Print("CheckBossKill") end -- debug
-- self:Print("CheckBossKill")
local allBossesDead, bossFound = self:AllBossesDead()
if debug then self:Print(allBossesDead) end -- debug
if allBossesDead or ((not bossFound) and self:GroupSurvived()) then
if debug then self:Print("boss fight: kill") end -- debug
if allBossesDead or (self:GroupSurvived() and not bossFound) then
-- self:Print("boss fight: kill")
self.numKilledBosses = self.numKilledBosses + 1
self:ReplyAllMissedBoss("kill")
self:ReplyAllMissedBoss("kill")
self:HandleBossFightEnd()
-- Reschedule kill check in case:
-- 1) Player is dead (so no PLAYER_REGEN_DISABLED will trigger when out of combat).
-- 2) Boss is down and its frame/body vanish
-- 3) Other players are still in combat for some time until the encounter ends.
elseif (not bossFound) and self:GroupInCombat() and
((not self:TimeLeft(self.checkBossKillTimer)) or self:TimeLeft(self.checkBossKillTimer) <= 0.1) then -- Do not schedule more than one at a time.
self.checkBossKillTimer = self:ScheduleTimer("CheckBossKill", 0.5)
end
end
end
end
 
--------------------------------------
311,7 → 214,7
local unitId = ((GetNumRaidMembers() == 0) and "party") or "raid"
for i = 0, math.max(GetNumRaidMembers(), GetNumPartyMembers()) do
local id = (i == 0 and "player") or unitId..i
if UnitAffectingCombat(id) and UnitIsVisible(id) and not UnitIsDeadOrGhost(id) then
if UnitAffectingCombat(id) and not UnitIsDeadOrGhost(id) then
return true
end
end
329,14 → 232,56
-- Check if player is out of combat and didn't use any feign death ability to reset the boss.
-- Check in addition if player is in 100 yard range.
if UnitIsVisible(id) and not (UnitAffectingCombat(id) or UnitIsDeadOrGhost(id) or UnitIsFeignDeath(id) or
UnitAura(id, "Vanish") or UnitAura(id, "Invisibility") or UnitAura(id, "Shadowmeld") or UnitAura(id, "Spirit of Redemption")) then
if debug then self:Print(GetUnitName(id)) end
UnitAura(id, "Vanish") or UnitAura(id, "Invisibility") or UnitAura(id, "Shadowmeld")) then
-- self:Print(UnitName(id))
return true
end
end
return false
end
 
---------------------------------------------
-- Manual check targets for boss
-- Returns bossAlive, targetExist, bossFound
---------------------------------------------
function AutoReply:CheckTargetBoss()
local targetExist = false
local bossFound = false
local unitId = ((GetNumRaidMembers() == 0) and "party") or "raid"
local target = nil
local targetUnitID = nil
 
for i = 0, math.max(GetNumRaidMembers(), GetNumPartyMembers()) do
target = (i == 0 and "playertarget") or unitId..i.."target"
if UnitExists(target) and not UnitIsPlayer(target) then
-- if UnitExists(target) and not UnitIsDead(target) and not UnitIsPlayer(target) then
targetExist = true
if UnitClassification(target) == "worldboss" then
-- worldboss
bossFound = true
if not UnitIsDead(target) then
if self.bossName == "Unknown" then self.bossName = UnitName(target) end
return true, targetExist, bossFound
end
else
-- check against boss ID list
targetUnitID = self:GetUnitId(target)
for _, unitID in pairs(bossIDList) do
if targetUnitID == unitID then
bossFound = true
if not UnitIsDead(target) then
if self.bossName == "Unknown" then self.bossName = UnitName(target) end
return true, targetExist, bossFound
end
end
end
end
end
end
 
return false, targetExist, bossFound
end
 
----------------------------------------
-- Get unit ID
----------------------------------------
trunk/Core.lua
138,8 → 138,8
local locationName = ""
local instanceType = ""
 
-- Check that message doesn't start with addons prefix.
if not (msg:find("^<.*>") or msg:find("^%[.*%]")) then
-- Check that message doesn't start with addons prefix.
if not (msg:find(self.msgPrefix) or msg:find("^<DBM>") or msg:find("^<Deadly Boss Mods>") or msg:find("^<BW>")) then
locationName, instanceType = GetInstanceInfo()
-- Open world location
if instanceType == "none" then
248,11 → 248,8
----------------------------------------
-- 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
function AutoReply:CHAT_MSG_WHISPER(_, msg, sender)
self:HandleWhisper(msg, sender)
end
 
----------------------------------------
265,7 → 262,7
end
 
----------------------------------------
-- Reply to all away missed whisperers
-- Reply to all away missed whisperes
----------------------------------------
function AutoReply:PLAYER_FLAGS_CHANGED()
-- Reply whispers to all missed away senders
297,22 → 294,22
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("%%TN", "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).."%%")
if self.bossID then
msg = msg:gsub("%%BHP", math.floor(UnitHealth(self.bossID)/UnitHealthMax(self.bossID)*100).."%%")
else
msg = msg:gsub("%s*%(?%%BHP%)?", "")
end
end
 
msg = self.msgPrefix..msg
--self:Print(msg)
return msg
end
 
320,6 → 317,7
-- Send reply
----------------------------------------
function AutoReply:SendReply(replyMsg, target)
--self:Print(replyMsg)
if type(target) == "number" and select(7, BNGetFriendInfoByID(target)) then -- check if BN friend is online
BNSendWhisper(target, replyMsg)
elseif type(target) == "string" then
422,9 → 420,9
if AutoReplyHistory:IsShown() then
-- If already shown, then hide
AutoReplyHistory:Hide()
AutoReplyHistory.messageFrame:Clear()
else
-- Add messages from DB in history window
-- Add messages from DB in history window
AutoReplyHistory.messageFrame:Clear()
for idx, value in pairs(dbChar.msgHistory) do
if (value.sender == "_") then
AutoReplyHistory.messageFrame:AddMessage(string.rep("_", 30))
462,7 → 460,6
----------------------------------------
function AutoReply:ClearHistory()
wipe (dbChar.msgHistory)
AutoReplyHistory.messageFrame:Clear()
self:Print(L["Missed whispers history was cleared."])
end
 
634,9 → 631,9
local numEnemyRemain = tonumber((team2Remain or ""):match("(%d+)")) or 0
 
if myBGFaction == 1 then
myArenaFaction = L["Gold"]
myArenaFaction = "Gold"
else
myArenaFaction = L["Green"]
myArenaFaction = "Green"
end
 
if team2Remain:match(myArenaFaction) then
704,7 → 701,7
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.
self.locationName = "Dragon Soul"
else
self.locationName = instanceName
end
718,7 → 715,7
 
----------------------------------------
-- Out of combat event:
-- 1) Reply to all missed whisperers
-- 1) Reply to all missed whisperes
-- 2) Check for boss kill
----------------------------------------
function AutoReply:PLAYER_REGEN_ENABLED()
732,27 → 729,22
----------------------------------------
-- Zone Change event:
-- 1) Reset numKilledBosses on new instance
-- 2) Reply to all missed whisperers
-- 2) Reply to all missed whisperes
----------------------------------------
function AutoReply:ZONE_CHANGED_NEW_AREA()
 
-- If new instance, reset numKilledBosses
if db.raidEn or db.dungeonEn then
 
-- If new instance, reset numKilledBosses
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()
-- Reply whispers to all missed senders
if not self:CheckPlayerState ("", "") and not UnitIsDeadOrGhost("player") then
self:ReplyAllMissed()
end
end
 
-- Clear PvP status for next time
myBGFaction = nil
myBGName = ""
BGWinner = nil
end
 
----------------------------------------
802,7 → 794,7
 
-- 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
if type(sender) == "number" or IsInInstance() or not sender:find("-") then -- Do not reply cross-realm whisperes when out of instance
self:SendReply(replyMsg, sender)
end
end
940,10 → 932,9
 
-- Init boss fight trakcing
self.bossEngaged = false
self.bossName = L["Unknown"]
self.bossNum = nil
self.bossName = "Unknown"
self.bossID = nil
self.locationName = ""
self.checkBossKillTimer = nil
 
-- Init PvP status for reply message
myBGFaction = nil
977,5 → 968,6
self:UnregisterEvent("UPDATE_BATTLEFIELD_STATUS")
self:UnregisterEvent("PLAYER_ALIVE")
self:UnregisterEvent("PLAYER_UNGHOST")
self:HandleBossFightEnd() -- unregister boss fight events, cancel all timers
self:HandleBossFightEnd() -- unregister boss fight events
self:CancelAllTimers()
end
trunk/Options.lua
83,8 → 83,8
replyWhisperersEn = {
order = 3,
type = "toggle",
name = L["Notify missed whisperers when available"],
desc = L["Notify missed whisperers when becoming available (except for AFK)."],
name = L["Notify missed whisperes when available"],
desc = L["Notify missed whisperes when becoming available (except for AFK)."],
width = "double",
disabled = function(info) return not AutoReply.db.profile.globalEn end,
},
136,8 → 136,8
replyAwayWhisperersEn = {
order = 7.4,
type = "toggle",
name = L["Notify missed whisperers when no longer AFK"],
desc = L["Notify missed whisperers when no longer AFK"],
name = L["Notify missed whisperes when no longer AFK"],
desc = L["Notify missed whisperes when no longer AFK"],
width = "double",
disabled = function(info) return not (AutoReply.db.profile.awayHistoryEn and AutoReply.db.profile.globalEn) end,
},