diff --git a/CHANGELOG.md b/CHANGELOG.md index 510313d..390ae32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,2 @@ -* New Font Outline settings added: Shadow, Shadow Outline, and Shadow Thick. None setting no longer has a shadow. -* Wrath patch 3.4.3 +* Stacking of spells is supported now +* Retail patch 10.2 diff --git a/ElvUI_FCT/ElvUI_FCT-BCC.toc b/ElvUI_FCT/ElvUI_FCT-BCC.toc index 1178353..44a6d62 100644 --- a/ElvUI_FCT/ElvUI_FCT-BCC.toc +++ b/ElvUI_FCT/ElvUI_FCT-BCC.toc @@ -3,7 +3,7 @@ ## SavedVariables: ElvFCT ## RequiredDeps: ElvUI ## Interface: 20504 -## Version: 1.35 +## Version: 1.36 locales\load_locales.xml settings.lua diff --git a/ElvUI_FCT/ElvUI_FCT-Classic.toc b/ElvUI_FCT/ElvUI_FCT-Classic.toc index 306ee8b..2dc37d9 100644 --- a/ElvUI_FCT/ElvUI_FCT-Classic.toc +++ b/ElvUI_FCT/ElvUI_FCT-Classic.toc @@ -3,7 +3,7 @@ ## SavedVariables: ElvFCT ## RequiredDeps: ElvUI ## Interface: 11404 -## Version: 1.35 +## Version: 1.36 ## IconTexture: Interface\AddOns\ElvUI_FCT\Button locales\load_locales.xml diff --git a/ElvUI_FCT/ElvUI_FCT-Mainline.toc b/ElvUI_FCT/ElvUI_FCT-Mainline.toc index 0237c14..8437072 100644 --- a/ElvUI_FCT/ElvUI_FCT-Mainline.toc +++ b/ElvUI_FCT/ElvUI_FCT-Mainline.toc @@ -2,8 +2,8 @@ ## Title: |cff1784d1ElvUI|r |cFFdd2244Floating Combat Text|r ## SavedVariables: ElvFCT ## RequiredDeps: ElvUI -## Interface: 100107 -## Version: 1.35 +## Interface: 100200 +## Version: 1.36 ## IconTexture: Interface\AddOns\ElvUI_FCT\Button locales\load_locales.xml diff --git a/ElvUI_FCT/ElvUI_FCT-Wrath.toc b/ElvUI_FCT/ElvUI_FCT-Wrath.toc index e7a7bc3..77cb6c8 100644 --- a/ElvUI_FCT/ElvUI_FCT-Wrath.toc +++ b/ElvUI_FCT/ElvUI_FCT-Wrath.toc @@ -3,7 +3,7 @@ ## SavedVariables: ElvFCT ## RequiredDeps: ElvUI ## Interface: 30403 -## Version: 1.35 +## Version: 1.36 ## IconTexture: Interface\AddOns\ElvUI_FCT\Button locales\load_locales.xml diff --git a/ElvUI_FCT/core.lua b/ElvUI_FCT/core.lua index 84f3483..4d8a721 100644 --- a/ElvUI_FCT/core.lua +++ b/ElvUI_FCT/core.lua @@ -7,8 +7,8 @@ local _, ns = ... local FCT = ns[2] local S = E:GetModule('Skins') -local wipe, tinsert, tremove = wipe, tinsert, tremove local sin, cos, pi, rand = math.sin, math.cos, math.pi, math.random +local wipe, tinsert, tremove, CopyTable = wipe, tinsert, tremove, CopyTable local type, unpack, next, ipairs, format = type, unpack, next, ipairs, format local band, guid, uisu, uhm, gsi = bit.band, UnitGUID, UnitIsUnit, UnitHealthMax, GetSpellInfo local info, buln, cf = CombatLogGetCurrentEventInfo, BreakUpLargeNumbers, CreateFrame @@ -17,6 +17,82 @@ ns.objects, ns.spells, ns.color = {}, {}, {} ns.colorStep, ns.fallback = {1,2,4,8,16,32,64}, {1,1,1} ns.CT = E:CopyTable({}, _G.CombatFeedbackText) ns.CT.MISFIRE = _G.COMBAT_TEXT_MISFIRE +ns.IF = {} + +local stack = CreateFrame('Frame') +stack.tickWait = 3 -- time before sending hot to the update +stack.hitsWait = 2 -- time to check for rapid spells +stack.hitAmount = 5 -- amount of hits during hitsWait +stack.sendDelay = 0.1 -- delay of the spell being sent out +stack.watching = {} -- stacks to watch +stack.hitsSpells = {} -- stack count within wait time +stack.spells = {} -- spells to count as stacks +stack.sendSpells = {} -- spells pushed to be sent out + +stack.DelaySpell = function(data) + for fb in next, ns.objects do + FCT:Update(fb, data) + end +end + +stack.HasSpells = function(s) + return next(s.watching) or next(s.hitsSpells) or next(s.spells) or next(s.sendSpells) +end + +stack.CheckShown = function(s) + local shown = s:IsShown() + local spells = s:HasSpells() + if not shown and spells then + s:Show() + elseif shown and not spells then + s:Hide() + end +end + +stack.WatchSpells = function(s, elapsed) + s.hits = (s.hits or 0) + elapsed + if s.hits > s.hitsWait then + s.hits = 0 + + for key, hits in next, s.hitsSpells do + if hits > s.hitAmount then + s.watching[key] = true + end + + s.hitsSpells[key] = nil + end + end + + s.ticks = (s.ticks or 0) + elapsed + if s.ticks > stack.tickWait then + s.ticks = 0 + + for key, spell in next, s.spells do + for uid, data in next, spell do + s.sendSpells[key..'^'..uid] = data + end + + s.spells[key] = nil + end + end + + s.sends = (s.sends or 0) + elapsed + if s.sends > 0.1 then + s.sends = 0 + + local delay = 0 + for key, data in next, s.sendSpells do + delay = delay + s.sendDelay + E:Delay(delay, s.DelaySpell, data) + + s.sendSpells[key] = nil + end + end +end + +stack:Hide() +stack:SetScript('OnUpdate', stack.WatchSpells) +ns.SH = stack -- stacks handler local harlemShake = { StopIt = function(object) @@ -185,22 +261,39 @@ function FCT:StyleNumber(unit, style, number) return number end -function FCT:Update(frame, fb) - if not fb.unit or not fb.owner:IsShown() then return end +function FCT:Update(fb, data) + local unit = fb.unit + if not unit or not fb.owner:IsShown() then return end local a, b, c, d, e -- amount, critical, spellSchool, dmgColor, isSwing - local _, f, _, g, _, _, _, h, _, _, _, j, _, k, l, _, _, m, _, _, n = info() - -- event (2nd), sourceGUID (4th), destGUID (8th), 1st Parameter [spellId] (12th), spellSchool (14th), 1st Param (15th), 4th Param (18th), 7th Param [critical] (21st) + local f, g, h, j, k, l, m, n = data.f, data.g, data.h, data.j, data.k, data.l, data.m, data.n - if h ~= guid(fb.unit) then return end -- needs to be the frames unit! + -- needs to be the frames unit! + if h ~= guid(unit) then return end - if f == 'SPELL_HEAL' or (fb.showHots and f == 'SPELL_PERIODIC_HEAL') then + -- stack data for the unit + local udata = data[unit] + local hits, crits, amount + if udata then + hits, crits, amount = udata.hits, udata.crits, udata.amount + end + + -- check hot and dots + local dot = f == 'SPELL_PERIODIC_DAMAGE' + local hot = f == 'SPELL_PERIODIC_HEAL' + + -- not showing on this unit + local blockOvertime = (dot and not fb.showDots) or (hot and not fb.showHots) + if blockOvertime then return end + + -- convert data + if f == 'SPELL_HEAL' or (fb.showHots and hot) then a, b, d = l, m, ns.color.Heal elseif f == 'RANGE_DAMAGE' then a, b, d = l, n, ns.color.Ranged elseif f == 'SWING_DAMAGE' then a, b, d, e = j, m, ns.color.Physical, true - elseif f == 'SPELL_DAMAGE' or (fb.showDots and f == 'SPELL_PERIODIC_DAMAGE') then + elseif f == 'SPELL_DAMAGE' or (fb.showDots and dot) then a, b, c = l, n, k elseif f == 'SPELL_MISSED' or f == 'RANGE_MISSED' then a = l @@ -208,16 +301,21 @@ function FCT:Update(frame, fb) a, e = j, true end + -- check if the source is us + local petUID = guid('pet') + local sourceMe = g == E.myguid or g == petUID + + -- handle blocking spells local ex = not e and FCT.db.exclude[j] if ex and (ex.global or ex[fb.frametype]) then return end - local tb, pb - if fb.isTarget and not (h == guid('target') and uisu(fb.unit, 'target')) then + local tb, pb -- target block, player block + if fb.isTarget and not (h == guid('target') and uisu(unit, 'target')) then tb = true end if fb.isPlayer then - local y = h == E.myguid and uisu(fb.unit, 'player') - local z = g == E.myguid or (fb.showPet and g == guid('pet')) + local y = h == E.myguid and uisu(unit, 'player') + local z = g == E.myguid or (fb.showPet and g == petUID) if y or z then -- its player if fb.isPlayer == 1 and tb then tb = false end -- allow player on all elseif fb.isPlayer ~= 1 then -- dont pb when we are doing this @@ -226,7 +324,57 @@ function FCT:Update(frame, fb) end if tb or pb then return end - if (type(a) == 'number' and a > 0) or type(a) == 'string' then + -- just verify its an amount first + local A = (type(a) == 'number' and a > 0) and a + + -- handle stacking spells + if hits then + if not fb.stackingSelf then return end -- not allowed on this frame + if not amount or amount <= 0 then return end -- amount not valid + elseif A and not FCT.db.stacks.exclude[j] and ((fb.stackingSelf and sourceMe) or (fb.stackingOthers and not sourceMe)) then + local key = j..'^'..f -- neato + local overtime = dot or hot -- its a real hot or dot automatically add it + if overtime and stack.overtime and not stack.watching[key] then + stack.watching[key] = true + end + + if stack.watching[key] then + -- spell full data + local s = stack.spells[key] + if not s then -- if its not in spells, add it + s = {} + stack.spells[key] = s + end + + -- spell unit data + local p = s[h] + if not p then + p = CopyTable(data) + s[h] = p + end + + local u = p[unit] + if not u then + u = {} + p[unit] = u + end + + -- handle increases + u.hits = (u.hits or 0) + 1 -- amount of hits + u.crits = (u.crits or 0) + (b and 1 or 0) -- amount of crits + u.amount = (u.amount or 0) + (A or 0) -- add up the amount + + return -- dont need to continue + elseif not overtime and stack.hitsDetect then -- check if we need to stack it + stack.hitsSpells[key] = (stack.hitsSpells[key] or 0) + 1 + end + end + + -- dont need it running when its not watching + stack:CheckShown() + + -- handle displaying spells + if A or type(a) == 'string' then if (fb.showIcon or fb.showName) and not (e or ns.spells[j]) then ns.spells[j] = {gsi(j)} end local text @@ -274,6 +422,10 @@ function FCT:Update(frame, fb) end end + if hits then + b = nil -- ignore crit stuff during stacking + end + if b then if fb.critShake then local parent = fb.owner.unitFrame or fb.owner.UnitFrame or fb.owner @@ -305,17 +457,30 @@ function FCT:Update(frame, fb) if ct then text:SetText(ct) + elseif hits then + if hits > 1 then + local red, green, blue = ns.color.Stack[1] * 255, ns.color.Stack[2] * 255, ns.color.Stack[3] * 255 + local _r, _g, _b = ns.color.Prefix[1] * 255, ns.color.Prefix[2] * 255, ns.color.Prefix[3] * 255 + + local allowCrits = stack.showCrits and crits > 0 + text:SetFormattedText('%s|cff%02x%02x%02x%s%s|r|cff%02x%02x%02x%s%s|r', FCT:StyleNumber(unit, fb.numberStyle, amount), red, green, blue, stack.prefix, hits, _r, _g, _b, allowCrits and fb.prefix or '', allowCrits and crits or '') + elseif crits > 0 then + local red, green, blue = ns.color.Prefix[1] * 255, ns.color.Prefix[2] * 255, ns.color.Prefix[3] * 255 + text:SetFormattedText('|cff%02x%02x%02x%s|r%s|cff%02x%02x%02x%s|r', red, green, blue, fb.prefix, FCT:StyleNumber(unit, fb.numberStyle, amount), red, green, blue, fb.prefix) + else + text:SetText(FCT:StyleNumber(unit, fb.numberStyle, amount)) + end elseif b and fb.prefix ~= '' then local red, green, blue = ns.color.Prefix[1] * 255, ns.color.Prefix[2] * 255, ns.color.Prefix[3] * 255 - text:SetFormattedText('|cff%02x%02x%02x%s|r%s|cff%02x%02x%02x%s|r', red, green, blue, fb.prefix, FCT:StyleNumber(fb.unit, fb.numberStyle, a), red, green, blue, fb.prefix) + text:SetFormattedText('|cff%02x%02x%02x%s|r%s|cff%02x%02x%02x%s|r', red, green, blue, fb.prefix, FCT:StyleNumber(unit, fb.numberStyle, a), red, green, blue, fb.prefix) else - text:SetText(FCT:StyleNumber(fb.unit, fb.numberStyle, a)) + text:SetText(FCT:StyleNumber(unit, fb.numberStyle, a)) end if fb.mode == 'Simpy' then if not fb.FadeOut then fb.FadeOut = { mode = 'OUT' } else fb.FadeOut.fadeTimer = nil end if not fb.FaderIn then fb.FaderIn = { mode = 'IN' } else fb.FaderIn.fadeTimer = nil end - ns.SI.FadeIn(fb.FaderIn, fb.Frame, 0.2, text.fadeTime + (b and 0.3 or 0), 0.4, 0.0, 0.8) + ns.SI.FadeIn(fb.FaderIn, fb.Frame, 0.2, text.fadeTime + (hits and 0.5 or (b and 0.3) or 0), 0.4, 0.0, 0.8) elseif fb.mode == 'LS' then tinsert(fb.objs, text) text.frame:SetAlpha(1) @@ -417,6 +582,8 @@ function FCT:SetOptions(fb, db) fb.critFontOutline = db.critFontOutline fb.alternateIcon = db.alternateIcon fb.shakeDuration = db.shakeDuration + fb.stackingSelf = db.stackingSelf + fb.stackingOthers = db.stackingOthers fb.cycleColors = db.cycleColors fb.numberStyle = db.numberStyle fb.critShake = db.critShake @@ -428,8 +595,8 @@ function FCT:SetOptions(fb, db) fb.isTarget = db.isTarget fb.isPlayer = db.isPlayer fb.iconSize = db.iconSize - fb.followSize = db.followSize fb.showPet = db.showPet + fb.followSize = db.followSize fb.prefix = db.prefix fb.mode = db.mode @@ -456,11 +623,29 @@ function FCT:SetOptions(fb, db) end function FCT:COMBAT_LOG_EVENT_UNFILTERED() - for object, texts in next, ns.objects do - FCT:Update(object, texts) + local data, _ = ns.IF -- update the table before using it + _, data.f, _, data.g, _, _, _, data.h, _, _, _, data.j, _, data.k, data.l, _, _, data.m, _, _, data.n = info() + -- event (2nd), sourceGUID (4th), destGUID (8th), 1st Parameter [spellId] (12th), spellSchool (14th), 1st Param (15th), 4th Param (18th), 7th Param [critical] (21st) + + for fb in next, ns.objects do + FCT:Update(fb, data) end end +function FCT:UpdateStacks(db) + stack.sendDelay = db.sendDelay + stack.tickWait = db.tickWait + stack.hitsWait = db.hitsWait + stack.hitAmount = db.hitAmount + stack.hitsDetect = db.hitsDetect + stack.overtime = db.overtime + stack.showCrits = db.showCrits + stack.prefix = db.prefix + + wipe(stack.watching) + stack:CheckShown() +end + function FCT:Toggle(frame, module, db) if module.enable and db.enable then FCT:Enable(frame, db) @@ -475,8 +660,8 @@ function FCT:Enable(frame, db) FCT:SetOptions(fb, db) FCT:EnableMode(fb, db.mode) - if not ns.objects[fb.owner] then - ns.objects[fb.owner] = fb + if not ns.objects[fb] then + ns.objects[fb] = true end end end @@ -486,8 +671,8 @@ function FCT:Disable(frame) if fb then ns.LS.onShowHide(frame) - if ns.objects[fb.owner] then - ns.objects[fb.owner] = nil + if ns.objects[fb] then + ns.objects[fb] = nil end end end diff --git a/ElvUI_FCT/init.lua b/ElvUI_FCT/init.lua index c4f106f..332891b 100644 --- a/ElvUI_FCT/init.lua +++ b/ElvUI_FCT/init.lua @@ -28,6 +28,10 @@ local version = format('[|cFF508cf7v%s|r]', Version) local title = '|cFFdd2244Floating Combat Text|r' local by = 'by |cFF8866ccSimpy|r and |cFF34dd61Lightspark|r (ls-)' +local subsetting = { + advanced = true +} + FCT.orders = { colors = { ['1'] = 1, -- Damage @@ -163,10 +167,10 @@ end do local spellList = {} - function FCT:ExcludeList() + function FCT:ExcludeList(db) wipe(spellList) - for spell in pairs(FCT.db.exclude) do + for spell in pairs(db) do spellList[spell] = FCT:GetSpellNameRank(spell) end @@ -180,41 +184,41 @@ end function FCT:AddOptions(arg1, arg2) local i = (type(arg2) == 'number' and tostring(arg2)) or arg2 - if E.Options.args.ElvFCT.args[arg1].args[i] then return end + local path = E.Options.args.ElvFCT.args[arg1] local L = FCT.L - if arg1 == 'colors' then - E.Options.args.ElvFCT.args[arg1].args[i] = { + local db = FCT.db[arg1] + if arg1 == 'stacks' then + path.args.exclude.args.spells.values[arg2] = FCT:GetSpellNameRank(arg2) + elseif path.args[i] then + return + elseif arg1 == 'colors' then + path.args[i] = { order = FCT.orders.colors[i], name = L[ns.colors[arg2].n], type = 'color', } elseif arg1 == 'exclude' then local spellName = FCT:GetSpellNameRank(arg2) - local option = { - name = spellName, - type = 'group', - order = 3, - args = { - name = { order = 1, type = 'header', name = spellName }, - global = { order = 2, type = 'toggle', name = L["Global"] }, - nameplates = { order = 3, type = 'group', name = L["Nameplates"], inline = true, args = {} }, - unitframes = { order = 4, type = 'group', name = L["UnitFrames"], inline = true, args = {} } - }, - get = function(info) return FCT.db.exclude[arg2][ info[#info] ] end, - set = function(info, value) - local which = info[#info] - if which == 'global' then - if value then wipe(FCT.db.exclude[arg2]) end - FCT.db.exclude[arg2].global = value or nil - else - if value then FCT.db.exclude[arg2].global = nil end - FCT.db.exclude[arg2][which] = value or nil - end - end, - } + local option = { order = 3, type = 'group', name = spellName, args = { + name = { order = 1, type = 'header', name = spellName }, + global = { order = 2, type = 'toggle', name = L["Global"] }, + nameplates = { order = 3, type = 'group', name = L["Nameplates"], inline = true, args = {} }, + unitframes = { order = 4, type = 'group', name = L["UnitFrames"], inline = true, args = {} } + }} - E.Options.args.ElvFCT.args[arg1].args[i] = option + path.args[i] = option + option.get = function(info) return db[arg2][ info[#info] ] end + option.set = function(info, value) + local which = info[#info] + if which == 'global' then + if value then wipe(db[arg2]) end + db[arg2].global = value or nil + else + if value then db[arg2].global = nil end + db[arg2][which] = value or nil + end + end for key, name in next, FCT.nameplateTypes do option.args.nameplates.args[key] = { order = FCT.orders[name][1], type = 'toggle', name = L[FCT.orders[name][2]] } @@ -223,23 +227,25 @@ function FCT:AddOptions(arg1, arg2) option.args.unitframes.args[key] = { order = FCT.orders[name][1], type = 'toggle', name = L[FCT.orders[name][2]] } end else - E.Options.args.ElvFCT.args[arg1].args[arg2] = { + path.args[arg2] = { order = FCT.orders[arg2][1], name = L[FCT.orders[arg2][2]], args = FCT.options, type = 'group', get = function(info) - if info[4] == 'advanced' then - return FCT.db[arg1].frames[arg2][info[4]][ info[#info] ] + local sub = info[4] + if subsetting[sub] then + return db.frames[arg2][sub][ info[#info] ] else - return FCT.db[arg1].frames[arg2][ info[#info] ] + return db.frames[arg2][ info[#info] ] end end, set = function(info, value) - if info[4] == 'advanced' then - FCT.db[arg1].frames[arg2][info[4]][ info[#info] ] = value + local sub = info[4] + if subsetting[sub] then + db.frames[arg2][sub][ info[#info] ] = value else - FCT.db[arg1].frames[arg2][ info[#info] ] = value + db.frames[arg2][ info[#info] ] = value end if arg1 == 'unitframes' then @@ -269,19 +275,22 @@ function FCT:Options() showDots = { order = 6, type = 'toggle', name = L["Show Dots"] }, isTarget = { order = 7, type = 'toggle', name = L["Is Target"] }, isPlayer = { order = 8, type = 'toggle', name = L["From Player"] }, - critShake = { order = 9, type = 'toggle', name = L["Critical Frame Shake"] }, - textShake = { order = 10, type = 'toggle', name = L["Critical Text Shake"] }, - cycleColors = { order = 11, type = 'toggle', name = L["Cycle Spell Colors"] }, - prefix = { order = 12, type = 'input', name = L["Critical Prefix"] } + stackingSelf = { order = 9, type = 'toggle', name = E.NewSign..L["Stacking Self"] }, + stackingOthers = { order = 10, type = 'toggle', name = E.NewSign..L["Stacking Others"] }, + critShake = { order = 11, type = 'toggle', name = L["Critical Frame Shake"] }, + textShake = { order = 12, type = 'toggle', name = L["Critical Text Shake"] }, + cycleColors = { order = 13, type = 'toggle', name = L["Cycle Spell Colors"] } }}, fonts = { order = 3, type = 'group', name = '', guiInline = true, args = { header = { order = 0, name = FCT:ColorOption(L["Fonts"]), type = 'header' }, font = { order = 1, type = 'select', dialogControl = 'LSM30_Font', name = L["Font"], values = _G.AceGUIWidgetLSMlists.font }, fontOutline = { order = 2, name = L["Font Outline"], desc = L["Set the font outline."], type = 'select', sortByValue = true, values = C.Values.FontFlags}, fontSize = { order = 3, name = _G.FONT_SIZE, type = 'range', min = 4, max = 60, step = 1 }, - critFont = { order = 4, type = 'select', dialogControl = 'LSM30_Font', name = L["Critical Font"], values = _G.AceGUIWidgetLSMlists.font }, - critFontOutline = { order = 5, name = L["Critical Font Outline"], desc = L["Set the font outline."], type = 'select', sortByValue = true, values = C.Values.FontFlags}, - critFontSize = { order = 6, name = L["Critical Font Size"], type = 'range', min = 4, max = 60, step = 1 } + spacer1 = { order = 4, type = 'description', name = ' ', width = 'full' }, + critFont = { order = 5, type = 'select', dialogControl = 'LSM30_Font', name = L["Critical Font"], values = _G.AceGUIWidgetLSMlists.font }, + critFontOutline = { order = 6, name = L["Critical Font Outline"], desc = L["Set the font outline."], type = 'select', sortByValue = true, values = C.Values.FontFlags}, + critFontSize = { order = 7, name = L["Critical Font Size"], type = 'range', min = 4, max = 60, step = 1 }, + prefix = { order = 8, type = 'input', name = L["Critical Prefix"] } }}, settings = { order = 4, type = 'group', name = '', guiInline = true, args = { header = { order = 0, name = FCT:ColorOption(L["Settings"]), type = 'header' }, @@ -291,7 +300,7 @@ function FCT:Options() followSize = { order = 4, name = L["Icon Follow Text Size"], type = 'toggle' }, shakeDuration = { order = 5, name = L["Shake Duration"], type = 'range', min = 0, max = 1, step = 0.1 } }}, - offsets = { order = 5, type = 'group', name = '', guiInline = true, args = { + offsets = { order = 6, type = 'group', name = '', guiInline = true, args = { header = { order = 0, name = FCT:ColorOption(L["Offsets"]), type = 'header' }, textY = { order = 1, name = L["Text Y"], desc = L["Only applies to Fade mode."], type = 'range', min = -100, max = 100, step = 1 }, textX = { order = 2, name = L["Text X"], desc = L["Only applies to Fade mode."], type = 'range', min = -100, max = 100, step = 1 }, @@ -300,7 +309,7 @@ function FCT:Options() spellY = { order = 5, name = L["Spell Y"], type = 'range', min = -100, max = 100, step = 1 }, spellX = { order = 6, name = L["Spell X"], type = 'range', min = -100, max = 100, step = 1 }, }}, - advanced = { order = 6, type = 'group', name = '', guiInline = true, args = { + advanced = { order = 7, type = 'group', name = '', guiInline = true, args = { header = { order = 0, name = FCT:ColorOption(L["Animations"], L["Only applies on Animation mode."]), type = 'header' }, anim = { order = 1, name = L["Animation"], type = 'select', values = { fountain = L["Fountain"], @@ -364,8 +373,66 @@ function FCT:Options() end, args = {} }, + stacks = { order = 5, type = 'group', name = E.NewSign..L["Stacks"], args = { + sendDelay = { order = 1, name = L["Send Delay"], desc = L["How far apart each stack will display."], type = 'range', min = 0.01, max = 10, step = 0.01, bigStep = 0.1 }, + tickWait = { order = 2, name = L["Tick Wait"], desc = L["How long to gather stacks."], type = 'range', min = 0.01, max = 30, step = 0.01, bigStep = 0.1 }, + hitsWait = { order = 3, name = L["Hits Wait"], desc = L["How long to gather hits."], type = 'range', min = 0.01, max = 30, step = 0.01, bigStep = 0.1 }, + hitAmount = { order = 4, name = L["Hits Amount"], desc = L["How many hits until it is considered a stacking aura."], type = 'range', min = 2, max = 30, step = 1 }, + prefix = { order = 10, type = 'input', name = L["Stack Prefix"] }, + overtime = { order = 11, type = 'toggle', name = L["Overtime Spells"], desc = L["Heals over time and Damage over time spells to stack."] }, + showCrits = { order = 12, type = 'toggle', name = L["Show Crits"], desc = L["Display criticals beside stack count."]}, + hitsDetect = { order = 13, type = 'toggle', name = L["Detect Hits"], desc = L["Required to gather fast spells to stack."] }, + spacer1 = { order = 14, type = 'description', name = ' ', width = 'full' }, + exclude = { order = -1, type = 'group', name = L["Exclude"], inline = true, args = { + remove = { + order = 1, + name = L["Remove Spell"], + type = 'select', + values = function() return FCT:ExcludeList(FCT.db.stacks.exclude) end, + confirm = function(_, value) return format(L["Remove Spell - %s"], FCT:GetSpellNameRank(value)) end, + get = function() return '' end, + set = function(_, value) + FCT.db.stacks.exclude[value] = nil + E.Options.args.ElvFCT.args.stacks.args.exclude.args.spells.values[value] = nil + end + }, + add = { + order = 2, + name = L["Add SpellID"], + type = 'input', + get = function(_) return '' end, + set = function(_, str) + local value = tonumber(str) + if not value then return end + + local spellName = GetSpellInfo(value) + if not spellName then return end + + FCT.db.stacks.exclude[value] = true + FCT:AddOptions('stacks', value) + end + }, + spells = { + order = 5, + name = '', + values = {}, + type = 'multiselect', + hidden = function() return not next(FCT.db.stacks.exclude) end, + get = function(_, value) return FCT.db.stacks.exclude[value] end, + set = function(_, value) + FCT.db.stacks.exclude[value] = not FCT.db.stacks.exclude[value] + FCT:AddOptions('stacks', value) + end + }} + }}, + get = function(info) return FCT.db.stacks[ info[#info] ] end, + set = function(info, value) + FCT.db.stacks[ info[#info] ] = value + + FCT:UpdateStacks(FCT.db.stacks) + end}, exclude = { - order = 5, + order = 6, type = 'group', name = L["Exclude"], args = { @@ -373,10 +440,8 @@ function FCT:Options() order = 1, name = L["Remove Spell"], type = 'select', - values = FCT.ExcludeList, - confirm = function(_, value) - return format(L["Remove Spell - %s"], FCT:GetSpellNameRank(value)) - end, + values = function() return FCT:ExcludeList(FCT.db.exclude) end, + confirm = function(_, value) return format(L["Remove Spell - %s"], FCT:GetSpellNameRank(value)) end, get = function() return '' end, set = function(_, value) FCT.db.exclude[value] = nil @@ -424,6 +489,9 @@ function FCT:Options() for spell in pairs(FCT.db.exclude) do FCT:AddOptions('exclude', spell) end + for spell in pairs(FCT.db.stacks.exclude) do + FCT:AddOptions('stacks', spell) + end end function FCT:PLAYER_LOGOUT() @@ -523,6 +591,7 @@ function FCT:Initialize() -- Settings FCT:UpdateColors() + FCT:UpdateStacks(FCT.db.stacks) -- Events FCT:RegisterEvent('PLAYER_LOGOUT') diff --git a/ElvUI_FCT/settings.lua b/ElvUI_FCT/settings.lua index 5e2a91c..65ed0b4 100644 --- a/ElvUI_FCT/settings.lua +++ b/ElvUI_FCT/settings.lua @@ -3,6 +3,17 @@ local _, ns = ... ns.defaults = { colors = {}, exclude = {}, + stacks = { + overtime = true, + showCrits = false, + sendDelay = 0.3, + tickWait = 5, + hitsDetect = true, + hitsWait = 5, + hitAmount = 5, + prefix = 'x', + exclude = {} + }, nameplates = { enable = true, frames = { @@ -13,6 +24,8 @@ ns.defaults = { alternateIcon = true, isTarget = true, showIcon = true, + showHots = true, + showDots = true, iconX = -5, spellY = 5 }, @@ -22,6 +35,8 @@ ns.defaults = { alternateIcon = true, isTarget = true, showIcon = true, + showHots = true, + showDots = true, iconX = -5, spellY = 5 }, @@ -31,6 +46,8 @@ ns.defaults = { alternateIcon = true, isTarget = true, showIcon = true, + showHots = true, + showDots = true, iconX = -5, spellY = 5 }, @@ -40,6 +57,8 @@ ns.defaults = { alternateIcon = true, isTarget = true, showIcon = true, + showHots = true, + showDots = true, iconX = -5, spellY = 5 }, @@ -51,12 +70,18 @@ ns.defaults = { Player = { enable = true, showName = true, + showHots = true, + showDots = true, + stackingOthers = true, iconX = -5, spellY = 2 }, Target = { enable = true, showName = true, + showHots = true, + showDots = true, + stackingOthers = true, iconX = -5, spellY = 2 }, @@ -103,6 +128,8 @@ ns.frames = { critFontSize = 18, critFontOutline = 'OUTLINE', mode = 'Simpy', + stackingSelf = true, + stackingOthers = false, alternateIcon = false, shakeDuration = 0.25, critShake = false, @@ -141,6 +168,7 @@ ns.frames = { } ns.colors = { + Stack = {r=0.46, g=0.33, b=1.00, n='Stack Prefix'}, --[7755FF] Prefix = {r=0.00, g=0.60, b=1.00, n='Critical Prefix'}, --[0099FF] Heal = {r=0.20, g=1.00, b=0.20, n='Heal'}, --[32FF32] Ranged = {r=0.40, g=0.40, b=0.40, n='Ranged'}, --[666666]