diff --git a/RaidSummon/Locales/RaidSummon-enUS.lua b/RaidSummon/Locales/RaidSummon-enUS.lua index 1a71150..5272b72 100644 --- a/RaidSummon/Locales/RaidSummon-enUS.lua +++ b/RaidSummon/Locales/RaidSummon-enUS.lua @@ -20,6 +20,9 @@ end L["MemberAdded"] = function(X,Y) return '|cff9482c9RaidSummon:|r Adding player ' .. X .. ' to the summoning frame as requested by ' .. Y end +L["MemberInRange"] = function(X) + return '|cff9482c9RaidSummon:|r Removing player ' .. X .. ' from the summoning frame, already in range' +end L["AddAllMessage"] = "|cff9482c9RaidSummon:|r Adding all players" --Options @@ -33,6 +36,8 @@ L["OptionFlashwindowName"] = "Flash Window" L["OptionFlashwindowDesc"] = "Flashes the Windows when someone requests a summon." L["OptionSummoningStoneName"] = "Summoning Stone" L["OptionSummoningStoneDesc"] = "Enable announcement when interacting with a Summoning Stone." +L["OptionAutoRemoveInRangeName"] = "Auto-Remove In Range" +L["OptionAutoRemoveInRangeDesc"] = "Automatically remove a player from the summoning frame once they're already within interact range of you (Warlock only)." L["OptionHelpName"] = "Help" L["OptionHelpDesc"] = "Shows a list of supported commands and options." L["OptionConfigName"] = "Config" @@ -80,6 +85,8 @@ L["OptionFlashwindowEnabled"] = "|cff9482c9RaidSummon:|r Option flash window |cf L["OptionFlashwindowDisabled"] = "|cff9482c9RaidSummon:|r Option flash window |cffff0000disabled|r" L["OptionSummoningStoneEnabled"] = "|cff9482c9RaidSummon:|r Option Summoning Stone |cff00ff00enabled|r" L["OptionSummoningStoneDisabled"] = "|cff9482c9RaidSummon:|r Option Summoning Stone |cffff0000disabled|r" +L["OptionAutoRemoveInRangeEnabled"] = "|cff9482c9RaidSummon:|r Option auto-remove in range |cff00ff00enabled|r" +L["OptionAutoRemoveInRangeDisabled"] = "|cff9482c9RaidSummon:|r Option auto-remove in range |cffff0000disabled|r" L["OptionHelpPrint"] = [[ |cff9482c9RaidSummon usage:|r /rs or /raidsummon { clear | config | help | list | add | addall | remove | toggle | whisper | zone | kwlist | kwadd | kwremove } diff --git a/RaidSummon/RaidSummon.lua b/RaidSummon/RaidSummon.lua index 810d21c..5e906cb 100644 --- a/RaidSummon/RaidSummon.lua +++ b/RaidSummon/RaidSummon.lua @@ -1,5 +1,8 @@ RaidSummon = LibStub("AceAddon-3.0"):NewAddon("RaidSummon", "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0", "AceComm-3.0") local L = LibStub("AceLocale-3.0"):GetLocale("RaidSummon", true) +-- Classic Era's latest patch moved GetAddOnMetadata to C_AddOns; fall +-- back to the old global for clients that haven't made the switch. +local GetAddOnMetadata = (C_AddOns and C_AddOns.GetAddOnMetadata) or GetAddOnMetadata --set options local options = { @@ -53,6 +56,14 @@ local options = { set = "SetOptionSummoningStone", order = 15, }, + autoremoveinrange = { + type = "toggle", + name = L["OptionAutoRemoveInRangeName"], + desc = L["OptionAutoRemoveInRangeDesc"], + get = "GetOptionAutoRemoveInRange", + set = "SetOptionAutoRemoveInRange", + order = 16, + }, } }, commands = { @@ -187,10 +198,16 @@ local defaults = { zone = true, flashwindow = true, keywordsinit = false, - summoningstone = true + summoningstone = true, + autoremoveinrange = true } } +-- CheckInteractDistance's follow-range index (confirmed working on the +-- current client). Interval in seconds between range checks. +local AUTO_REMOVE_DISTANCE_INDEX = 4 +local AUTO_REMOVE_CHECK_INTERVAL = 2 + function RaidSummon:OnEnable() self:Print(L["AddonEnabled"](GetAddOnMetadata("RaidSummon", "Version"), GetAddOnMetadata("RaidSummon", "Author"))) self:RegisterEvent("GROUP_JOINED", "GroupEvent") @@ -204,6 +221,15 @@ function RaidSummon:OnEnable() self:RegisterEvent("CHAT_MSG_WHISPER", "msgParser") self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START") + -- Auto-remove queued players once they're back in range. Only + -- meaningful from the summoner's own position, so Warlock-only (a + -- non-Warlock's proximity to a queued player says nothing about + -- whether the Warlock still needs to summon them). + local _, playerClassFilename = UnitClass("player") + if playerClassFilename == "WARLOCK" then + self.autoRemoveInRangeTimer = self:ScheduleRepeatingTimer("CheckQueueRange", AUTO_REMOVE_CHECK_INTERVAL) + end + --Blizzard Menu Menu.ModifyMenu("MENU_UNIT_RAID_PLAYER", function(ownerRegion, rootDescription, contextData) -- Append a new section to the end of the menu. @@ -227,6 +253,10 @@ end function RaidSummon:OnDisable() self:Print(L["AddonDisabled"]) + if self.autoRemoveInRangeTimer then + self:CancelTimer(self.autoRemoveInRangeTimer) + self.autoRemoveInRangeTimer = nil + end RaidSummonSyncDB = {} end @@ -340,6 +370,31 @@ function RaidSummon:UNIT_SPELLCAST_CHANNEL_START(eventName,...) end end +--Periodically drops queued players who are already back in interact +--range. Only runs for Warlocks (see OnEnable) since range only means +--anything relative to the summoner's own position. +function RaidSummon:CheckQueueRange() + if not self.db.profile.autoremoveinrange then + return + end + if not IsInRaid() or not RaidSummonSyncDB or not RaidSummonSyncDB[1] then + return + end + + --copy first: table.remove while iterating would skip entries + local inRange = {} + for i, v in ipairs(RaidSummonSyncDB) do + if UnitExists(v) and CheckInteractDistance(v, AUTO_REMOVE_DISTANCE_INDEX) then + table.insert(inRange, v) + end + end + + for _, v in ipairs(inRange) do + print(L["MemberInRange"](v)) + RaidSummon:SendCommMessage(COMM_PREFIX_REMOVE, v, "RAID") + end +end + --Ace3 Comm function RaidSummon:OnCommReceived(prefix, message, distribution, sender) if (prefix) then @@ -449,27 +504,13 @@ function RaidSummon:NameListButton_PreClick(source, button) RaidSummon:getRaidMembers() - if RaidSummonRaidMembersDB then - for i, v in ipairs (RaidSummonRaidMembersDB) do - if v.rName == name then - raidIndex = "raid"..v.rIndex - end - end - - if raidIndex then - --set target when not in combat (securetemplate) - if not InCombatLockdown() then - if RaidSummonRaidMembersDB then - source:SetAttribute("type1", "target") - source:SetAttribute("unit", raidIndex) - end - source:SetAttribute("type2", "spell") - source:SetAttribute("spell", "698") --698 - Ritual of Summoning - else - print(L["Lockdown"]) - end - end - end + -- Secure attributes (type1/macrotext1/type2/macrotext2) are staged + -- once in UpdateList() when the button's name/text is set, not here. + -- Re-staging in PreClick on every click did not reliably take effect + -- in time for the same click to use. Attributes staged before combat + -- remain valid through combat, so clicking still works mid-fight + -- even though UpdateList() itself can't restage anything new while + -- InCombatLockdown() is true. if buttonName == "RightButton" and targetname ~= nil and not InCombatLockdown() then @@ -567,14 +608,33 @@ function RaidSummon:UpdateList() end if not InCombatLockdown() then - _G["RaidSummon_NameList"..i]:Show() + -- Stage secure attributes here, once, when the list is + -- built, rather than inside a PreClick handler on every + -- click. Re-staging in PreClick (the old approach) did not + -- reliably take effect in time for the same click to use. + local btn = _G["RaidSummon_NameList"..i] + local rName = RaidSummonBrowseDB[i].rName + local ritualSpellName = GetSpellInfo(698) --698 - Ritual of Summoning + btn:SetAttribute("unit", nil) + btn:SetAttribute("type1", "macro") + btn:SetAttribute("macrotext1", "/target "..rName) + if ritualSpellName then + btn:SetAttribute("type2", "macro") + btn:SetAttribute("macrotext2", "/target "..rName.."\n/cast "..ritualSpellName) + end + btn:Show() else RaidSummon:UpdateListCombatCheck() end else if not InCombatLockdown() then _G["RaidSummon_NameList"..i.."TextName"]:SetText("") - _G["RaidSummon_NameList"..i]:Hide() + local btn = _G["RaidSummon_NameList"..i] + btn:SetAttribute("type1", nil) + btn:SetAttribute("macrotext1", nil) + btn:SetAttribute("type2", nil) + btn:SetAttribute("macrotext2", nil) + btn:Hide() else RaidSummon:UpdateListCombatCheck() end @@ -605,15 +665,37 @@ function RaidSummon:getRaidMembers() if (members > 0) then RaidSummonRaidMembersDB = {} + -- GetRaidRosterInfo(i)'s index is the roster LIST position, + -- which is not guaranteed to match the "raidN" unit token + -- (actual subgroup slot). They only coincidentally line up + -- for some raid compositions. Resolve rIndex from the actual + -- unit token instead of trusting the roster-list position. for i = 1, members do local rName, rRank, rSubgroup, rLevel, rClass, rfileName = GetRaidRosterInfo(i) if rName and rClass and rfileName then - RaidSummonRaidMembersDB[i] = {} - RaidSummonRaidMembersDB[i].rIndex = i - RaidSummonRaidMembersDB[i].rName = rName - RaidSummonRaidMembersDB[i].rClass = rClass - RaidSummonRaidMembersDB[i].rfileName = rfileName + -- Prefer the verified "raidN" unit token, but fall + -- back to the roster-list position if it can't be + -- cross-matched (e.g. a name mismatch between + -- GetRaidRosterInfo and UnitName for names with + -- accented/special characters) -- dropping the + -- member entirely instead left a hole in this + -- array, which silently truncated every ipairs() + -- loop over it after the first unmatched member. + local unitToken + for u = 1, MAX_RAID_MEMBERS do + if UnitName("raid"..u) == rName then + unitToken = u + break + end + end + + table.insert(RaidSummonRaidMembersDB, { + rIndex = unitToken or i, + rName = rName, + rClass = rClass, + rfileName = rfileName, + }) end end end @@ -741,6 +823,10 @@ function RaidSummon:GetOptionSummoningStone(info) return self.db.profile.summoningstone end +function RaidSummon:GetOptionAutoRemoveInRange(info) + return self.db.profile.autoremoveinrange +end + function RaidSummon:SetOptionWhisper(info, value) self.db.profile.whisper = value if value == true then @@ -786,6 +872,15 @@ function RaidSummon:SetOptionSummoningStone(info, value) end end +function RaidSummon:SetOptionAutoRemoveInRange(info, value) + self.db.profile.autoremoveinrange = value + if value == true then + print(L["OptionAutoRemoveInRangeEnabled"]) + else + print(L["OptionAutoRemoveInRangeDisabled"]) + end +end + function RaidSummon:ExecuteHelp() print(L["OptionHelpPrint"]) end diff --git a/RaidSummon/RaidSummon.xml b/RaidSummon/RaidSummon.xml index 20158c4..e8bb7ad 100644 --- a/RaidSummon/RaidSummon.xml +++ b/RaidSummon/RaidSummon.xml @@ -1,5 +1,9 @@ -