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.

976 lines
30 KiB

local Details = _G.Details
local Loc = LibStub("AceLocale-3.0"):GetLocale ( "Details" )
local _
local addonName, Details222 = ...
--[[global]] DETAILS_TOTALS_ONLYGROUP = true
--[[global]] DETAILS_SEGMENTID_OVERALL = -1
--[[global]] DETAILS_SEGMENTID_CURRENT = 0
--[[global]] DETAILS_COMBAT_AMOUNT_CONTAINERS = 4
--enum segments type
--[[global]] DETAILS_SEGMENTTYPE_GENERIC = 0
--[[global]] DETAILS_SEGMENTTYPE_OVERALL = 1
--[[global]] DETAILS_SEGMENTTYPE_DUNGEON_TRASH = 5
--[[global]] DETAILS_SEGMENTTYPE_DUNGEON_BOSS = 6
--[[global]] DETAILS_SEGMENTTYPE_RAID_TRASH = 7
--[[global]] DETAILS_SEGMENTTYPE_RAID_BOSS = 8
--[[global]] DETAILS_SEGMENTTYPE_MYTHICDUNGEON = 100
--[[global]] DETAILS_SEGMENTTYPE_MYTHICDUNGEON_GENERIC = 10
--[[global]] DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH = 11
--[[global]] DETAILS_SEGMENTTYPE_MYTHICDUNGEON_OVERALL = 12
--[[global]] DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASHOVERALL = 13
--[[global]] DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSS = 14
--[[global]] DETAILS_SEGMENTTYPE_PVP_ARENA = 20
--[[global]] DETAILS_SEGMENTTYPE_PVP_BATTLEGROUND = 21
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--local pointers
local ipairs = ipairs -- lua local
local pairs = pairs -- lua local
local bitBand = bit.band -- lua local
local date = date -- lua local
local tremove = table.remove -- lua local
local rawget = rawget
local _math_max = math.max
local floor = math.floor
local GetTime = GetTime
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--constants
local classCombat = Details.combate
local classActorContainer = Details.container_combatentes
local class_type_dano = Details.atributos.dano
local class_type_cura = Details.atributos.cura
local class_type_e_energy = Details.atributos.e_energy
local class_type_misc = Details.atributos.misc
local classTypeDamage = Details.atributos.dano
local classTypeHeal = Details.atributos.cura
local classTypeResource = Details.atributos.e_energy
local classTypeUtility = Details.atributos.misc
local REACTION_HOSTILE = 0x00000040
local CONTROL_PLAYER = 0x00000100
--local _tempo = time()
local _tempo = GetTime()
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--api functions
--combat (container type, actor name)
Details.call_combate = function(self, classType, actorName)
local container = self[classType]
local index_mapa = container._NameIndexTable[actorName]
local actor = container._ActorTable[index_mapa]
return actor
end
classCombat.__call = Details.call_combate
---get the unique combat identifier
---@param self combat
---@return number
function classCombat:GetCombatUID()
return self.combat_counter
end
--get the start date and end date
function classCombat:GetDate()
return self.data_inicio, self.data_fim
end
--set the combat date
function classCombat:SetDate(started, ended)
if (started and type(started) == "string") then
self.data_inicio = started
end
if (ended and type(ended) == "string") then
self.data_fim = ended
end
end
---return a table representing a chart data
---@param name string
---@return number[]
function classCombat:GetTimeData(name)
if (self.TimeData) then
return self.TimeData[name]
end
return {max_value = 0}
end
---erase a time data if exists
---@param name string
function classCombat:EraseTimeData(name)
if (self.TimeData[name]) then
self.TimeData[name] = nil
return true
end
return false
end
function classCombat:GetContainer(attribute)
return self [attribute]
end
function classCombat:GetRoster()
return self.raid_roster
end
function classCombat:InstanceType()
return rawget(self, "instance_type")
end
function classCombat:IsTrash()
return rawget(self, "is_trash")
end
function classCombat:GetDifficulty()
return self.is_boss and self.is_boss.diff
end
function classCombat:GetEncounterCleuID()
return self.is_boss and self.is_boss.id
end
function classCombat:GetBossInfo()
return self.is_boss
end
function classCombat:GetPhases()
return self.PhaseData
end
function classCombat:GetPvPInfo()
return self.is_pvp
end
function classCombat:GetMythicDungeonInfo()
return self.is_mythic_dungeon
end
function classCombat:GetMythicDungeonTrashInfo()
return self.is_mythic_dungeon_trash
end
---return if the combat is a mythic dungeon segment and the run id
---@return boolean
---@return number
function classCombat:IsMythicDungeon()
local bIsMythicPlusSegment = self.is_mythic_dungeon_segment
local runId = self.is_mythic_dungeon_run_id
return bIsMythicPlusSegment, runId
end
function classCombat:IsMythicDungeonOverall()
return self.is_mythic_dungeon and self.is_mythic_dungeon.OverallSegment
end
function classCombat:GetArenaInfo()
return self.is_arena
end
function classCombat:GetDeaths()
return self.last_events_tables
end
function classCombat:GetPlayerDeaths(deadPlayerName)
local allDeaths = self:GetDeaths()
local deaths = {}
for i = 1, #allDeaths do
local thisDeath = allDeaths[i]
local thisPlayerName = thisDeath[3]
if (deadPlayerName == thisPlayerName) then
deaths[#deaths+1] = thisDeath
end
end
return deaths
end
function classCombat:GetCombatId()
return self.combat_id
end
function classCombat:GetCombatNumber()
return self.combat_counter
end
function classCombat:GetAlteranatePower()
return self.alternate_power
end
---return the amount of casts of a spells from an actor
---@param self combat
---@param actorName string
---@param spellName string
---@return number
function classCombat:GetSpellCastAmount(actorName, spellName)
return self.amountCasts[actorName] and self.amountCasts[actorName][spellName] or 0
end
---return the cast amount table
---@param self combat
---@param actorName string|nil
---@return table
function classCombat:GetSpellCastTable(actorName)
if (actorName) then
return self.amountCasts[actorName] or {}
else
return self.amountCasts
end
end
---delete an actor from the spell casts amount
---@param self combat
---@param actorName string
function classCombat:RemoveActorFromSpellCastTable(actorName)
self.amountCasts[actorName] = nil
end
---return the uptime of a buff from an actor
---@param actorName string
---@param spellId number
---@param auraType string|nil if nil get 'buff'
---@return number
function classCombat:GetSpellUptime(actorName, spellId, auraType)
---@type actorcontainer
local utilityContainer = self:GetContainer(DETAILS_ATTRIBUTE_MISC)
---@type actor
local actorObject = utilityContainer:GetActor(actorName)
if (actorObject) then
if (auraType) then
---@type spellcontainer
local buffUptimeContainer = actorObject:GetSpellContainer(auraType)
if (buffUptimeContainer) then
---@type spelltable
local spellTable = buffUptimeContainer:GetSpell(spellId)
if (spellTable) then
return spellTable.uptime or 0
end
end
else
do --if not auraType passed, attempt to get the uptime from debuffs first, if it fails, get from buffs
---@type spellcontainer
local debuffContainer = actorObject:GetSpellContainer("debuff")
if (debuffContainer) then
---@type spelltable
local spellTable = debuffContainer:GetSpell(spellId)
if (spellTable) then
return spellTable.uptime or 0
end
end
end
do
---@type spellcontainer
local buffContainer = actorObject:GetSpellContainer("buff")
if (buffContainer) then
---@type spelltable
local spellTable = buffContainer:GetSpell(spellId)
if (spellTable) then
return spellTable.uptime or 0
end
end
end
end
end
return 0
end
--return the name of the encounter or enemy
function classCombat:GetCombatName(try_find)
if (self.is_pvp) then
return self.is_pvp.name
elseif (self.is_boss) then
return self.is_boss.encounter
elseif (self.is_mythic_dungeon_trash) then
return self.is_mythic_dungeon_trash.ZoneName .. " (" .. Loc ["STRING_SEGMENTS_LIST_TRASH"] .. ")"
elseif (rawget(self, "is_trash")) then
return Loc ["STRING_SEGMENT_TRASH"]
else
if (self.enemy) then
return self.enemy
end
if (try_find) then
return Details:FindEnemy()
end
end
return Loc ["STRING_UNKNOW"]
end
function classCombat:GetCombatType()
--mythic dungeon
local isMythicDungeon = self.is_mythic_dungeon_segment
if (isMythicDungeon) then
local isMythicDungeonTrash = self.is_mythic_dungeon_trash
if (isMythicDungeonTrash) then
return DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH, DETAILS_SEGMENTTYPE_MYTHICDUNGEON
else
local isMythicDungeonOverall = self.is_mythic_dungeon and self.is_mythic_dungeon.OverallSegment
local isMythicDungeonTrashOverall = self.is_mythic_dungeon and self.is_mythic_dungeon.TrashOverallSegment
if (isMythicDungeonOverall) then
return DETAILS_SEGMENTTYPE_MYTHICDUNGEON_OVERALL, DETAILS_SEGMENTTYPE_MYTHICDUNGEON
elseif (isMythicDungeonTrashOverall) then
return DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASHOVERALL, DETAILS_SEGMENTTYPE_MYTHICDUNGEON
end
local bossEncounter = self.is_boss
if (bossEncounter) then
return DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSS, DETAILS_SEGMENTTYPE_MYTHICDUNGEON
end
return DETAILS_SEGMENTTYPE_MYTHICDUNGEON_GENERIC, DETAILS_SEGMENTTYPE_MYTHICDUNGEON
end
end
--arena
local arenaInfo = self.is_arena
if (arenaInfo) then
return DETAILS_SEGMENTTYPE_PVP_ARENA
end
--battleground
local battlegroundInfo = self.is_pvp
if (battlegroundInfo) then
return DETAILS_SEGMENTTYPE_PVP_BATTLEGROUND
end
--dungeon or raid
local instanceType = self.instance_type
if (instanceType == "party") then
local bossEncounter = self.is_boss
if (bossEncounter) then
return DETAILS_SEGMENTTYPE_DUNGEON_BOSS
else
return DETAILS_SEGMENTTYPE_DUNGEON_TRASH
end
elseif (instanceType == "raid") then
local bossEncounter = self.is_boss
if (bossEncounter) then
return DETAILS_SEGMENTTYPE_RAID_BOSS
else
return DETAILS_SEGMENTTYPE_RAID_TRASH
end
end
--overall data
if (self == Details.tabela_overall) then
return DETAILS_SEGMENTTYPE_OVERALL
end
return DETAILS_SEGMENTTYPE_GENERIC
end
--return a numeric table with all actors on the specific containter
function classCombat:GetActorList (container)
return self [container]._ActorTable
end
---return an actor object for the given container and actor name
---@param container number
---@param name string
---@return actor|nil
function classCombat:GetActor(container, name)
local index = self[container] and self[container]._NameIndexTable[name]
if (index) then
return self[container]._ActorTable[index]
end
return nil
end
---return the combat time in seconds
---@return number, number
function classCombat:GetFormatedCombatTime()
local combatTime = self:GetCombatTime()
local minute, second = floor(combatTime / 60), floor(combatTime % 60)
return minute, second
end
---return the amount of time the combat has elapsed
---@return number
function classCombat:GetCombatTime()
if (self.end_time) then
return _math_max (self.end_time - self.start_time, 0.1)
elseif (self.start_time and Details.in_combat and self ~= Details.tabela_overall) then
return _math_max (GetTime() - self.start_time, 0.1)
else
return 0.1
end
end
function classCombat:GetStartTime()
return self.start_time
end
function classCombat:SetStartTime(thisTime)
self.start_time = thisTime
end
function classCombat:GetEndTime()
return self.end_time
end
function classCombat:SetEndTime(thisTime)
self.end_time = thisTime
end
---copy deaths from combat2 into combat1
---if bMythicPlus is true it'll check if the death has mythic plus death time and use it instead of the normal death time
---@param combat1 combat
---@param combat2 combat
---@param bMythicPlus boolean
function classCombat.CopyDeathsFrom(combat1, combat2, bMythicPlus)
local deathsTable = combat1:GetDeaths()
local deathsToCopy = combat2:GetDeaths()
for i = 1, #deathsToCopy do
local thisDeath = DetailsFramework.table.copy({}, deathsToCopy[i])
if (bMythicPlus and thisDeath.mythic_plus) then
thisDeath[6] = thisDeath.mythic_plus_dead_at_string
thisDeath.dead_at = thisDeath.mythic_plus_dead_at
end
deathsTable[#deathsTable+1] = thisDeath
end
end
--return the total of a specific attribute
local power_table = {0, 1, 3, 6, 0, "alternatepower"}
function classCombat:GetTotal(attribute, subAttribute, onlyGroup)
if (attribute == 1 or attribute == 2) then
if (onlyGroup) then
return self.totals_grupo [attribute]
else
return self.totals [attribute]
end
elseif (attribute == 3) then
if (subAttribute == 5) then --resources
return self.totals.resources or 0
end
if (onlyGroup) then
return self.totals_grupo [attribute] [power_table [subAttribute]]
else
return self.totals [attribute] [power_table [subAttribute]]
end
elseif (attribute == 4) then
local subName = Details:GetInternalSubAttributeName (attribute, subAttribute)
if (onlyGroup) then
return self.totals_grupo [attribute] [subName]
else
return self.totals [attribute] [subName]
end
end
return 0
end
---create an alternate power table for the given actor
---@param actorName string
---@return alternatepowertable
function classCombat:CreateAlternatePowerTable(actorName)
---@type alternatepowertable
local alternatePowerTable = {last = 0, total = 0}
self.alternate_power[actorName] = alternatePowerTable
return alternatePowerTable
end
--delete an actor from the combat ~delete ~erase ~remove
function classCombat:DeleteActor(attribute, actorName, removeDamageTaken, cannotRemap)
local container = self[attribute]
if (container) then
local actorTable = container._ActorTable
--store the index it was found
local indexToDelete
--get the object for the deleted actor
local deletedActor = self(attribute, actorName)
if (not deletedActor) then
return
else
for i = 1, #actorTable do
local actor = actorTable[i]
if (actor.nome == actorName) then
--print("Details: found the actor: ", actorName, actor.nome, i)
indexToDelete = i
break
end
end
end
for i = 1, #actorTable do
--is this not the actor we want to remove?
if (i ~= indexToDelete) then
local actor = actorTable[i]
if (not actor.isTank) then
--get the damage dealt and remove
local damageDoneToRemovedActor = (actor.targets[actorName]) or 0
actor.targets[actorName] = nil
actor.total = actor.total - damageDoneToRemovedActor
actor.total_without_pet = actor.total_without_pet - damageDoneToRemovedActor
--damage taken
if (removeDamageTaken) then
local hadDamageTaken = actor.damage_from[actorName]
if (hadDamageTaken) then
--query the deleted actor to know how much damage it applied to this actor
local damageDoneToActor = (deletedActor.targets[actor.nome]) or 0
actor.damage_taken = actor.damage_taken - damageDoneToActor
end
end
--spells
local spellsTable = actor.spells._ActorTable
for spellId, spellTable in pairs(spellsTable) do
local damageDoneToRemovedActor = (spellTable.targets[actorName]) or 0
spellTable.targets[actorName] = nil
spellTable.total = spellTable.total - damageDoneToRemovedActor
end
end
end
end
if (indexToDelete) then
local actorToDelete = self(attribute, actorName)
local actorToDelete2 = container._ActorTable[indexToDelete]
if (actorToDelete ~= actorToDelete2) then
Details:Msg("error 0xDE8745")
end
local index = container._NameIndexTable[actorName]
if (indexToDelete ~= index) then
Details:Msg("error 0xDE8751")
end
--remove actor
tremove(container._ActorTable, index)
--remap
if (not cannotRemap) then
container:Remap()
end
return true
end
end
end
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--internals
function classCombat:CreateNewCombatTable()
return classCombat:NovaTabela()
end
---class constructor
---@param bTimeStarted boolean if true set the start time to now with GetTime
---@param overallCombatObject combat
---@param combatId number
---@param ... unknown
---@return combat
function classCombat:NovaTabela(bTimeStarted, overallCombatObject, combatId, ...) --~init
---@type combat
local combatObject = {}
combatObject[1] = classActorContainer:NovoContainer(Details.container_type.CONTAINER_DAMAGE_CLASS, combatObject, combatId) --Damage
combatObject[2] = classActorContainer:NovoContainer(Details.container_type.CONTAINER_HEAL_CLASS, combatObject, combatId) --Healing
combatObject[3] = classActorContainer:NovoContainer(Details.container_type.CONTAINER_ENERGY_CLASS, combatObject, combatId) --Energies
combatObject[4] = classActorContainer:NovoContainer(Details.container_type.CONTAINER_MISC_CLASS, combatObject, combatId) --Misc
combatObject[5] = classActorContainer:NovoContainer(Details.container_type.CONTAINER_DAMAGE_CLASS, combatObject, combatId) --place holder for customs
setmetatable(combatObject, classCombat)
Details.combat_counter = Details.combat_counter + 1
combatObject.combat_counter = Details.combat_counter
--try discover if is a pvp combat
local who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags = ...
if (who_serial) then --aqui ir� identificar o boss ou o oponente
if (alvo_name and bitBand (alvo_flags, REACTION_HOSTILE) ~= 0) then --tentando pegar o inimigo pelo alvo
combatObject.contra = alvo_name
if (bitBand (alvo_flags, CONTROL_PLAYER) ~= 0) then
combatObject.pvp = true --o alvo � da fac��o oposta ou foi dado mind control
end
elseif (who_name and bitBand (who_flags, REACTION_HOSTILE) ~= 0) then --tentando pegar o inimigo pelo who caso o mob � quem deu o primeiro hit
combatObject.contra = who_name
if (bitBand (who_flags, CONTROL_PLAYER) ~= 0) then
combatObject.pvp = true --o who � da fac��o oposta ou foi dado mind control
end
else
combatObject.pvp = true --se ambos s�o friendly, seria isso um PVP entre jogadores da mesma fac��o?
end
end
--start/end time (duration)
combatObject.data_fim = 0
combatObject.data_inicio = 0
combatObject.tempo_start = _tempo
combatObject.bossTimers = {}
---store trinket procs
combatObject.trinketProcs = {}
---store the amount of casts of each player
---@type table<actorname, table<spellname, number>>
combatObject.amountCasts = {}
--record deaths
combatObject.last_events_tables = {}
--last events from players
combatObject.player_last_events = {}
--players in the raid
combatObject.raid_roster = {}
combatObject.raid_roster_indexed = {}
--frags
combatObject.frags = {}
combatObject.frags_need_refresh = false
--alternate power
combatObject.alternate_power = {}
--time data container
combatObject.TimeData = Details:TimeDataCreateChartTables()
combatObject.PhaseData = {{1, 1}, damage = {}, heal = {}, damage_section = {}, heal_section = {}} --[1] phase number [2] phase started
--for external plugin usage, these tables are guaranteed to be saved with the combat
combatObject.spells_cast_timeline = {}
combatObject.aura_timeline = {}
combatObject.cleu_timeline = {}
--cleu events
combatObject.cleu_events = {
n = 1 --event counter
}
--a tabela sem o tempo de inicio � a tabela descartavel do inicio do addon
if (bTimeStarted) then
--esta_tabela.start_time = _tempo
combatObject.start_time = GetTime()
combatObject.end_time = nil
else
combatObject.start_time = 0
combatObject.end_time = nil
end
-- o container ir� armazenar as classes de dano -- cria um novo container de indexes de seriais de jogadores --par�metro 1 classe armazenada no container, par�metro 2 = flag da classe
combatObject[1].need_refresh = true
combatObject[2].need_refresh = true
combatObject[3].need_refresh = true
combatObject[4].need_refresh = true
combatObject[5].need_refresh = true
combatObject.totals = {
0, --dano
0, --cura
{--e_energy
[0] = 0, --mana
[1] = 0, --rage
[3] = 0, --energy (rogues cat)
[6] = 0, --runepower (dk)
alternatepower = 0,
},
{--misc
cc_break = 0, --armazena quantas quebras de CC
ress = 0, --armazena quantos pessoas ele reviveu
interrupt = 0, --armazena quantos interrupt a pessoa deu
dispell = 0, --armazena quantos dispell esta pessoa recebeu
dead = 0, --armazena quantas vezes essa pessia morreu
cooldowns_defensive = 0, --armazena quantos cooldowns a raid usou
buff_uptime = 0, --armazena quantos cooldowns a raid usou
debuff_uptime = 0 --armazena quantos cooldowns a raid usou
},
--avoid using this values bellow, they aren't updated by the parser, only on demand by a user interaction.
voidzone_damage = 0,
frags_total = 0,
--end
}
combatObject.totals_grupo = {
0, --dano
0, --cura
{--e_energy
[0] = 0, --mana
[1] = 0, --rage
[3] = 0, --energy (rogues cat)
[6] = 0, --runepower (dk)
alternatepower = 0,
},
{--misc
cc_break = 0, --armazena quantas quebras de CC
ress = 0, --armazena quantos pessoas ele reviveu
interrupt = 0, --armazena quantos interrupt a pessoa deu
dispell = 0, --armazena quantos dispell esta pessoa recebeu
dead = 0, --armazena quantas vezes essa oessia morreu
cooldowns_defensive = 0, --armazena quantos cooldowns a raid usou
buff_uptime = 0,
debuff_uptime = 0
}
}
return combatObject
end
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--core
---create the table which will contain the latest events of the player while alive
---@param self combat
---@param playerName string
---@return table
function classCombat:CreateLastEventsTable(playerName)
local lastEventsTable = {}
for i = 1, Details.deadlog_events do
lastEventsTable[i] = {}
end
lastEventsTable.n = 1
self.player_last_events[playerName] = lastEventsTable
return lastEventsTable
end
---pass through all actors and check if the activity time is unlocked, if it is, lock it
---@param self combat
function classCombat:LockActivityTime()
---@cast self combat
---@type actorcontainer
local containerDamage = self:GetContainer(DETAILS_ATTRIBUTE_DAMAGE)
---@type actorcontainer
local containerHeal = self:GetContainer(DETAILS_ATTRIBUTE_HEAL)
for _, actorObject in containerDamage:ListActors() do
if (actorObject:GetOrChangeActivityStatus()) then --check if the timer is unlocked
Details222.TimeMachine.StopTime(actorObject)
actorObject:GetOrChangeActivityStatus(false) --lock the actor timer
else
if (actorObject.start_time == 0) then
actorObject.start_time = _tempo
end
if (not actorObject.end_time) then
actorObject.end_time = _tempo
end
end
end
for _, actorObject in containerHeal:ListActors() do
--check if the timer is unlocked
if (actorObject:GetOrChangeActivityStatus()) then
--lock the actor timer
Details222.TimeMachine.StopTime(actorObject)
--remove the actor from the time machine
actorObject:GetOrChangeActivityStatus(false)
else
if (actorObject.start_time == 0) then
actorObject.start_time = _tempo
end
if (not actorObject.end_time) then
actorObject.end_time = _tempo
end
end
end
end
function classCombat:seta_data(tipo)
if (tipo == Details._detalhes_props.DATA_TYPE_START) then
self.data_inicio = date("%H:%M:%S")
elseif (tipo == Details._detalhes_props.DATA_TYPE_END) then
self.data_fim = date("%H:%M:%S")
end
end
function classCombat:seta_tempo_decorrido()
--self.end_time = _tempo
self.end_time = GetTime()
end
---set combat metatable and class lookup
---@self any
---@param combatObject combat
function Details.refresh:r_combate(combatObject)
setmetatable(combatObject, Details.combate)
combatObject.__index = Details.combate
end
---clear combat object
---@self any
---@param combatObject combat
function Details.clear:c_combate(combatObject)
combatObject.__index = nil
combatObject.__call = nil
end
classCombat.__sub = function(combate1, combate2)
if (combate1 ~= Details.tabela_overall) then
return
end
--sub dano
for index, actor_T2 in ipairs(combate2[1]._ActorTable) do
local actor_T1 = combate1[1]:PegarCombatente (actor_T2.serial, actor_T2.nome, actor_T2.flag_original, true)
actor_T1 = actor_T1 - actor_T2
actor_T2:subtract_total (combate1)
end
combate1 [1].need_refresh = true
--sub heal
for index, actor_T2 in ipairs(combate2[2]._ActorTable) do
local actor_T1 = combate1[2]:PegarCombatente (actor_T2.serial, actor_T2.nome, actor_T2.flag_original, true)
actor_T1 = actor_T1 - actor_T2
actor_T2:subtract_total (combate1)
end
combate1 [2].need_refresh = true
--sub energy
for index, actor_T2 in ipairs(combate2[3]._ActorTable) do
local actor_T1 = combate1[3]:PegarCombatente (actor_T2.serial, actor_T2.nome, actor_T2.flag_original, true)
actor_T1 = actor_T1 - actor_T2
actor_T2:subtract_total (combate1)
end
combate1 [3].need_refresh = true
--sub misc
for index, actor_T2 in ipairs(combate2[4]._ActorTable) do
local actor_T1 = combate1[4]:PegarCombatente (actor_T2.serial, actor_T2.nome, actor_T2.flag_original, true)
actor_T1 = actor_T1 - actor_T2
actor_T2:subtract_total (combate1)
end
combate1 [4].need_refresh = true
--reduz o tempo
combate1.start_time = combate1.start_time + combate2:GetCombatTime()
--apaga as mortes da luta diminuida
local amt_mortes = #combate2.last_events_tables --quantas mortes teve nessa luta
if (amt_mortes > 0) then
for i = #combate1.last_events_tables, #combate1.last_events_tables-amt_mortes, -1 do
tremove(combate1.last_events_tables, #combate1.last_events_tables)
end
end
--frags
for fragName, fragAmount in pairs(combate2.frags) do
if (fragAmount) then
if (combate1.frags [fragName]) then
combate1.frags [fragName] = combate1.frags [fragName] - fragAmount
else
combate1.frags [fragName] = fragAmount
end
end
end
combate1.frags_need_refresh = true
--alternate power
local overallPowerTable = combate1.alternate_power
for actorName, powerTable in pairs(combate2.alternate_power) do
local power = overallPowerTable [actorName]
if (power) then
power.total = power.total - powerTable.total
end
combate2.alternate_power [actorName].last = 0
end
return combate1
end
---add combatToAdd into combatRecevingTheSum
---@param combatRecevingTheSum combat
---@param combatToAdd combat
---@return combat
classCombat.__add = function(combatRecevingTheSum, combatToAdd)
---@type combat
local customCombat
if (combatRecevingTheSum ~= Details.tabela_overall) then
customCombat = combatRecevingTheSum
end
local bRefreshActor = false
for classType = 1, DETAILS_COMBAT_AMOUNT_CONTAINERS do
local actorContainer = combatToAdd[classType]
local actorTable = actorContainer._ActorTable
for _, actorObject in ipairs(actorTable) do
---@cast actorObject actor
---@type actor
local actorCreatedInTheReceivingCombat
if (classType == classTypeDamage) then
actorCreatedInTheReceivingCombat = Details.atributo_damage:AddToCombat(actorObject, bRefreshActor, customCombat)
elseif (classType == classTypeHeal) then
actorCreatedInTheReceivingCombat = Details.atributo_heal:AddToCombat(actorObject, bRefreshActor, customCombat)
elseif (classType == classTypeResource) then
actorCreatedInTheReceivingCombat = Details.atributo_energy:r_connect_shadow(actorObject, true, customCombat)
elseif (classType == classTypeUtility) then
actorCreatedInTheReceivingCombat = Details.atributo_misc:r_connect_shadow(actorObject, true, customCombat)
end
actorCreatedInTheReceivingCombat.boss_fight_component = actorObject.boss_fight_component or actorCreatedInTheReceivingCombat.boss_fight_component
actorCreatedInTheReceivingCombat.fight_component = actorObject.fight_component or actorCreatedInTheReceivingCombat.fight_component
actorCreatedInTheReceivingCombat.grupo = actorObject.grupo or actorCreatedInTheReceivingCombat.grupo
end
end
--alternate power
local overallPowerTable = combatRecevingTheSum.alternate_power
for actorName, powerTable in pairs(combatToAdd.alternate_power) do
local alternatePowerTable = overallPowerTable[actorName]
if (not alternatePowerTable) then
alternatePowerTable = combatRecevingTheSum:CreateAlternatePowerTable(actorName)
end
alternatePowerTable.total = alternatePowerTable.total + powerTable.total
combatToAdd.alternate_power[actorName].last = 0
end
--cast amount
local combat1CastData = combatRecevingTheSum.amountCasts
for actorName, castData in pairs(combatToAdd.amountCasts) do
local playerCastTable = combat1CastData[actorName]
if (not playerCastTable) then
playerCastTable = {}
combat1CastData[actorName] = playerCastTable
end
for spellName, amountOfCasts in pairs(castData) do
local spellAmount = playerCastTable[spellName]
if (not spellAmount) then
spellAmount = 0
playerCastTable[spellName] = spellAmount
end
playerCastTable[spellName] = spellAmount + amountOfCasts
end
end
return combatRecevingTheSum
end
function Details:UpdateCombat()
_tempo = Details._tempo
end