internal FinalGameplayStatsAll(ParsedEvtcLog log, PhaseData phase, AbstractSingleActor actor) : base(log, phase, actor, null)
        {
            // If fake actor, stop
            if (actor.IsFakeActor)
            {
                return;
            }
            int phaseIndex = log.FightData.GetPhases(log).IndexOf(phase);

            foreach (AbstractCastEvent cl in actor.GetCastLogs(log, phase.Start, phase.End))
            {
                switch (cl.Status)
                {
                case AbstractCastEvent.AnimationStatus.Iterrupted:
                    Wasted++;
                    TimeWasted += cl.SavedDuration;
                    break;

                case AbstractCastEvent.AnimationStatus.Reduced:
                    Saved++;
                    TimeSaved += cl.SavedDuration;
                    break;
                }
                if (cl.Skill.IsSwap)
                {
                    SwapCount++;
                }
            }
            TimeSaved  = Math.Round(TimeSaved / 1000.0, ParserHelper.TimeDigit);
            TimeWasted = -Math.Round(TimeWasted / 1000.0, ParserHelper.TimeDigit);

            double avgBoons = 0;

            foreach (long duration in actor.GetBuffPresence(log, phaseIndex).Where(x => log.Buffs.BuffsByIds[x.Key].Nature == BuffNature.Boon).Select(x => x.Value))
            {
                avgBoons += duration;
            }
            AvgBoons = Math.Round(avgBoons / phase.DurationInMS, ParserHelper.BuffDigit);
            long activeDuration = phase.GetActorActiveDuration(actor, log);

            AvgActiveBoons = activeDuration > 0 ? Math.Round(avgBoons / activeDuration, ParserHelper.BuffDigit) : 0.0;

            double avgCondis = 0;

            foreach (long duration in actor.GetBuffPresence(log, phaseIndex).Where(x => log.Buffs.BuffsByIds[x.Key].Nature == BuffNature.Condition).Select(x => x.Value))
            {
                avgCondis += duration;
            }
            AvgConditions       = Math.Round(avgCondis / phase.DurationInMS, ParserHelper.BuffDigit);
            AvgActiveConditions = activeDuration > 0 ? Math.Round(avgCondis / activeDuration, ParserHelper.BuffDigit) : 0.0;

            if (log.CombatData.HasMovementData && actor is Player player)
            {
                StackDist = GetDistanceToTarget(player, log, phase, log.Statistics.GetStackCenterPositions(log));
                DistToCom = GetDistanceToTarget(player, log, phase, log.Statistics.GetStackCommanderPositions(log));
            }
        }
        private static long[] GetReses(ParsedEvtcLog log, AbstractSingleActor actor, long start, long end)
        {
            List <AbstractCastEvent> cls = actor.GetCastLogs(log, start, end);

            long[] reses = { 0, 0 };
            foreach (AbstractCastEvent cl in cls)
            {
                if (cl.SkillId == SkillItem.ResurrectId)
                {
                    reses[0]++;
                    reses[1] += cl.ActualDuration;
                }
            }
            return(reses);
        }
        internal FinalDefenses(ParsedEvtcLog log, PhaseData phase, AbstractSingleActor actor, AbstractSingleActor from)
        {
            long start = phase.Start;
            long end   = phase.End;
            List <AbstractDamageEvent> damageLogs = actor.GetDamageTakenLogs(from, log, start, end);

            DamageTaken      = damageLogs.Sum(x => (long)x.Damage);
            BlockedCount     = damageLogs.Count(x => x.IsBlocked);
            MissedCount      = damageLogs.Count(x => x.IsBlind);
            InvulnedCount    = damageLogs.Count(x => x.IsAbsorbed);
            EvadedCount      = damageLogs.Count(x => x.IsEvaded);
            DodgeCount       = actor.GetCastLogs(log, start, end).Count(x => x.SkillId == SkillItem.DodgeId || x.SkillId == SkillItem.MirageCloakDodgeId);
            DamageBarrier    = damageLogs.Sum(x => x.ShieldDamage);
            InterruptedCount = damageLogs.Count(x => x.HasInterrupted);
        }