-- 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 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 _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