[Feature Request] Class-based DR icons
marco-vrinssen opened this issue · 18 comments
Hey, I would like to suggest the implementation of class-specific Diminishing Returns (DR) icons. This can be especially relevant for new players to create a quicker association for using CC abilities. For now, I have attached a first suggestion on how this could be achieved, but I believe that making this a toggleable option in the settings menu would provide more flexibility for different user preferences.
Thank you for your dedication to improving this addon.
Reference:
local AddonName, Data = ...
local BattleGroundEnemies = BattleGroundEnemies
local L = Data.L
local LSM = LibStub("LibSharedMedia-3.0")
local GetSpellTexture = C_Spell and C_Spell.GetSpellTexture or GetSpellTexture
local CreateFrame = CreateFrame
local BackdropTemplateMixin = BackdropTemplateMixin
local GameTooltip = GameTooltip
local IsClassic = WOW_PROJECT_ID == WOW_PROJECT_CLASSIC
local DRList = LibStub("DRList-1.0")
local defaultSettings = {
Enabled = true,
Parent = "Button",
ActivePoints = 1,
DisplayType = "Frame",
IconSize = 20,
Cooldown = {
ShowNumber = true,
FontSize = 12,
FontOutline = "OUTLINE",
EnableShadow = false,
DrawSwipe = false,
ShadowColor = {0, 0, 0, 1},
},
Container = {
UseButtonHeightAsSize = true,
IconSize = 15,
IconsPerRow = 10,
HorizontalGrowDirection = "rightwards",
HorizontalSpacing = 2,
VerticalGrowdirection = "downwards",
VerticalSpacing = 1,
},
Filtering_Enabled = false,
Filtering_Filterlist = {},
}
local options = function(location)
return {
ContainerSettings = {
type = "group",
name = L.ContainerSettings,
order = 1,
get = function(option)
return Data.GetOption(location.Container, option)
end,
set = function(option, ...)
return Data.SetOption(location.Container, option, ...)
end,
args = Data.AddContainerSettings(location.Container),
},
DisplayType = {
type = "select",
name = L.DisplayType,
desc = L.DrTracking_DisplayType_Desc,
values = Data.DisplayType,
order = 2
},
CooldownTextSettings = {
type = "group",
name = L.Countdowntext,
get = function(option)
return Data.GetOption(location.Cooldown, option)
end,
set = function(option, ...)
return Data.SetOption(location.Cooldown, option, ...)
end,
order = 3,
args = Data.AddCooldownSettings(location.Cooldown)
},
Fake1 = Data.AddVerticalSpacing(6),
FilteringSettings = {
type = "group",
name = FILTER,
order = 4,
args = {
Filtering_Enabled = {
type = "toggle",
name = L.Filtering_Enabled,
desc = L.DrTrackingFiltering_Enabled_Desc,
width = 'normal',
order = 1
},
Filtering_Filterlist = {
type = "multiselect",
name = L.Filtering_Filterlist,
desc = L.DrTrackingFiltering_Filterlist_Desc,
disabled = function() return not location.Filtering_Enabled end,
get = function(option, key)
return location.Filtering_Filterlist[key]
end,
set = function(option, key, state)
location.Filtering_Filterlist[key] = state or nil
end,
values = Data.DrCategorys,
order = 2
}
}
}
}
end
local dRstates = {
[1] = { 0, 1, 0, 1}, --green (next cc in DR time will be only half duration)
[2] = { 1, 1, 0, 1}, --yellow (next cc in DR time will be only 1/4 duration)
[3] = { 1, 0, 0, 1}, --red (next cc in DR time will not apply, player is immune)
}
local function drFrameUpdateStatusBorder(drFrame)
drFrame:SetBackdropBorderColor(unpack(dRstates[drFrame:GetStatus()]))
end
local function drFrameUpdateStatusText(drFrame)
drFrame.Cooldown.Text:SetTextColor(unpack(dRstates[drFrame:GetStatus()]))
end
local flags = {
HasDynamicSize = true
}
local dRTracking = BattleGroundEnemies:NewButtonModule({
moduleName = "DRTracking",
localizedModuleName = L.DRTracking,
flags = flags,
defaultSettings = defaultSettings,
options = options,
events = {"AuraRemoved"},
enabledInThisExpansion = true
})
local _, playerClass = UnitClass("player")
if playerClass == "DEATHKNIGHT" then
drClassIcons = {
stun = GetSpellTexture(108194), -- Asphyxiate
disorient = GetSpellTexture(207167), -- Blinding Sleet
incapacitate = GetSpellTexture(108194), -- Asphyxiate
knockback = GetSpellTexture(132469), -- Typhoon
root = GetSpellTexture(45524), -- Chains of Ice
silence = GetSpellTexture(47476), -- Strangulate
disarm = GetSpellTexture(236077) -- Disarm
}
elseif playerClass == "DEMONHUNTER" then
drClassIcons = {
stun = GetSpellTexture(211881), -- Fel Eruption
disorient = GetSpellTexture(207684), -- Sigil of Misery
incapacitate = GetSpellTexture(217832), -- Imprison
knockback = GetSpellTexture(132469), -- Typhoon
root = GetSpellTexture(202138), -- Sigil of Chains
silence = GetSpellTexture(204490), -- Sigil of Silence
disarm = GetSpellTexture(236077) -- Disarm
}
elseif playerClass == "DRUID" then
drClassIcons = {
stun = GetSpellTexture(5211), -- Mighty Bash
disorient = GetSpellTexture(33786), -- Cyclone
incapacitate = GetSpellTexture(99), -- Incapacitating Roar
knockback = GetSpellTexture(132469), -- Typhoon
root = GetSpellTexture(339), -- Entangling Roots
silence = GetSpellTexture(15487), -- Silence
disarm = GetSpellTexture(236077) -- Disarm
}
elseif playerClass == "EVOKER" then
drClassIcons = {
stun = GetSpellTexture(357210), -- Deep Breath
disorient = GetSpellTexture(360806), -- Sleep Walk
incapacitate = GetSpellTexture(6770), -- Sap
knockback = GetSpellTexture(357214), -- Wing Buffet
root = GetSpellTexture(358385), -- Landslide
silence = GetSpellTexture(351338), -- Quell
disarm = GetSpellTexture(236077) -- Disarm
}
elseif playerClass == "HUNTER" then
drClassIcons = {
stun = GetSpellTexture(19577), -- Intimidation
disorient = GetSpellTexture(2094), -- Blind
incapacitate = GetSpellTexture(187650), -- Freezing Trap
knockback = GetSpellTexture(13813), -- Explosive Trap
root = GetSpellTexture(162487), -- Steel Trap
silence = GetSpellTexture(147362), -- Counter Shot
disarm = GetSpellTexture(202900) -- Scorpid Sting
}
elseif playerClass == "MAGE" then
drClassIcons = {
stun = GetSpellTexture(389794), -- Dragon's Breath
disorient = GetSpellTexture(31661), -- Dragon's Breath
incapacitate = GetSpellTexture(118), -- Polymorph
knockback = GetSpellTexture(157981), -- Blast Wave
root = GetSpellTexture(122), -- Frost Nova
silence = GetSpellTexture(2139), -- Counterspell
disarm = GetSpellTexture(236077) -- Disarm
}
elseif playerClass == "MONK" then
drClassIcons = {
stun = GetSpellTexture(119381), -- Leg Sweep
disorient = GetSpellTexture(198898), -- Song of Chi-Ji
incapacitate = GetSpellTexture(115078), -- Paralysis
knockback = GetSpellTexture(116844), -- Ring of Peace
root = GetSpellTexture(343731), -- Disable
silence = GetSpellTexture(116705), -- Spear Hand Strike
disarm = GetSpellTexture(233759) -- Grapple Weapon
}
elseif playerClass == "PALADIN" then
drClassIcons = {
stun = GetSpellTexture(853), -- Hammer of Justice
disorient = GetSpellTexture(115750), -- Blinding Light
incapacitate = GetSpellTexture(20066), -- Repentance
knockback = GetSpellTexture(132469), -- Typhoon
root = GetSpellTexture(339), -- Entangling Roots
silence = GetSpellTexture(96231), -- Rebuke
disarm = GetSpellTexture(236077) -- Disarm
}
elseif playerClass == "PRIEST" then
drClassIcons = {
stun = GetSpellTexture(64044), -- Psychic Horror
disorient = GetSpellTexture(8122), -- Psychic Scream
incapacitate = GetSpellTexture(88625), -- Holy Word: Chastise
knockback = GetSpellTexture(132469), -- Typhoon
root = GetSpellTexture(108920), -- Void Tendrils
silence = GetSpellTexture(15487), -- Silence
disarm = GetSpellTexture(236077) -- Disarm
}
elseif playerClass == "ROGUE" then
drClassIcons = {
stun = GetSpellTexture(408), -- Kidney Shot
disorient = GetSpellTexture(2094), -- Blind
incapacitate = GetSpellTexture(6770), -- Sap
knockback = GetSpellTexture(132469), -- Typhoon
root = GetSpellTexture(339), -- Entangling Roots
silence = GetSpellTexture(1766), -- Kick
disarm = GetSpellTexture(207777) -- Dismantle
}
elseif playerClass == "SHAMAN" then
drClassIcons = {
stun = GetSpellTexture(305483), -- Capacitor Totem
disorient = GetSpellTexture(2094), -- Blind
incapacitate = GetSpellTexture(51514), -- Hex
knockback = GetSpellTexture(51490), -- Thunderstorm
root = GetSpellTexture(64695), -- Earthgrab Totem
silence = GetSpellTexture(57994), -- Wind Shear
disarm = GetSpellTexture(236077) -- Disarm
}
elseif playerClass == "WARLOCK" then
drClassIcons = {
stun = GetSpellTexture(30283), -- Shadowfury
disorient = GetSpellTexture(5782), -- Fear
incapacitate = GetSpellTexture(6789), -- Mortal Coil
knockback = GetSpellTexture(132469), -- Typhoon
root = GetSpellTexture(51485), -- Earthgrab Totem
silence = GetSpellTexture(19647), -- Spell Lock
disarm = GetSpellTexture(236077) -- Disarm
}
elseif playerClass == "WARRIOR" then
drClassIcons = {
stun = GetSpellTexture(107570), -- Storm Bolt
disorient = GetSpellTexture(5246), -- Intimidating Shout
incapacitate = GetSpellTexture(6770), -- Sap
knockback = GetSpellTexture(132469), -- Typhoon
root = GetSpellTexture(6343), -- Thunder Clap
silence = GetSpellTexture(6552), -- Pummel
disarm = GetSpellTexture(236077) -- Disarm
}
end
local function createNewDrFrame(playerButton, container)
local drFrame = CreateFrame("Frame", nil, container, BackdropTemplateMixin and "BackdropTemplate")
drFrame.Cooldown = BattleGroundEnemies.MyCreateCooldown(drFrame)
drFrame.Cooldown:SetScript("OnCooldownDone", function()
drFrame:Remove()
end)
drFrame:HookScript("OnEnter", function(self)
BattleGroundEnemies:ShowTooltip(self, function()
if IsClassic then return end
GameTooltip:SetSpellByID(self.spellId)
end)
end)
drFrame:HookScript("OnLeave", function(self)
if GameTooltip:IsOwned(self) then
GameTooltip:Hide()
end
end)
drFrame.Container = container
drFrame.ApplyChildFrameSettings = function(self)
self.Cooldown:ApplyCooldownSettings(container.config.Cooldown, false)
self:SetDisplayType()
end
drFrame.GetStatus = function(self)
local status = self.input.status
status = (math.min(status, 3))
return status
end
drFrame.SetDisplayType = function(self)
if container.config.DisplayType == "Frame" then
self.SetStatus = drFrameUpdateStatusBorder
else
self.SetStatus = drFrameUpdateStatusText
end
self.Cooldown.Text:SetTextColor(1, 1, 1, 1)
self:SetBackdropBorderColor(0, 0, 0, 0)
if self.input and self.input.status ~= 0 then self:SetStatus() end
end
drFrame:SetBackdrop({
bgFile = "Interface/Buttons/WHITE8X8", --drawlayer "BACKGROUND"
edgeFile = 'Interface/Buttons/WHITE8X8', --drawlayer "BORDER"
edgeSize = 1
})
drFrame:SetBackdropColor(0, 0, 0, 0)
drFrame:SetBackdropBorderColor(0, 0, 0, 0)
drFrame.Icon = drFrame:CreateTexture(nil, "BORDER", nil, -1) -- -1 to make it behind the SetBackdrop bg
drFrame.Icon:SetAllPoints()
drFrame:ApplyChildFrameSettings()
drFrame:Hide()
return drFrame
end
local function setupDrFrame(container, drFrame, drDetails)
drFrame:SetStatus()
drFrame.spellId = drDetails.spellId
local drCat = drDetails.drCat
if drClassIcons and drClassIcons[drCat] then
drFrame.Icon:SetTexture(drClassIcons[drCat])
else
drFrame.Icon:SetTexture(GetSpellTexture(drDetails.spellId))
end
local duration = DRList:GetResetTime(drCat)
drFrame.Cooldown:SetCooldown(drDetails.startTime, duration)
end
function dRTracking:AttachToPlayerButton(playerButton)
local container = BattleGroundEnemies:NewContainer(playerButton, createNewDrFrame, setupDrFrame)
function container:AuraRemoved(spellId, spellName)
local config = self.config
local drCat = DRList:GetCategoryBySpellID(spellId)
if not drCat then return end
local drTrackingEnabled = not config.Filtering_Enabled or config.Filtering_Filterlist[drCat]
if drTrackingEnabled then
local input = self:FindInputByAttribute("drCat", drCat)
if input then
input = self:UpdateInput(input, {spellId = spellId})
else
input = self:NewInput({
drCat = drCat,
spellId = spellId
})
end
input.status = (input.status or 0) + 1
input.startTime = GetTime()
self:Display()
end
end
playerButton.DRTracking = container
end
Hey, on my current dev version i implemented the option to select an icon for each dr category (stun, fear) . But i also like your approach, it would basically automate that selection. I could add an button for it like "set icon based on my class" i feel like that could work well and still offer the way to customize.
Thanks so much for handling the request, I’m really happy to hear the news! I think enabling the assignment of user-defined individual Spell IDs to the different DR categories makes a lot of sense—actually, it’s even better than what I suggested and is more consistent with the behavior of other arena/battleground addons like Gladius. At the time, I thought class-based icons might be simpler to maintain and implement, especially since I’m new to addon development. It could still be helpful for newer players who don’t want to think about their CC abilities and can just click a button, but overall, I think the way you’ve done it is really great.
Would it be possible to gain access to the current version of your development environment?
It would be possible to push the new branch i created for that, but i am working on some features that aren't finished yet, i wanna rework the way modules are moved – basically like a editmode. There is still quite some work to do there. But sure, if you are interested in that i can push it to GitHub.
So i published the dev branch https://github.com/BullseiWoWAddons/BattleGroundEnemies/tree/dev
its nowhere near complete but i made quite some progress today, it should be working fine in pvp but the editing mode side of things needs work. If you want to check the new editing view enter
/run BattleGroundEnemies.EditMode.EditModeManager:OpenEditmode() into the chat
once you select a system when the config menu is open you should see it change the current selected option if you select on of the blue frames.
Things i am currently working on
- make modules more static in edit mode, just like in blizz editmode so its not that jumpy (don't create new fake events every second instead show a predefined number of buffs, trinkets, etc)
- rework some of the modules, for example merge class, spec and highest priority into one module. (not sure if thats the best way to to, and how to name it then ... )
- fix the whole snappy system in the editmode
- reorder the settings menu
- make more options global to minimize complexity (for example the dr icons don't need to be specific to player size and faction)
- and probably much more i just didn't think about yet...
If you got time to check it out feedback is highly appreciated even tho its still pretty early
In case you are curious the latest alpha version contains the option to select the icons based on dr category besides that it features many more new features and improvements.
for comparison this is how it looks like for me with the default options panel size. i feel like there can't be much more done than that.
#48 (comment)
in comparison your screenshot it looks like the window for you is not that wide?
Thank you for the quick update and fix. Unfortunately, the problem persists in other categories. I assume it’s already on your roadmap, but I just wanted to confirm. I’m happy to provide additional screenshots if the issue doesn’t appear on your end, possibly due to different resolution or screen size, if that impacts the options panel layout.
will close this for now since its implemented in the latest release version. Feel free to create a new issue for more suggestions or bug reports.
Many, many thanks for the quick update and the excellent work; it looks great and has been working very well so far. One small issue is that in the General DR settings, when the upper section is expanded, the lower section is no longer accessible. Otherwise, everything is perfect so far, thank you!
Hey, so it should still be accessible, it should be possible to scroll down. I will test this out
To be precise, after resetting my settings from the previous version, I noticed that this issue affects all subareas (see highlighted in red in the attachment). Perhaps the dropdowns for managing and applying default or preset configurations could be made more compact and placed directly next to the enable checkbox, to create more space in the lower area.
Here’s an example in the DR module where resolving the issue might be challenging. A practical solution could be implementing a global scroll container that integrates the enabled toggle, “Jump to General Options,” and “Restore Defaults” buttons alongside the module-specific settings, avoiding the complexity of nested scroll containers.
yeah, thats a bit of a problem with sizing, i think for the Dr tracking i will just move that section to choose own category icons to a new tab. I decresed the length of the copy settings from and restore defaults under the enable button so it will fit in one line with it. But i guess there is always the option to resize the whole options panel in the bottom right corner too.
Edit: 11.0.5.5 moves the dr category icon selection into its own tab
I think the size of the option panel might depend on the resolution. I play in Full HD. Do you play in 2K? This could be the issue.
i am currenly using 5120 x 1440, but i mostly play in window mode, not fullscreen,
So yeah, i see the issue when i try to use it on smaller screens, i was also thinking about adding a slider for the options panel scale to make it smaller this would mean the text and buttons got smaller but maybe that would be a good option to make it more usuable without having too short/unusable scroll frames when trying to size it to screen size. I will play around it using lower resolutions and see what would be a good solution