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.

1181 lines
41 KiB

-- actor container file
-- group members are the actors which will be shown in the window while in standard view mode, most of the times they are players in the same group as the player
local Details = _G.Details
local DF = _G.DetailsFramework
local _
local addonName, Details222 = ...
local bIsDragonflight = DetailsFramework.IsDragonflight()
local CONST_CLIENT_LANGUAGE = DF.ClientLanguage
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--local pointers
local _IsInInstance = IsInInstance --api local
local UnitGUID = UnitGUID --api local
local strsplit = strsplit --api local
local setmetatable = setmetatable --lua local
local bitBand = bit.band --lua local
local tableSort = table.sort --lua local
local ipairs = ipairs --lua local
local pairs = pairs --lua local
local AddUnique = DetailsFramework.table.addunique --framework
local UnitGroupRolesAssigned = DetailsFramework.UnitGroupRolesAssigned --framework
local GetNumDeclensionSets = _G.GetNumDeclensionSets
local DeclineName = _G.DeclineName
local pet_tooltip_frame = _G.DetailsPetOwnerFinder
local openRaidLib = LibStub:GetLibrary("LibOpenRaid-1.0", true)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--constants
local actorContainer = Details.container_combatentes
local alvo_da_habilidade = Details.alvo_da_habilidade
local atributo_damage = Details.atributo_damage
local atributo_heal = Details.atributo_heal
local atributo_energy = Details.atributo_energy
local atributo_misc = Details.atributo_misc
local container_damage = Details.container_type.CONTAINER_DAMAGE_CLASS
local container_heal = Details.container_type.CONTAINER_HEAL_CLASS
local container_heal_target = Details.container_type.CONTAINER_HEALTARGET_CLASS
local container_friendlyfire = Details.container_type.CONTAINER_FRIENDLYFIRE
local container_damage_target = Details.container_type.CONTAINER_DAMAGETARGET_CLASS
local container_energy = Details.container_type.CONTAINER_ENERGY_CLASS
local container_energy_target = Details.container_type.CONTAINER_ENERGYTARGET_CLASS
local container_misc = Details.container_type.CONTAINER_MISC_CLASS
local container_misc_target = Details.container_type.CONTAINER_MISCTARGET_CLASS
local container_enemydebufftarget_target = Details.container_type.CONTAINER_ENEMYDEBUFFTARGET_CLASS
local container_pets = {}
--flags
local REACTION_HOSTILE = 0x00000040
local IS_GROUP_OBJECT = 0x00000007
local REACTION_FRIENDLY = 0x00000010
local OBJECT_TYPE_MASK = 0x0000FC00
local OBJECT_TYPE_OBJECT = 0x00004000
local OBJECT_TYPE_PETGUARDIAN = 0x00003000
local OBJECT_TYPE_GUARDIAN = 0x00002000
local OBJECT_TYPE_PET = 0x00001000
local OBJECT_TYPE_NPC = 0x00000800
local OBJECT_TYPE_PLAYER = 0x00000400
local OBJECT_TYPE_PETS = OBJECT_TYPE_PET + OBJECT_TYPE_GUARDIAN
local debugPetname = false
local SPELLID_SANGUINE_HEAL = 226510
local sanguineActorName = GetSpellInfo(SPELLID_SANGUINE_HEAL)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--api functions
--[=[
["AzeriteItemPowerDescription"] = 9,
["SellPrice"] = 11,
["CurrencyTotal"] = 14,
["GemSocket"] = 3,
["QuestObjective"] = 8,
["UnitName"] = 2,
["SpellName"] = 13,
["ItemEnchantmentPermanent"] = 15,
["RuneforgeLegendaryPowerDescription"] = 10,
["QuestPlayer"] = 18,
["Blank"] = 1,
["UnitOwner"] = 16,
["LearnableSpell"] = 6,
["ProfessionCraftingQuality"] = 12,
["UnitThreat"] = 7,
["QuestTitle"] = 17,
["ItemBinding"] = 20,
["NestedBlock"] = 19,
["AzeriteEssencePower"] = 5,
["AzeriteEssenceSlot"] = 4,
["None"] = 0,
--]=]
---attempt to get the owner of rogue's Akaari's Soul from Secrect Technique
---@param petGUID string
---@return string|any
---@return string|any
---@return number|any
function Details222.Pets.AkaarisSoulOwner(petGUID)
local tooltipData = C_TooltipInfo.GetHyperlink("unit:" .. petGUID)
local args = tooltipData.args
if (not args) then
do
local ownerGUID = tooltipData.guid --tooltipData.guid seems to exists on all akari soul tooltips and point to the owner guid
if (ownerGUID) then
if (ownerGUID:find("^P")) then
local playerGUID = ownerGUID
local actorObject = Details:GetActorFromCache(playerGUID) --quick cache only exists during conbat
if (actorObject) then
return actorObject.nome, playerGUID, actorObject.flag_original
end
local guidCache = Details:GetParserPlayerCache() --cache exists until the next combat starts
local ownerName = guidCache[playerGUID]
if (ownerName) then
return ownerName, playerGUID, 0x514
end
end
end
end
do
if (tooltipData.lines) then
for i = 1, #tooltipData.lines do
local lineData = tooltipData.lines[i]
if (lineData.unitToken) then --unit token seems to exists when the add belongs to the "player"
local ownerGUID = UnitGUID(lineData.unitToken)
if (ownerGUID and ownerGUID:find("^P")) then
local playerGUID = ownerGUID
local actorObject = Details:GetActorFromCache(playerGUID) --quick cache only exists during conbat
if (actorObject) then
return actorObject.nome, playerGUID, actorObject.flag_original
end
local guidCache = Details:GetParserPlayerCache() --cache exists until the next combat starts
local ownerName = guidCache[playerGUID]
if (ownerName) then
return ownerName, playerGUID, 0x514
end
end
end
end
end
end
end
if (not args) then
--new tooltip data from 10.1.0 seems to not have .args
return
end
local playerGUID
--iterate among args and find into the value field == guid and it must have guidVal
for i = 1, #args do --this is erroring in the ptr 10.1.0, as .args doesn't seem to exists on akari soul tooltip
local arg = args[i]
if (arg.field == "guid") then
playerGUID = arg.guidVal
break
end
end
if (playerGUID) then
local actorObject = Details:GetActorFromCache(playerGUID) --quick cache only exists during conbat
if (actorObject) then
return actorObject.nome, playerGUID, actorObject.flag_original
end
local guidCache = Details:GetParserPlayerCache() --cache exists until the next combat starts
local ownerName = guidCache[playerGUID]
if (ownerName) then
return ownerName, playerGUID, 0x514
end
end
end
---Determine if the inputted pet string contains any declension variation of the given player name.
---@param tooltipString string
---@param playerName string
---@return boolean hasDeclension
--check pet owner name with correct declension for ruRU locale (from user 'denis-kam' on github)
local find_name_declension = function(tooltipString, playerName)
--2 - male, 3 - female
for gender = 3, 2, -1 do
for declensionSet = 1, GetNumDeclensionSets(playerName, gender) do
--check genitive case of player name
local genitive = DeclineName(playerName, gender, declensionSet)
if tooltipString:find(genitive) then
--print("found genitive: ", gender, declensionSet, playerName, petTooltip:find(genitive))
return true
end
end
end
return false
end
---attempt to the owner of a pet using tooltip scan, if the owner isn't found, return nil
---@param petGUID string
---@param petName string
---@return string|nil ownerName
---@return string|nil ownerGUID
---@return integer|nil ownerFlags
function Details222.Pets.GetPetOwner(petGUID, petName)
pet_tooltip_frame:SetOwner(WorldFrame, "ANCHOR_NONE")
pet_tooltip_frame:SetHyperlink(("unit:" .. petGUID) or "")
--C_TooltipInfo.GetHyperlink
if (bIsDragonflight) then
local tooltipData = pet_tooltip_frame:GetTooltipData() --is pet tooltip reliable with the new tooltips changes?
if (tooltipData) then
if (not tooltipData.args and tooltipData.lines[1].leftText == '') then --Assume this unit acts like Akaari's soul, where it returns the tooltip for the player instead, with line 1 blank.
do
local ownerGUID = tooltipData.guid --tooltipData.guid points to the player attributed to this tooltip.
if (ownerGUID) then --If we have an owner GUID, then we should make sure it starts with a P for Player and then attempt to find the owner object from the caches.
if (ownerGUID:find("^P")) then
local playerGUID = ownerGUID
local actorObject = Details:GetActorFromCache(playerGUID) --quick cache only exists during conbat
if (actorObject) then
return actorObject.nome, playerGUID, actorObject.flag_original
end
local guidCache = Details:GetParserPlayerCache() --cache exists until the next combat starts
local ownerName = guidCache[playerGUID]
if (ownerName) then
return ownerName, playerGUID, 0x514
end
if(Details.zone_type == 'arena') then --Attempt to find enemy pet owner
for enemyName, enemyToken in pairs(Details.arena_enemies) do
if(UnitGUID(enemyToken) == ownerGUID) then
return enemyName, ownerGUID, 0x548
end
end
end
end
end
end
do
if (tooltipData.lines) then
for i = 1, #tooltipData.lines do
local lineData = tooltipData.lines[i]
if (lineData.unitToken) then --unit token seems to exists when the add belongs to the "player"
local ownerGUID = UnitGUID(lineData.unitToken)
if (ownerGUID and ownerGUID:find("^P")) then
local playerGUID = ownerGUID
local actorObject = Details:GetActorFromCache(playerGUID) --quick cache only exists during conbat
if (actorObject) then
return actorObject.nome, playerGUID, actorObject.flag_original
end
local guidCache = Details:GetParserPlayerCache() --cache exists until the next combat starts
local ownerName = guidCache[playerGUID]
if (ownerName) then
return ownerName, playerGUID, 0x514
end
if(Details.zone_type == 'arena') then --Attempt to find enemy pet owner
for enemyName, enemyToken in pairs(Details.arena_enemies) do
if(UnitGUID(enemyToken) == ownerGUID) then
return enemyName, ownerGUID, 0x548
end
end
end
end
end
end
end
end
end
local tooltipLines = tooltipData.lines
for lineIndex = 1, #tooltipLines do
local thisLine = tooltipLines[lineIndex]
--get the type of information this line is showing
local lineType = thisLine.type --type 0 = 'friendly' type 2 = 'name' type 16 = controller guid
--parse the different types of information
if (lineType == 2) then --unit name
if (thisLine.leftText ~= petName) then
--tooltip isn't showing our pet
return
end
elseif (lineType == 16) then --controller guid
--assuming the unit name always comes before the controller guid
local GUID = thisLine.guid
--very fast way to get an actorObject, this cache only lives while in combat
local actorObject = Details:GetActorFromCache(GUID)
if (actorObject) then
--Details:Msg("(debug) pet found (1)", petName, "owner:", actorObject.nome)
return actorObject.nome, GUID, actorObject.flag_original
else
--return the actor name for a guid, this cache lives for current combat until next segment
local guidCache = Details:GetParserPlayerCache()
local ownerName = guidCache[GUID]
if (ownerName) then
--Details:Msg("(debug) pet found (2)", petName, "owner:", ownerName)
return ownerName, GUID, 0x514
end
if(Details.zone_type == 'arena') then --Attempt to find enemy pet owner
for enemyName, enemyToken in pairs(Details.arena_enemies) do
if(UnitGUID(enemyToken) == ownerGUID) then
return enemyName, ownerGUID, 0x548
end
end
end
end
end
end
end
end
local ownerName, ownerGUID, ownerFlags
if (not Details.tabela_vigente) then return end --Should exist at all times but load. Just in case.
for i=1,3 do --Loop through the 3 texts on the PetOwnerFinder tooltip
local actorNameString = _G["DetailsPetOwnerFinderTextLeft"..i]
if (actorNameString and not ownerName) then --Tooltip line exists and we haven't found a valid match yes.
local actorName = actorNameString:GetText()
if (actorName and type(actorName) == "string") then
local isInRaid = Details.tabela_vigente.raid_roster[actorName]
if (isInRaid) then
ownerGUID = UnitGUID(actorName)
ownerName = actorName
ownerFlags = 0x514
else
if (CONST_CLIENT_LANGUAGE == "ruRU") then --If russian client, then test for declensions in the string of text.
for playerName, _ in pairs(Details.tabela_vigente.raid_roster) do
local pName = playerName
playerName = playerName:gsub("%-.*", "") --remove realm name
if (find_name_declension(actorName, playerName)) then
ownerGUID = UnitGUID(pName)
ownerName = pName
ownerFlags = 0x514
break
end
end
else
for playerName in actorName:gmatch("([^%s]+)") do
playerName = playerName:gsub(",", "")
local playerIsOnRaidCache = Details.tabela_vigente.raid_roster[playerName]
if (playerIsOnRaidCache) then
ownerGUID = UnitGUID(playerName)
ownerName = playerName
ownerFlags = 0x514
break
end
end
end
end
end
end
end
if (ownerGUID) then
return ownerName, ownerGUID, ownerFlags
end
end
---return the actor object for a given actor name
---@param actorName string
---@return table|nil
function actorContainer:GetActor(actorName)
local index = self._NameIndexTable [actorName]
if (index) then
return self._ActorTable [index]
end
end
---return an actor name which used the spell passed 'spellId'
---@param spellId number
---@return string|nil
function actorContainer:GetSpellSource(spellId)
local t = self._ActorTable
for i = 1, #t do
if (t[i].spells._ActorTable[spellId]) then
return t[i].nome
end
end
end
---return the value stored in the 'key' for an actor, the key can be any value stored in the actor table such like 'total', 'damage_taken', 'heal', 'interrupt', etc
---@param actorName string
---@param key string
---@return number
function actorContainer:GetAmount(actorName, key)
key = key or "total"
local index = self._NameIndexTable[actorName]
if (index) then
return self._ActorTable[index][key] or 0
else
return 0
end
end
---return the total value stored in the 'key' for all actors, the key can be any value stored in the actor table such like 'total', 'damage_taken', 'heal', 'interrupt', etc
---@param key string
---@return number
function actorContainer:GetTotal(key)
local total = 0
key = key or "total"
for _, actor in ipairs(self._ActorTable) do
total = total + (actor[key] or 0)
end
return total
end
function actorContainer:GetTotalOnRaid(key, combat)
local total = 0
key = key or "total"
local roster = combat.raid_roster
for _, actor in ipairs(self._ActorTable) do
if (roster [actor.nome]) then
total = total + (actor[key] or 0)
end
end
return total
end
---return an ipairs iterator for all actors stored in this Container
---usage: for index, actorObject in container:ListActors() do
---@return function
function actorContainer:ListActors()
return ipairs(self._ActorTable)
end
---return a table<actorIndex, actorObject> for all actors stored in this Container
---@return table
function actorContainer:GetActorTable()
return self._ActorTable
end
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--internals
---create a new actor container, can be a damage container, heal container, enemy container or utility container
---actors can be added by using newContainer.GetOrCreateActor
---actors can be retrieved using the same function above
---@param containerType number
---@param combatObject table
---@param combatId number
---@return table
function actorContainer:NovoContainer(containerType, combatObject, combatId)
local newContainer = {
funcao_de_criacao = actorContainer:FuncaoDeCriacao(containerType),
tipo = containerType,
combatId = combatId,
---@type actor[]
_ActorTable = {},
---@type table<string, number>
_NameIndexTable = {}
}
setmetatable(newContainer, actorContainer)
return newContainer
end
--try to get the actor class from name
local getActorClass = function(actorObject, actorName, actorFlags, actorSerial)
--get spec
local specId = Details.cached_specs[actorSerial]
if (specId) then
actorObject:SetSpecId(specId)
end
if (not specId and Details.track_specs) then
Details:ScheduleTimer("GuessSpec", 2, {actorObject, nil, 1})
-- if (Details.streamer_config.quick_detection) then
-- else
-- Details:ScheduleTimer("GuessSpec", 3, {actorObject, nil, 1})
-- end
end
local _, engClass = UnitClass(actorName or "")
if (engClass) then
actorObject.classe = engClass
return
else
if (actorFlags) then
--check if the actor is a player
if (bitBand(actorFlags, OBJECT_TYPE_PLAYER) ~= 0) then
actorObject.classe = "UNGROUPPLAYER"
return
elseif (bitBand(actorFlags, OBJECT_TYPE_PETGUARDIAN) ~= 0) then
actorObject.classe = "PET"
return
end
end
actorObject.classe = "UNKNOW" --it's a typo, can't be changed at this point
return true
end
end
--check if the nickname fit some minimal rules to be presented to other players
local checkValidNickname = function(nickname, playerName)
if (nickname and type(nickname) == "string") then
if (nickname == "") then
return playerName
elseif (nickname:find(" ")) then
return playerName
end
else
return playerName
end
return nickname
end
--read the actor flag
local readActorFlag = function(actorObject, ownerActorObject, actorSerial, actorFlags, actorName)
if (actorFlags) then
local _, zoneType = GetInstanceInfo()
--this is player actor
if (bitBand(actorFlags, OBJECT_TYPE_PLAYER) ~= 0) then
if (not Details.ignore_nicktag) then
actorObject.displayName = checkValidNickname(Details:GetNickname(actorName, false, true), actorName) --defaults to player name
if (Details.remove_realm_from_name) then
actorObject.displayName = actorObject.displayName:gsub(("%-.*"), "")
end
end
if (not actorObject.displayName) then
if (Details.remove_realm_from_name) then
actorObject.displayName = actorName:gsub(("%-.*"), "")
else
actorObject.displayName = actorName
end
end
if (zoneType ~= "arena" and (Details.all_players_are_group or Details.immersion_enabled)) then
actorObject.grupo = true
end
--special spells to add into the group view - they are set within the parser.lua file
local spellId = Details.SpecialSpellActorsName[actorObject.nome]
if (spellId) then
actorObject.grupo = true
actorObject.spellicon = GetSpellTexture(spellId)
end
--check if this actor can be flagged as a unit in the player's group
if ((bitBand(actorFlags, IS_GROUP_OBJECT) ~= 0 and actorObject.classe ~= "UNKNOW" and actorObject.classe ~= "UNGROUPPLAYER") or Details:IsInCache(actorSerial)) then
actorObject.grupo = true
--check if this actor is a tank (player)
if (Details:IsATank(actorSerial)) then
actorObject.isTank = true
end
else
--if this is a pvp segment (combat) and the option to show pvp players as group is enabled
if (Details.pvp_as_group and (Details.tabela_vigente and Details.tabela_vigente.is_pvp) and Details.is_in_battleground) then
actorObject.grupo = true
end
end
--pvp duel - this functionality needs more development, the goal is to show the duel players as group members
if (Details.duel_candidates[actorSerial]) then
--check if is recent
if (Details.duel_candidates[actorSerial]+20 > GetTime()) then
actorObject.grupo = true
actorObject.enemy = true
end
end
if (zoneType == "arena") then
--local my_team_color = GetBattlefieldArenaFaction and GetBattlefieldArenaFaction() or 0
--my team
if (actorObject.grupo) then
actorObject.arena_ally = true
actorObject.arena_team = 0 -- former my_team_color | forcing the player team to always be the same color
--enemy team
else
actorObject.enemy = true
actorObject.arena_enemy = true
actorObject.arena_team = 1 -- former my_team_color
Details:GuessArenaEnemyUnitId(actorName)
end
local playerArenaInfo = Details.arena_table[actorName]
if (playerArenaInfo) then
actorObject.role = playerArenaInfo.role
if (playerArenaInfo.role == "NONE") then
local role = UnitGroupRolesAssigned and UnitGroupRolesAssigned(actorName)
if (role and role ~= "NONE") then
actorObject.role = role
end
end
else
local oponentes = GetNumArenaOpponentSpecs and GetNumArenaOpponentSpecs() or 5
local found = false
for i = 1, oponentes do
local name = GetUnitName("arena" .. i, true)
if (name == actorName) then
local spec = GetArenaOpponentSpec and GetArenaOpponentSpec(i)
if (spec) then
local id, name, description, icon, role, class = DetailsFramework.GetSpecializationInfoByID(spec) --thanks pas06
actorObject.role = role
actorObject.classe = class
actorObject.enemy = true
actorObject.arena_enemy = true
found = true
end
end
end
local role = UnitGroupRolesAssigned and UnitGroupRolesAssigned(actorName)
if (role and role ~= "NONE") then
actorObject.role = role
found = true
end
if (not found and actorName == Details.playername) then
local role = UnitGroupRolesAssigned("player")
if (role and role ~= "NONE") then
actorObject.role = role
end
end
end
actorObject.grupo = true
end
--player custom bar color
--at this position in the code, the color will replace colors from arena matches
if (Details.use_self_color) then
if (actorName == Details.playername) then
actorObject.customColor = Details.class_colors.SELF
end
end
--does this actor has an owner?
elseif (ownerActorObject) then
actorObject.owner = ownerActorObject
actorObject.ownerName = ownerActorObject.nome
if (_IsInInstance() and Details.remove_realm_from_name) then
actorObject.displayName = actorName:gsub(("%-.*"), ">")
else
actorObject.displayName = actorName
end
else
--anything else that isn't a player or a pet
actorObject.displayName = actorName
end
--check if is hostile
if (bitBand(actorFlags, REACTION_HOSTILE) ~= 0) then
if (bitBand(actorFlags, OBJECT_TYPE_PLAYER) == 0) then
--is hostile and isn't a player
if (bitBand(actorFlags, OBJECT_TYPE_PETGUARDIAN) == 0) then
--isn't a pet or guardian
actorObject.monster = true
end
if (actorSerial and type(actorSerial) == "string") then
local npcID = Details:GetNpcIdFromGuid(actorSerial)
if (npcID and not Details.npcid_pool[npcID] and type(npcID) == "number") then
Details.npcid_pool [npcID] = actorName
end
end
end
end
end
end
local petBlackList = {}
local petOwnerFound = function(ownerName, petGUID, petName, petFlags, self, ownerGUID)
local ownerGuid = ownerGUID or UnitGUID(ownerName)
if (ownerGuid) then
Details.tabela_pets:Adicionar(petGUID, petName, petFlags, ownerGuid, ownerName, 0x00000417)
local petNameWithOwner, ownerName, ownerGUID, ownerFlags = Details.tabela_pets:PegaDono(petGUID, petName, petFlags)
local petOwnerActorObject
if (petNameWithOwner and ownerName) then
petName = petNameWithOwner
petOwnerActorObject = self:PegarCombatente(ownerGUID, ownerName, ownerFlags, true)
end
return petName, petOwnerActorObject
end
end
--Deprecated 4/3/2023 in favor of Details222.Pets.GetPetOwner
local find_pet_owner = function(petGUID, petName, petFlags, self)
if (not Details.tabela_vigente) then
return
end
if (bIsDragonflight) then
pet_tooltip_frame:SetOwner(WorldFrame, "ANCHOR_NONE")
pet_tooltip_frame:SetHyperlink("unit:" .. (petGUID or ""))
local tooltipData = pet_tooltip_frame:GetTooltipData()
if (tooltipData and tooltipData.lines[1]) then
if (tooltipData.lines[1].leftText == petName) then
for i = 2, #tooltipData.lines do
local tooltipLine = tooltipData.lines[i]
local args = tooltipLine.args
if (args) then
if (args[4] and args[4].field == "guid") then
local guidVal = args[4].guidVal
local guidCache = Details:GetParserPlayerCache()
if (guidCache[guidVal]) then
return petOwnerFound(guidCache[guidVal], petGUID, petName, petFlags, self, guidVal)
end
end
end
end
end
end
end
Details.tabela_vigente.raid_roster_indexed = Details.tabela_vigente.raid_roster_indexed or {}
local line1 = _G ["DetailsPetOwnerFinderTextLeft2"]
local text1 = line1 and line1:GetText()
if (text1 and text1 ~= "") then
--for _, playerName in ipairs(Details.tabela_vigente.raid_roster_indexed) do
for playerName, _ in pairs(Details.tabela_vigente.raid_roster) do
local pName = playerName
playerName = playerName:gsub("%-.*", "") --remove realm name
--if the user client is in russian language
--make an attempt to remove declensions from the character's name
--this is equivalent to remove 's from the owner on enUS
if (CONST_CLIENT_LANGUAGE == "ruRU") then
if (find_name_declension (text1, playerName)) then
return petOwnerFound (pName, petGUID, petName, petFlags, self)
else
--print("not found declension (1):", pName, nome)
if (text1:find(playerName)) then
return petOwnerFound (pName, petGUID, petName, petFlags, self)
end
end
else
if (text1:find(playerName)) then
return petOwnerFound (pName, petGUID, petName, petFlags, self)
else
local ownerName = (string.match(text1, string.gsub(UNITNAME_TITLE_PET, "%%s", "(%.*)")) or string.match(text1, string.gsub(UNITNAME_TITLE_MINION, "%%s", "(%.*)")) or string.match(text1, string.gsub(UNITNAME_TITLE_GUARDIAN, "%%s", "(%.*)")))
if (ownerName) then
if (Details.tabela_vigente.raid_roster[ownerName]) then
return petOwnerFound (ownerName, petGUID, petName, petFlags, self)
end
end
end
end
end
end
local line2 = _G ["DetailsPetOwnerFinderTextLeft3"]
local text2 = line2 and line2:GetText()
if (text2 and text2 ~= "") then
for playerName, _ in pairs(Details.tabela_vigente.raid_roster) do
--for _, playerName in ipairs(Details.tabela_vigente.raid_roster_indexed) do
local pName = playerName
playerName = playerName:gsub("%-.*", "") --remove realm name
if (CONST_CLIENT_LANGUAGE == "ruRU") then
if (find_name_declension (text2, playerName)) then
return petOwnerFound (pName, petGUID, petName, petFlags, self)
else
--print("not found declension (2):", pName, nome)
if (text2:find(playerName)) then
return petOwnerFound (pName, petGUID, petName, petFlags, self)
end
end
else
if (text2:find(playerName)) then
return petOwnerFound (pName, petGUID, petName, petFlags, self)
else
local ownerName = (string.match(text2, string.gsub(UNITNAME_TITLE_PET, "%%s", "(%.*)")) or string.match(text2, string.gsub(UNITNAME_TITLE_MINION, "%%s", "(%.*)")) or string.match(text2, string.gsub(UNITNAME_TITLE_GUARDIAN, "%%s", "(%.*)")))
if (ownerName) then
if (Details.tabela_vigente.raid_roster[ownerName]) then
return petOwnerFound (ownerName, petGUID, petName, petFlags, self)
end
end
end
end
end
end
end
---get an actor from the container, if the actor doesn't exists, and the bShouldCreateActor is true, create a new actor
---this function is an alias for PegarCombatente which is the function name is in portuguese
---@param actorSerial string
---@param actorName string
---@param actorFlags number
---@param bShouldCreateActor boolean
---@return table
function actorContainer:GetOrCreateActor(actorSerial, actorName, actorFlags, bShouldCreateActor)
return self:PegarCombatente(actorSerial, actorName, actorFlags, bShouldCreateActor)
end
---@param actorSerial string
---@param actorName string
---@param actorFlags number
---@param bShouldCreateActor boolean
---@return table
function actorContainer:PegarCombatente(actorSerial, actorName, actorFlags, bShouldCreateActor)
--[[statistics]]-- _detalhes.statistics.container_calls = _detalhes.statistics.container_calls + 1
--verifica se � um pet, se for confere se tem o nome do dono, se n�o tiver, precisa por
local dono_do_pet
actorSerial = actorSerial or "ns"
if (container_pets[actorSerial]) then --� um pet reconhecido
--[[statistics]]-- _detalhes.statistics.container_pet_calls = _detalhes.statistics.container_pet_calls + 1
local petName, ownerName, ownerGUID, ownerFlag = Details.tabela_pets:PegaDono (actorSerial, actorName, actorFlags)
if (petName and ownerName) then
actorName = petName
dono_do_pet = self:PegarCombatente(ownerGUID, ownerName, ownerFlag, true)
end
elseif (not petBlackList[actorSerial]) then --verifica se � um pet
petBlackList[actorSerial] = true
--try to find the owner
if (actorFlags and bitBand(actorFlags, OBJECT_TYPE_PETGUARDIAN) ~= 0) then
--[[statistics]]-- _detalhes.statistics.container_unknow_pet = _detalhes.statistics.container_unknow_pet + 1
local ownerName, ownerGUID, ownerFlags = Details222.Pets.GetPetOwner(actorSerial, actorName)
if (ownerName and ownerGUID) then
local newPetName, ownerObject = petOwnerFound (ownerName, actorSerial, actorName, actorFlags, self, ownerGUID)
if (newPetName and ownerObject) then
actorName, dono_do_pet = newPetName, ownerObject
end
end
end
end
--pega o index no mapa
local index = self._NameIndexTable[actorName]
--retorna o actor
if (index) then
return self._ActorTable[index], dono_do_pet, actorName
--n�o achou, criar
elseif (bShouldCreateActor) then
local novo_objeto = self.funcao_de_criacao(_, actorSerial, actorName)
novo_objeto.nome = actorName
novo_objeto.flag_original = actorFlags
novo_objeto.serial = actorSerial
--seta a classe default para desconhecido, assim nenhum objeto fica com classe nil
novo_objeto.classe = "UNKNOW"
local forceClass
--get the aID (actor id)
if (actorSerial:match("^C")) then
novo_objeto.aID = tostring(Details:GetNpcIdFromGuid(actorSerial))
if (Details.immersion_special_units) then
local shouldBeInGroup, class = Details.Immersion.IsNpcInteresting(novo_objeto.aID)
novo_objeto.grupo = shouldBeInGroup
if (class) then
novo_objeto.classe = class
forceClass = novo_objeto.classe
end
end
elseif (actorSerial:match("^P")) then
novo_objeto.aID = actorSerial:gsub("Player%-", "")
else
novo_objeto.aID = ""
end
--check ownership
if (dono_do_pet and Details.immersion_pets_on_solo_play) then
if (UnitIsUnit("player", dono_do_pet.nome)) then
if (not Details.in_group) then
novo_objeto.grupo = true
end
end
end
-- tipo do container
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
if (self.tipo == container_damage) then --CONTAINER DAMAGE
local shouldScanOnce = getActorClass (novo_objeto, actorName, actorFlags, actorSerial)
readActorFlag (novo_objeto, dono_do_pet, actorSerial, actorFlags, actorName, "damage")
if (dono_do_pet) then
AddUnique (dono_do_pet.pets, actorName)
end
if (self.shadow) then
if (novo_objeto.grupo and Details.in_combat) then
Details.cache_damage_group [#Details.cache_damage_group+1] = novo_objeto
end
end
if (novo_objeto.classe == "UNGROUPPLAYER") then --is a player
if (bitBand (actorFlags, REACTION_HOSTILE ) ~= 0) then --is hostile
novo_objeto.enemy = true
end
--try to guess his class
if (self.shadow) then --n�o executar 2x
Details:ScheduleTimer("GuessClass", 1, {novo_objeto, self, 1})
end
elseif (shouldScanOnce) then
end
if (novo_objeto.isTank) then
novo_objeto.avoidance = Details:CreateActorAvoidanceTable()
end
elseif (self.tipo == container_heal) then --CONTAINER HEALING
local shouldScanOnce = getActorClass (novo_objeto, actorName, actorFlags, actorSerial)
readActorFlag (novo_objeto, dono_do_pet, actorSerial, actorFlags, actorName, "heal")
if (dono_do_pet) then
AddUnique (dono_do_pet.pets, actorName)
end
if (self.shadow) then
if (novo_objeto.grupo and Details.in_combat) then
Details.cache_healing_group [#Details.cache_healing_group+1] = novo_objeto
end
end
if (novo_objeto.classe == "UNGROUPPLAYER") then --is a player
if (bitBand (actorFlags, REACTION_HOSTILE ) ~= 0) then --is hostile
novo_objeto.enemy = true
end
--try to guess his class
if (self.shadow) then --n�o executar 2x
Details:ScheduleTimer("GuessClass", 1, {novo_objeto, self, 1})
end
end
elseif (self.tipo == container_energy) then --CONTAINER ENERGY
local shouldScanOnce = getActorClass (novo_objeto, actorName, actorFlags, actorSerial)
readActorFlag (novo_objeto, dono_do_pet, actorSerial, actorFlags, actorName, "energy")
if (dono_do_pet) then
AddUnique (dono_do_pet.pets, actorName)
end
if (novo_objeto.classe == "UNGROUPPLAYER") then --is a player
if (bitBand (actorFlags, REACTION_HOSTILE ) ~= 0) then --is hostile
novo_objeto.enemy = true
end
--try to guess his class
if (self.shadow) then --n�o executar 2x
Details:ScheduleTimer("GuessClass", 1, {novo_objeto, self, 1})
end
end
elseif (self.tipo == container_misc) then --CONTAINER MISC
local shouldScanOnce = getActorClass (novo_objeto, actorName, actorFlags, actorSerial)
readActorFlag (novo_objeto, dono_do_pet, actorSerial, actorFlags, actorName, "misc")
if (dono_do_pet) then
AddUnique (dono_do_pet.pets, actorName)
end
if (novo_objeto.classe == "UNGROUPPLAYER") then --is a player
if (bitBand (actorFlags, REACTION_HOSTILE ) ~= 0) then --is hostile
novo_objeto.enemy = true
end
--try to guess his class
if (self.shadow) then --n�o executar 2x
Details:ScheduleTimer("GuessClass", 1, {novo_objeto, self, 1})
end
end
elseif (self.tipo == container_damage_target) then --CONTAINER ALVO DO DAMAGE
elseif (self.tipo == container_energy_target) then --CONTAINER ALVOS DO ENERGY
novo_objeto.mana = 0
novo_objeto.e_rage = 0
novo_objeto.e_energy = 0
novo_objeto.runepower = 0
elseif (self.tipo == container_enemydebufftarget_target) then
novo_objeto.uptime = 0
novo_objeto.actived = false
novo_objeto.activedamt = 0
elseif (self.tipo == container_misc_target) then --CONTAINER ALVOS DO MISC
elseif (self.tipo == container_friendlyfire) then --CONTAINER FRIENDLY FIRE
local shouldScanOnce = getActorClass (novo_objeto, actorName, actorSerial)
end
--sanguine affix
if (actorName == sanguineActorName) then
novo_objeto.grupo = true
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- grava o objeto no mapa do container
local size = #self._ActorTable+1
self._ActorTable [size] = novo_objeto --grava na tabela de indexes
self._NameIndexTable [actorName] = size --grava no hash map o index deste jogador
if (Details.is_in_battleground or Details.is_in_arena) then
novo_objeto.pvp = true
end
if (Details.debug) then
if (Details.debug_chr and actorName:find(Details.debug_chr) and self.tipo == 1) then
local logLine = ""
local when = "[" .. date ("%H:%M:%S") .. format(".%4f", GetTime()-floor(GetTime())) .. "]"
local log = "actor created - class: " .. (novo_objeto.classe or "noclass")
local from = debugstack (2, 1, 0)
logLine = logLine .. when .. " " .. log .. " " .. from .. "\n"
_detalhes_global.debug_chr_log = _detalhes_global.debug_chr_log .. logLine
end
end
--only happens with npcs from immersion feature
if (forceClass) then
novo_objeto.classe = forceClass
end
return novo_objeto, dono_do_pet, actorName
else
return nil, nil, nil
end
end
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--core
--_detalhes:AddToNpcIdCache (novo_objeto)
function Details:AddToNpcIdCache (actor)
if (flag and serial) then
if (bitBand (flag, REACTION_HOSTILE) ~= 0 and bitBand (flag, OBJECT_TYPE_NPC) ~= 0 and bitBand (flag, OBJECT_TYPE_PETGUARDIAN) == 0) then
local npc_id = Details:GetNpcIdFromGuid (serial)
if (npc_id) then
Details.cache_npc_ids [npc_id] = nome
end
end
end
end
function Details:UpdateContainerCombatentes()
container_pets = Details.tabela_pets.pets
Details:UpdatePetsOnParser()
end
function Details:ClearCCPetsBlackList()
table.wipe(petBlackList)
end
function actorContainer:FuncaoDeCriacao (tipo)
if (tipo == container_damage_target) then
return alvo_da_habilidade.NovaTabela
elseif (tipo == container_damage) then
return atributo_damage.NovaTabela
elseif (tipo == container_heal_target) then
return alvo_da_habilidade.NovaTabela
elseif (tipo == container_heal) then
return atributo_heal.NovaTabela
elseif (tipo == container_enemydebufftarget_target) then
return alvo_da_habilidade.NovaTabela
elseif (tipo == container_energy) then
return atributo_energy.NovaTabela
elseif (tipo == container_energy_target) then
return alvo_da_habilidade.NovaTabela
elseif (tipo == container_misc) then
return atributo_misc.NovaTabela
elseif (tipo == container_misc_target) then
return alvo_da_habilidade.NovaTabela
end
end
--chama a fun��o para ser executada em todos os atores
function actorContainer:ActorCallFunction (funcao, ...)
for index, actor in ipairs(self._ActorTable) do
funcao (nil, actor, ...)
end
end
local bykey
local sort = function(t1, t2)
return (t1 [bykey] or 0) > (t2 [bykey] or 0)
end
function actorContainer:SortByKey (key)
assert(type(key) == "string", "Container:SortByKey() expects a keyname on parameter 1.")
bykey = key
tableSort (self._ActorTable, sort)
self:remapear()
end
function actorContainer:Remap()
return self:remapear()
end
function actorContainer:remapear()
local namingMap = self._NameIndexTable
local actorList = self._ActorTable
for i = 1, #actorList do
namingMap[actorList[i].nome] = i
end
end
function Details.refresh:r_container_combatentes (container, shadow)
--reconstr�i meta e indexes
setmetatable(container, Details.container_combatentes)
container.__index = Details.container_combatentes
container.funcao_de_criacao = actorContainer:FuncaoDeCriacao (container.tipo)
--repara mapa
local mapa = {}
for i = 1, #container._ActorTable do
mapa [container._ActorTable[i].nome] = i
end
container._NameIndexTable = mapa
--seta a shadow
container.shadow = shadow
end
function Details.clear:c_container_combatentes (container)
container.__index = nil
container.shadow = nil
--container._NameIndexTable = nil
container.need_refresh = nil
container.funcao_de_criacao = nil
end
function Details.clear:c_container_combatentes_index (container)
container._NameIndexTable = nil
end