diff --git a/EllesmereUIQoL/EUI_QoL_RaidTools_Options.lua b/EllesmereUIQoL/EUI_QoL_RaidTools_Options.lua index f1afe383..2900131c 100644 --- a/EllesmereUIQoL/EUI_QoL_RaidTools_Options.lua +++ b/EllesmereUIQoL/EUI_QoL_RaidTools_Options.lua @@ -91,7 +91,7 @@ initFrame:SetScript("OnEvent", function(self) local kbRow kbRow, h = W:DualRow(parent, y, { type = "dropdown", text = "Show Raid Tools", - tooltip = "A raid control panel with ready check, pull timer and raid markers.", + tooltip = "A raid control panel with ready check, pull timer and raid markers. In a raid it only shows while you are the leader or an assistant, since none of its buttons work without that; in a party it always shows.", values = { never = "Never", raid = "In Raid Group", group = "In Any Group", always = "Always" }, order = { "never", "raid", "group", "always" }, diff --git a/EllesmereUIQoL/EllesmereUIQoL_RaidTools.lua b/EllesmereUIQoL/EllesmereUIQoL_RaidTools.lua index d1bdb195..094d912b 100644 --- a/EllesmereUIQoL/EllesmereUIQoL_RaidTools.lua +++ b/EllesmereUIQoL/EllesmereUIQoL_RaidTools.lua @@ -15,6 +15,12 @@ -- "always" -- always shown (no driver; the visible attribute just stays -- true). -- +-- On top of the mode sits ONE unconditional gate: in a raid without leader or +-- assist the whole feature is off the screen, because the server refuses +-- every button on it there. It is raid-only (a party has no assistants) and +-- Lua-side, since no macro conditional can express it -- see AssistSuppressed +-- and RefreshAssistGate. +-- -- The Toggle Raid Tools keybind works in every active mode, and what it -- toggles follows Default to Collapsed When Shown: with it ON the key rocks -- between the collapsed icon and the full windows (the icon is the minimized @@ -218,6 +224,7 @@ end local db local applyPending -- true when combat blocked an Apply() local previewOn = false -- Raid Tools settings page is in front (see ApplyVisibility) +local lastSuppressed -- assist gate verdict currently ON SCREEN (see AssistSuppressed) local toggleButton -- keybind target; also the out-of-combat path local sections = {} -- key -> shell frame local shellTitle = {} -- key -> title fontstring @@ -578,6 +585,24 @@ local function IsLeader() return UnitIsGroupLeader("player") end +-- In a RAID, every control on the panel needs leader or assist: ready check, +-- role check, the countdown, convert, disband and the marker buttons are all +-- refused by the server without it. So the feature steps off the screen there +-- instead of sitting around fully dimmed. +-- +-- Raid only, deliberately. A party has no assistants -- UnitIsGroupAssistant +-- is false for everyone in one -- so the same test would hide the panel from +-- every non-leader in a 5-man, where marking is open to all of them. +-- +-- There is no macro conditional for leader/assist, so NO state driver can +-- express this: the gate is Lua's, it lands on the enabled attribute, and a +-- promotion mid-combat is picked up on PLAYER_REGEN_ENABLED like every other +-- Lua-side change (see the combat model in the header). +local function AssistSuppressed() + if previewOn then return false end -- configuring the thing beats hiding it + return IsInRaid() and not HasAssist() +end + -- Durations are the only pull-timer setting that can change at runtime: the -- button count is fixed at build, so re-labelling is all it takes. local function RefreshPullTimes() @@ -1137,10 +1162,14 @@ local function ApplyVisibility() -- Which SHELLS may show, straight from Show as: the Group shell is the -- window everywhere except Markers-only; the Markers shell exists only in -- Two Windows and Markers-only. + -- + -- The assist gate rides on top of that and takes ALL of them, icon + -- included -- a raid without assist is a raid where nothing here works. local showAs = ShowAs() + local suppressed = AssistSuppressed() local shellOn = { - Group = showAs ~= "markers", - Markers = showAs == "two" or showAs == "markers", + Group = showAs ~= "markers" and not suppressed, + Markers = (showAs == "two" or showAs == "markers") and not suppressed, } -- One seed for every show (see header): Default to Collapsed When Shown. -- With the toggle off the seed is "expanded" and the icon never shows. @@ -1176,13 +1205,18 @@ local function ApplyVisibility() end -- The icon represents the whole feature; every Show as choice shows - -- something, so it is simply on while the mode is active. - iconBtn:SetAttribute("enabled", true) + -- something, so it is on while the mode is active and the assist gate is + -- open. With it shut the keybind and the slash command go quiet too -- + -- both run the secure snippets, and those refuse a disabled frame. + iconBtn:SetAttribute("enabled", not suppressed) iconBtn:SetAttribute("visible", visNow) iconBtn:SetAttribute("override", "") iconBtn:SetAttribute("startexpanded", startExpanded) iconBtn:SetAttribute("expanded", expandedNow) + -- What is now ON SCREEN, for the roster handler to compare against. + lastSuppressed = suppressed + -- Run the snippets rather than re-deciding in Lua: attributes are set -- first so "apply" sees them. if SecureHandlerExecute then @@ -1202,7 +1236,10 @@ local function ApplyToggleKeybind() ClearOverrideBindings(toggleButton) local p = P() local k = p and p.toggleKey - if k and k ~= "" and Mode() ~= "never" then + -- The gate takes the binding with it rather than leaving a key that eats + -- its own keypress: the snippet would refuse a disabled frame, and an + -- override binding swallows whatever the key does otherwise. + if k and k ~= "" and Mode() ~= "never" and not AssistSuppressed() then SetOverrideBindingClick(toggleButton, false, k, "EllesmereUIRaidToolsToggle") end end @@ -1214,6 +1251,19 @@ end -- no bindings, no unlock rows. Apply() is the single entry point. ------------------------------------------------------------------------------- +-- The assist gate is Lua's, so a promotion, a demotion or a raid you join +-- without assist has to bring Apply back around -- no state driver will do it +-- for us. Compared against what ApplyVisibility last put on screen, because +-- GROUP_ROSTER_UPDATE bursts and Apply is not free. +-- +-- In combat Apply parks itself behind applyPending, which leaves lastSuppressed +-- untouched: the next roster event re-enters here and parks again, and +-- PLAYER_REGEN_ENABLED finishes the job. That is the module's standard +-- deferral, not an omission. +local function RefreshAssistGate() + if AssistSuppressed() ~= lastSuppressed then Apply() end +end + -- Events live only while the feature is active (or while a combat-deferred -- Apply is pending, since PLAYER_REGEN_ENABLED is what completes it). The -- frame itself is created on first need and reused. @@ -1232,6 +1282,7 @@ local function EnsureEvents() end if Mode() == "never" then return end RefreshPermissions() + RefreshAssistGate() end) end ev:RegisterEvent("GROUP_ROSTER_UPDATE") @@ -1264,6 +1315,9 @@ local function RegisterUnlock() noResize = true, getFrame = function() if Mode() == "never" then return nil end + -- Nothing to move while the assist gate has the whole feature + -- off the screen -- same opt-out as the modes below. + if AssistSuppressed() then return nil end -- Offer exactly the shells the Show as choice puts on screen: -- One Window / Only Group & Pull = the Group element alone, -- Two Windows = both, Only Markers = the Markers element alone. @@ -1406,6 +1460,12 @@ SlashCmdList["EUIRAIDTOOLS"] = function() EllesmereUI.Print("|cff0cd29fEllesmereUI:|r " .. EllesmereUI.L("Raid Tools cannot be toggled by slash command in combat -- use the keybind.")) return end + -- The snippet would refuse anyway (enabled is false while the gate is + -- shut); saying so beats a slash command that looks broken. + if AssistSuppressed() then + EllesmereUI.Print("|cff0cd29fEllesmereUI:|r " .. EllesmereUI.L("Raid Tools is hidden in a raid without leader or assist -- none of its buttons work there.")) + return + end BuildAll() ToggleOutOfCombat() end diff --git a/Locales/_keys.txt b/Locales/_keys.txt index 421a2ea2..df8ad75d 100644 --- a/Locales/_keys.txt +++ b/Locales/_keys.txt @@ -1,6 +1,6 @@ # Auto-generated by .tools/extract-locale-keys.sh -- do not edit by hand. # Canonical list of translatable English keys passed as string literals -# (661 unique). Regenerate after wrapping new strings. Keys passed as +# (662 unique). Regenerate after wrapping new strings. Keys passed as # variables are not listed here -- use the in-game /euiloc harvester for # the complete runtime set. (Raid) @@ -452,6 +452,7 @@ REAGENTS Racial Raid Tools cannot be toggled by slash command in combat -- use the keybind. Raid Tools is disabled in the EllesmereUI options. +Raid Tools is hidden in a raid without leader or assist -- none of its buttons work there. Raids Raise Strata Re-sync diff --git a/Locales/deDE.lua b/Locales/deDE.lua index b1a9f650..eca591a6 100644 --- a/Locales/deDE.lua +++ b/Locales/deDE.lua @@ -5322,3 +5322,7 @@ L["~%dx Myth Crest"] = "~%dx Wappen des Mythos" L["~%dx Myth Crest\r\n|cff888888Scan at Upgrader for exact costs|r"] = "~%dx Wappen des Mythos\r\n|cff888888Beim Aufwerter scannen für exakte Kosten|r" L["~%dx Veteran Crest"] = "~%dx Wappen des Veterans" L["~%dx Veteran Crest\r\n|cff888888Scan at Upgrader for exact costs|r"] = "~%dx Wappen des Veterans\r\n|cff888888Beim Aufwerter scannen für exakte Kosten|r" + +-- QoL: Raid Tools -- hidden in a raid without leader or assist +L["A raid control panel with ready check, pull timer and raid markers. In a raid it only shows while you are the leader or an assistant, since none of its buttons work without that; in a party it always shows."] = "Ein Kontrollfeld für Schlachtzüge mit Bereitschaftsprüfung, Pull-Timer und Schlachtzugsmarkierungen. Im Schlachtzug wird es nur angezeigt, solange Ihr Anführer oder Assistent seid, da ohne diese Rechte keine seiner Schaltflächen funktioniert; in einer Gruppe wird es immer angezeigt." +L["Raid Tools is hidden in a raid without leader or assist -- none of its buttons work there."] = "Die Raid-Tools werden im Schlachtzug ohne Anführer- oder Assistentenrechte ausgeblendet -- dort funktioniert keine ihrer Schaltflächen."