401 lines
14 KiB
Lua
401 lines
14 KiB
Lua
--[[
|
|
Name: DRList-1.0
|
|
Description: Diminishing returns categorization. Fork of outdated DRData-1.0.
|
|
Website: https://github.com/wardz/DRList-1.0/
|
|
Documentation: https://wardz.github.io/DRList-1.0/
|
|
Dependencies: LibStub
|
|
License: MIT
|
|
]]
|
|
|
|
--- DRList-1.0
|
|
-- @module DRList-1.0
|
|
local MAJOR, MINOR = "DRList-1.0", 42 -- Don't forget to change this in Spells.lua aswell!
|
|
local Lib = assert(LibStub, MAJOR .. " requires LibStub."):NewLibrary(MAJOR, MINOR)
|
|
if not Lib then return end -- already loaded
|
|
|
|
-------------------------------------------------------------------------------
|
|
-- *** LOCALIZATIONS ARE AUTOMATICALLY GENERATED ***
|
|
-- Please see Curseforge localization page if you'd like to help translate.
|
|
-- https://www.curseforge.com/wow/addons/drlist-1-0/localization
|
|
local L = {}
|
|
Lib.L = L
|
|
L["DISARMS"] = "Disarms"
|
|
L["DISORIENTS"] = "Disorients"
|
|
L["INCAPACITATES"] = "Incapacitates"
|
|
L["KNOCKBACKS"] = "Knockbacks"
|
|
L["ROOTS"] = "Roots"
|
|
L["SILENCES"] = "Silences"
|
|
L["STUNS"] = "Stuns"
|
|
L["TAUNTS"] = "Taunts"
|
|
L["FEARS"] = "Fears"
|
|
L["RANDOM_ROOTS"] = "Random roots"
|
|
L["RANDOM_STUNS"] = "Random stuns"
|
|
L["OPENER_STUN"] = "Opener Stuns"
|
|
L["HORROR"] = "Horrors"
|
|
L["SCATTERS"] = "Scatters"
|
|
L["SLEEPS"] = GetSpellInfo(1090) or "Sleep"
|
|
L["MIND_CONTROL"] = GetSpellInfo(605) or "Mind Control"
|
|
L["FROST_SHOCK"] = GetSpellInfo(15089) or "Frost Shock"
|
|
L["KIDNEY_SHOT"] = GetSpellInfo(408) or "Kidney Shot"
|
|
L["DEATH_COIL"] = GetSpellInfo(28412) or "Death Coil"
|
|
L["UNSTABLE_AFFLICTION"] = GetSpellInfo(31117) or "Unstable Affliction"
|
|
L["CHASTISE"] = GetSpellInfo(44041) or "Chastise"
|
|
L["COUNTERATTACK"] = GetSpellInfo(19306) or "Counterattack"
|
|
L["CYCLONE"] = GetSpellInfo(33786) or "Cyclone"
|
|
L["BANISH"] = GetSpellInfo(710) or "Banish"
|
|
L["CHARGE"] = GetSpellInfo(100) or "Charge"
|
|
|
|
-- luacheck: push ignore 542
|
|
local locale = GetLocale()
|
|
if locale == "deDE" then
|
|
L["FEARS"] = "Furchteffekte"
|
|
L["KNOCKBACKS"] = "Rückstoßeffekte"
|
|
L["ROOTS"] = "Bewegungsunfähigkeitseffekte"
|
|
L["SILENCES"] = "Stilleeffekte"
|
|
L["STUNS"] = "Betäubungseffekte"
|
|
L["TAUNTS"] = "Spotteffekte"
|
|
elseif locale == "frFR" then
|
|
L["FEARS"] = "Peurs"
|
|
L["KNOCKBACKS"] = "Projections"
|
|
L["ROOTS"] = "Immobilisations"
|
|
L["SILENCES"] = "Silences"
|
|
L["STUNS"] = "Etourdissements"
|
|
L["TAUNTS"] = "Provocations"
|
|
elseif locale == "itIT" then
|
|
--@localization(locale="itIT", namespace="Categories", format="lua_additive_table", handle-unlocalized="ignore")@
|
|
elseif locale == "koKR" then
|
|
L["DISORIENTS"] = "방향 감각 상실"
|
|
L["INCAPACITATES"] = "행동 불가"
|
|
L["KNOCKBACKS"] = "밀쳐내기"
|
|
L["ROOTS"] = "이동 불가"
|
|
L["SILENCES"] = "침묵"
|
|
L["STUNS"] = "기절"
|
|
elseif locale == "ptBR" then
|
|
--@localization(locale="ptBR", namespace="Categories", format="lua_additive_table", handle-unlocalized="ignore")@
|
|
elseif locale == "ruRU" then
|
|
L["DISARMS"] = "Разоружение"
|
|
L["DISORIENTS"] = "Дезориентация"
|
|
L["FEARS"] = "Опасения"
|
|
L["INCAPACITATES"] = "Паралич"
|
|
L["KNOCKBACKS"] = "Отбрасывание"
|
|
L["RANDOM_ROOTS"] = "Случайные корни"
|
|
L["RANDOM_STUNS"] = "Случайные оглушения"
|
|
L["ROOTS"] = "Сковывание"
|
|
L["SILENCES"] = "Немота"
|
|
L["STUNS"] = "Оглушение"
|
|
L["TAUNTS"] = "Насмешки"
|
|
elseif locale == "esES" or locale == "esMX" then
|
|
L["DISARMS"] = "Desarmar"
|
|
L["DISORIENTS"] = "Desorientar"
|
|
L["FEARS"] = "Miedos"
|
|
L["INCAPACITATES"] = "Incapacitar"
|
|
L["KNOCKBACKS"] = "Derribos"
|
|
L["RANDOM_ROOTS"] = "Raíces aleatorias"
|
|
L["RANDOM_STUNS"] = "Aturdir aleatorio"
|
|
L["ROOTS"] = "Raíces"
|
|
L["SILENCES"] = "Silencios"
|
|
L["STUNS"] = "Aturdimientos"
|
|
L["TAUNTS"] = "Provocaciones"
|
|
elseif locale == "zhCN" then
|
|
L["DISARMS"] = "缴械"
|
|
L["DISORIENTS"] = "迷惑"
|
|
L["FEARS"] = "恐惧"
|
|
L["INCAPACITATES"] = "瘫痪"
|
|
L["KNOCKBACKS"] = "击退"
|
|
L["RANDOM_ROOTS"] = "随机定身"
|
|
L["RANDOM_STUNS"] = "随机眩晕"
|
|
L["ROOTS"] = "定身"
|
|
L["SILENCES"] = "沉默"
|
|
L["STUNS"] = "昏迷"
|
|
L["TAUNTS"] = "嘲讽"
|
|
elseif locale == "zhTW" then
|
|
L["DISARMS"] = "繳械"
|
|
L["DISORIENTS"] = "迷惑"
|
|
L["FEARS"] = "恐懼"
|
|
L["INCAPACITATES"] = "癱瘓"
|
|
L["KNOCKBACKS"] = "擊退"
|
|
L["RANDOM_ROOTS"] = "隨機定身"
|
|
L["RANDOM_STUNS"] = "隨機昏迷"
|
|
L["ROOTS"] = "定身"
|
|
L["SILENCES"] = "沉默"
|
|
L["STUNS"] = "昏迷"
|
|
L["TAUNTS"] = "嘲諷"
|
|
end
|
|
-- luacheck: pop
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- Check what game version we're running
|
|
Lib.gameExpansion = ({
|
|
[WOW_PROJECT_MAINLINE] = "retail",
|
|
[WOW_PROJECT_CLASSIC] = "classic",
|
|
[WOW_PROJECT_BURNING_CRUSADE_CLASSIC or 5] = "tbc",
|
|
})[WOW_PROJECT_ID]
|
|
|
|
local tocVersion = select(4, GetBuildInfo())
|
|
if tocVersion >= 30400 and tocVersion < 40000 then
|
|
Lib.gameExpansion = "wotlk" -- temporary check for wotlk build until new constant is added
|
|
end
|
|
|
|
-- How long it takes for a DR to expire, in seconds.
|
|
Lib.resetTimes = {
|
|
retail = {
|
|
["default"] = 18.5, -- 18 sec + 0.5 latency
|
|
["npc"] = 23, -- Against mobs it seems to last slightly longer, depending on server load
|
|
["knockback"] = 10, -- Knockbacks are immediately immune and only DRs for 10s
|
|
},
|
|
|
|
classic = {
|
|
["default"] = 19, -- dynamic between 15 and 20s
|
|
["npc"] = 23,
|
|
},
|
|
|
|
tbc = {
|
|
["default"] = 19, -- dynamic between 15 and 20s
|
|
["npc"] = 23,
|
|
},
|
|
|
|
wotlk = {
|
|
["default"] = 19, -- dynamic between 15 and 20s
|
|
["npc"] = 23,
|
|
},
|
|
}
|
|
|
|
-- List of all DR categories, english -> localized.
|
|
Lib.categoryNames = {
|
|
retail = {
|
|
["disorient"] = L.DISORIENTS,
|
|
["incapacitate"] = L.INCAPACITATES,
|
|
["silence"] = L.SILENCES,
|
|
["stun"] = L.STUNS,
|
|
["root"] = L.ROOTS,
|
|
["disarm"] = L.DISARMS,
|
|
["taunt"] = L.TAUNTS,
|
|
["knockback"] = L.KNOCKBACKS,
|
|
},
|
|
|
|
classic = {
|
|
["incapacitate"] = L.INCAPACITATES,
|
|
["stun"] = L.STUNS, -- controlled stun
|
|
["root"] = L.ROOTS, -- controlled root
|
|
["random_stun"] = L.RANDOM_STUNS, -- random proc stun, usually short (<3s)
|
|
["random_root"] = L.RANDOM_ROOTS,
|
|
["fear"] = L.FEARS,
|
|
["mind_control"] = L.MIND_CONTROL,
|
|
["frost_shock"] = L.FROST_SHOCK,
|
|
["kidney_shot"] = L.KIDNEY_SHOT,
|
|
},
|
|
|
|
tbc = {
|
|
["disorient"] = L.DISORIENTS,
|
|
["incapacitate"] = L.INCAPACITATES,
|
|
["stun"] = L.STUNS,
|
|
["random_stun"] = L.RANDOM_STUNS,
|
|
["random_root"] = L.RANDOM_ROOTS,
|
|
["root"] = L.ROOTS,
|
|
["disarm"] = L.DISARMS,
|
|
["fear"] = L.FEARS,
|
|
["scatter"] = L.SCATTERS,
|
|
["mind_control"] = L.MIND_CONTROL,
|
|
["kidney_shot"] = L.KIDNEY_SHOT,
|
|
["death_coil"] = L.DEATH_COIL,
|
|
["unstable_affliction"] = L.UNSTABLE_AFFLICTION,
|
|
["chastise"] = L.CHASTISE,
|
|
["counterattack"] = L.COUNTERATTACK,
|
|
},
|
|
|
|
wotlk = { -- WORK IN PROGRESS
|
|
["incapacitate"] = L.INCAPACITATES,
|
|
["stun"] = L.STUNS,
|
|
["random_stun"] = L.RANDOM_STUNS,
|
|
["random_root"] = L.RANDOM_ROOTS,
|
|
["root"] = L.ROOTS,
|
|
["disarm"] = L.DISARMS,
|
|
["fear"] = L.FEARS,
|
|
["scatter"] = L.SCATTERS,
|
|
["silence"] = L.SILENCES,
|
|
["horror"] = L.HORROR,
|
|
["mind_control"] = L.MIND_CONTROL,
|
|
["cyclone"] = L.CYCLONE,
|
|
["charge"] = L.CHARGE,
|
|
["opener_stun"] = L.OPENER_STUN,
|
|
["counterattack"] = L.COUNTERATTACK,
|
|
},
|
|
}
|
|
|
|
-- Categories that have DR against normal mobs.
|
|
-- Note that this is only for normal mobs on retail. Special mobs or pets have DR on all categories,
|
|
-- see UnitClassification() and UnitIsQuestBoss().
|
|
Lib.categoriesPvE = {
|
|
retail = {
|
|
["taunt"] = L.TAUNTS, -- Lib.categoryNames.retail.taunt
|
|
["stun"] = L.STUNS,
|
|
["root"] = L.ROOTS,
|
|
},
|
|
|
|
classic = {
|
|
["stun"] = L.STUNS,
|
|
["kidney_shot"] = L.KIDNEY_SHOT,
|
|
},
|
|
|
|
tbc = {
|
|
["stun"] = L.STUNS,
|
|
["random_stun"] = L.RANDOM_STUNS,
|
|
["kidney_shot"] = L.KIDNEY_SHOT,
|
|
},
|
|
|
|
wotlk = {
|
|
--["taunt"] = L.TAUNTS,
|
|
["stun"] = L.STUNS,
|
|
["random_stun"] = L.RANDOM_STUNS,
|
|
["opener_stun"] = L.OPENER_STUN,
|
|
},
|
|
}
|
|
|
|
-- Successives diminished durations
|
|
Lib.diminishedDurations = {
|
|
retail = {
|
|
-- Decreases by 50%, immune at the 4th application
|
|
["default"] = { 0.50, 0.25 },
|
|
-- Decreases by 35%, immune at the 5th application
|
|
["taunt"] = { 0.65, 0.42, 0.27 },
|
|
-- Immediately immune
|
|
["knockback"] = {},
|
|
},
|
|
|
|
classic = {
|
|
["default"] = { 0.50, 0.25 },
|
|
},
|
|
|
|
tbc = {
|
|
["default"] = { 0.50, 0.25 },
|
|
},
|
|
|
|
wotlk = {
|
|
["default"] = { 0.50, 0.25 },
|
|
},
|
|
}
|
|
|
|
-------------------------------------------------------------------------------
|
|
-- Public API
|
|
-------------------------------------------------------------------------------
|
|
|
|
--- Get table of all spells that DRs.
|
|
-- Key is the spellID, and value is the unlocalized DR category.
|
|
-- For Classic the key is the localized spell name instead, and value
|
|
-- is a table containing both the DR category and spell ID. (Classic has no spellID payload in the combat log)
|
|
-- @see IterateSpellsByCategory
|
|
-- @treturn ?table {number=string}|table {string=table}
|
|
function Lib:GetSpells()
|
|
return Lib.spellList
|
|
end
|
|
|
|
--- Get table of all DR categories.
|
|
-- Key is unlocalized name used for API functions, value is localized name used for UI.
|
|
-- @treturn table {string=string}
|
|
function Lib:GetCategories()
|
|
return Lib.categoryNames[Lib.gameExpansion]
|
|
end
|
|
|
|
--- Get table of all categories that DRs in PvE only.
|
|
-- Key is unlocalized name used for API functions, value is localized name used for UI.
|
|
-- Note that this is only for normal mobs on retail. Special mobs or pets have DR on all categories,
|
|
-- see UnitClassification() and UnitIsQuestBoss().
|
|
-- Tip: you can combine :GetPvECategories() and :IterateSpellsByCategory() to get spellIDs only for PvE aswell.
|
|
-- @treturn table {string=string}
|
|
function Lib:GetPvECategories()
|
|
return Lib.categoriesPvE[Lib.gameExpansion]
|
|
end
|
|
|
|
--- Get constant for how long a DR lasts for a given category.
|
|
-- @tparam[opt="default"] string category Unlocalized category name, or "npc" for PvE timer.
|
|
-- @treturn number
|
|
function Lib:GetResetTime(category)
|
|
return Lib.resetTimes[Lib.gameExpansion][category or "default"] or Lib.resetTimes[Lib.gameExpansion].default
|
|
end
|
|
|
|
--- Get unlocalized DR category by spell ID.
|
|
-- For Classic (vanilla) you should pass in the spell name instead of ID.
|
|
-- For Classic you also get an optional second return value
|
|
-- which is the hardcoded spell ID of the spell name you passed in.
|
|
-- You should use this ID to query additional info from Blizzard API if needed, as
|
|
-- spell names only works for the player if they have the spell in their current spellbook.
|
|
-- @tparam number spellID
|
|
-- @treturn[1] string|nil The category name.
|
|
-- @treturn[2] number|nil The spell ID. (Classic only)
|
|
function Lib:GetCategoryBySpellID(spellID)
|
|
if Lib.gameExpansion == "classic" then
|
|
-- special case for classic as CLEU doesn't provide spellIDs
|
|
local data = Lib.spellList[spellID]
|
|
if not data then return end
|
|
return data.category, data.spellID
|
|
end
|
|
|
|
return Lib.spellList[spellID]
|
|
end
|
|
|
|
--- Get localized category from unlocalized category name, case sensitive.
|
|
-- @tparam string category Unlocalized category name
|
|
-- @treturn ?string|nil The localized category name.
|
|
function Lib:GetCategoryLocalization(category)
|
|
return Lib.categoryNames[Lib.gameExpansion][category]
|
|
end
|
|
|
|
--- Check if a category has DR against mobs.
|
|
-- Note that this is only for normal mobs on retail. Special mobs or pets have DR on all categories,
|
|
-- see UnitClassification() and UnitIsQuestBoss().
|
|
-- @tparam string category Unlocalized category name
|
|
-- @treturn bool
|
|
function Lib:IsPvECategory(category)
|
|
return Lib.categoriesPvE[Lib.gameExpansion][category] and true or false -- make sure bool is always returned here
|
|
end
|
|
|
|
--- Get next successive diminished duration
|
|
-- @tparam number diminished How many times the DR has been applied so far
|
|
-- @tparam[opt="default"] string category Unlocalized category name
|
|
-- @usage local reduction = DRList:GetNextDR(1) -- returns 0.50, half duration on debuff
|
|
-- @treturn number DR percentage in decimals. Returns 0 if max DR is reached or arguments are invalid.
|
|
function Lib:GetNextDR(diminished, category)
|
|
local durations = Lib.diminishedDurations[Lib.gameExpansion][category or "default"]
|
|
if not durations and Lib.categoryNames[Lib.gameExpansion][category] then
|
|
-- Redirect to default when "stun", "root" etc is passed
|
|
durations = Lib.diminishedDurations[Lib.gameExpansion]["default"]
|
|
end
|
|
|
|
return durations and durations[diminished] or 0
|
|
end
|
|
|
|
do
|
|
local next = _G.next
|
|
|
|
local function CategoryIterator(category, index)
|
|
local spellList, newCat = Lib.spellList
|
|
repeat
|
|
index, newCat = next(spellList, index)
|
|
if index then
|
|
if newCat == category or newCat.category == category then
|
|
return index, category
|
|
end
|
|
end
|
|
until not index
|
|
end
|
|
|
|
--- Iterate through the spells of a given category.
|
|
-- @tparam string category Unlocalized category name
|
|
-- @usage for spellID in DRList:IterateSpellsByCategory("root") do print(spellID) end
|
|
-- @warning Slow function, do not use for frequent combat related stuff unless you cache results.
|
|
-- @return Iterator function
|
|
function Lib:IterateSpellsByCategory(category)
|
|
assert(Lib.categoryNames[Lib.gameExpansion][category], "invalid category")
|
|
return CategoryIterator, category
|
|
end
|
|
end
|
|
|
|
-- keep same API as DRData-1.0 for easier transitions
|
|
Lib.GetCategoryName = Lib.GetCategoryLocalization
|
|
Lib.IsPVE = Lib.IsPvECategory
|
|
Lib.NextDR = Lib.GetNextDR
|
|
Lib.GetSpellCategory = Lib.GetCategoryBySpellID
|
|
Lib.IterateSpells = Lib.IterateSpellsByCategory
|
|
Lib.RESET_TIME = Lib.resetTimes[Lib.gameExpansion].default
|
|
Lib.pveDR = Lib.categoriesPvE
|