refactor faerie fire and shared debuffs

This commit is contained in:
pepopo978
2025-06-15 13:12:43 -07:00
parent 6a4a9fb641
commit acc7d93e79
8 changed files with 190 additions and 79 deletions
+1
View File
@@ -28,6 +28,7 @@ global.lua
utils.lua
settings.lua
core.lua
spells\shared_debuffs.lua
spells\druid.lua
spells\hunter.lua
spells\mage.lua
+5 -1
View File
@@ -30,6 +30,7 @@ L:RegisterTranslations("enUS", function()
["Same as HIGHEST_HP_RAID_MARK but with INVERSE_RAID_MARK mark prio."] = true,
["|cffffcc00Cursive:|cffffaaaa Couldn't find a target to curse."] = true,
["curse_duration_format"] = ".*over ([%d.]+) sec.",
["Shared Debuffs"] = true,
-- curses
["(.+) fades from (.+)"] = true,
@@ -99,7 +100,7 @@ L:RegisterTranslations("enUS", function()
["Ignored Mobs List (Enter to save)"] = true,
["Comma separated list of strings to ignore if found in the unit name"] = true,
["Shared Faerie Fire"] = true,
["This will show other player's Faerie Fires as well as your own"] = true,
["This will show other player's Faerie Fires and avoid trying to cast Faerie Fire on those mobs"] = true,
-- spells
["Rank"] = true,
@@ -230,6 +231,7 @@ L:RegisterTranslations("zhCN", function()
-- 虫群:敌人被飞虫围绕,攻击命中率降低2%,在18秒内受到总计99点自然伤害。
-- 月火术:灼烧敌人,对其造成40到48点伤害,并在18秒内造成额外的120点奥术伤害。
["curse_duration_format"] = "(%d+%.?%d*)秒",
["Shared Debuffs"] = "共享debuff",
-- curses
["(.+) fades from (.+)"] = "(.+)效果从(.+)身上消失",
@@ -294,6 +296,8 @@ L:RegisterTranslations("zhCN", function()
["Not ignored"] = "不被忽略",
["Ignored Mobs List (Enter to save)"] = "忽略的怪物列表(回车保存)",
["Comma separated list of strings to ignore if found in the unit name"] = "如果在单位名称中找到,则忽略的字符串列表,用半角逗号分隔",
["Shared Faerie Fire"] = "共享精灵之火",
["This will show other player's Faerie Fires and avoid trying to cast Faerie Fire on those mobs"] = "这将显示其他玩家的精灵之火,并避免尝试在这些怪物上施放精灵之火",
-- spells
["Rank"] = "等级",
+63 -33
View File
@@ -26,7 +26,14 @@ local curses = {
pendingCast = {},
resistSoundGuids = {},
expiringSoundGuids = {},
requestedExpiringSoundGuids = {} -- guid added on spellcast, moved to expiringSoundGuids once rendered by ui
requestedExpiringSoundGuids = {}, -- guid added on spellcast, moved to expiringSoundGuids once rendered by ui
sharedDebuffs = {
faeriefire = {},
},
sharedDebuffGuids = {
faeriefire = {}, -- used for scanning for shared debuffs like faerie fire
}, -- used for scanning for shared debuffs like faerie fire
}
-- combat events for curses
@@ -46,25 +53,38 @@ function curses:LoadCurses()
curses.trackedCurseNamesToTextures = {}
curses.trackedCurseNameRanksToSpellSlots = {}
curses.isWarlock = playerClassName == "WARLOCK"
curses.isPriest = playerClassName == "PRIEST"
curses.isMage = playerClassName == "MAGE"
curses.isDruid = playerClassName == "DRUID"
curses.isHunter = playerClassName == "HUNTER"
curses.isRogue = playerClassName == "ROGUE"
curses.isShaman = playerClassName == "SHAMAN"
curses.isWarrior = playerClassName == "WARRIOR"
-- curses to track
if playerClassName == "WARLOCK" then
if curses.isWarlock then
curses.trackedCurseIds = getWarlockSpells()
elseif playerClassName == "PRIEST" then
elseif curses.isPriest then
curses.trackedCurseIds = getPriestSpells()
elseif playerClassName == "MAGE" then
elseif curses.isMage then
curses.trackedCurseIds = getMageSpells()
elseif playerClassName == "DRUID" then
elseif curses.isDruid then
curses.trackedCurseIds = getDruidSpells()
elseif playerClassName == "HUNTER" then
elseif curses.isHunter then
curses.trackedCurseIds = getHunterSpells()
elseif playerClassName == "ROGUE" then
elseif curses.isRogue then
curses.trackedCurseIds = getRogueSpells()
elseif playerClassName == "SHAMAN" then
elseif curses.isShaman then
curses.trackedCurseIds = getShamanSpells()
elseif playerClassName == "WARRIOR" then
elseif curses.isWarrior then
curses.trackedCurseIds = getWarriorSpells()
end
-- load shared debuffs
curses.sharedDebuffs = getSharedDebuffs()
-- go through spell slots and
local i = 1
while true do
@@ -165,35 +185,17 @@ Cursive:RegisterEvent("SPELLCAST_CHANNEL_STOP", StopChanneling);
Cursive:RegisterEvent("SPELLCAST_INTERRUPTED", StopChanneling);
Cursive:RegisterEvent("SPELLCAST_FAILED", StopChanneling);
local FaerieFire = {
[770] = true, --r1
[778] = true, --r2
[9749] = true, --r3
[9907] = true, --r4
[16855] = true, --bear r1
[17387] = true, --bear r2
[17388] = true, --bear r3
[17389] = true, --bear r4
[16857] = true, --cat r1
[17390] = true, --cat r2
[17391] = true, --cat r3
[17392] = true, --cat r4
}
Cursive:RegisterEvent("UNIT_CASTEVENT", function(casterGuid, targetGuid, event, spellID, castDuration)
-- immolate will fire both start and cast
if event == "CAST" then
local _, guid = UnitExists("player")
if casterGuid ~= guid then
if Cursive.db.profile.sharedFaerieFire and FaerieFire[spellID] then
lastGuid = targetGuid
Cursive:ScheduleEvent("addCurse" .. targetGuid .. curses.trackedCurseIds[spellID].name, curses.ApplyCurse, 0.2, self, spellID, targetGuid, GetTime())
else
return
-- check for faeriefire
if Cursive.db.profile.shareddebuffs.faeriefire and curses.sharedDebuffs.faeriefire[spellID] then
curses.sharedDebuffGuids.faeriefire[targetGuid] = GetTime()
end
return
end
-- store pending cast
@@ -441,6 +443,12 @@ function curses:HasCurse(spellName, targetGuid, minRemaining)
minRemaining = 0 -- default to 0
end
-- handle faerie fire special case
if curses.isDruid and string.find(spellName, L["faerie fire"]) then
-- remove (feral) or (bear) from spell name
spellName = L["faerie fire"]
end
if curses.guids[targetGuid] and curses.guids[targetGuid][spellName] then
local remaining = Cursive.curses:TimeRemaining(curses.guids[targetGuid][spellName])
if remaining > minRemaining then
@@ -460,6 +468,27 @@ function curses:HasCurse(spellName, targetGuid, minRemaining)
return nil
end
-- Apply shared curse from another player
function curses:ApplySharedCurse(sharedDebuffKey, spellID, targetGuid, startTime)
local name = curses.sharedDebuffs[sharedDebuffKey][spellID].name
local rank = curses.sharedDebuffs[sharedDebuffKey][spellID].rank
local duration = curses.sharedDebuffs[sharedDebuffKey][spellID].duration
if not curses.guids[targetGuid] then
curses.guids[targetGuid] = {}
end
curses.guids[targetGuid][name] = {
rank = rank,
duration = duration,
start = startTime,
spellID = spellID,
targetGuid = targetGuid,
currentPlayer = false,
}
end
-- Apply curse from player
function curses:ApplyCurse(spellID, targetGuid, startTime)
-- clear pending cast
curses.pendingCast = {}
@@ -477,7 +506,8 @@ function curses:ApplyCurse(spellID, targetGuid, startTime)
duration = duration,
start = startTime,
spellID = spellID,
targetGuid = targetGuid
targetGuid = targetGuid,
currentPlayer = true,
}
end
+19 -22
View File
@@ -98,44 +98,41 @@ function Cursive:ShouldDisplayGuid(guid)
return true
end
-- apply filters
local shouldDisplay = true -- default to true
if Cursive.db.profile.filterincombat then
shouldDisplay = shouldDisplay and filter.infight(guid)
if Cursive.db.profile.filterincombat and not filter.infight(guid) then
return false
end
if Cursive.db.profile.filterhascurse then
shouldDisplay = shouldDisplay and filter.hascurse(guid)
if Cursive.db.profile.filterhascurse and not filter.hascurse(guid) then
return false
end
if Cursive.db.profile.filterhostile then
shouldDisplay = shouldDisplay and filter.hostile(guid)
if Cursive.db.profile.filterhostile and not filter.hostile(guid) then
return false
end
if Cursive.db.profile.filterattackable then
shouldDisplay = shouldDisplay and filter.attackable(guid)
if Cursive.db.profile.filterattackable and not filter.attackable(guid) then
return false
end
if Cursive.db.profile.filterrange then
shouldDisplay = shouldDisplay and filter.range(guid)
if Cursive.db.profile.filterrange and not filter.range(guid) then
return false
end
if Cursive.db.profile.filterraidmark then
shouldDisplay = shouldDisplay and filter.icon(guid)
if Cursive.db.profile.filterraidmark and not filter.icon(guid) then
return false
end
if Cursive.db.profile.filterplayer then
shouldDisplay = shouldDisplay and filter.player(guid)
if Cursive.db.profile.filterplayer and not filter.player(guid) then
return false
end
if Cursive.db.profile.filternotplayer then
shouldDisplay = shouldDisplay and filter.notplayer(guid)
if Cursive.db.profile.filternotplayer and not filter.notplayer(guid) then
return false
end
if Cursive.db.profile.filterignored then
shouldDisplay = shouldDisplay and filter.notignored(guid)
if Cursive.db.profile.filterignored and not filter.notignored(guid) then
return false
end
return shouldDisplay
return true
end
+28 -15
View File
@@ -19,7 +19,10 @@ Cursive:RegisterDefaults("profile", {
showraidicons = true,
showhealthbar = true,
showunitname = true,
sharedFaerieFire = false,
shareddebuffs = {
faeriefire = false,
},
alwaysshowcurrenttarget = true,
@@ -411,6 +414,22 @@ local mobFilters = {
},
}
local sharedDebuffs = {
["sharedFaerieFire"] = {
type = "toggle",
name = L["Shared Faerie Fire"],
desc = L["This will show other player's Faerie Fires and avoid trying to cast Faerie Fire on those mobs"],
order = 10,
get = function()
return Cursive.db.profile.shareddebuffs.faeriefire
end,
set = function(v)
Cursive.db.profile.shareddebuffs.faeriefire = v
Cursive.UpdateFramesFromConfig()
end,
},
}
Cursive.cmdtable = {
type = "group",
handler = Cursive,
@@ -499,9 +518,16 @@ Cursive.cmdtable = {
type = "group",
name = L["Mob filters"],
desc = L["Target and Raid Marks always shown"],
order = 20,
order = 19,
args = mobFilters
},
["shareddebuffs"] = {
type = "group",
name = L["Shared Debuffs"],
desc = L["Shared Debuffs"],
order = 20,
args = sharedDebuffs
},
["spacer2"] = {
type = "header",
name = " ",
@@ -561,19 +587,6 @@ Cursive.cmdtable = {
end
end,
},
["sharedFaerieFire"] = {
type = "toggle",
name = L["Shared Faerie Fire"],
desc = L["This will show other player's Faerie Fires as well as your own"],
order = 10,
get = function()
return Cursive.db.profile.sharedFaerieFire
end,
set = function(v)
Cursive.db.profile.sharedFaerieFire = v
Cursive.UpdateFramesFromConfig()
end,
},
}
}
+8 -8
View File
@@ -17,15 +17,15 @@ function getDruidSpells()
[9749] = { name = L["faerie fire"], rank = 3, duration = 40 },
[9907] = { name = L["faerie fire"], rank = 4, duration = 40 },
[16855] = { name = L["faerie fire (bear)()"], rank = 1, duration = 40 },
[17387] = { name = L["faerie fire (bear)()"], rank = 2, duration = 40 },
[17388] = { name = L["faerie fire (bear)()"], rank = 3, duration = 40 },
[17389] = { name = L["faerie fire (bear)()"], rank = 4, duration = 40 },
[16855] = { name = L["faerie fire"], rank = 1, duration = 40 }, -- use faerie fire instead of (bear) version so they block each other
[17387] = { name = L["faerie fire"], rank = 2, duration = 40 },
[17388] = { name = L["faerie fire"], rank = 3, duration = 40 },
[17389] = { name = L["faerie fire"], rank = 4, duration = 40 },
[16857] = { name = L["faerie fire (feral)()"], rank = 1, duration = 40 },
[17390] = { name = L["faerie fire (feral)()"], rank = 2, duration = 40 },
[17391] = { name = L["faerie fire (feral)()"], rank = 3, duration = 40 },
[17392] = { name = L["faerie fire (feral)()"], rank = 4, duration = 40 },
[16857] = { name = L["faerie fire"], rank = 1, duration = 40 }, -- use faerie fire instead of (feral) version so they block each other
[17390] = { name = L["faerie fire"], rank = 2, duration = 40 },
[17391] = { name = L["faerie fire"], rank = 3, duration = 40 },
[17392] = { name = L["faerie fire"], rank = 4, duration = 40 },
[2637] = { name = L["hibernate"], rank = 1, duration = 20 },
[18657] = { name = L["hibernate"], rank = 2, duration = 30 },
+21
View File
@@ -0,0 +1,21 @@
local L = AceLibrary("AceLocale-2.2"):new("Cursive")
function getSharedDebuffs()
return {
faeriefire = {
[770] = { name = L["faerie fire"], rank = 1, duration = 40 },
[778] = { name = L["faerie fire"], rank = 2, duration = 40 },
[9749] = { name = L["faerie fire"], rank = 3, duration = 40 },
[9907] = { name = L["faerie fire"], rank = 4, duration = 40 },
[16855] = { name = L["faerie fire"], rank = 1, duration = 40 }, -- use faerie fire instead of (bear) version so they block each other
[17387] = { name = L["faerie fire"], rank = 2, duration = 40 },
[17388] = { name = L["faerie fire"], rank = 3, duration = 40 },
[17389] = { name = L["faerie fire"], rank = 4, duration = 40 },
[16857] = { name = L["faerie fire"], rank = 1, duration = 40 }, -- use faerie fire instead of (feral) version so they block each other
[17390] = { name = L["faerie fire"], rank = 2, duration = 40 },
[17391] = { name = L["faerie fire"], rank = 3, duration = 40 },
[17392] = { name = L["faerie fire"], rank = 4, duration = 40 },
}
}
end
+45
View File
@@ -416,6 +416,30 @@ local function GetBarCords(row, col)
return x, y
end
local function hasAnySpellId(guid, spellIds)
for i = 1, 16 do
local texture, stacks, spellSchool, spellId = UnitDebuff(guid, i);
if not spellId then
break
end
if spellIds[spellId] then
return spellId
end
end
for i = 1, 32 do
local texture, stacks, spellId = UnitBuff(guid, i);
if not spellId then
break
end
if spellIds[spellId] then
return spellId
end
end
return nil
end
local function GetSortedCurses(guidCurses)
-- Collect keys
local curseNames = {}
@@ -470,6 +494,20 @@ local function DisplayGuid(guid)
unitFrame.pos = x .. -y
end
-- check for shared debuffs
for sharedDebuffKey, guids in pairs(Cursive.curses.sharedDebuffGuids) do
if guids[guid] then
local sharedDebuffSpellIds = Cursive.curses.sharedDebuffs[sharedDebuffKey]
local spellId = hasAnySpellId(guid, sharedDebuffSpellIds)
if spellId ~= nil then
-- add curse to curses
Cursive.curses:ApplySharedCurse(sharedDebuffKey, spellId, guid, GetTime())
-- remove guid
Cursive.curses.sharedDebuffGuids[sharedDebuffKey][guid] = nil
end
end
end
-- update curses
local curseNumber = 1
@@ -491,6 +529,13 @@ local function DisplayGuid(guid)
local curse = unitFrame["curse" .. curseNumber]
if remaining >= 0 then
curse:SetTexture(Cursive.curses.trackedCurseIds[curseData.spellID].texture)
if curseData["currentPlayer"] == false then
curse:SetDesaturated(true); -- desaturate if not applied by current player
else
curse:SetDesaturated(false); -- saturate if applied by current player
end
-- curse:SetTexCoord(.078, .92, .079, .937) rounded icons
curse.timer:SetText(remaining)
curse.timer:Show()