You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1058 lines
40 KiB

--[=[
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 GetInventoryItemLink = GetInventoryItemLink
-- TWW compat
-- TODO: Remove when TWW is released
local GetItemStats = C_Item.GetItemStats
local GetSpellInfo = GetSpellInfo or function(spellID)
if not spellID then return nil end
local spellInfo = C_Spell.GetSpellInfo(spellID)
if spellInfo then
return spellInfo.name, nil, spellInfo.iconID, spellInfo.castTime, spellInfo.minRange,
spellInfo.maxRange, spellInfo.spellID, spellInfo.originalIconID
end
end
local GetSpellCooldown = GetSpellCooldown or C_Spell.GetSpellCooldown
local GetDetailedItemLevelInfo = GetDetailedItemLevelInfo or C_Item.GetDetailedItemLevelInfo
local GetSpellTabInfo = GetSpellTabInfo or (function(tabLine)
if not tabLine then return nil end
local skillLine = C_SpellBook.GetSpellBookSkillLineInfo(tabLine)
if skillLine then
return skillLine.name, skillLine.iconID, skillLine.itemIndexOffset,
skillLine.numSpellBookItems, skillLine.isGuild, skillLine.specID
end
end)
local GetSpellBookItemInfo = GetSpellBookItemInfo or C_SpellBook.GetSpellBookItemType
local IsPassiveSpell = IsPassiveSpell or C_SpellBook.IsSpellBookItemPassive
local GetNumSpellTabs = GetNumSpellTabs or C_SpellBook.GetNumSpellBookSkillLines
local spellBookPlayerEnum = Enum.SpellBookSpellBank and Enum.SpellBookSpellBank.Player or "player"
local HasPetSpells = HasPetSpells or C_SpellBook.HasPetSpells
local GetOverrideSpell = C_SpellBook.GetOverrideSpell or C_Spell.GetOverrideSpell
local GetSpellBookItemName = GetSpellBookItemName or C_SpellBook.GetSpellBookItemName
local spellBookPetEnum = Enum.SpellBookSpellBank and Enum.SpellBookSpellBank.Pet or "pet"
local GetSpellCharges = GetSpellCharges or function(spellId)
local chargesInfo = C_Spell.GetSpellCharges(spellId)
if (chargesInfo) then
return chargesInfo.currentCharges, chargesInfo.maxCharges, chargesInfo.cooldownStartTime, chargesInfo.cooldownDuration, chargesInfo.chargeModRate
end
end
local _, _, _, buildInfo = GetBuildInfo()
local isTimewalkWoW = function()
if (buildInfo < 40000) then
return true
end
end
local IsTWWExpansion = function()
if (buildInfo >= 110000) then
return true
end
end
local IsDragonflight = function() --and beyond
return buildInfo >= 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
if (definitionId) then
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
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) --deprecated in 10.2.5
local itemStatsTable = GetItemStats(itemLink)
--check if the item has a socket
if (itemStatsTable) then
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
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
local itemStatsTable = GetItemStats(itemLink)
--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")
--Enum.SpellBookSkillLineIndex
--["OffSpecStart"] = 4,
--["Class"] = 2,
--["General"] = 1,
--["MainSpec"] = 3,
--get racials from the general tab
local generalIndex = Enum.SpellBookSkillLineIndex and Enum.SpellBookSkillLineIndex.General or CONST_SPELLBOOK_GENERAL_TABID
local tabName, tabTexture, offset, numSpells, isGuild, offspecId = GetSpellTabInfo(generalIndex) --CONST_SPELLBOOK_GENERAL_TABID
if (not offset) then
return completeListOfSpells
end
offset = offset + 1
local tabEnd = offset + numSpells
for entryOffset = offset, tabEnd - 1 do
local spellType, spellId = GetSpellBookItemInfo(entryOffset, spellBookPlayerEnum)
local spellData = LIB_OPEN_RAID_COOLDOWNS_INFO[spellId] --from the cooldowns table
if (spellData) then
local raceId = spellData.raceid
if (raceId) then
if (type(raceId) == "table") then
if (raceId[playerRaceId]) then
spellId = GetOverrideSpell(spellId)
local spellName = GetSpellInfo(spellId)
local bIsPassive = IsPassiveSpell(spellId, spellBookPlayerEnum)
if (spellName and not bIsPassive) then
completeListOfSpells[spellId] = true
end
end
elseif (type(raceId) == "number") then
if (raceId == playerRaceId) then
spellId = GetOverrideSpell(spellId)
local spellName = GetSpellInfo(spellId)
local bIsPassive = IsPassiveSpell(spellId, spellBookPlayerEnum)
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 --called "lines" in new v11 api
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, spellBookPlayerEnum)
if (spellId) then
if (spellType == "SPELL" or spellType == 1) then
--print(tabName, tabTexture == specIconTexture, offset, tabEnd,spellType, spellId)
spellId = GetOverrideSpell(spellId)
local spellName = GetSpellInfo(spellId)
local bIsPassive = IsPassiveSpell(spellId, spellBookPlayerEnum)
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, spellBookPlayerEnum)
if (spellId) then
if (spellType == "SPELL") then
spellId = GetOverrideSpell(spellId)
local spellName = GetSpellInfo(spellId)
local bIsPassive = IsPassiveSpell(spellId, spellBookPlayerEnum)
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, spellBookPetEnum)
if (unmaskedSpellId) then
unmaskedSpellId = GetOverrideSpell(unmaskedSpellId)
local bIsPassive = IsPassiveSpell(unmaskedSpellId, spellBookPetEnum)
if (spellName and not bIsPassive) then
completeListOfSpells[unmaskedSpellId] = true
end
end
end
end
--dumpt(completeListOfSpells)
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 bUsePackedAura = true
auraSpellID = customBuffDuration or spellId
auraDurationTime = 0 --reset duration
auraUnitId = unitId or "player"
AuraUtil.ForEachAura(auraUnitId, "HELPFUL", nil, 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
if (IsTWWExpansion()) then
local spellCooldownInfo = GetSpellCooldown(spellId)
local start = spellCooldownInfo.startTime
local duration = spellCooldownInfo.duration
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
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
end
else
return openRaidLib.DiagnosticError("CooldownManager|GetPlayerCooldownStatus()|cooldownInfo not found|", spellId)
end
end
do
--make new namespace
openRaidLib.AuraTracker = {}
do if (false) then --do not load this section as it isn't in use
function openRaidLib.AuraTracker.ScanCallback(auraInfo)
if (auraInfo) then
local spellId = auraInfo.spellId
if (spellId) then
local unitId = openRaidLib.AuraTracker.CurrentUnitId
local thisUnitAuras = openRaidLib.AuraTracker.CurrentAuras[unitId]
thisUnitAuras[spellId] = true
openRaidLib.AuraTracker.AurasFoundOnScan[spellId] = true
end
end
end
function openRaidLib.AuraTracker.ScanUnitAuras(unitId)
local maxCount = nil
local bUsePackedAura = true
openRaidLib.AuraTracker.CurrentUnitId = unitId
openRaidLib.AuraTracker.AurasFoundOnScan = {}
--code of 'ForEachAura' has been updated to use the latest API available
AuraUtil.ForEachAura(unitId, "HELPFUL", maxCount, openRaidLib.AuraTracker.ScanCallback, bUsePackedAura)
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) --this function isn't getting called (was called from Entering World event)
openRaidLib.AuraTracker.CurrentAuras = {
[unitId] = {} --storing using the unitId as key, won't work for any other unit other than the "player"
}
local auraFrameEvent = CreateFrame("frame")
auraFrameEvent:RegisterUnitEvent("UNIT_AURA", unitId)
auraFrameEvent:SetScript("OnEvent", function()
openRaidLib.AuraTracker.ScanUnitAuras(unitId)
end)
end
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
},
}