Files
coa-details/Libs/LibOpenRaid/GetPlayerInformation.lua
T
Tercio Jose 1830359943 General Fixes, Backend Improvements, Library Updates.
Release Documentation:
- Classic now uses the same combat log reader as retail (Flamanis).
- Merged Rage of Fyr'alath spells (equara).
- Added Rogue Ambushes to merged spells (WillowGryph).
- The Remove Common Segments option now also removes segments trash between raid bosses.
- Fixed an issue where auras applied before combat start, such as Power Infusion and Prescience, which are counted towards the target, were not being accounted for.
- Added to Combat Class: classCombat:GetRunTimeNoDefault(). This returns the run time of the Mythic+ if available, nil otherwise.

Technical Notes:
- Classic now uses retail parser.
- Combat class now have the member: classCombat:GetRunTimeNoDefault(); Returns the run time of a M+ (after completed).
- The Utility class's buff scan at the start of combat has been improved, and the code has been cleaned. Also, the scan runs now on the next frame after combat start.
- Augmentation Evoker won't track auras from the combat start aura scan, if the player isn't in combat (example: a player in the group enters in combat).
- Remove tier bonus for Augmentation Evoker Ebon Might damage prediction and nerfed Close as Cluthmates to 10%.
- Segments Container's ResetDataByCombatType() now supports multiple combat types per classification.
- Code cleanup on Segments menu code to use the new Mythic+ functions added to Combat class.
- Mythic+ start detection produced errors if a WORLD_STATE_TIMER_START event triggered before the CHALLENGE_MODE_START event.
- Mythic+ finish code was bugging when 'time' returned by C_ChallengeMode.GetCompletionInfo() wasn't being checked again nil value.
- Rogue's Ambush ability and Rage of Fyr'alath spellIds added to override_spellId within the parser.
- Details! Framework updated.
- Open Raid Library updated.
2023-12-14 11:33:30 -03:00

979 lines
35 KiB
Lua

