Пример #1
0
        private void CalculateDefenses()
        {
            CombatData combatData = _log.CombatData;

            foreach (Player player in _log.PlayerList)
            {
                FinalDefenses[] phaseDefense = new FinalDefenses[_statistics.Phases.Count];
                for (int phaseIndex = 0; phaseIndex < _statistics.Phases.Count; phaseIndex++)
                {
                    FinalDefenses final = new FinalDefenses();

                    PhaseData phase = _statistics.Phases[phaseIndex];
                    long      start = _log.FightData.ToLogSpace(phase.Start);
                    long      end   = _log.FightData.ToLogSpace(phase.End);

                    List <DamageLog> damageLogs = player.GetDamageTakenLogs(null, _log, phase.Start, phase.End);
                    //List<DamageLog> healingLogs = player.getHealingReceivedLogs(log, phase.getStart(), phase.getEnd());

                    final.DamageTaken = damageLogs.Sum(x => (long)x.Damage);
                    //final.allHealReceived = healingLogs.Sum(x => x.getDamage());
                    final.BlockedCount     = damageLogs.Count(x => x.Result == ParseEnum.Result.Block);
                    final.InvulnedCount    = 0;
                    final.DamageInvulned   = 0;
                    final.EvadedCount      = damageLogs.Count(x => x.Result == ParseEnum.Result.Evade);
                    final.DodgeCount       = player.GetCastLogs(_log, 0, _log.FightData.FightDuration).Count(x => x.SkillId == SkillItem.DodgeId);
                    final.DamageBarrier    = damageLogs.Sum(x => x.ShieldDamage);
                    final.InterruptedCount = damageLogs.Count(x => x.Result == ParseEnum.Result.Interrupt);
                    foreach (DamageLog log in damageLogs.Where(x => x.Result == ParseEnum.Result.Absorb))
                    {
                        final.InvulnedCount++;
                        final.DamageInvulned += log.Damage;
                    }
                    List <CombatItem> deads = combatData.GetStates(player.InstID, ParseEnum.StateChange.ChangeDead, start, end);
                    List <CombatItem> downs = combatData.GetStates(player.InstID, ParseEnum.StateChange.ChangeDown, start, end);
                    List <CombatItem> dcs   = combatData.GetStates(player.InstID, ParseEnum.StateChange.Despawn, start, end);
                    final.DownCount = downs.Count;
                    final.DeadCount = deads.Count;
                    final.DCCount   = dcs.Count;

                    phaseDefense[phaseIndex] = final;
                }
                List <Tuple <long, long> > dead = new List <Tuple <long, long> >();
                List <Tuple <long, long> > down = new List <Tuple <long, long> >();
                List <Tuple <long, long> > dc   = new List <Tuple <long, long> >();
                combatData.GetAgentStatus(player.FirstAware, player.LastAware, player.InstID, dead, down, dc);

                for (int phaseIndex = 0; phaseIndex < _statistics.Phases.Count; phaseIndex++)
                {
                    FinalDefenses defenses = phaseDefense[phaseIndex];
                    PhaseData     phase    = _statistics.Phases[phaseIndex];
                    long          start    = phase.Start;
                    long          end      = phase.End;
                    defenses.DownDuration = (int)down.Where(x => x.Item2 >= start && x.Item1 <= end).Sum(x => Math.Min(end, x.Item2) - Math.Max(x.Item1, start));
                    defenses.DeadDuration = (int)dead.Where(x => x.Item2 >= start && x.Item1 <= end).Sum(x => Math.Min(end, x.Item2) - Math.Max(x.Item1, start));
                    defenses.DCDuration   = (int)dc.Where(x => x.Item2 >= start && x.Item1 <= end).Sum(x => Math.Min(end, x.Item2) - Math.Max(x.Item1, start));
                }

                _statistics.Defenses[player] = phaseDefense;
            }
        }
        private FinalStatsAll GetFinalStats(Player p, int phaseIndex)
        {
            PhaseData      phase       = _statistics.Phases[phaseIndex];
            long           start       = phase.Start + _log.FightData.FightStart;
            long           end         = phase.End + _log.FightData.FightStart;
            FinalStatsAll  final       = new FinalStatsAll();
            HashSet <long> nonCritable = new HashSet <long>
            {
                9292,
                52370
            };

            foreach (DamageLog dl in p.GetJustPlayerDamageLogs(null, _log, phase.Start, phase.End))
            {
                if (dl.IsCondi == 0)
                {
                    if (dl.Result == ParseEnum.Result.Crit)
                    {
                        final.CriticalRate++;
                        final.CriticalDmg += dl.Damage;
                    }

                    if (dl.IsNinety > 0)
                    {
                        final.ScholarRate++;
                        final.ScholarDmg += (int)(dl.Damage / 11.0); //regular+10% damage
                    }

                    if (dl.IsMoving > 0)
                    {
                        final.MovingRate++;
                        final.MovingDamage += (int)(dl.Damage / 21.0);
                    }

                    final.FlankingRate += dl.IsFlanking;

                    if (dl.Result == ParseEnum.Result.Glance)
                    {
                        final.GlanceRate++;
                    }

                    if (dl.Result == ParseEnum.Result.Blind)
                    {
                        final.Missed++;
                    }

                    if (dl.Result == ParseEnum.Result.Interrupt)
                    {
                        final.Interrupts++;
                    }

                    if (dl.Result == ParseEnum.Result.Absorb)
                    {
                        final.Invulned++;
                    }
                    final.PowerLoopCount++;
                    if (!nonCritable.Contains(dl.SkillId))
                    {
                        final.CritablePowerLoopCount++;
                    }
                }
            }
            if (p.Account == ":Conjured Sword")
            {
                return(final);
            }
            foreach (CastLog cl in p.GetCastLogs(_log, phase.Start, phase.End))
            {
                if (cl.EndActivation == ParseEnum.Activation.CancelCancel)
                {
                    final.Wasted++;
                    final.TimeWasted += cl.ActualDuration;
                }
                if (cl.EndActivation == ParseEnum.Activation.CancelFire)
                {
                    final.Saved++;
                    if (cl.ActualDuration < cl.ExpectedDuration)
                    {
                        final.TimeSaved += cl.ExpectedDuration - cl.ActualDuration;
                    }
                }
            }
            final.TimeSaved  = final.TimeSaved / 1000f;
            final.TimeWasted = final.TimeWasted / 1000f;

            double avgBoons = 0;

            foreach (long duration in p.GetBoonPresence(_log, phaseIndex).Values)
            {
                avgBoons += duration;
            }
            final.AvgBoons = avgBoons / phase.GetDuration();

            double avgCondis = 0;

            foreach (long duration in p.GetCondiPresence(_log, phaseIndex).Values)
            {
                avgCondis += duration;
            }
            final.AvgConditions = avgCondis / phase.GetDuration();


            // Counts
            CombatData combatData = _log.CombatData;

            final.SwapCount  = combatData.GetStates(p.InstID, ParseEnum.StateChange.WeaponSwap, start, end).Count;
            final.DownCount  = combatData.GetStates(p.InstID, ParseEnum.StateChange.ChangeDown, start, end).Count;
            final.DodgeCount = combatData.GetSkillCount(p.InstID, SkillItem.DodgeId, start, end) + combatData.GetBuffCount(p.InstID, 40408, start, end);//dodge = 65001 mirage cloak =40408

            if (_settings.ParseCombatReplay && _log.FightData.Logic.CanCombatReplay)
            {
                if (_statistics.StackCenterPositions == null)
                {
                    _statistics.StackCenterPositions = new List <Point3D>();
                    List <List <Point3D> > GroupsPosList = new List <List <Point3D> >();
                    foreach (Player player in _log.PlayerList)
                    {
                        if (player.Account == ":Conjured Sword")
                        {
                            continue;
                        }
                        GroupsPosList.Add(player.CombatReplay.GetActivePositions());
                    }
                    for (int time = 0; time < GroupsPosList[0].Count; time++)
                    {
                        float x             = 0;
                        float y             = 0;
                        float z             = 0;
                        int   activePlayers = GroupsPosList.Count;
                        foreach (List <Point3D> points in GroupsPosList)
                        {
                            Point3D point = points[time];
                            if (point != null)
                            {
                                x += point.X;
                                y += point.Y;
                                z += point.Z;
                            }
                            else
                            {
                                activePlayers--;
                            }
                        }
                        x = x / activePlayers;
                        y = y / activePlayers;
                        z = z / activePlayers;
                        _statistics.StackCenterPositions.Add(new Point3D(x, y, z, _settings.PollingRate * time));
                    }
                }
                List <Point3D> positions = p.CombatReplay.Positions.Where(x => x.Time >= phase.Start && x.Time <= phase.End).ToList();
                int            offset    = p.CombatReplay.Positions.Count(x => x.Time < phase.Start);
                if (positions.Count > 1)
                {
                    List <float> distances = new List <float>();
                    for (int time = 0; time < positions.Count; time++)
                    {
                        float deltaX = positions[time].X - _statistics.StackCenterPositions[time + offset].X;
                        float deltaY = positions[time].Y - _statistics.StackCenterPositions[time + offset].Y;
                        //float deltaZ = positions[time].Z - StackCenterPositions[time].Z;


                        distances.Add((float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY));
                    }
                    final.StackDist = distances.Sum() / distances.Count;
                }
                else
                {
                    final.StackDist = -1;
                }
            }

            List <CombatItem> dead = combatData.GetStates(p.InstID, ParseEnum.StateChange.ChangeDead, start, end);
            List <CombatItem> up   = combatData.GetStates(p.InstID, ParseEnum.StateChange.ChangeUp, start, end);

            final.Died = 0.0;
            if (dead.Count > 0)
            {
                final.Died = up.Count > 0 && up.Last().Time > dead.Last().Time ? -dead.Count : dead.Last().Time - start;
            }

            List <CombatItem> disconnect = combatData.GetStates(p.InstID, ParseEnum.StateChange.Despawn, start, end);

            final.Dcd = 0.0;
            if (disconnect.Count > 0)
            {
                final.Dcd = disconnect.Last().Time - start;
            }
            return(final);
        }
        public void ComputeMechanics(ParsedLog log)
        {
            MechanicData mechData   = log.MechanicData;
            FightData    fightData  = log.FightData;
            CombatData   combatData = log.CombatData;
            long         start      = fightData.FightStart;
            long         end        = fightData.FightEnd;

            Mechanic.CheckSpecialCondition condition;
            HashSet <ushort> playersIds = new HashSet <ushort>(log.PlayerList.Select(x => x.InstID));
            Dictionary <ushort, AbstractMasterPlayer> regroupedMobs = new Dictionary <ushort, AbstractMasterPlayer>();

            foreach (Mechanic mech in MechanicList)
            {
                switch (mech.MechanicType)
                {
                case Mechanic.MechType.PlayerStatus:
                    foreach (Player p in log.PlayerList)
                    {
                        List <CombatItem> cList = new List <CombatItem>();
                        switch (mech.SkillId)
                        {
                        case SkillItem.DeathId:
                            cList = combatData.GetStates(p.InstID, ParseEnum.StateChange.ChangeDead, start, end);
                            break;

                        case SkillItem.DownId:
                            cList = combatData.GetStates(p.InstID, ParseEnum.StateChange.ChangeDown, start, end);
                            break;

                        case SkillItem.ResurrectId:
                            cList = log.GetCastData(p.InstID).Where(x => x.SkillID == SkillItem.ResurrectId && x.IsActivation.IsCasting()).ToList();
                            break;
                        }
                        foreach (CombatItem mechItem in cList)
                        {
                            mechData[mech].Add(new MechanicLog(mechItem.Time - start, mech, p));
                        }
                    }
                    break;

                case Mechanic.MechType.SkillOnPlayer:
                    foreach (Player p in log.PlayerList)
                    {
                        List <DamageLog> dls = p.GetDamageTakenLogs(log, 0, fightData.FightDuration);
                        condition = mech.SpecialCondition;
                        foreach (DamageLog dLog in dls)
                        {
                            if (condition != null && !condition(new SpecialConditionItem(dLog)))
                            {
                                continue;
                            }
                            if (dLog.SkillId == mech.SkillId && dLog.Result.IsHit())
                            {
                                mechData[mech].Add(new MechanicLog(dLog.Time, mech, p));
                            }
                        }
                    }
                    break;

                case Mechanic.MechType.PlayerBoon:
                case Mechanic.MechType.PlayerOnPlayer:
                case Mechanic.MechType.PlayerBoonRemove:
                    foreach (Player p in log.PlayerList)
                    {
                        condition = mech.SpecialCondition;
                        foreach (CombatItem c in log.GetBoonData(mech.SkillId))
                        {
                            if (condition != null && !condition(new SpecialConditionItem(c)))
                            {
                                continue;
                            }
                            if (mech.MechanicType == Mechanic.MechType.PlayerBoonRemove)
                            {
                                if (c.IsBuffRemove == ParseEnum.BuffRemove.Manual && p.InstID == c.SrcInstid)
                                {
                                    mechData[mech].Add(new MechanicLog(c.Time - start, mech, p));
                                }
                            }
                            else
                            {
                                if (c.IsBuffRemove == ParseEnum.BuffRemove.None && p.InstID == c.DstInstid)
                                {
                                    mechData[mech].Add(new MechanicLog(c.Time - start, mech, p));
                                    if (mech.MechanicType == Mechanic.MechType.PlayerOnPlayer)
                                    {
                                        mechData[mech].Add(new MechanicLog(c.Time - start, mech, log.PlayerList.FirstOrDefault(x => x.InstID == c.SrcInstid)));
                                    }
                                }
                            }
                        }
                    }
                    break;

                case Mechanic.MechType.HitOnEnemy:
                    foreach (Player p in log.PlayerList)
                    {
                        condition = mech.SpecialCondition;
                        IEnumerable <AgentItem> agents = log.AgentData.GetAgentsByID((ushort)mech.SkillId);
                        foreach (AgentItem a in agents)
                        {
                            foreach (DamageLog dl in p.GetDamageLogs(null, log, 0, log.FightData.FightDuration))
                            {
                                if (dl.DstInstId != a.InstID || dl.IsCondi > 0 || dl.Time < a.FirstAware - start || dl.Time > a.LastAware - start || (condition != null && !condition(new SpecialConditionItem(dl))))
                                {
                                    continue;
                                }
                                mechData[mech].Add(new MechanicLog(dl.Time, mech, p));
                            }
                        }
                    }
                    break;

                case Mechanic.MechType.PlayerSkill:
                    foreach (Player p in log.PlayerList)
                    {
                        condition = mech.SpecialCondition;
                        foreach (CombatItem c in log.GetCastDataById(mech.SkillId))
                        {
                            if (condition != null && !condition(new SpecialConditionItem(c)))
                            {
                                continue;
                            }
                            if (c.IsActivation.IsCasting() && c.SrcInstid == p.InstID)
                            {
                                mechData[mech].Add(new MechanicLog(c.Time - fightData.FightStart, mech, p));
                            }
                        }
                    }
                    break;

                case Mechanic.MechType.EnemyBoon:
                case Mechanic.MechType.EnemyBoonStrip:
                    condition = mech.SpecialCondition;
                    foreach (CombatItem c in log.GetBoonData(mech.SkillId))
                    {
                        if (condition != null && !condition(new SpecialConditionItem(c)))
                        {
                            continue;
                        }
                        AbstractMasterPlayer amp = null;
                        if (mech.MechanicType == Mechanic.MechType.EnemyBoon && c.IsBuffRemove == ParseEnum.BuffRemove.None)
                        {
                            Boss target = Targets.Find(x => x.InstID == c.DstInstid && x.FirstAware <= c.Time && x.LastAware >= c.Time);
                            if (target != null)
                            {
                                amp = target;
                            }
                            else
                            {
                                AgentItem a = log.AgentData.GetAgent(c.DstAgent);
                                if (playersIds.Contains(a.InstID))
                                {
                                    continue;
                                }
                                else if (a.MasterAgent != 0)
                                {
                                    AgentItem m = log.AgentData.GetAgent(a.MasterAgent);
                                    if (playersIds.Contains(m.InstID))
                                    {
                                        continue;
                                    }
                                }
                                if (!regroupedMobs.TryGetValue(a.ID, out amp))
                                {
                                    amp = new DummyPlayer(a);
                                    regroupedMobs.Add(a.ID, amp);
                                }
                            }
                        }
                        else if (mech.MechanicType == Mechanic.MechType.EnemyBoonStrip && c.IsBuffRemove == ParseEnum.BuffRemove.Manual)
                        {
                            Boss target = Targets.Find(x => x.InstID == c.SrcInstid && x.FirstAware <= c.Time && x.LastAware >= c.Time);
                            if (target != null)
                            {
                                amp = target;
                            }
                            else
                            {
                                AgentItem a = log.AgentData.GetAgent(c.SrcAgent);
                                if (playersIds.Contains(a.InstID))
                                {
                                    continue;
                                }
                                else if (a.MasterAgent != 0)
                                {
                                    AgentItem m = log.AgentData.GetAgent(a.MasterAgent);
                                    if (playersIds.Contains(m.InstID))
                                    {
                                        continue;
                                    }
                                }
                                if (!regroupedMobs.TryGetValue(a.ID, out amp))
                                {
                                    amp = new DummyPlayer(a);
                                    regroupedMobs.Add(a.ID, amp);
                                }
                            }
                        }
                        if (amp != null)
                        {
                            mechData[mech].Add(new MechanicLog(c.Time - fightData.FightStart, mech, amp));
                        }
                    }
                    break;

                case Mechanic.MechType.EnemyCastEnd:
                case Mechanic.MechType.EnemyCastStart:
                    condition = mech.SpecialCondition;
                    foreach (CombatItem c in log.GetCastDataById(mech.SkillId))
                    {
                        if (condition != null && !condition(new SpecialConditionItem(c)))
                        {
                            continue;
                        }
                        AbstractMasterPlayer amp = null;
                        if ((mech.MechanicType == Mechanic.MechType.EnemyCastStart && c.IsActivation.IsCasting()) || (mech.MechanicType == Mechanic.MechType.EnemyCastEnd && !c.IsActivation.IsCasting()))
                        {
                            Boss target = Targets.Find(x => x.InstID == c.SrcInstid && x.FirstAware <= c.Time && x.LastAware >= c.Time);
                            if (target != null)
                            {
                                amp = target;
                            }
                            else
                            {
                                AgentItem a = log.AgentData.GetAgent(c.SrcAgent);
                                if (playersIds.Contains(a.InstID))
                                {
                                    continue;
                                }
                                else if (a.MasterAgent != 0)
                                {
                                    AgentItem m = log.AgentData.GetAgent(a.MasterAgent);
                                    if (playersIds.Contains(m.InstID))
                                    {
                                        continue;
                                    }
                                }
                                if (!regroupedMobs.TryGetValue(a.ID, out amp))
                                {
                                    amp = new DummyPlayer(a);
                                    regroupedMobs.Add(a.ID, amp);
                                }
                            }
                        }
                        if (amp != null)
                        {
                            mechData[mech].Add(new MechanicLog(c.Time - fightData.FightStart, mech, amp));
                        }
                    }
                    break;

                case Mechanic.MechType.Spawn:
                    foreach (AgentItem a in log.AgentData.GetAgentByType(AgentItem.AgentType.NPC).Where(x => x.ID == mech.SkillId))
                    {
                        if (!regroupedMobs.TryGetValue(a.ID, out AbstractMasterPlayer amp))
                        {
                            amp = new DummyPlayer(a);
                            regroupedMobs.Add(a.ID, amp);
                        }
                        mechData[mech].Add(new MechanicLog(a.FirstAware - fightData.FightStart, mech, amp));
                    }
                    break;
                }
            }
            mechData.ComputePresentMechanics(log);
        }