private void CalculateConditions() { foreach (Target target in _log.FightData.Logic.Targets) { Dictionary <long, FinalTargetBoon>[] stats = new Dictionary <long, FinalTargetBoon> [_statistics.Phases.Count]; for (int phaseIndex = 0; phaseIndex < _statistics.Phases.Count; phaseIndex++) { BoonDistribution boonDistribution = target.GetBoonDistribution(_log, phaseIndex); Dictionary <long, FinalTargetBoon> rates = new Dictionary <long, FinalTargetBoon>(); Dictionary <long, long> boonPresence = target.GetBoonPresence(_log, phaseIndex); Dictionary <long, long> condiPresence = target.GetCondiPresence(_log, phaseIndex); PhaseData phase = _statistics.Phases[phaseIndex]; long fightDuration = phase.GetDuration(); foreach (Boon boon in target.BoonToTrack) { FinalTargetBoon condition = new FinalTargetBoon(_log.PlayerList); rates[boon.ID] = condition; if (boonDistribution.ContainsKey(boon.ID)) { if (boon.Type == Boon.BoonType.Duration) { condition.Uptime = Math.Round(100.0 * boonDistribution.GetUptime(boon.ID) / fightDuration, 1); foreach (Player p in _log.PlayerList) { long gen = boonDistribution.GetGeneration(boon.ID, p.InstID); condition.Generated[p] = Math.Round(100.0 * gen / fightDuration, 1); condition.Overstacked[p] = Math.Round(100.0 * (boonDistribution.GetOverstack(boon.ID, p.InstID) + gen) / fightDuration, 1); } } else if (boon.Type == Boon.BoonType.Intensity) { condition.Uptime = Math.Round((double)boonDistribution.GetUptime(boon.ID) / fightDuration, 1); foreach (Player p in _log.PlayerList) { long gen = boonDistribution.GetGeneration(boon.ID, p.InstID); condition.Generated[p] = Math.Round((double)gen / fightDuration, 1); condition.Overstacked[p] = Math.Round((double)(boonDistribution.GetOverstack(boon.ID, p.InstID) + gen) / fightDuration, 1); } if (boonPresence.TryGetValue(boon.ID, out long presenceValueBoon)) { condition.Presence = Math.Round(100.0 * presenceValueBoon / fightDuration, 1); } else if (condiPresence.TryGetValue(boon.ID, out long presenceValueCondi)) { condition.Presence = Math.Round(100.0 * presenceValueCondi / fightDuration, 1); } } rates[boon.ID] = condition; } } stats[phaseIndex] = rates; } _statistics.TargetConditions[target] = stats; } }
public PhaseDto(PhaseData phaseData, List <PhaseData> phases, ParsedLog log) { Name = phaseData.Name; Duration = phaseData.GetDuration(); Start = phaseData.Start / 1000.0; End = phaseData.End / 1000.0; foreach (Target target in phaseData.Targets) { Targets.Add(log.FightData.Logic.Targets.IndexOf(target)); } // add phase markup MarkupLines = new List <double>(); MarkupAreas = new List <AreaLabelDto>(); for (int j = 1; j < phases.Count; j++) { PhaseData curPhase = phases[j]; if (curPhase.Start < phaseData.Start || curPhase.End > phaseData.End || (curPhase.Start == phaseData.Start && curPhase.End == phaseData.End)) { continue; } if (SubPhases == null) { SubPhases = new List <int>(); } SubPhases.Add(j); long start = curPhase.Start - phaseData.Start; long end = curPhase.End - phaseData.Start; if (curPhase.DrawStart) { MarkupLines.Add(start / 1000.0); } if (curPhase.DrawEnd) { MarkupLines.Add(end / 1000.0); } AreaLabelDto phaseArea = new AreaLabelDto { Start = start / 1000.0, End = end / 1000.0, Label = curPhase.Name, Highlight = curPhase.DrawArea }; MarkupAreas.Add(phaseArea); } if (MarkupAreas.Count == 0) { MarkupAreas = null; } if (MarkupLines.Count == 0) { MarkupLines = null; } }
private void CreateUptimeTable(List <Boon> listToUse, int phaseIndex) { //generate Uptime Table table PhaseData phase = _statistics.Phases[phaseIndex]; long fightDuration = phase.GetDuration(); WriteCells(new [] { "Name", "Avg Boons" }); foreach (Boon boon in listToUse) { WriteCell(boon.Name); } NewLine(); int count = 0; foreach (Player player in _log.PlayerList) { Dictionary <long, Statistics.FinalBuffs> uptimes = _statistics.SelfBuffs[player][phaseIndex]; WriteCell(player.Character); WriteCell(Math.Round(_statistics.StatsAll[player][phaseIndex].AvgBoons, 1).ToString()); foreach (Boon boon in listToUse) { if (uptimes.TryGetValue(boon.ID, out var value)) { if (boon.Type == Boon.BoonType.Duration) { WriteCell(value.Uptime + "%"); } else if (boon.Type == Boon.BoonType.Intensity) { WriteCell(value.ToString()); } } else { WriteCell("0"); } } NewLine(); count++; } while (count < 15)//so each graph has equal spacing { NewLine(); count++; } }
private FinalDPS GetFinalDPS(AbstractPlayer player, int phaseIndex, Boss target) { PhaseData phase = _statistics.Phases[phaseIndex]; double phaseDuration = (phase.GetDuration()) / 1000.0; double damage; double dps = 0.0; FinalDPS final = new FinalDPS(); //DPS damage = player.GetDamageLogs(target, _log, phase.Start, phase.End).Sum(x => x.Damage); if (phaseDuration > 0) { dps = damage / phaseDuration; } final.Dps = (int)dps; final.Damage = (int)damage; //Condi DPS damage = player.GetDamageLogs(target, _log, phase.Start, phase.End).Where(x => x.IsCondi > 0).Sum(x => x.Damage); if (phaseDuration > 0) { dps = damage / phaseDuration; } final.CondiDps = (int)dps; final.CondiDamage = (int)damage; //Power DPS damage = final.Damage - final.CondiDamage; if (phaseDuration > 0) { dps = damage / phaseDuration; } final.PowerDps = (int)dps; final.PowerDamage = (int)damage; final.PlayerPowerDamage = player.GetJustPlayerDamageLogs(target, _log, phase.Start, phase.End).Where(x => x.IsCondi == 0).Sum(x => x.Damage); return(final); }
public static void WritePlayerTabBoonGraph(StreamWriter sw, BoonsGraphModel bgm, PhaseData phase) { long roundedEnd = phase.Start + 1000 * phase.GetDuration("s"); List <BoonsGraphModel.Segment> bChart = bgm.BoonChart.Where(x => x.End >= phase.Start && x.Start <= roundedEnd).ToList(); if (bChart.Count == 0 || (bChart.Count == 1 && bChart.First().Value == 0)) { return; } sw.Write("y: ["); { foreach (BoonsGraphModel.Segment seg in bChart) { sw.Write("'" + seg.Value + "',"); } sw.Write("'" + bChart.Last().Value + "'"); } sw.Write("],"); sw.Write("x: ["); { foreach (BoonsGraphModel.Segment seg in bChart) { double segStart = Math.Round(Math.Max(seg.Start - phase.Start, 0) / 1000.0, 3); sw.Write("'" + segStart + "',"); } sw.Write("'" + Math.Round(Math.Min(bChart.Last().End - phase.Start, roundedEnd - phase.Start) / 1000.0, 3) + "'"); } sw.Write("],"); sw.Write(" yaxis: 'y2'," + " type: 'scatter',"); // "legendgroup: '"+Boon.getEnum(bgm.getBoonName()).getPloltyGroup()+"',"; if (!(bgm.BoonName == "Might" || bgm.BoonName == "Quickness")) { sw.Write(" visible: 'legendonly',"); } sw.Write(" line: {color:'" + GetLink("Color-" + bgm.BoonName) + "', shape: 'hv'},"); sw.Write(" fill: 'tozeroy'," + " name: \"" + bgm.BoonName + "\""); }
private FinalDPS GetFinalDPS(AbstractActor player, int phaseIndex, Target target) { PhaseData phase = _statistics.Phases[phaseIndex]; double phaseDuration = (phase.GetDuration()) / 1000.0; int damage; double dps = 0.0; FinalDPS final = new FinalDPS(); //DPS damage = player.GetDamageLogs(target, _log, phase.Start, phase.End).Sum(x => x.Damage); if (phaseDuration > 0) { dps = damage / phaseDuration; } final.Dps = (int)Math.Round(dps); final.Damage = damage; //Condi DPS damage = player.GetDamageLogs(target, _log, phase.Start, phase.End).Sum(x => x.IsCondi ? x.Damage : 0); if (phaseDuration > 0) { dps = damage / phaseDuration; } final.CondiDps = (int)Math.Round(dps); final.CondiDamage = damage; //Power DPS damage = final.Damage - final.CondiDamage; if (phaseDuration > 0) { dps = damage / phaseDuration; } final.PowerDps = (int)Math.Round(dps); final.PowerDamage = damage; return(final); }
private FinalStatsAll GetFinalStats(Player p, int phaseIndex) { PhaseData phase = _statistics.Phases[phaseIndex]; long start = _log.FightData.ToLogSpace(phase.Start); long end = _log.FightData.ToLogSpace(phase.End); Dictionary <Target, FinalStats> targetDict = new Dictionary <Target, FinalStats>(); foreach (Target target in _log.FightData.Logic.Targets) { if (!_statistics.StatsTarget.ContainsKey(target)) { _statistics.StatsTarget[target] = new Dictionary <Player, FinalStats[]>(); } Dictionary <Player, FinalStats[]> targetStats = _statistics.StatsTarget[target]; if (!targetStats.ContainsKey(p)) { targetStats[p] = new FinalStats[_statistics.Phases.Count]; } targetStats[p][phaseIndex] = new FinalStats(); targetDict[target] = targetStats[p][phaseIndex]; } FinalStatsAll final = new FinalStatsAll(); FillFinalStats(p.GetJustPlayerDamageLogs(null, _log, phase.Start, phase.End), final, targetDict); 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) { if (cl.ActualDuration < cl.ExpectedDuration) { final.Saved++; final.TimeSaved += cl.ExpectedDuration - cl.ActualDuration; } } } final.TimeSaved = Math.Round(final.TimeSaved / 1000.0, 3); final.TimeWasted = Math.Round(final.TimeWasted / 1000.0, 3); 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 = p.GetCastLogs(_log, 0, _log.FightData.FightDuration).Count(x => x.SkillId == SkillItem.WeaponSwapId); 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; } } return(final); }
private void CreateDPSTable(int phaseIndex) { PhaseData phase = _statistics.Phases[phaseIndex]; WriteLine(new[] { "Sub Group", "Profession", "Role", "Name", "Account", "WepSet1_1", "WepSet1_2", "WepSet2_1", "WepSet2_2", "Boss DPS", "Boss DMG", "Boss Power DPS", "Boss Power DMG", "Boss Condi DPS", "Boss Condi DMG", "All DPS", "All DMG", "All Power DPS", "All Power DMG", "All Condi DPS", "All Condi DMG", "Times Downed", "Time Died", "Percent Alive" }); int count = 0; foreach (Player player in _log.PlayerList) { Statistics.FinalDPS dps = _statistics.DpsAll[player][phaseIndex]; Statistics.FinalDefenses defense = _statistics.Defenses[player][phaseIndex]; Statistics.FinalDPS dpsBoss = _statistics.DpsTarget[_log.LegacyTarget][player][phaseIndex]; string deathString = defense.DeadCount.ToString(); string deadthTooltip = ""; if (defense.DeadCount > 0) { TimeSpan deathDuration = TimeSpan.FromMilliseconds(defense.DeadDuration); deadthTooltip = deathDuration.TotalSeconds + " seconds dead, " + (100.0 - Math.Round((deathDuration.TotalMilliseconds / phase.GetDuration()) * 100, 1)) + "% Alive"; } string[] wep = player.GetWeaponsArray(_log); string build = ""; if (player.Condition > 0) { build += " Condi:" + player.Condition; } if (player.Concentration > 0) { build += " Concentration:" + player.Concentration; } if (player.Healing > 0) { build += " Healing:" + player.Healing; } if (player.Toughness > 0) { build += " Toughness:" + player.Toughness; } WriteLine(new [] { player.Group.ToString(), player.Prof, build, player.Character, player.Account.TrimStart(':'), wep[0], wep[1], wep[2], wep[3], dpsBoss.Dps.ToString(), dpsBoss.Damage.ToString(), dpsBoss.PowerDps.ToString(), dpsBoss.PowerDamage.ToString(), dpsBoss.CondiDps.ToString(), dpsBoss.CondiDamage.ToString(), dps.Dps.ToString(), dps.Damage.ToString(), dps.PowerDps.ToString(), dps.PowerDamage.ToString(), dps.CondiDps.ToString(), dps.CondiDamage.ToString(), defense.DownCount.ToString(), deathString, deadthTooltip }); count++; } while (count < 15)//so each graph has equal spacing { NewLine(); count++; } }
private static List <Point> GetDPSGraph(ParsedLog log, AbstractMasterPlayer p, int phaseIndex, PhaseData phase, AbstractPlayer target, GraphMode mode) { ulong targetId = target != null ? target.Agent : 0; int askedId = (phaseIndex + "_" + targetId + "_" + mode).GetHashCode(); if (p.GetDPSGraph(askedId).Count > 0) { return(p.GetDPSGraph(askedId)); } List <Point> dmgList = new List <Point>(); List <Point> dmgList1s = new List <Point>(); List <Point> dmgList10s = new List <Point>(); List <Point> dmgList30s = new List <Point>(); List <DamageLog> damageLogs = p.GetDamageLogs(target, log, phase.Start, phase.End); // fill the graph, full precision List <double> dmgListFull = new List <double>(); for (int i = 0; i <= phase.GetDuration(); i++) { dmgListFull.Add(0.0); } int totalTime = 1; int totalDamage = 0; foreach (DamageLog dl in damageLogs) { int time = (int)(dl.Time - phase.Start); // fill for (; totalTime < time; totalTime++) { dmgListFull[totalTime] = totalDamage; } totalDamage += dl.Damage; dmgListFull[totalTime] = totalDamage; } // fill for (; totalTime <= phase.GetDuration(); totalTime++) { dmgListFull[totalTime] = totalDamage; } /*CombatReplay replay = p.Replay; * if (replay != null && dstid == 0 && phaseIndex == 0) * { * foreach (int i in replay.GetTimes()) * { * int limitId = 0; * replay.AddDPS((int)Math.Round(1000 * (dmgListFull[i] - dmgListFull[limitId]) / (i - limitId))); * if (Settings.Show10s) * { * limitId = Math.Max(i - 10000, 0); * replay.AddDPS10s((int)Math.Round(1000 * (dmgListFull[i] - dmgListFull[limitId]) / (i - limitId))); * } * if (Settings.Show30s) * { * limitId = Math.Max(i - 30000, 0); * replay.AddDPS30s((int)Math.Round(1000 * (dmgListFull[i] - dmgListFull[limitId]) / (i - limitId))); * } * } * }*/ dmgList.Add(new Point(0, 0)); dmgList1s.Add(new Point(0, 0)); dmgList10s.Add(new Point(0, 0)); dmgList30s.Add(new Point(0, 0)); for (int i = 1; i <= phase.GetDuration("s"); i++) { int limitId = 0; dmgList.Add(new Point(i, (int)Math.Round((dmgListFull[1000 * i] - dmgListFull[1000 * limitId]) / (i - limitId)))); limitId = i - 1; dmgList1s.Add(new Point(i, (int)Math.Round((dmgListFull[1000 * i] - dmgListFull[1000 * limitId]) / (i - limitId)))); if (Settings.Show10s) { limitId = Math.Max(i - 10, 0); dmgList10s.Add(new Point(i, (int)Math.Round((dmgListFull[1000 * i] - dmgListFull[1000 * limitId]) / (i - limitId)))); } if (Settings.Show30s) { limitId = Math.Max(i - 30, 0); dmgList30s.Add(new Point(i, (int)Math.Round((dmgListFull[1000 * i] - dmgListFull[1000 * limitId]) / (i - limitId)))); } } int id = (phaseIndex + "_" + targetId + "_" + GraphMode.Full).GetHashCode(); p.DpsGraph[id] = dmgList; id = (phaseIndex + "_" + targetId + "_" + GraphMode.S1).GetHashCode(); p.DpsGraph[id] = dmgList1s; if (Settings.Show10s) { id = (phaseIndex + "_" + targetId + "_" + GraphMode.S10).GetHashCode(); p.DpsGraph[id] = dmgList10s; } if (Settings.Show30s) { id = (phaseIndex + "_" + targetId + "_" + GraphMode.S30).GetHashCode(); p.DpsGraph[id] = dmgList30s; } return(p.GetDPSGraph(askedId)); }
public static List <object> GetDefenseStatData(Statistics.FinalDefenses defenses, PhaseData phase) { List <object> data = new List <object> { defenses.DamageTaken, defenses.DamageBarrier, defenses.BlockedCount, defenses.InvulnedCount, defenses.InterruptedCount, defenses.EvadedCount, defenses.DodgeCount }; if (defenses.DownDuration > 0) { TimeSpan downDuration = TimeSpan.FromMilliseconds(defenses.DownDuration); data.Add(defenses.DownCount); data.Add(downDuration.TotalSeconds + " seconds downed, " + Math.Round((downDuration.TotalMilliseconds / phase.GetDuration()) * 100, 1) + "% Downed"); } else { data.Add(0); data.Add("0% downed"); } if (defenses.DeadDuration > 0) { TimeSpan deathDuration = TimeSpan.FromMilliseconds(defenses.DeadDuration); data.Add(defenses.DeadCount); data.Add(deathDuration.TotalSeconds + " seconds dead, " + (100.0 - Math.Round((deathDuration.TotalMilliseconds / phase.GetDuration()) * 100, 1)) + "% Alive"); } else { data.Add(0); data.Add("100% Alive"); } return(data); }
private void CreateDPSTable(int phaseIndex) { PhaseData phase = _statistics.Phases[phaseIndex]; WriteLine(new[] { "Sub Group", "Profession", "Role", "Name", "Account", "WepSet1_1", "WepSet1_2", "WepSet2_1", "WepSet2_2", "Boss DPS", "Boss DMG", "Boss Power DPS", "Boss Power DMG", "Boss Condi DPS", "Boss Condi DMG", "All DPS", "All DMG", "All Power DPS", "All Power DMG", "All Condi DPS", "All Condi DMG", "Times Downed", "Time Died", "Percent Alive" }); int count = 0; foreach (Player player in _log.PlayerList) { Statistics.FinalDPS dps = _statistics.DpsAll[player][phaseIndex]; Statistics.FinalDPS dpsBoss = _statistics.DpsBoss[_log.Boss][player][phaseIndex]; Statistics.FinalStatsAll stats = _statistics.StatsAll[player][phaseIndex]; Statistics.FinalStats statsBoss = _statistics.StatsBoss[_log.Boss][player][phaseIndex]; string deathString = ""; string deadthTooltip = ""; if (stats.Died != 0.0) { if (stats.Died < 0) { deathString = -stats.Died + " time(s)"; } else { TimeSpan timedead = TimeSpan.FromMilliseconds(stats.Died); deathString = timedead.Minutes + " m " + timedead.Seconds + " s"; deadthTooltip = Math.Round((timedead.TotalMilliseconds / phase.GetDuration()) * 100, 1) + "%"; } } else { deadthTooltip = "Never died"; } string[] wep = player.GetWeaponsArray(_log); string build = ""; if (player.Condition > 0) { build += " Condi:" + player.Condition; } if (player.Concentration > 0) { build += " Concentration:" + player.Concentration; } if (player.Healing > 0) { build += " Healing:" + player.Healing; } if (player.Toughness > 0) { build += " Toughness:" + player.Toughness; } WriteLine(new [] { player.Group.ToString(), player.Prof, build, player.Character, player.Account.TrimStart(':'), wep[0], wep[1], wep[2], wep[3], dpsBoss.Dps.ToString(), dpsBoss.Damage.ToString(), dpsBoss.PowerDps.ToString(), dpsBoss.PowerDamage.ToString(), dpsBoss.CondiDps.ToString(), dpsBoss.CondiDamage.ToString(), dps.Dps.ToString(), dps.Damage.ToString(), dps.PowerDps.ToString(), dps.PowerDamage.ToString(), dps.CondiDps.ToString(), dps.CondiDamage.ToString(), stats.DownCount.ToString(), deathString, deadthTooltip }); count++; } while (count < 15)//so each graph has equal spacing { NewLine(); count++; } }
public static void WriteBossHealthGraph(StreamWriter sw, int maxDPS, PhaseData phase, double[] bossHealth, string yAxis = "") { int duration = (int)phase.GetDuration("s"); double[] chart = bossHealth.Skip((int)phase.Start / 1000).Take(duration + 1).ToArray(); //Boss Health //Adding dps axis sw.Write("y: ["); if (maxDPS == 0) { maxDPS = 1000; } for (int i = 0; i < chart.Length; i++) { double health = chart[i]; if (i == chart.Length - 1) { sw.Write("'" + ((health / 100.0) * maxDPS).ToString().Replace(',', '.') + "'"); } else { sw.Write("'" + ((health / 100.0) * maxDPS).ToString().Replace(',', '.') + "',"); } } sw.Write("],"); //text axis is boss hp in % sw.Write("text: ["); for (int i = 0; i < chart.Length; i++) { double health = chart[i]; if (i == chart.Length - 1) { sw.Write("'" + (health + "%").Replace(',', '.') + "'"); } else { sw.Write("'" + (health + "%").Replace(',', '.') + "',"); } } sw.Write("],"); //add time axis sw.Write("x: ["); for (int i = 0; i < chart.Length; i++) { double health = chart[i]; if (i == chart.Length - 1) { sw.Write("'" + i + "'"); } else { sw.Write("'" + i + "',"); } } sw.Write("],"); sw.Write(" mode: 'lines'," + " line: {shape: 'spline', dash: 'dashdot'}," + (yAxis.Length > 0 ? " yaxis: '" + yAxis + "'," : "") + "hoverinfo: 'text'," + " name: 'Boss health'"); }
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); }