--[=[
This file has the functions to get player information
Dumping them here, make the code of the main file smaller
--]=]
if (not LIB_OPEN_RAID_CAN_LOAD) then
return
end
local openRaidLib = LibStub:GetLibrary("LibOpenRaid-1.0")
local CONST_TALENT_VERSION_CLASSIC = 1
local CONST_TALENT_VERSION_LEGION = 4
local CONST_TALENT_VERSION_DRAGONFLIGHT = 5
local CONST_BTALENT_VERSION_COVENANTS = 9
local CONST_SPELLBOOK_CLASSSPELLS_TABID = 2
local CONST_SPELLBOOK_GENERAL_TABID = 1
local CONST_ISITEM_BY_TYPEID = {
[10] = true, --healing items
[11] = true, --attack items
[12] = true, --utility items
}
local GetItemInfo = GetItemInfo
local GetItemStats = GetItemStats
local GetInventoryItemLink = GetInventoryItemLink
local isTimewalkWoW = function()
local _, _, _, buildInfo = GetBuildInfo()
if (buildInfo < 40000) then
return true
end
end
local IsDragonflight = function()
return select(4, GetBuildInfo()) >= 100000
end
local IsShadowlands = function()
local versionString, revision, launchDate, gameVersion = GetBuildInfo()
if (gameVersion >= 90000 and gameVersion < 100000) then
return true
end
end
--information about the player character to send, each expansion has its own system and data can be different
--it's always a number
function openRaidLib.UnitInfoManager.GetPlayerInfo1()
if (IsShadowlands()) then
--return the renown level within the player covenant
local renown = C_CovenantSanctumUI.GetRenownLevel() or 1
return renown
end
return 0
end
--information about the player character to send, each expansion has its own system and data can be different
--it's always a number
function openRaidLib.UnitInfoManager.GetPlayerInfo2()
if (IsShadowlands()) then
--return which covenant the player picked
local covenant = C_Covenants.GetActiveCovenantID() or 0
return covenant
end
return 0
end
--default player class-spec talent system
function openRaidLib.GetTalentVersion()
local _, _, _, buildInfo = GetBuildInfo()
if (buildInfo >= 1 and buildInfo <= 40000) then --vanilla tbc wotlk cataclysm
return CONST_TALENT_VERSION_CLASSIC
end
if (buildInfo >= 70000 and buildInfo <= 100000) then --legion bfa shadowlands
return CONST_TALENT_VERSION_LEGION
end
if (buildInfo >= 100000 and buildInfo <= 200000) then --dragonflight
return CONST_TALENT_VERSION_DRAGONFLIGHT
end
end
--secondary talent tree, can be a legendary weapon talent tree, covenant talent tree, etc...
function openRaidLib.GetBorrowedTalentVersion()
if (IsShadowlands()) then
return CONST_BTALENT_VERSION_COVENANTS
end
end
local getDragonflightTalentsExportedString = function()
local exportStream = ExportUtil.MakeExportDataStream()
local configId = C_ClassTalents.GetActiveConfigID()
if (configId) then
local configInfo = C_Traits.GetConfigInfo(configId)
local currentSpecID = PlayerUtil.GetCurrentSpecID()
local treeInfo = C_Traits.GetTreeInfo(configId, configInfo.treeIDs[1])
local treeHash = C_Traits.GetTreeHash(treeInfo.ID)
local serializationVersion = C_Traits.GetLoadoutSerializationVersion()
end
end
local getDragonflightTalentsAsIndexTable = function()
local allTalents = {}
local configId = C_ClassTalents.GetActiveConfigID()
if (not configId) then
return allTalents
end
local configInfo = C_Traits.GetConfigInfo(configId)
for treeIndex, treeId in ipairs(configInfo.treeIDs) do
local treeNodes = C_Traits.GetTreeNodes(treeId)
for nodeIdIndex, treeNodeID in ipairs(treeNodes) do
local traitNodeInfo = C_Traits.GetNodeInfo(configId, treeNodeID)
if (traitNodeInfo) then
local activeEntry = traitNodeInfo.activeEntry
if (activeEntry) then
local entryId = activeEntry.entryID
local rank = activeEntry.rank
if (rank > 0) then
--get the entry info
local traitEntryInfo = C_Traits.GetEntryInfo(configId, entryId)
local definitionId = traitEntryInfo.definitionID
--definition info
local traitDefinitionInfo = C_Traits.GetDefinitionInfo(definitionId)
local spellId = traitDefinitionInfo.overriddenSpellID or traitDefinitionInfo.spellID
local spellName, _, spellTexture = GetSpellInfo(spellId)
if (spellName) then
allTalents[#allTalents+1] = spellId
end
end
end
end
end
end
return allTalents
end
--creates two tables, one with indexed talents and another with pairs values ([talentId] = true)
function openRaidLib.UnitInfoManager.GetPlayerTalentsAsPairsTable()
local talentsPairs = {}
local talentVersion = openRaidLib.GetTalentVersion()
if (talentVersion == CONST_TALENT_VERSION_DRAGONFLIGHT) then
local allTalents = getDragonflightTalentsAsIndexTable()
for i = 1, #allTalents do
local spellId = allTalents[i]
talentsPairs[spellId] = true
end
elseif (talentVersion == CONST_TALENT_VERSION_LEGION) then
for i = 1, 7 do
for o = 1, 3 do
local talentId, _, _, selected = GetTalentInfo(i, o, 1)
if (selected) then
talentsPairs[talentId] = true
break
end
end
end
end
return talentsPairs
end
function openRaidLib.UnitInfoManager.GetPlayerTalents()
local talents = {}
local talentVersion = openRaidLib.GetTalentVersion()
if (talentVersion == CONST_TALENT_VERSION_DRAGONFLIGHT) then
talents = getDragonflightTalentsAsIndexTable()
elseif (talentVersion == CONST_TALENT_VERSION_LEGION) then
talents = {0, 0, 0, 0, 0, 0, 0}
for talentTier = 1, 7 do
for talentColumn = 1, 3 do
local talentId, name, texture, selected, available = GetTalentInfo(talentTier, talentColumn, 1)
if (selected) then
talents[talentTier] = talentId
break
end
end
end
end
return talents
end
function openRaidLib.UnitInfoManager.GetPlayerPvPTalents()
if (IsDragonflight()) then
return {}
end
local talentsPvP = {0, 0, 0}
local talentList = C_SpecializationInfo.GetAllSelectedPvpTalentIDs()
for talentIndex, talentId in ipairs(talentList) do
local doesExists = GetPvpTalentInfoByID(talentId)
if (doesExists) then
talentsPvP[talentIndex] = talentId
end
end
return talentsPvP
end
--return the current specId of the player
function openRaidLib.GetPlayerSpecId()
if (isTimewalkWoW()) then
return 0
end
local spec = GetSpecialization()
if (spec) then
local specId = GetSpecializationInfo(spec)
if (specId and specId > 0) then
return specId
end
end
end
--borrowed talent tree from shadowlands
function openRaidLib.UnitInfoManager.GetPlayerConduits()
local conduits = {}
local soulbindID = C_Soulbinds.GetActiveSoulbindID()
if (soulbindID ~= 0) then
local soulbindData = C_Soulbinds.GetSoulbindData(soulbindID)
if (soulbindData ~= 0) then
local tree = soulbindData.tree
local nodes = tree.nodes
table.sort(nodes, function(t1, t2) return t1.row < t2.row end)
local C_Soulbinds_GetConduitCollectionData = C_Soulbinds.GetConduitCollectionData
for nodeId, nodeInfo in ipairs(nodes) do
--check if the node is a conduit placed by the player
if (nodeInfo.state == Enum.SoulbindNodeState.Selected) then
local conduitId = nodeInfo.conduitID
local conduitRank = nodeInfo.conduitRank
if (conduitId and conduitRank) then
--have spell id when it's a default conduit from the game
local spellId = nodeInfo.spellID
--have conduit id when is a conduid placed by the player
local conduitId = nodeInfo.conduitID
if (spellId == 0) then
--is player conduit
spellId = C_Soulbinds.GetConduitSpellID(nodeInfo.conduitID, nodeInfo.conduitRank)
conduits[#conduits+1] = spellId
local collectionData = C_Soulbinds_GetConduitCollectionData(conduitId)
conduits[#conduits+1] = collectionData and collectionData.conduitItemLevel or 0
else
--is default conduit
conduits[#conduits+1] = spellId
conduits[#conduits+1] = 0
end
end
end
end
end
end
return conduits
end
function openRaidLib.UnitInfoManager.GetPlayerBorrowedTalents()
local borrowedTalentVersion = openRaidLib.GetBorrowedTalentVersion()
if (borrowedTalentVersion == CONST_BTALENT_VERSION_COVENANTS) then
return openRaidLib.UnitInfoManager.GetPlayerConduits()
end
return {}
end
function openRaidLib.GearManager.GetPlayerItemLevel()
if (_G.GetAverageItemLevel) then
local _, itemLevel = GetAverageItemLevel()
itemLevel = floor(itemLevel)
return itemLevel
else
return 0
end
end
--return an integer between zero and one hundret indicating the player gear durability
function openRaidLib.GearManager.GetPlayerGearDurability()
local durabilityTotalPercent, totalItems = 0, 0
--hold the lowest item durability of all the player gear
--this prevent the case where the player has an average of 80% durability but an item with 15% durability
local lowestGearDurability = 100
for i = INVSLOT_FIRST_EQUIPPED, INVSLOT_LAST_EQUIPPED do
local durability, maxDurability = GetInventoryItemDurability(i)
if (durability and maxDurability) then
local itemDurability = durability / maxDurability * 100
if (itemDurability < lowestGearDurability) then
lowestGearDurability = itemDurability
end
durabilityTotalPercent = durabilityTotalPercent + itemDurability
totalItems = totalItems + 1
end
end
if (totalItems == 0) then
return 100, lowestGearDurability
end
return floor(durabilityTotalPercent / totalItems), lowestGearDurability
end
function openRaidLib.GearManager.GetPlayerWeaponEnchant()
local weaponEnchant = 0
local _, _, _, mainHandEnchantId, _, _, _, offHandEnchantId = GetWeaponEnchantInfo()
if (LIB_OPEN_RAID_WEAPON_ENCHANT_IDS[mainHandEnchantId]) then
weaponEnchant = 1
elseif(LIB_OPEN_RAID_WEAPON_ENCHANT_IDS[offHandEnchantId]) then
weaponEnchant = 1
end
return weaponEnchant, mainHandEnchantId or 0, offHandEnchantId or 0
end
function openRaidLib.GearManager.GetPlayerGemsAndEnchantInfo()
--hold equipmentSlotId of equipment with a gem socket but it's empty
local slotsWithoutGems = {}
--hold equipmentSlotId of equipments without an enchant
local slotsWithoutEnchant = {}
local gearWithEnchantIds = {}
for equipmentSlotId = 1, 17 do
local itemLink = GetInventoryItemLink("player", equipmentSlotId)
if (itemLink) then
--get the information from the item
local _, itemId, enchantId, gemId1, gemId2, gemId3, gemId4, suffixId, uniqueId, levelOfTheItem, specId, upgradeInfo, instanceDifficultyId, numBonusIds, restLink = strsplit(":", itemLink)
local gemsIds = {gemId1, gemId2, gemId3, gemId4}
--enchant
--check if the slot can receive enchat and if the equipment has an enchant
local enchantAttribute = LIB_OPEN_RAID_ENCHANT_SLOTS[equipmentSlotId]
local nEnchantId = 0
if (enchantAttribute) then --this slot can receive an enchant
if (enchantId and enchantId ~= "") then
local number = tonumber(enchantId)
nEnchantId = number
gearWithEnchantIds[#gearWithEnchantIds+1] = nEnchantId
else
gearWithEnchantIds[#gearWithEnchantIds+1] = 0
end
--6400 and above is dragonflight enchantId number space
if (nEnchantId < 6300 and not LIB_OPEN_RAID_DEATHKNIGHT_RUNEFORGING_ENCHANT_IDS[nEnchantId]) then
slotsWithoutEnchant[#slotsWithoutEnchant+1] = equipmentSlotId
end
end
--gems
local itemStatsTable = {}
--fill the table above with information about the item
GetItemStats(itemLink, itemStatsTable)
--check if the item has a socket
if (itemStatsTable.EMPTY_SOCKET_PRISMATIC) then
--check if the socket is empty
for i = 1, itemStatsTable.EMPTY_SOCKET_PRISMATIC do
local gemId = tonumber(gemsIds[i])
if (not gemId or gemId == 0) then
slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId
--check if the gem is not a valid gem (deprecated gem)
elseif (gemId < 180000) then
slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId
end
end
end
end
end
return slotsWithoutGems, slotsWithoutEnchant
end
function openRaidLib.GearManager.BuildPlayerEquipmentList()
local equipmentList = {}
local debug
for equipmentSlotId = 1, 17 do
local itemLink = GetInventoryItemLink("player", equipmentSlotId)
if (itemLink) then
local itemStatsTable = {}
local itemID, enchantID, gemID1, gemID2, gemID3, gemID4, suffixID, uniqueID, linkLevel, specializationID, modifiersMask, itemContext = select(2, strsplit(":", itemLink))
itemID = tonumber(itemID)
local effectiveILvl, isPreview, baseILvl = GetDetailedItemLevelInfo(itemLink)
if (not effectiveILvl) then
openRaidLib.mainControl.scheduleUpdatePlayerData()
effectiveILvl = 0
openRaidLib.__errors[#openRaidLib.__errors+1] = "Fail to get Item Level: " .. (itemID or "invalid itemID") .. " " .. (itemLink and itemLink:gsub("|H", "") or "invalid itemLink")
end
GetItemStats(itemLink, itemStatsTable)
local gemSlotsAvailable = itemStatsTable and itemStatsTable.EMPTY_SOCKET_PRISMATIC or 0
local noPrefixItemLink = itemLink : gsub("^|c%x%x%x%x%x%x%x%x|Hitem", "")
local linkTable = {strsplit(":", noPrefixItemLink)}
local numModifiers = linkTable[14]
numModifiers = numModifiers and tonumber(numModifiers) or 0
for i = #linkTable, 14 + numModifiers + 1, -1 do
tremove(linkTable, i)
end
local newItemLink = table.concat(linkTable, ":")
newItemLink = newItemLink
equipmentList[#equipmentList+1] = {equipmentSlotId, gemSlotsAvailable, effectiveILvl, newItemLink}
if (equipmentSlotId == 2) then
debug = {itemLink:gsub("|H", ""), newItemLink}
end
end
end
--[[ debug
local str = ""
for i = 1, #equipmentList do
local t = equipmentList[i]
local s = t[1] .. "," .. t[2] .. "," .. t[3] .. "," .. t[4]
str = str .. s
end
table.insert(debug, str)
dumpt(debug)
--]]
return equipmentList
end
local playerHasPetOfNpcId = function(npcId)
if (UnitExists("pet") and UnitHealth("pet") >= 1) then
local guid = UnitGUID("pet")
if (guid) then
local split = {strsplit("-", guid)}
local playerPetNpcId = tonumber(split[6])
if (playerPetNpcId) then
if (npcId == playerPetNpcId) then
return true
end
end
end
end
end
local addCooldownToTable = function(cooldowns, cooldownsHash, cooldownSpellId, timeNow)
local timeLeft, charges, startTimeOffset, duration, auraDuration = openRaidLib.CooldownManager.GetPlayerCooldownStatus(cooldownSpellId)
cooldowns[#cooldowns+1] = cooldownSpellId
cooldowns[#cooldowns+1] = timeLeft
cooldowns[#cooldowns+1] = charges
cooldowns[#cooldowns+1] = startTimeOffset
cooldowns[#cooldowns+1] = duration
cooldowns[#cooldowns+1] = auraDuration
cooldownsHash[cooldownSpellId] = {timeLeft, charges, startTimeOffset, duration, timeNow, auraDuration}
end
local canAddCooldown = function(cooldownInfo)
local petNpcIdNeeded = cooldownInfo.pet
if (petNpcIdNeeded) then
if (not playerHasPetOfNpcId(petNpcIdNeeded)) then
return false
end
end
return true
end
local getSpellListAsHashTableFromSpellBook = function()
local completeListOfSpells = {}
--this line might not be compatible with classic
local specId, specName, _, specIconTexture = GetSpecializationInfo(GetSpecialization())
--local classNameLoc, className, classId = UnitClass("player") --not in use
local locPlayerRace, playerRace, playerRaceId = UnitRace("player")
--get racials from the general tab
local tabName, tabTexture, offset, numSpells, isGuild, offspecId = GetSpellTabInfo(CONST_SPELLBOOK_GENERAL_TABID)
offset = offset + 1
local tabEnd = offset + numSpells
for entryOffset = offset, tabEnd - 1 do
local spellType, spellId = GetSpellBookItemInfo(entryOffset, "player")
local spellData = LIB_OPEN_RAID_COOLDOWNS_INFO[spellId]
if (spellData) then
local raceId = spellData.raceid
if (raceId) then
if (type(raceId) == "table") then
if (raceId[playerRaceId]) then
spellId = C_SpellBook.GetOverrideSpell(spellId)
local spellName = GetSpellInfo(spellId)
local bIsPassive = IsPassiveSpell(spellId, "player")
if (spellName and not bIsPassive) then
completeListOfSpells[spellId] = true
end
end
elseif (type(raceId) == "number") then
if (raceId == playerRaceId) then
spellId = C_SpellBook.GetOverrideSpell(spellId)
local spellName = GetSpellInfo(spellId)
local bIsPassive = IsPassiveSpell(spellId, "player")
if (spellName and not bIsPassive) then
completeListOfSpells[spellId] = true
end
end
end
end
end
end
--get spells from the Spec spellbook
for i = 1, GetNumSpellTabs() do
local tabName, tabTexture, offset, numSpells, isGuild, offspecId = GetSpellTabInfo(i)
if (tabTexture == specIconTexture) then
offset = offset + 1
local tabEnd = offset + numSpells
for entryOffset = offset, tabEnd - 1 do
local spellType, spellId = GetSpellBookItemInfo(entryOffset, "player")
if (spellId) then
if (spellType == "SPELL") then
spellId = C_SpellBook.GetOverrideSpell(spellId)
local spellName = GetSpellInfo(spellId)
local bIsPassive = IsPassiveSpell(spellId, "player")
if LIB_OPEN_RAID_MULTI_OVERRIDE_SPELLS[spellId] then
for _, overrideSpellId in pairs(LIB_OPEN_RAID_MULTI_OVERRIDE_SPELLS[spellId]) do
completeListOfSpells[overrideSpellId] = true
end
elseif (spellName and not bIsPassive) then
completeListOfSpells[spellId] = true
end
end
end
end
end
end
--get class shared spells from the spell book
local tabName, tabTexture, offset, numSpells, isGuild, offspecId = GetSpellTabInfo(CONST_SPELLBOOK_CLASSSPELLS_TABID)
offset = offset + 1
local tabEnd = offset + numSpells
for entryOffset = offset, tabEnd - 1 do
local spellType, spellId = GetSpellBookItemInfo(entryOffset, "player")
if (spellId) then
if (spellType == "SPELL") then
spellId = C_SpellBook.GetOverrideSpell(spellId)
local spellName = GetSpellInfo(spellId)
local bIsPassive = IsPassiveSpell(spellId, "player")
if LIB_OPEN_RAID_MULTI_OVERRIDE_SPELLS[spellId] then
for _, overrideSpellId in pairs(LIB_OPEN_RAID_MULTI_OVERRIDE_SPELLS[spellId]) do
completeListOfSpells[overrideSpellId] = true
end
elseif (spellName and not bIsPassive) then
completeListOfSpells[spellId] = true
else
if (not spellName) then
--print("no spellname")
--print(GetSpellInfo(spellId))
elseif (bIsPassive) then
--print("is passive")
--print(GetSpellInfo(spellId))
end
end
end
end
end
local getNumPetSpells = function()
--'HasPetSpells' contradicts the name and return the amount of pet spells available instead of a boolean
return HasPetSpells()
end
--get pet spells from the pet spellbook
local numPetSpells = getNumPetSpells()
if (numPetSpells) then
for i = 1, numPetSpells do
local spellName, _, unmaskedSpellId = GetSpellBookItemName(i, "pet")
if (unmaskedSpellId) then
unmaskedSpellId = C_SpellBook.GetOverrideSpell(unmaskedSpellId)
local bIsPassive = IsPassiveSpell(unmaskedSpellId, "pet")
if (spellName and not bIsPassive) then
completeListOfSpells[unmaskedSpellId] = true
end
end
end
end
return completeListOfSpells
end
local updateCooldownAvailableList = function()
table.wipe(LIB_OPEN_RAID_PLAYERCOOLDOWNS)
local _, playerClass = UnitClass("player")
local locPlayerRace, playerRace, playerRaceId = UnitRace("player")
local spellBookSpellList = getSpellListAsHashTableFromSpellBook()
--build a list of all spells assigned as cooldowns for the player class
for spellID, spellData in pairs(LIB_OPEN_RAID_COOLDOWNS_INFO) do
--type 10 is an item cooldown and does not have a class or race id
local passRaceId = false
local raceId = spellData.raceid
if (raceId) then
if (type(raceId) == "table") then
if (raceId[playerRaceId]) then
passRaceId = true
end
elseif (type(raceId) == "number") then
if (raceId == playerRaceId) then
passRaceId = true
end
end
end
if (spellData.class == playerClass or passRaceId or CONST_ISITEM_BY_TYPEID[spellData.type]) then --need to implement here to get the racial as racial cooldowns does not carry a class
--type 10 is an item cooldown and does not have a spellbook entry
if (spellBookSpellList[spellID] or CONST_ISITEM_BY_TYPEID[spellData.type]) then
LIB_OPEN_RAID_PLAYERCOOLDOWNS[spellID] = spellData
end
end
end
end
--build a list with the local player cooldowns
--called only from SendAllPlayerCooldowns()
function openRaidLib.CooldownManager.GetPlayerCooldownList()
--update the list of cooldowns the player has available
if (IsDragonflight()) then
--this fill the global LIB_OPEN_RAID_PLAYERCOOLDOWNS
updateCooldownAvailableList()
--get the player specId
local specId = openRaidLib.GetPlayerSpecId()
if (specId) then
--get the cooldowns for the specializationid
local playerCooldowns = LIB_OPEN_RAID_PLAYERCOOLDOWNS
if (not playerCooldowns) then
openRaidLib.DiagnosticError("CooldownManager|GetPlayerCooldownList|LIB_OPEN_RAID_PLAYERCOOLDOWNS is nil")
return {}, {}
end
local cooldowns = {} --table to ship on comm
local cooldownsHash = {} --table with [spellId] = cooldownInfo
local talentsHash = openRaidLib.UnitInfoManager.GetPlayerTalentsAsPairsTable()
local timeNow = GetTime()
for cooldownSpellId, cooldownInfo in pairs(playerCooldowns) do
--does this cooldown is based on a talent?
local talentId = cooldownInfo.talent
--check if the player has a talent which makes this cooldown unavailable
local ignoredByTalentId = cooldownInfo.ignoredIfTalent
local bIsIgnoredByTalentId = false
if (ignoredByTalentId) then
if (talentsHash[ignoredByTalentId]) then
bIsIgnoredByTalentId = true
end
end
if (not bIsIgnoredByTalentId) then
if (talentId) then
--check if the player has the talent selected
if (talentsHash[talentId]) then
if (canAddCooldown(cooldownInfo)) then
addCooldownToTable(cooldowns, cooldownsHash, cooldownSpellId, timeNow)
end
end
else
if (canAddCooldown(cooldownInfo)) then
addCooldownToTable(cooldowns, cooldownsHash, cooldownSpellId, timeNow)
end
end
end
end
return cooldowns, cooldownsHash
else
return {}, {}
end
end
return {}, {}
end
--aura frame handles only UNIT_AURA events to grab the duration of the buff placed by the aura
local bIsNewUnitAuraAvailable = C_UnitAuras and C_UnitAuras.GetAuraDataBySlot and true
local auraSpellID
local auraDurationTime
local auraUnitId
local handleBuffAura = function(aura)
local auraInfo = C_UnitAuras.GetAuraDataByAuraInstanceID(auraUnitId, aura.auraInstanceID)
if (auraInfo) then
local spellId = auraInfo.spellId
if (auraSpellID == spellId) then
auraSpellID = nil
auraDurationTime = auraInfo.duration
return true
end
end
end
local getAuraDuration = function(spellId, unitId)
--some auras does not have the same spellId of the cast as the spell for its aura duration
--in these cases, it's necessary to declare the buff spellId which tells the duration of the effect by adding 'durationSpellId = spellId' within the cooldown data
if (not LIB_OPEN_RAID_PLAYERCOOLDOWNS[spellId]) then
--local spellname = GetSpellInfo(spellId)
--print("spell not found:", spellname)
return 0
end
local customBuffDuration = LIB_OPEN_RAID_PLAYERCOOLDOWNS[spellId].durationSpellId
--spellId = customBuffDuration or spellId --can't replace the spellId by customBuffDurationSpellId has it wount be found in LIB_OPEN_RAID_PLAYERCOOLDOWNS
if (bIsNewUnitAuraAvailable) then
local bBatchCount = false
local bUsePackedAura = true
auraSpellID = customBuffDuration or spellId
auraDurationTime = 0 --reset duration
auraUnitId = unitId or "player"
AuraUtil.ForEachAura(auraUnitId, "HELPFUL", bBatchCount, handleBuffAura, bUsePackedAura) --check auras to find a buff for the spellId
if (auraDurationTime == 0) then --if the buff wasn't found, attempt to get the duration from the file
return LIB_OPEN_RAID_PLAYERCOOLDOWNS[spellId].duration or 0
end
return auraDurationTime
else
--this is classic
end
end
---get the duration of a buff placed by a spell
---@param spellId number
---@param unitId string?
---@return number duration
function openRaidLib.CooldownManager.GetSpellBuffDuration(spellId, unitId)
return getAuraDuration(spellId, unitId)
end
---check if a player cooldown is ready or if is in cooldown
---@spellId: the spellId to check for cooldown
---@return number timeLeft
---@return number charges
---@return number startTimeOffset
---@return number duration
---@return number buffDuration
function openRaidLib.CooldownManager.GetPlayerCooldownStatus(spellId)
--check if is a charge spell
local spellData = LIB_OPEN_RAID_COOLDOWNS_INFO[spellId]
if (spellData) then
local buffDuration = getAuraDuration(spellId)
local chargesAvailable, chargesTotal, start, duration = GetSpellCharges(spellId)
if chargesAvailable then
if (chargesAvailable == chargesTotal) then
return 0, chargesTotal, 0, 0, 0 --all charges are ready to use
else
--return the time to the next charge
local timeLeft = start + duration - GetTime()
local startTimeOffset = start - GetTime()
return ceil(timeLeft), chargesAvailable, startTimeOffset, duration, buffDuration
end
else
local start, duration = GetSpellCooldown(spellId)
if (start == 0) then --cooldown is ready
return 0, 1, 0, 0, 0 --time left, charges, startTime
else
local timeLeft = start + duration - GetTime()
local startTimeOffset = start - GetTime()
return ceil(timeLeft), 0, ceil(startTimeOffset), duration, buffDuration --time left, charges, startTime, duration, buffDuration
end
end
else
return openRaidLib.DiagnosticError("CooldownManager|GetPlayerCooldownStatus()|cooldownInfo not found|", spellId)
end
end
do
--make new namespace
openRaidLib.AuraTracker = {}
function openRaidLib.AuraTracker.ScanCallback(aura)
local unitId = openRaidLib.AuraTracker.CurrentUnitId
local thisUnitAuras = openRaidLib.AuraTracker.CurrentAuras[unitId]
local auraInfo = C_UnitAuras.GetAuraDataByAuraInstanceID(unitId, aura.auraInstanceID)
if (auraInfo) then
local spellId = auraInfo.spellId
if (spellId) then
thisUnitAuras[spellId] = true
openRaidLib.AuraTracker.AurasFoundOnScan[spellId] = true
end
end
end
function openRaidLib.AuraTracker.ScanUnitAuras(unitId)
local batchCount = nil
local usePackedAura = true
openRaidLib.AuraTracker.CurrentUnitId = unitId
openRaidLib.AuraTracker.AurasFoundOnScan = {}
AuraUtil.ForEachAura(unitId, "HELPFUL", batchCount, openRaidLib.AuraTracker.ScanCallback, usePackedAura)
local thisUnitAuras = openRaidLib.AuraTracker.CurrentAuras[unitId]
for spellId in pairs(thisUnitAuras) do
if (not openRaidLib.AuraTracker.AurasFoundOnScan[spellId]) then
--aura removed
openRaidLib.internalCallback.TriggerEvent("unitAuraRemoved", unitId, spellId)
end
end
end
--run when the open raid lib loads
function openRaidLib.AuraTracker.StartScanUnitAuras(unitId)
openRaidLib.AuraTracker.CurrentAuras = {
[unitId] = {}
}
local auraFrameEvent = CreateFrame("frame")
auraFrameEvent:RegisterUnitEvent("UNIT_AURA", unitId)
auraFrameEvent:SetScript("OnEvent", function()
openRaidLib.AuraTracker.ScanUnitAuras(unitId)
end)
end
--test case:
local debugModule = {}
function debugModule.AuraRemoved(event, unitId, spellId)
local spellName = GetSpellInfo(spellId)
--print("aura removed:", unitId, spellId, spellName)
end
openRaidLib.internalCallback.RegisterCallback("unitAuraRemoved", debugModule.AuraRemoved)
end
do
local getUnitName = function(unitId)
local unitName, realmName = UnitName(unitId)
if (unitName) then
if (realmName and realmName ~= "") then
unitName = unitName .. "-" .. realmName
end
return unitName
end
end
local predicateFunc = function(spellIdToFind, casterName, _, name, icon, applications, dispelName, duration, expirationTime, sourceUnitId, isStealable, nameplateShowPersonal, spellId, canApplyAura, isBossAura, isFromPlayerOrPlayerPet, nameplateShowAll, timeMod, applications)
if (spellIdToFind == spellId and UnitExists(sourceUnitId)) then
if (casterName == getUnitName(sourceUnitId)) then
return true
end
end
end
---find the duration of a debuff by passing the spellId and the caster name
---@param unitId unit
---@param spellId spellid
---@param casterName actorname
---@return auraduration|nil auraDuration
---@return number|nil expirationTime
function openRaidLib.AuraTracker.FindBuffDuration(unitId, casterName, spellId)
local name, texture, count, buffType, duration, expirationTime = AuraUtil.FindAura(predicateFunc, unitId, "HELPFUL", spellId, casterName)
if (name) then
return duration, expirationTime
end
end
---find the duration of a buff placed by a unit
---@param targetString string
---@param casterString string
---@param spellId number
function openRaidLib.AuraTracker.FindBuffDurationByUnitName(targetString, casterString, spellId)
local targetName = Ambiguate(targetString, "none")
local casterName = Ambiguate(casterString, "none")
return openRaidLib.AuraTracker.FindBuffDuration(targetName, casterName, spellId)
end
end
--which is the main attribute of each spec
--1 Intellect
--2 Agility
--3 Strenth
openRaidLib.specAttribute = {
["DEMONHUNTER"] = {
[577] = 2,
[581] = 2,
},
["DEATHKNIGHT"] = {
[250] = 3,
[251] = 3,
[252] = 3,
},
["WARRIOR"] = {
[71] = 3,
[72] = 3,
[73] = 3,
},
["MAGE"] = {
[62] = 1,
[63] = 1,
[64] = 1,
},
["ROGUE"] = {
[259] = 2,
[260] = 2,
[261] = 2,
},
["DRUID"] = {
[102] = 1,
[103] = 2,
[104] = 2,
[105] = 1,
},
["HUNTER"] = {
[253] = 2,
[254] = 2,
[255] = 2,
},
["SHAMAN"] = {
[262] = 1,
[263] = 2,
[264] = 1,
},
["PRIEST"] = {
[256] = 1,
[257] = 1,
[258] = 1,
},
["WARLOCK"] = {
[265] = 1,
[266] = 1,
[267] =1 ,
},
["PALADIN"] = {
[65] = 1,
[66] = 3,
[70] = 3,
},
["MONK"] = {
[268] = 2,
[269] = 2,
[270] = 1,
},
["EVOKER"] = {
[1467] = 1, --Devastation
[1468] = 1, --Preservation
[1473] = 1, --Augmentation
},
}