diff --git a/CombatMode/Config.lua b/CombatMode/Config.lua index e5a06ee..fdeee4b 100644 --- a/CombatMode/Config.lua +++ b/CombatMode/Config.lua @@ -1046,6 +1046,186 @@ local AdvancedConfigOptions = { } } +--------------------------------------------------------------------------------------- +-- HEALING RADIAL CONFIG -- +--------------------------------------------------------------------------------------- +local HealingRadialOptions = { + name = CM.METADATA["TITLE"], + handler = CM, + type = "group", + args = { + header = { + type = "header", + name = "|cff00FF7FHEALING RADIAL|r", + order = 1 + }, + description = { + type = "description", + name = "\nA radial menu for quickly targeting party members when healing. While |cffE52B50Mouse Look|r is active and you're in a party, hold a mouse button to display the radial, flick toward your target, and release to cast.\n\n", + fontSize = "medium", + order = 2 + }, + enabled = { + type = "toggle", + name = "Enable |cff00FF7FHealing Radial|r", + desc = "Shows a radial menu when using click-cast buttons while in a party. Party members are arranged by role with the tank at 12 o'clock.\n\n|cffffd700Default:|r |cffE52B50Off|r", + width = "full", + order = 3, + set = function(_, value) + CM.DB.global.healingRadial.enabled = value + -- Re-apply mouse button bindings (clears them if radial enabled, sets them if disabled) + CM.OverrideDefaultButtons() + if CM.HealingRadial and CM.HealingRadial.SetCaptureActive then + CM.HealingRadial.SetCaptureActive(value) + end + end, + get = function() + return CM.DB.global.healingRadial.enabled + end, + }, + spacing1 = Spacing("full", 3.1), + visualGroup = { + type = "group", + name = "Visual Settings", + order = 4, + inline = true, + args = { + showHealthBars = { + type = "toggle", + name = "Show Health Bars", + desc = "Display health bars on each party member slice.", + width = 1.2, + order = 1, + set = function(_, value) + CM.DB.global.healingRadial.showHealthBars = value + end, + get = function() + return CM.DB.global.healingRadial.showHealthBars + end, + disabled = function() + return not CM.DB.global.healingRadial.enabled + end + }, + showHealthPercent = { + type = "toggle", + name = "Show Health %", + desc = "Display health percentage on each slice.", + width = 1.2, + order = 2, + set = function(_, value) + CM.DB.global.healingRadial.showHealthPercent = value + end, + get = function() + return CM.DB.global.healingRadial.showHealthPercent + end, + disabled = function() + return not CM.DB.global.healingRadial.enabled + end + }, + showPlayerNames = { + type = "toggle", + name = "Show Names", + desc = "Display player names on each slice.", + width = 1.2, + order = 3, + set = function(_, value) + CM.DB.global.healingRadial.showPlayerNames = value + end, + get = function() + return CM.DB.global.healingRadial.showPlayerNames + end, + disabled = function() + return not CM.DB.global.healingRadial.enabled + end + }, + showRoleIcons = { + type = "toggle", + name = "Show Role Icons", + desc = "Display role icons (tank, healer, DPS) on each slice.", + width = 1.2, + order = 4, + set = function(_, value) + CM.DB.global.healingRadial.showRoleIcons = value + end, + get = function() + return CM.DB.global.healingRadial.showRoleIcons + end, + disabled = function() + return not CM.DB.global.healingRadial.enabled + end + }, + spacing2 = Spacing("full", 4.1), + sliceRadius = { + type = "range", + name = "Radial Size", + desc = "Distance from center to each party member slice.\n\n|cffffd700Default:|r |cff00FF7F120|r", + min = 60, + max = 200, + step = 10, + width = 1.5, + order = 5, + set = function(_, value) + CM.DB.global.healingRadial.sliceRadius = value + end, + get = function() + return CM.DB.global.healingRadial.sliceRadius + end, + disabled = function() + return not CM.DB.global.healingRadial.enabled + end + }, + sliceSize = { + type = "range", + name = "Slice Size", + desc = "Size of each party member slice.\n\n|cffffd700Default:|r |cff00FF7F80|r", + min = 50, + max = 120, + step = 10, + width = 1.5, + order = 6, + set = function(_, value) + CM.DB.global.healingRadial.sliceSize = value + end, + get = function() + return CM.DB.global.healingRadial.sliceSize + end, + disabled = function() + return not CM.DB.global.healingRadial.enabled + end + }, + } + }, + spacing3 = Spacing("full", 5), + layoutInfo = { + type = "group", + name = "|cffffd700Layout Information|r", + order = 6, + inline = true, + args = { + layoutNote = { + type = "description", + name = "|cff909090Party members are automatically positioned by role:|r\n\n|cffcfcfcf• |cff00d1ffTank|r at 12 o'clock (top)\n• |cff00ff00Healer|r at 7 o'clock (bottom-left)\n• |cffff6060DPS|r fill remaining positions\n\nYour character is included in the radial at your role's position.|r", + order = 1 + } + } + }, + spacing4 = Spacing("full", 7), + devnote = { + type = "group", + name = "|cffffd700Developer Note|r", + order = 8, + inline = true, + args = { + note = { + type = "description", + name = "|cff909090The Healing Radial uses the same spell assignments as |cffB47EDCClick Casting|r. Configure which spells are bound to each mouse button in the Click Casting tab.|r\n\n|cffFF5050Note:|r Party assignments can only be updated outside of combat due to WoW API restrictions.", + order = 1 + } + } + } + } +} + --------------------------------------------------------------------------------------- -- SETTINGS CATEGORY TREE -- --------------------------------------------------------------------------------------- @@ -1069,6 +1249,11 @@ CM.Config.OptionCategories = { name = "|cffB47EDC • Click Casting|r", table = ClickCastingOptions }, + { + id = "CombatMode_HealingRadial", + name = "|cff00FF7F • Healing Radial|r", + table = HealingRadialOptions + }, { id = "CombatMode_Advanced", name = "|cffffffff • Advanced|r", diff --git a/CombatMode/Constants.lua b/CombatMode/Constants.lua index 0be0054..bad6bd8 100644 --- a/CombatMode/Constants.lua +++ b/CombatMode/Constants.lua @@ -142,9 +142,28 @@ CM.Constants.BLIZZARD_EVENTS = { "PLAYER_MOUNT_DISPLAY_CHANGED", -- Toggling crosshair when mounting/dismounting "PLAYER_REGEN_ENABLED" -- Resetting crosshair when leaving combat }, + -- Events for Healing Radial + HEALING_RADIAL_EVENTS = { + "GROUP_ROSTER_UPDATE", -- Party composition changed + }, } +--------------------------------------------------------------------------------------- +-- HEALING RADIAL POSITIONS -- +--------------------------------------------------------------------------------------- +-- Slice positions for 5-man content (angles in degrees, 0 = right, 90 = up) +-- Each slice covers 72 degrees (360/5) +CM.Constants.HealingRadialSlices = { + [1] = { defaultRole = "TANK", angle = 90, label = "12 o'clock (top)" }, + [2] = { defaultRole = "DAMAGER", angle = 162, label = "10 o'clock (upper-left)" }, + [3] = { defaultRole = "HEALER", angle = 234, label = "7 o'clock (lower-left)" }, + [4] = { defaultRole = "DAMAGER", angle = 306, label = "5 o'clock (lower-right)" }, + [5] = { defaultRole = "DAMAGER", angle = 18, label = "2 o'clock (upper-right)" }, +} + +CM.Constants.HealingRadialSliceArc = 72 -- degrees per slice + --------------------------------------------------------------------------------------- -- ASSETS -- --------------------------------------------------------------------------------------- @@ -370,7 +389,8 @@ CM.Constants.FramesToCheck = { "WantAds", "SubscriptionInterstitialFrame", "CinematicFrameCloseDialog", - "MovieFrame" + "MovieFrame", + "CombatModeHealingRadialFrame" } -- Default frames to check with a dynamic name: any frame containing a string defined here will be matched, e.g. "OPieRT" will match the frame "OPieRT-1234-5678" @@ -642,7 +662,24 @@ CM.Constants.DatabaseDefaults = { crosshairY = 50, silenceAlerts = false, debugMode = false, - bindings = DefaultBindings + bindings = DefaultBindings, + -- Healing Radial settings + healingRadial = { + enabled = false, + sliceRadius = 120, + sliceSize = 80, + showHealthBars = true, + showHealthPercent = true, + showPlayerNames = true, + showRoleIcons = true, + highlightColor = {1, 1, 0, 0.4}, + backgroundColor = {0, 0, 0, 0.7}, + healthyColor = {0, 0.8, 0, 1}, + damagedColor = {1, 1, 0, 1}, + criticalColor = {1, 0, 0, 1}, + fadeInDuration = 0.08, + fadeOutDuration = 0.05, + } }, char = { useGlobalBindings = false, diff --git a/CombatMode/Core.lua b/CombatMode/Core.lua index bace8de..3009510 100644 --- a/CombatMode/Core.lua +++ b/CombatMode/Core.lua @@ -642,10 +642,15 @@ local function IsUnlockFrameVisible() CursorUnlockFrameGroupVisible(CM.Constants.WildcardFramesToCheck) or isGenericPanelOpen end +local function IsHealingRadialActive() + return CM.HealingRadial and CM.HealingRadial.IsActive and CM.HealingRadial.IsActive() +end + local function ShouldFreeLookBeOff() local evaluate = IsCustomConditionTrue() or (FreeLookOverride or SpellIsTargeting() or InCinematic() or IsInCinematicScene() or - IsUnlockFrameVisible() or IsVendorMountOut() or IsInPetBattle() or IsFeignDeathActive()) + IsUnlockFrameVisible() or IsVendorMountOut() or IsInPetBattle() or IsFeignDeathActive() or + IsHealingRadialActive()) return evaluate end @@ -681,6 +686,11 @@ function CM.SetNewBinding(buttonSettings) return end + -- If healing radial is enabled, it manages its own bindings + if CM.DB.global.healingRadial and CM.DB.global.healingRadial.enabled then + return + end + local valueToUse if buttonSettings.value == "MACRO" then valueToUse = "MACRO " .. buttonSettings.macroName @@ -753,6 +763,10 @@ local function LockFreeLook() MouselookStart() CenterCursor(true) HandleFreeLookUIState(true, false) + -- Notify Healing Radial of mouselook state change + if CM.HealingRadial and CM.HealingRadial.OnMouselookChanged then + CM.HealingRadial.OnMouselookChanged(true) + end CM.DebugPrint("Free Look Enabled") end end @@ -767,6 +781,10 @@ local function UnlockFreeLook() end HandleFreeLookUIState(false, false) + -- Notify Healing Radial of mouselook state change + if CM.HealingRadial and CM.HealingRadial.OnMouselookChanged then + CM.HealingRadial.OnMouselookChanged(false) + end CM.DebugPrint("Free Look Disabled") end end @@ -781,6 +799,10 @@ local function UnlockFreeLookPermanent() end HandleFreeLookUIState(false, true) + -- Notify Healing Radial of mouselook state change + if CM.HealingRadial and CM.HealingRadial.OnMouselookChanged then + CM.HealingRadial.OnMouselookChanged(false) + end CM.DebugPrint("Free Look Disabled (Permanent)") end end @@ -856,10 +878,19 @@ local function HandleEventByCategory(category, event) end, FRIENDLY_TARGETING_EVENTS = function() HandleFriendlyTargetingInCombat() + -- Also handle combat end for healing radial pending updates + if event == "PLAYER_REGEN_ENABLED" and CM.HealingRadial and CM.HealingRadial.OnCombatEnd then + CM.HealingRadial.OnCombatEnd() + end end, UNCATEGORIZED_EVENTS = function() SetCrosshairAppearance(HideCrosshairWhileMounted() and "mounted" or "base") end, + HEALING_RADIAL_EVENTS = function() + if CM.HealingRadial and CM.HealingRadial.OnGroupRosterUpdate then + CM.HealingRadial.OnGroupRosterUpdate() + end + end, } @@ -994,6 +1025,11 @@ function CM:OnEnable() CreatePulse() CreateTargetMacros() + -- Initialize Healing Radial module + if CM.HealingRadial and CM.HealingRadial.Initialize then + CM.HealingRadial.Initialize() + end + -- Registering Blizzard Events from Constants.lua for _, events_to_register in pairs(CM.Constants.BLIZZARD_EVENTS) do for _, event in ipairs(events_to_register) do diff --git a/CombatMode/Embeds.xml b/CombatMode/Embeds.xml index a92407c..515e99d 100644 --- a/CombatMode/Embeds.xml +++ b/CombatMode/Embeds.xml @@ -12,6 +12,7 @@