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); }