public void UpdateDetailedStats() { if (!DamageRecords.Any()) { return; } #region Loop through abilities #region Damage foreach (var dmgGroup in DamageRecords.GroupBy(d => d.Ability.Name)) { long critDamage = 0; long hitDamage = 0; int crits = dmgGroup.Count(d => d.CriticalHit); int swings = dmgGroup.Count(); int hits = swings - crits; decimal critrate = crits > 0 ? (((decimal)crits / (decimal)swings) * 100) : 0; Ability ability = new Ability { //Name = isPetAbility ? string.Format("{0} (Pet)", dmgGroup.Key) : dmgGroup.Key, Name = dmgGroup.Key, IsPetAbility = !string.IsNullOrEmpty(dmgGroup.First().SourcePetName), DamageType = dmgGroup.First().Ability.DamageType ?? "unknown", Statistics = new AbilityStatistics { Swings = swings, Hits = hits, Crits = crits, CritRate = critrate }, IconPath = dmgGroup.First().Ability.Icon }; foreach (var dmg in dmgGroup) { if (dmg.CriticalHit) { #region Min Crit if (ability.Statistics.MinCrit == 0 || dmg.TotalDamage < ability.Statistics.MinCrit) { ability.Statistics.MinCrit = dmg.TotalDamage; } #endregion #region Max Crit if (ability.Statistics.MaxCrit == 0 || dmg.TotalDamage > ability.Statistics.MaxCrit) { ability.Statistics.MaxCrit = dmg.TotalDamage; } #endregion critDamage += dmg.TotalDamage; } else { #region Min Hit if (ability.Statistics.MinHit == 0 || dmg.TotalDamage < ability.Statistics.MinHit) { ability.Statistics.MinHit = dmg.TotalDamage; } #endregion #region Max Hit if (ability.Statistics.MaxHit == 0 || dmg.TotalDamage > ability.Statistics.MaxHit) { ability.Statistics.MaxHit = dmg.TotalDamage; } #endregion hitDamage += dmg.TotalDamage; } } #region AverageHit ability.Statistics.AverageHit = hits > 0 ? hitDamage / hits : 0; #endregion #region AverageCrit ability.Statistics.AverageCrit = crits > 0 ? critDamage / crits : 0; #endregion ability.TotalDamage = critDamage + hitDamage; ability.DamagePerSecond = EncounterLength.TotalSeconds > 0 ? ability.TotalDamage / (long)EncounterLength.TotalSeconds : 0; if (dmgGroup.First().SourcePlayer == null || dmgGroup.First().SourcePlayerId != Player.Id) { // An NPC or other player dealt damage to this player DamageIncomingAbilityBreakdown.Abilities.Add(ability); } else { if (dmgGroup.First().TargetPlayerId == null) // Ignore damage to other players { DamageOutgoingAbilityBreakdown.Abilities.Add(ability); } } } #endregion #region Healing var healSourceBreakdown = new Dictionary <string, long>(); foreach (var healGroup in HealingRecords.GroupBy(h => h.Ability.Name)) { long critHeal = 0; long hitHeal = 0; // Track total healing so the outgoing healing type breakdown is accurate long totalCritHeal = 0; long totalHitHeal = 0; int crits = healGroup.Where(h => h.EffectiveHealing > 0).Count(h => h.CriticalHit); int swings = healGroup.Count(h => h.EffectiveHealing > 0); int hits = swings - crits; decimal critrate = crits > 0 ? (((decimal)crits / (decimal)swings) * 100) : 0; Ability ability = new Ability { Name = healGroup.Key, IsPetAbility = !string.IsNullOrEmpty(healGroup.First().SourcePetName), Statistics = new AbilityStatistics { Swings = swings, Hits = hits, Crits = crits, CritRate = critrate }, IconPath = healGroup.First().Ability.Icon }; foreach (var heal in healGroup) { if (heal.SourcePlayerId != null) { //if (heal.SourcePlayerId != Player.Id) //{ if (healSourceBreakdown.ContainsKey(heal.SourcePlayer.Name)) { healSourceBreakdown[heal.SourcePlayer.Name] += heal.EffectiveHealing; } else { healSourceBreakdown.Add(heal.SourcePlayer.Name, heal.EffectiveHealing); } //} } if (heal.CriticalHit) { #region Min Crit if (ability.Statistics.MinCrit == 0 || heal.EffectiveHealing < ability.Statistics.MinCrit) { if (heal.EffectiveHealing > 0) { ability.Statistics.MinCrit = heal.EffectiveHealing; } } #endregion #region Max Crit if (ability.Statistics.MaxCrit == 0 || heal.EffectiveHealing > ability.Statistics.MaxCrit) { ability.Statistics.MaxCrit = heal.EffectiveHealing; } #endregion critHeal += heal.EffectiveHealing; totalCritHeal += heal.TotalHealing; } else { #region Min Hit if (ability.Statistics.MinHit == 0 || heal.EffectiveHealing < ability.Statistics.MinHit) { if (heal.EffectiveHealing > 0) { ability.Statistics.MinHit = heal.EffectiveHealing; } } #endregion #region Max Hit if (ability.Statistics.MaxHit == 0 || heal.EffectiveHealing > ability.Statistics.MaxHit) { ability.Statistics.MaxHit = heal.EffectiveHealing; } #endregion hitHeal += heal.EffectiveHealing; totalHitHeal += heal.TotalHealing; } } #region AverageHit ability.Statistics.AverageHit = hits > 0 ? hitHeal / hits : 0; #endregion #region AverageCrit ability.Statistics.AverageCrit = crits > 0 ? critHeal / crits : 0; #endregion ability.TotalEffectiveHealing = critHeal + hitHeal; ability.TotalHealing = totalCritHeal + totalHitHeal; ability.EffectiveHealingPerSecond = EncounterLength.TotalSeconds > 0 ? ability.TotalEffectiveHealing / (long)EncounterLength.TotalSeconds : 0; if (ability.TotalEffectiveHealing > 0) { if (healGroup.First().SourcePlayerId == Player.Id) { if (healGroup.First().TargetPlayerId == Player.Id) { // Self Healing HealingIncomingAbilityBreakdown.Abilities.Add(new Ability(ability)); HealingOutgoingAbilityBreakdown.Abilities.Add(new Ability(ability)); HealingOutgoingTypeBreakdown.Abilities.Add(new Ability(ability)); } else { // Healing someone else HealingOutgoingAbilityBreakdown.Abilities.Add(new Ability(ability)); HealingOutgoingTypeBreakdown.Abilities.Add(new Ability(ability)); } } else if (healGroup.First().TargetPlayerId == Player.Id) { // Being healed by someone else HealingIncomingAbilityBreakdown.Abilities.Add(new Ability(ability)); } } } #endregion #endregion #region Lists var secondsElapsed = new List <string>(); var tDps = new List <object>(); // Total Damage var eDps = new List <object>(); // Effective Damage var aDps = new List <object>(); // Average DPS long totalDamageDone = 0; var tHps = new List <object>(); // Total Healing var eHps = new List <object>(); // Effective Healing var aHps = new List <object>(); // Average HPS long totalHealingDone = 0; #endregion #region Loop through the encounter events by second for (int i = 0; i <= EncounterLength.TotalSeconds; i++) { int secondElapsed = i; secondsElapsed.Add(secondElapsed.ToString(CultureInfo.InvariantCulture)); #region Damage var damageThisSecond = DamageRecords .Where(d => d.SecondsElapsed == secondElapsed && d.SourcePlayer != null).ToList(); if (damageThisSecond.Any()) { long damageDealt = damageThisSecond.Sum(d => d.TotalDamage); tDps.Add(damageDealt); eDps.Add(damageThisSecond.Sum(d => d.EffectiveDamage)); totalDamageDone += damageDealt; } else { tDps.Add(0); eDps.Add(0); } if (secondElapsed > 0) { aDps.Add((int)(totalDamageDone / secondElapsed)); } else { aDps.Add(0); } #endregion #region Healing var healingThisSecond = HealingRecords .Where(h => h.SecondsElapsed == secondElapsed && h.SourcePlayerId == Player.Id).ToList(); if (healingThisSecond.Any()) { long healingDone = healingThisSecond.Sum(d => d.EffectiveHealing); tHps.Add(healingThisSecond.Sum(d => d.TotalHealing)); eHps.Add(healingDone); totalHealingDone += healingDone; } else { tHps.Add(0); eHps.Add(0); } if (secondElapsed > 0) { aHps.Add((int)(totalHealingDone / secondElapsed)); } else { aHps.Add(0); } #endregion } #endregion #region Create arrays from our lists var secondsArray = secondsElapsed.ToArray(); var tDpsArray = tDps.ToArray(); var eDpsArray = eDps.ToArray(); var aDpsArray = aDps.ToArray(); var tHpsArray = tHps.ToArray(); var eHpsArray = eHps.ToArray(); var aHpsArray = aHps.ToArray(); #endregion #region Ability Percentages long totalDamageDealt = DamageOutgoingAbilityBreakdown.Abilities.Sum(a => a.TotalDamage); long totalDamageTaken = DamageIncomingAbilityBreakdown.Abilities.Sum(a => a.TotalDamage); foreach (var ability in DamageOutgoingAbilityBreakdown.Abilities) { ability.BreakdownPercentage = ability.TotalDamage > 0 ? ((decimal)ability.TotalDamage / (decimal)totalDamageDealt) * 100 : 0; } foreach (var ability in DamageIncomingAbilityBreakdown.Abilities) { ability.BreakdownPercentage = ability.TotalDamage > 0 ? ((decimal)ability.TotalDamage / (decimal)totalDamageTaken) * 100 : 0; } long totalHealingDealt = HealingOutgoingAbilityBreakdown.Abilities.Sum(a => a.TotalEffectiveHealing); long totalHealingTaken = HealingIncomingAbilityBreakdown.Abilities.Sum(a => a.TotalEffectiveHealing); foreach (var ability in HealingOutgoingAbilityBreakdown.Abilities) { ability.BreakdownPercentage = ability.TotalEffectiveHealing > 0 ? ((decimal)ability.TotalEffectiveHealing / (decimal)totalHealingDealt) * 100 : 0; } foreach (var ability in HealingIncomingAbilityBreakdown.Abilities) { ability.BreakdownPercentage = ability.TotalEffectiveHealing > 0 ? ((decimal)ability.TotalEffectiveHealing / (decimal)totalHealingTaken) * 100 : 0; } #endregion #region Update the charts #region DamageOutgoingPerSecond DamageOutgoingPerSecondChart = new Highcharts(string.Format("encounter{0}dps", EncounterId)) .InitChart(new Chart { DefaultSeriesType = ChartTypes.Line, ZoomType = ZoomTypes.Xy, Height = 300 }) .SetCredits(new Credits() { Enabled = true, Href = "#", Text = "Hewi@Laethys" }) .SetTitle(new Title { Text = "Damage per second" }) .SetXAxis( new XAxis { Categories = secondsArray, MinTickInterval = (EncounterLength.TotalSeconds / 10), Title = new XAxisTitle() { Text = "Seconds Elapsed" } }) .SetYAxis(new[] { new YAxis { Title = new YAxisTitle { Text = "Damage" }, Min = 0, //PlotLines = new YAxisPlotLines[] //{ // plotLine //}, } }) .SetPlotOptions(new PlotOptions { Line = new PlotOptionsLine { EnableMouseTracking = true, Marker = new PlotOptionsLineMarker { Enabled = false } } }) .SetSeries(new[] { new Series { Name = "Average Damage Per Second", Data = new Data(aDpsArray) }, new Series { Name = "Total Damage", Data = new Data(tDpsArray), PlotOptionsLine = new PlotOptionsLine { Visible = false } }, new Series { Name = "Effective Damage", Data = new Data(eDpsArray) } }) .SetExporting(new Exporting { Enabled = false }); #endregion #region HealingOutgoingPerSecond HealingOutgoingPerSecondChart = new Highcharts(string.Format("encounter{0}hps", EncounterId)) .InitChart(new Chart { DefaultSeriesType = ChartTypes.Line, ZoomType = ZoomTypes.Xy, Height = 300 }) .SetCredits(new Credits() { Enabled = true, Href = "#", Text = "Hewi@Laethys" }) .SetTitle(new Title { Text = "Healing per second" }) .SetXAxis( new XAxis { Categories = secondsArray, MinTickInterval = (EncounterLength.TotalSeconds / 10), Title = new XAxisTitle() { Text = "Seconds Elapsed" } }) .SetYAxis(new[] { new YAxis { Title = new YAxisTitle { Text = "Healing" }, Min = 0, } }) .SetPlotOptions(new PlotOptions { Line = new PlotOptionsLine { EnableMouseTracking = true, Marker = new PlotOptionsLineMarker { Enabled = false } } }) .SetSeries(new[] { new Series { Name = "Average Healing Per Second", Data = new Data(aHpsArray) }, new Series { Name = "Total Healing", Data = new Data(tHpsArray), PlotOptionsLine = new PlotOptionsLine { Visible = false } }, new Series { Name = "Effective Healing", Data = new Data(eHpsArray) } }) .SetExporting(new Exporting { Enabled = false }); #endregion #region DamageOutgoingAbilityBreakdownChart DamageOutgoingAbilityBreakdownChart = new Highcharts(string.Format("encounter{0}damageoutgoingbreakdown", EncounterId)) .InitChart(new Chart { PlotShadow = false }) .SetTitle(new Title { Text = "Outgoing Damage Breakdown" }) .SetTooltip(new Tooltip { Formatter = "function() { return '<b>'+ this.point.name +'</b>: '+ Highcharts.numberFormat(this.percentage, 2) +' %'; }" }) .SetPlotOptions(new PlotOptions { Pie = new PlotOptionsPie { AllowPointSelect = true, Cursor = Cursors.Pointer, Size = new PercentageOrPixel(85, true) } }) .SetCredits(new Credits() { Enabled = true, Href = "#", Text = "Hewi@Laethys" }) .SetSeries(new Series { Type = ChartTypes.Pie, Data = new Data(DamageOutgoingAbilityBreakdown.Abilities.OrderBy(a => a.TotalDamage).ToList().ToPieChartSeries()) }); #endregion #region DamageOutgoingTypeBreakdownChart DamageOutgoingTypeBreakdownChart = new Highcharts(string.Format("encounter{0}damageoutgoingtypes", EncounterId)) .InitChart(new Chart { PlotShadow = false }) .SetTitle(new Title { Text = "Outgoing Damage Types" }) .SetTooltip(new Tooltip { Formatter = "function() { return '<b>'+ this.point.name +'</b>: '+ Highcharts.numberFormat(this.percentage, 2) +' %'; }" }) .SetPlotOptions(new PlotOptions { Pie = new PlotOptionsPie { AllowPointSelect = true, Cursor = Cursors.Pointer, Size = new PercentageOrPixel(85, true) } }) .SetCredits(new Credits() { Enabled = true, Href = "#", Text = "Hewi@Laethys" }) .SetSeries(DamageOutgoingAbilityBreakdown.Abilities.ToList().ToFullPieChartSeries()); #endregion #region DamageIncomingAbilityBreakdownChart DamageIncomingAbilityBreakdownChart = new Highcharts(string.Format("encounter{0}damageincomingbreakdown", EncounterId)) .InitChart(new Chart { PlotShadow = false }) .SetTitle(new Title { Text = "Incoming Damage Breakdown" }) .SetTooltip(new Tooltip { Formatter = "function() { return '<b>'+ this.point.name +'</b>: '+ Highcharts.numberFormat(this.percentage, 2) +' %'; }" }) .SetPlotOptions(new PlotOptions { Pie = new PlotOptionsPie { AllowPointSelect = true, Cursor = Cursors.Pointer, Size = new PercentageOrPixel(85, true) } }) .SetCredits(new Credits() { Enabled = true, Href = "#", Text = "Hewi@Laethys" }) .SetSeries(new Series { Type = ChartTypes.Pie, Data = new Data(DamageIncomingAbilityBreakdown.Abilities.OrderBy(a => a.TotalDamage).ToList().ToPieChartSeries()) }); #endregion #region DamageIncomingTypeBreakdownChart DamageIncomingTypeBreakdownChart = new Highcharts(string.Format("encounter{0}damageincomingtypes", EncounterId)) .InitChart(new Chart { PlotShadow = false }) .SetTitle(new Title { Text = "Incoming Damage Types" }) .SetTooltip(new Tooltip { Formatter = "function() { return '<b>'+ this.point.name +'</b>: '+ Highcharts.numberFormat(this.percentage, 2) +' %'; }" }) .SetPlotOptions(new PlotOptions { Pie = new PlotOptionsPie { AllowPointSelect = true, Cursor = Cursors.Pointer, Size = new PercentageOrPixel(85, true) } }) .SetCredits(new Credits() { Enabled = true, Href = "#", Text = "Hewi@Laethys" }) .SetSeries(DamageIncomingAbilityBreakdown.Abilities.ToList().ToFullPieChartSeries()); #endregion #region HealingOutgoingAbilityBreakdownChart HealingOutgoingAbilityBreakdownChart = new Highcharts(string.Format("encounter{0}Healingoutgoingbreakdown", EncounterId)) .InitChart(new Chart { PlotShadow = false }) .SetTitle(new Title { Text = "Outgoing Healing Breakdown" }) .SetTooltip(new Tooltip { Formatter = "function() { return '<b>'+ this.point.name +'</b>: '+ Highcharts.numberFormat(this.percentage, 2) +' %'; }" }) .SetPlotOptions(new PlotOptions { Pie = new PlotOptionsPie { AllowPointSelect = true, Cursor = Cursors.Pointer, Size = new PercentageOrPixel(85, true) } }) .SetCredits(new Credits() { Enabled = true, Href = "#", Text = "Hewi@Laethys" }) .SetSeries(new Series { Type = ChartTypes.Pie, Data = new Data(HealingOutgoingAbilityBreakdown.Abilities.OrderBy(a => a.TotalEffectiveHealing).ToList().ToPieChartSeries(true)) }); #endregion #region HealingOutgoingTypeBreakdownChart HealingOutgoingTypeBreakdownChart = new Highcharts(string.Format("encounter{0}Healingoutgoingtypes", EncounterId)) .InitChart(new Chart { PlotShadow = false }) .SetTitle(new Title { Text = "Outgoing Healing Types" }) .SetTooltip(new Tooltip { Formatter = "function() { return '<b>'+ this.point.name +'</b>: '+ Highcharts.numberFormat(this.percentage, 2) +' %'; }" }) .SetPlotOptions(new PlotOptions { Pie = new PlotOptionsPie { AllowPointSelect = true, Cursor = Cursors.Pointer, Size = new PercentageOrPixel(85, true) } }) .SetCredits(new Credits() { Enabled = true, Href = "#", Text = "Hewi@Laethys" }) .SetSeries(HealingOutgoingTypeBreakdown.Abilities.ToList().HealingToFullPieChartSeries()); #endregion #region HealingIncomingAbilityBreakdownChart HealingIncomingAbilityBreakdownChart = new Highcharts(string.Format("encounter{0}Healingincomingbreakdown", EncounterId)) .InitChart(new Chart { PlotShadow = false }) .SetTitle(new Title { Text = "Incoming Healing Breakdown" }) .SetTooltip(new Tooltip { Formatter = "function() { return '<b>'+ this.point.name +'</b>: '+ Highcharts.numberFormat(this.percentage, 2) +' %'; }" }) .SetPlotOptions(new PlotOptions { Pie = new PlotOptionsPie { AllowPointSelect = true, Cursor = Cursors.Pointer, Size = new PercentageOrPixel(85, true) } }) .SetCredits(new Credits() { Enabled = true, Href = "#", Text = "Hewi@Laethys" }) .SetSeries(new Series { Type = ChartTypes.Pie, Data = new Data(HealingIncomingAbilityBreakdown.Abilities.OrderBy(a => a.TotalEffectiveHealing).ToList().ToPieChartSeries(true)) }); #endregion #region HealingIncomingSourceBreakdownChart HealingIncomingSourceBreakdownChart = new Highcharts(string.Format("encounter{0}Healingsources", EncounterId)) .InitChart(new Chart { PlotShadow = false }) .SetTitle(new Title { Text = "Incoming Healing Sources" }) .SetTooltip(new Tooltip { Formatter = "function() { return '<b>'+ this.point.name +'</b>: '+ Highcharts.numberFormat(this.percentage, 2) +' %'; }" }) .SetPlotOptions(new PlotOptions { Pie = new PlotOptionsPie { AllowPointSelect = true, Cursor = Cursors.Pointer, Size = new PercentageOrPixel(85, true) } }) .SetCredits(new Credits() { Enabled = true, Href = "#", Text = "Hewi@Laethys" }) .SetSeries(healSourceBreakdown.ToFullPieChartSeries()); #endregion #endregion }
public void UpdateDetailedStats() { if (!DamageRecords.Any()) { return; } #region Loop through abilities for players / pets foreach (var dmgGroup in DamageRecords.Where(e => e.SourcePlayer != null || e.SourcePetName != null).GroupBy(d => d.Ability.Name)) { bool isPetAbility = !string.IsNullOrEmpty(dmgGroup.First().SourcePetName); long critDamage = 0; long hitDamage = 0; int crits = dmgGroup.Count(d => d.CriticalHit); int swings = dmgGroup.Count(); int hits = swings - crits; decimal critrate = crits > 0 ? (((decimal)crits / (decimal)swings) * 100) : 0; Ability ability = new Ability { Name = isPetAbility ? string.Format("{0} (Pet)", dmgGroup.Key) : dmgGroup.Key, DamageType = dmgGroup.First().Ability.DamageType, Statistics = new AbilityStatistics { Swings = swings, Hits = hits, Crits = crits, CritRate = critrate }, IconPath = dmgGroup.First().Ability.Icon }; foreach (var dmg in dmgGroup) { if (dmg.SourcePlayerId != null && dmg.TargetPlayerId != null) { // Ignore this - player damage to other players. //TODO: catch this and add to a player damage to other players group continue; } if (dmg.CriticalHit) { #region Min Crit if (ability.Statistics.MinCrit == 0 || dmg.TotalDamage < ability.Statistics.MinCrit) { ability.Statistics.MinCrit = dmg.TotalDamage; } #endregion #region Max Crit if (ability.Statistics.MaxCrit == 0 || dmg.TotalDamage > ability.Statistics.MaxCrit) { ability.Statistics.MaxCrit = dmg.TotalDamage; } #endregion critDamage += dmg.TotalDamage; } else { #region Min Hit if (ability.Statistics.MinHit == 0 || dmg.TotalDamage < ability.Statistics.MinHit) { ability.Statistics.MinHit = dmg.TotalDamage; } #endregion #region Max Hit if (ability.Statistics.MaxHit == 0 || dmg.TotalDamage > ability.Statistics.MinHit) { ability.Statistics.MaxHit = dmg.TotalDamage; } #endregion hitDamage += dmg.TotalDamage; } } #region AverageHit ability.Statistics.AverageHit = hits > 0 ? hitDamage / hits : 0; #endregion #region AverageCrit ability.Statistics.AverageCrit = crits > 0 ? critDamage / crits : 0; #endregion ability.TotalDamage = critDamage + hitDamage; ability.DamagePerSecond = EncounterLength.TotalSeconds > 0 ? ability.TotalDamage / (long)EncounterLength.TotalSeconds : 0; PlayerAbilityBreakdown.Abilities.Add(ability); } #endregion #region Loop through NPC Abilities foreach (var dmgGroup in DamageRecords.Where(e => e.SourceNpcName != null).GroupBy(d => d.Ability.Name)) { long critDamage = 0; long hitDamage = 0; int crits = dmgGroup.Count(d => d.CriticalHit); int swings = dmgGroup.Count(); int hits = swings - crits; decimal critrate = crits > 0 ? (((decimal)crits / (decimal)swings) * 100) : 0; Ability ability = new Ability { Name = dmgGroup.Key, DamageType = dmgGroup.First().Ability.DamageType, Statistics = new AbilityStatistics { Swings = swings, Hits = hits, Crits = crits, CritRate = critrate } }; foreach (var dmg in dmgGroup) { if (dmg.CriticalHit) { #region Min Crit if (ability.Statistics.MinCrit == 0 || dmg.TotalDamage < ability.Statistics.MinCrit) { ability.Statistics.MinCrit = dmg.TotalDamage; } #endregion #region Max Crit if (ability.Statistics.MaxCrit == 0 || dmg.TotalDamage > ability.Statistics.MaxCrit) { ability.Statistics.MaxCrit = dmg.TotalDamage; } #endregion critDamage += dmg.TotalDamage; } else { #region Min Hit if (ability.Statistics.MinHit == 0 || dmg.TotalDamage < ability.Statistics.MinHit) { ability.Statistics.MinHit = dmg.TotalDamage; } #endregion #region Max Hit if (ability.Statistics.MaxHit == 0 || dmg.TotalDamage > ability.Statistics.MinHit) { ability.Statistics.MaxHit = dmg.TotalDamage; } #endregion hitDamage += dmg.TotalDamage; } } #region AverageHit ability.Statistics.AverageHit = hits > 0 ? hitDamage / hits : 0; #endregion #region AverageCrit ability.Statistics.AverageCrit = crits > 0 ? critDamage / crits : 0; #endregion ability.TotalDamage = critDamage + hitDamage; ability.DamagePerSecond = EncounterLength.TotalSeconds > 0 ? ability.TotalDamage / (long)EncounterLength.TotalSeconds : 0; ability.Source = dmgGroup.First().SourceNpcName; NpcAbilityBreakdown.Abilities.Add(ability); } #endregion #region Player and NPC ability breakdown percentages long totalDamage = PlayerAbilityBreakdown.Abilities.Sum(a => a.TotalDamage); foreach (var ability in PlayerAbilityBreakdown.Abilities) { ability.BreakdownPercentage = ability.TotalDamage > 0 ? ((decimal)ability.TotalDamage / (decimal)totalDamage) * 100 : 0; } long totalNpcDamage = NpcAbilityBreakdown.Abilities.Sum(a => a.TotalDamage); foreach (var ability in NpcAbilityBreakdown.Abilities) { ability.BreakdownPercentage = ability.TotalDamage > 0 ? ((decimal)ability.TotalDamage / (decimal)totalNpcDamage) * 100 : 0; } #endregion TopPlayerDamageDoneRecords = new List <TopDamageDone>(); foreach (var dmg in DamageRecords.Where(d => d.SourcePlayerId != null).OrderByDescending(d => d.TotalDamage).Take(5)) { TopPlayerDamageDoneRecords.Add(new TopDamageDone() { AbilityName = dmg.Ability.Name, AttackerName = dmg.SourcePlayer.Name, DamageType = dmg.Ability.DamageType, TargetName = dmg.TargetNpcName, IconPath = dmg.Ability.Icon, Value = dmg.TotalDamage }); } TopNpcDamageDoneRecords = new List <TopDamageDone>(); foreach (var dmg in DamageRecords.Where(d => d.SourcePlayerId == null && d.TargetPlayerId != null).OrderByDescending(d => d.EffectiveDamage).Take(5)) { TopNpcDamageDoneRecords.Add(new TopDamageDone() { AbilityName = dmg.Ability.Name, AttackerName = dmg.SourceNpcName, DamageType = dmg.Ability.DamageType, TargetName = dmg.TargetPlayer.Name, IconPath = dmg.Ability.Icon, Value = dmg.EffectiveDamage }); } }