private static ExcelHyperLink CreateUserSheet(ExcelWorkbook wb, Members user, ExtendedStats exdata, ExcelWorksheet details) { var ws = wb.Worksheets.Add($"{user.playerServer}_{user.playerName}"); var rgc = new RaceGenderClass("Common", "Common", user.playerClass); ws.DefaultRowHeight = 30; ws.Cells.Style.Font.Size = 14; ws.Cells.Style.Font.Name = "Arial"; AddImage(ws, 1, 1, ClassIcons.Instance.GetBitmap((PlayerClass) Enum.Parse(typeof(PlayerClass), user.playerClass))); ws.Cells[1, 2].Value = $"{user.playerServer}: {user.playerName}"; ws.Cells[1, 2, 1, 11].Merge = true; ws.Cells[1, 2, 1, 11].Style.Font.Bold = true; ws.Cells[2, 2].Value = LP.SkillName; ws.Cells[2, 3].Value = LP.DamagePercent; ws.Cells[2, 4].Value = LP.Damage; ws.Cells[2, 5].Value = LP.CritPercent; ws.Cells[2, 6].Value = LP.Hits; ws.Cells[2, 7].Value = LP.Crits; ws.Cells[2, 8].Value = LP.MaxCrit; ws.Cells[2, 9].Value = LP.MinCrit; ws.Cells[2, 10].Value = LP.AverageCrit; ws.Cells[2, 11].Value = LP.AvgWhite; var i = 2; foreach (var stat in exdata.PlayerSkillsAggregated[user.playerServer+"/"+user.playerName].OrderByDescending(x => x.Amount())) { i++; ws.Cells[i, 1].Value = i - 2; foreach (var skillInfo in stat.Skills) { if (string.IsNullOrEmpty(skillInfo.Key.IconName)) continue; AddImage(ws, i, 1, BTD.Icons.GetBitmap(skillInfo.Key.IconName)); break; } ws.Cells[i, 2].Value = stat.Name; ws.Cells[i, 3].Value = stat.DamagePercent() / 100; ws.Cells[i, 3].Style.Numberformat.Format = "0.0%"; ws.Cells[i, 4].Value = stat.Amount(); ws.Cells[i, 4].Style.Numberformat.Format = @"#,#0,\k"; ws.Cells[i, 5].Value = stat.CritRate() / 100; ws.Cells[i, 5].Style.Numberformat.Format = "0.0%"; ws.Cells[i, 6].Value = stat.Hits(); ws.Cells[i, 7].Value = stat.Crits(); ws.Cells[i, 8].Value = stat.BiggestCrit(); ws.Cells[i, 8].Style.Numberformat.Format = @"#,#0,\k"; ws.Cells[i, 9].Value = stat.LowestCrit(); ws.Cells[i, 9].Style.Numberformat.Format = @"#,#0,\k"; ws.Cells[i, 10].Value = stat.AvgCrit(); ws.Cells[i, 10].Style.Numberformat.Format = @"#,#0,\k"; ws.Cells[i, 11].Value = stat.AvgWhite(); ws.Cells[i, 11].Style.Numberformat.Format = @"#,#0,\k"; } var border = ws.Cells[1, 1, i, 11].Style.Border; border.Bottom.Style = border.Top.Style = border.Left.Style = border.Right.Style = ExcelBorderStyle.Thick; ws.Cells[2, 1, i, 11].AutoFilter = true; var j = i + 3; ws.Cells[j, 2].Value = LP.Name; ws.Cells[j, 2, j, 10].Merge = true; ws.Cells[j, 11].Value = "%"; ws.Cells[j, 2, j, 11].Style.Font.Bold = true; foreach (var buf in user.buffUptime) { j++; var hotdot = BTD.HotDotDatabase.Get(int.Parse(buf.Key)); ws.Cells[j, 1].Value = j - i - 3; AddImage(ws, j, 1, BTD.Icons.GetBitmap(hotdot.IconName)); ws.Cells[j, 2].Value = hotdot.Name; if (!string.IsNullOrEmpty(hotdot.Tooltip)) ws.Cells[j, 2].AddComment("" + hotdot.Tooltip, "info"); ws.Cells[j, 2, j, 10].Merge = true; ws.Cells[j, 11].Value = double.Parse(buf.Value) / 100; ws.Cells[j, 11].Style.Numberformat.Format = "0%"; if (!string.IsNullOrEmpty(hotdot.ItemName)) ws.Cells[j, 10].AddComment("" + hotdot.ItemName, "info"); } border = ws.Cells[i + 3, 1, j, 11].Style.Border; border.Bottom.Style = border.Top.Style = border.Left.Style = border.Right.Style = ExcelBorderStyle.Thick; AddCharts(ws, exdata, details, j); ws.Column(1).Width = 5.6; ws.Column(2).AutoFit(); ws.Column(3).AutoFit(); ws.Column(4).AutoFit(); ws.Column(5).AutoFit(); ws.Column(6).AutoFit(); ws.Column(7).AutoFit(); ws.Column(8).AutoFit(); ws.Column(9).AutoFit(); ws.Column(10).AutoFit(); ws.Column(11).AutoFit(); ws.Column(2).Width = GetTrueColumnWidth(ws.Column(2).Width * scale); ws.Column(3).Width = GetTrueColumnWidth(ws.Column(3).Width * scale); ws.Column(4).Width = GetTrueColumnWidth(ws.Column(4).Width * scale); ws.Column(5).Width = GetTrueColumnWidth(ws.Column(5).Width * scale); ws.Column(6).Width = GetTrueColumnWidth(ws.Column(6).Width * scale); ws.Column(7).Width = GetTrueColumnWidth(ws.Column(7).Width * scale); ws.Column(8).Width = GetTrueColumnWidth(ws.Column(8).Width * scale); ws.Column(9).Width = GetTrueColumnWidth(ws.Column(9).Width * scale); ws.Column(10).Width = GetTrueColumnWidth(ws.Column(10).Width * scale); ws.Column(11).Width = GetTrueColumnWidth(ws.Column(11).Width * scale); ws.Cells[1, 1, j, 11].Style.VerticalAlignment = ExcelVerticalAlignment.Center; ws.Cells[1, 1, j, 11].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; ws.PrinterSettings.FitToPage = true; // I don't know why, but sometimes column height setting is lost. for (var x = 1; x <= j; ++x) { ws.Row(x).CustomHeight = true; ws.Row(x).Height = 30; } // If sheet name contains space character, name should be enclosed in single quotes. return new ExcelHyperLink($"'{user.playerServer}_{user.playerName}'!A1", $"{user.playerServer}: {user.playerName}"); }
private static ExcelWorksheet CreateDetailsSheet(ExcelPackage package, ExtendedStats exdata) { var timeFormat = (exdata.LastTick - exdata.FirstTick)/TimeSpan.TicksPerSecond < 40 ? "ss" : "mm:ss"; var details = package.Workbook.Worksheets.Add("Details"); details.Cells[1, 1].Value = "Boss"; details.Cells[2, 1].Value = "Seconds"; details.Cells[2, 2].Value = "Time"; details.Column(2).Style.Numberformat.Format = timeFormat; details.Cells[2, 3].Value = "BuffNum"; details.Cells[2, 4].Value = "Start"; details.Column(4).Style.Numberformat.Format = timeFormat; details.Cells[2, 5].Value = "Duration"; details.Column(5).Style.Numberformat.Format = timeFormat; details.Cells[2, 6].Value = "BuffName"; details.Cells[2, 7].Value = "Axis"; details.Cells[2, 8].Value = "SMADPS"; details.Column(8).Style.Numberformat.Format = @"#,#0\k\/\s"; details.Cells[2, 9].Value = "AvgDPS"; details.Column(9).Style.Numberformat.Format = @"#,#0\k\/\s"; details.Cells[2, 10].Value = "BossHP"; details.Column(10).Style.Numberformat.Format = "0%"; details.Cells[1, 1, 1, 10].Merge = true; for (int t = 0; t <= exdata.LastTick / TimeSpan.TicksPerSecond - exdata.FirstTick / TimeSpan.TicksPerSecond; t++) { details.Cells[t + 3, 1].Value = t; details.Cells[t + 3, 2].Value = (double) t/86400; } var buffnum = 0; var j = 0; foreach (var buffPair in exdata.Debuffs) { if (buffPair.Value.Count() == 0) continue; buffnum++; details.Cells[2 + buffnum, 6].Value = buffPair.Key.Name; details.Cells[2 + buffnum, 7].Value = 0; foreach (var buff in buffPair.Value.AllDurations()) { j++; details.Cells[2 + j, 3].Value = buffnum; details.Cells[2 + j, 4].Value = (double) (buff.Begin - exdata.FirstTick)/TimeSpan.TicksPerDay; details.Cells[2 + j, 5].Value = (double) (buff.End - buff.Begin)/TimeSpan.TicksPerDay; } } long dealtDamage = 0; var totalDamage = exdata.PlayerSkills.Sum( x => x.Value.Where(time => time.Time >= exdata.FirstTick && time.Time <= exdata.LastTick) .Sum(y => y.Amount)); j = 0; var xCMA = BasicTeraData.Instance.WindowData.ExcelCMADPSSeconds<=0 ? 1: BasicTeraData.Instance.WindowData.ExcelCMADPSSeconds; var last=new Queue<long>(); for (var curTick = exdata.FirstTick; curTick <= exdata.LastTick; curTick += TimeSpan.TicksPerSecond) { j++; var damage = exdata.PlayerSkills.Sum( x => x.Value.Where(time => time.Time >= curTick && time.Time <= curTick + TimeSpan.TicksPerSecond) .Sum(skill => skill.Amount)); dealtDamage += damage; last.Enqueue(damage); if (last.Count> xCMA) last.Dequeue(); if (curTick >= exdata.LastTick - TimeSpan.TicksPerSecond) { if (j > xCMA) details.Cells[j + 2 - xCMA / 2, 8].Value = last.ToArray().Sum(x => x)/(xCMA>1?xCMA-1+TimeSpan.TicksPerSecond/(exdata.LastTick-curTick):1)/1000; details.Cells[j + 2, 9].Value = dealtDamage*TimeSpan.TicksPerSecond/(exdata.LastTick - exdata.FirstTick)/1000; } else { if (j >= xCMA) details.Cells[j + 2 - xCMA / 2, 8].Value = last.ToArray().Sum(x => x) / xCMA / 1000; if (j != 1) details.Cells[j + 2, 9].Value = dealtDamage/(j - 1)/1000; } details.Cells[j + 2, 10].Value = totalDamage == 0 ? 0 : (double)(totalDamage - dealtDamage) / totalDamage; } var i = 4; foreach (var user in exdata.PlayerBuffs) { i += 7; details.Cells[1, i].Value = user.Key; details.Cells[2, i].Value = "BuffNum"; details.Cells[2, i + 1].Value = "Start"; details.Column(i + 1).Style.Numberformat.Format = timeFormat; details.Cells[2, i + 2].Value = "Duration"; details.Column(i + 2).Style.Numberformat.Format = timeFormat; details.Cells[2, i + 3].Value = "BuffName"; details.Cells[2, i + 4].Value = "Axis"; details.Cells[2, i + 5].Value = "SMADPS"; details.Column(i + 5).Style.Numberformat.Format = @"#,#0\k\/\s"; details.Cells[2, i + 6].Value = "AvgDPS"; details.Column(i + 6).Style.Numberformat.Format = @"#,#0\k\/\s"; details.Cells[1, i, 1, i + 6].Merge = true; buffnum = 0; j = 0; foreach (var buffPair in user.Value.Times) { if (buffPair.Value.Count() == 0) continue; buffnum++; details.Cells[2 + buffnum, i + 3].Value = buffPair.Key.Name; details.Cells[2 + buffnum, i + 4].Value = 0; foreach (var buff in buffPair.Value.AllDurations()) { j++; details.Cells[2 + j, i].Value = buffnum; details.Cells[2 + j, i + 1].Value = (double) (buff.Begin - exdata.FirstTick)/ TimeSpan.TicksPerDay; details.Cells[2 + j, i + 2].Value = (double) (buff.End - buff.Begin)/TimeSpan.TicksPerDay; } } if (user.Value.Death.Count() > 0) { buffnum++; details.Cells[2 + buffnum, i + 3].Value = LP.Deaths; details.Cells[2 + buffnum, i + 4].Value = 0; foreach (var buff in user.Value.Death.AllDurations()) { j++; details.Cells[2 + j, i].Value = buffnum; details.Cells[2 + j, i + 1].Value = (double) (buff.Begin - exdata.FirstTick)/ TimeSpan.TicksPerDay; details.Cells[2 + j, i + 2].Value = (double) (buff.End - buff.Begin)/TimeSpan.TicksPerDay; } } if (user.Value.Aggro(exdata.Entity).Count() > 0) { buffnum++; details.Cells[2 + buffnum, i + 3].Value = LP.Aggro; details.Cells[2 + buffnum, i + 4].Value = 0; foreach (var buff in user.Value.Aggro(exdata.Entity).AllDurations()) { j++; details.Cells[2 + j, i].Value = buffnum; details.Cells[2 + j, i + 1].Value = (double) (buff.Begin - exdata.FirstTick)/ TimeSpan.TicksPerDay; details.Cells[2 + j, i + 2].Value = (double) (buff.End - buff.Begin)/TimeSpan.TicksPerDay; } } dealtDamage = 0; j = 0; last = new Queue<long>(); for (var curTick = exdata.FirstTick; curTick <= exdata.LastTick; curTick += TimeSpan.TicksPerSecond) { j++; var damage = exdata.PlayerSkills.Where(all => all.Key == user.Key).Sum( x => x.Value.Where(time => time.Time >= curTick && time.Time <= curTick + TimeSpan.TicksPerSecond).Sum(skill => skill.Amount)); dealtDamage += damage; last.Enqueue(damage); if (last.Count > xCMA) last.Dequeue(); if (curTick >= exdata.LastTick - TimeSpan.TicksPerSecond) { if (j>xCMA) details.Cells[j + 2 - xCMA / 2, i + 5].Value = last.ToArray().Sum(x=>x)/(xCMA>1?xCMA-1+TimeSpan.TicksPerSecond/(exdata.LastTick-curTick):1)/1000; details.Cells[j + 2, i + 6].Value = dealtDamage * TimeSpan.TicksPerSecond / (exdata.LastTick - exdata.FirstTick) / 1000; } else { if (j >= xCMA) details.Cells[j + 2 - xCMA /2, i + 5].Value = last.ToArray().Sum(x => x) / xCMA / 1000; if (j != 1) details.Cells[j + 2, i + 6].Value = dealtDamage/(j - 1) / 1000; } } } return details; }
public static void ExcelSave(ExtendedStats exdata, string userName="") { lock (savelock) //can't save 2 excel files at one time { if (!BTD.WindowData.Excel) return; var data = exdata.BaseStats; var Boss = exdata.Entity.Info; scale= 96/Graphics.FromImage(new Bitmap(1, 1)).DpiX;//needed if user have not standart DPI setting in control panel, workaround EPPlus autofit bug /* Select save directory */ string dir; if (BTD.WindowData.DateInExcelPath) { dir = $"{BTD.WindowData.ExcelSaveDirectory}/{Boss.Area.Replace(":", "-")}/{DateTime.Now.ToString("yyyy-MM-dd")}"; } else { dir = $"{BTD.WindowData.ExcelSaveDirectory}/{Boss.Area.Replace(":", "-")}"; } /* Test if you have access to the user choice directory, if not, switch back to the default save directory */ try { Directory.CreateDirectory(dir); } catch { if (BTD.WindowData.DateInExcelPath) { dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), $"ShinraMeter/{Boss.Area.Replace(":", "-")}/{DateTime.Now.ToString("yyyy-MM-dd")}"); } else { dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), $"ShinraMeter/{Boss.Area.Replace(":", "-")}"); } Directory.CreateDirectory(dir); } var fname = ""; if (BTD.WindowData.DateInExcelPath) { fname = Path.Combine(dir, $"{Boss.Name.Replace(":", "-")} {DateTime.Now.ToString("HH-mm-ss", CultureInfo.InvariantCulture)} {userName}.xlsx"); } else { fname = Path.Combine(dir, $"{Boss.Name.Replace(":", "-")} {DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture)} {userName}.xlsx"); } var file = new FileInfo(fname); if (file.Exists) return; //the only case this can happen is BAM mobtraining, that's not so interesting statistic to deal with more complex file names. using (var package = new ExcelPackage(file)) { var details = CreateDetailsSheet(package, exdata); var ws = package.Workbook.Worksheets.Add(LP.Boss); var linkStyle = package.Workbook.Styles.CreateNamedStyle("HyperLink"); //This one is language dependent linkStyle.Style.Font.UnderLine = true; linkStyle.Style.Font.Color.SetColor(Color.Blue); ws.DefaultRowHeight = 30; ws.Cells.Style.Font.Size = 14; ws.Cells.Style.Font.Name = "Arial"; ws.Cells[1, 1].Value = $"{Boss.Area}: {Boss.Name} {TimeSpan.FromSeconds(double.Parse(data.fightDuration)).ToString(@"mm\:ss")}"; ws.Cells[1, 1, 1, 9].Merge = true; ws.Cells[1, 1, 1, 11].Style.Font.Bold = true; ws.Cells[1, 10].Value = long.Parse(data.partyDps); ws.Cells[1, 10].Style.Numberformat.Format = @"#,#00,\k\/\s"; ws.Cells[2, 1].Value = "Ic"; ws.Cells[2, 1].Style.Font.Color.SetColor(Color.Transparent); ws.Cells[2, 2].Value = LP.Name; ws.Cells[2, 3].Value = LP.Deaths; ws.Cells[2, 4].Value = LP.Death_Time; ws.Cells[2, 5].Value = LP.DamagePercent; ws.Cells[2, 6].Value = LP.CritPercent; ws.Cells[2, 7].Value = LP.HealCritPercent; ws.Cells[2, 8].Value = LP.HitsTaken; ws.Cells[2, 9].Value = LP.DamgeTaken; ws.Cells[2, 10].Value = LP.Dps; ws.Cells[2, 11].Value = LP.Damage; var i = 2; foreach (var user in data.members.OrderByDescending(x => long.Parse(x.playerTotalDamage))) { i++; ws.Cells[i, 1].Value = i - 2; AddImage(ws, i, 1, ClassIcons.Instance.GetBitmap( (PlayerClass) Enum.Parse(typeof(PlayerClass), user.playerClass))); ws.Cells[i, 2].Value = $"{user.playerServer}: {user.playerName}"; ws.Cells[i, 2].Hyperlink = CreateUserSheet(package.Workbook, user, exdata, details); ws.Cells[i, 3].Value = long.Parse(user.playerDeaths); ws.Cells[i, 4].Value = long.Parse(user.playerDeathDuration); ws.Cells[i, 4].Style.Numberformat.Format = @"0\s"; ws.Cells[i, 5].Value = double.Parse(user.playerTotalDamagePercentage) / 100; ws.Cells[i, 5].Style.Numberformat.Format = "0.0%"; ws.Cells[i, 6].Value = double.Parse(user.playerAverageCritRate) / 100; ws.Cells[i, 6].Style.Numberformat.Format = "0.0%"; ws.Cells[i, 7].Value = string.IsNullOrEmpty(user.healCrit) ? 0 : double.Parse(user.healCrit) / 100; ws.Cells[i, 7].Style.Numberformat.Format = "0.0%"; ws.Cells[i, 8].Value = exdata.PlayerReceived[user.playerName].Item1; ws.Cells[i, 9].Value = exdata.PlayerReceived[user.playerName].Item2; ws.Cells[i, 9].Style.Numberformat.Format = @"#,#0,\k"; ws.Cells[i, 10].Value = long.Parse(user.playerDps); ws.Cells[i, 10].Style.Numberformat.Format = @"#,#0,\k\/\s"; ws.Cells[i, 11].Value = long.Parse(user.playerTotalDamage); ws.Cells[i, 11].Style.Numberformat.Format = @"#,#0,\k"; } ws.Cells[1, 11].Formula = $"SUM(K3:K{i})"; ws.Cells[1, 11].Style.Numberformat.Format = @"#,#0,\k"; var border = ws.Cells[1, 1, i, 11].Style.Border; border.Bottom.Style = border.Top.Style = border.Left.Style = border.Right.Style = ExcelBorderStyle.Thick; ws.Cells[2, 1, i, 11].AutoFilter = true; var j = i + 3; ws.Cells[j, 1].Value = "Ic"; ws.Cells[j, 1].Style.Font.Color.SetColor(Color.Transparent); ws.Cells[j, 2].Value = LP.Name; ws.Cells[j, 2, j, 10].Merge = true; ws.Cells[j, 11].Value = "%"; ws.Cells[j, 2, j, 11].Style.Font.Bold = true; foreach (var buf in data.debuffUptime) { j++; var hotdot = BTD.HotDotDatabase.Get(int.Parse(buf.Key)); ws.Cells[j, 1].Value = j - i - 3; AddImage(ws, j, 1, BTD.Icons.GetBitmap(hotdot.IconName)); ws.Cells[j, 2].Value = hotdot.Name; if (!string.IsNullOrEmpty(hotdot.Tooltip)) ws.Cells[j, 2].AddComment("" + hotdot.Tooltip, "info"); ws.Cells[j, 2, j, 10].Merge = true; ws.Cells[j, 11].Value = double.Parse(buf.Value) / 100; ws.Cells[j, 11].Style.Numberformat.Format = "0%"; } border = ws.Cells[i + 3, 1, j, 11].Style.Border; border.Bottom.Style = border.Top.Style = border.Left.Style = border.Right.Style = ExcelBorderStyle.Thick; AddCharts(ws, exdata, details, j); ws.Column(1).Width = 5.6; ws.Column(2).AutoFit(); ws.Column(3).AutoFit(); ws.Column(4).AutoFit(); ws.Column(5).AutoFit(); ws.Column(6).AutoFit(); ws.Column(7).AutoFit(); ws.Column(8).AutoFit(); ws.Column(9).AutoFit(); ws.Column(10).AutoFit(); ws.Column(11).Width = 20; ws.Column(2).Width = GetTrueColumnWidth(ws.Column(2).Width * scale); ws.Column(3).Width = GetTrueColumnWidth(ws.Column(3).Width * scale); ws.Column(4).Width = GetTrueColumnWidth(ws.Column(4).Width * scale); ws.Column(5).Width = GetTrueColumnWidth(ws.Column(5).Width * scale); ws.Column(6).Width = GetTrueColumnWidth(ws.Column(6).Width * scale); ws.Column(7).Width = GetTrueColumnWidth(ws.Column(7).Width * scale); ws.Column(8).Width = GetTrueColumnWidth(ws.Column(8).Width * scale); ws.Column(9).Width = GetTrueColumnWidth(ws.Column(9).Width * scale); ws.Column(10).Width = GetTrueColumnWidth(ws.Column(10).Width * scale); ws.Cells[1, 1, j, 11].Style.VerticalAlignment = ExcelVerticalAlignment.Center; ws.Cells[1, 1, j, 11].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; ws.PrinterSettings.FitToPage = true; // I don't know why, but sometimes column height setting is lost. for (var x = 1; x <= j; ++x) { ws.Row(x).CustomHeight = true; ws.Row(x).Height = 30; } ws.View.TabSelected = true; details.Hidden = eWorkSheetHidden.Hidden; package.Workbook.Properties.Title = Boss.Name; package.Workbook.Properties.Author = "ShinraMeter " + UpdateManager.Version; package.Workbook.Properties.Company = "github.com/neowutran & github.com/Gl0"; package.Save(); } } }
private static void AddCharts(ExcelWorksheet ws, ExtendedStats exdata, ExcelWorksheet details, int startrow) { var time = (int) (exdata.LastTick/TimeSpan.TicksPerSecond - exdata.FirstTick/TimeSpan.TicksPerSecond); var offset = exdata.PlayerBuffs.Keys.ToList().IndexOf(ws.Name) + 1; var bossSheet = ws.Name == LP.Boss; if (!bossSheet && offset <= 0) return; //no buff data for user -> no graphs. offset = bossSheet ? 3 : 4 + offset*7; var dps = ws.Drawings.AddChart(ws.Name + LP.Dps, eChartType.Line); dps.SetPosition(startrow + 1, 5, 0, 5); dps.SetSize(1200, 300); dps.Legend.Position = eLegendPosition.Top; if (time > 40) dps.XAxis.MajorUnit = time/20; ExcelChart typeDmg; ExcelChartSerie serieDmg; if (!bossSheet) { typeDmg = dps.PlotArea.ChartTypes[0]; typeDmg.YAxis.Title.Text = BasicTeraData.Instance.WindowData.ExcelCMADPSSeconds + LP.CMADPS; typeDmg.YAxis.Title.Rotation = 90; serieDmg = typeDmg.Series.Add(details.Cells[3, offset + 5, time + 3, offset + 5], details.Cells[3, 2, time + 3, 2]); serieDmg.Header = ws.Name + " "+ BasicTeraData.Instance.WindowData.ExcelCMADPSSeconds + LP.CMADPS; } else { typeDmg = dps.PlotArea.ChartTypes[0]; typeDmg.YAxis.Title.Text = LP.BossHP; typeDmg.YAxis.Title.Rotation = 90; typeDmg.YAxis.MaxValue = 1; serieDmg = typeDmg.Series.Add(details.Cells[3, offset + 7, time + 3, offset + 7], details.Cells[3, 2, time + 3, 2]); serieDmg.Header = LP.BossHP+" %"; } typeDmg.YAxis.MinValue = 0; var typeDps = dps.PlotArea.ChartTypes.Add(eChartType.Line); typeDps.UseSecondaryAxis = true; typeDps.YAxis.Title.Text = LP.AvgDPS; typeDps.YAxis.Title.Rotation = 90; typeDps.YAxis.SourceLinked = false; typeDps.YAxis.Format = @"#,#0\k\/\s"; //not sure why, but it loss sourcelink itself if we show only dps. var serieDps = typeDps.Series.Add(details.Cells[3, offset + 6, time + 3, offset + 6], details.Cells[3, 2, time + 3, 2]); serieDps.Header = ws.Name + " "+LP.AvgDPS; if (bossSheet) { typeDps.YAxis.MaxValue = details.Cells[3, offset + 6, time + 3, offset + 6].Max(x => (long)x.Value); typeDps.YAxis.MinValue = 0; int col = 4; foreach (var user in exdata.PlayerBuffs) { col += 7; //var userDmg = typeDmg.Series.Add(details.Cells[3, col + 5, time + 3, col + 5], details.Cells[3, 2, time + 3, 2]); //userDmg.Header = user.Key + " Dmg"; var userDps = typeDps.Series.Add(details.Cells[3, col + 6, time + 3, col + 6], details.Cells[3, 2, time + 3, 2]); userDps.Header = user.Key + " "+LP.AvgDPS; } } //dps.FixEppPlusBug();// needed only if adding users dmg to main boss chart var numInt = bossSheet ? exdata.Debuffs.Sum(x => x.Value.Count()) - 1 : exdata.PlayerBuffs[ws.Name].Times.Sum(x => x.Value.Count()) + exdata.PlayerBuffs[ws.Name].Death.Count() + exdata.PlayerBuffs[ws.Name].Aggro(exdata.Entity).Count() - 1; var numBuff = bossSheet ? exdata.Debuffs.Count : exdata.PlayerBuffs[ws.Name].Times.Count(x => x.Value.Count() > 0) + (exdata.PlayerBuffs[ws.Name].Death.Count() > 0 ? 1 : 0) + (exdata.PlayerBuffs[ws.Name].Aggro(exdata.Entity).Count() > 0 ? 1 : 0); if (numInt >= 0 && numBuff > 0) { var buff = ws.Drawings.AddChart(ws.Name + LP.Buff, eChartType.BarStacked); var typeBuff = buff.PlotArea.ChartTypes[0]; buff.SetPosition(startrow + 9, 5, 0, 5); buff.SetSize(1200, numBuff*25 + 38); buff.Legend.Remove(); var serieStart = typeBuff.Series.Add(details.Cells[3, offset + 1, numInt + 3, offset + 1], details.Cells[3, offset, numInt + 3, offset]); serieStart.Header = LP.Start; (buff as ExcelBarChart).InvisibleSerie(serieStart); var serieTime = typeBuff.Series.Add(details.Cells[3, offset + 2, numInt + 3, offset + 2], details.Cells[3, offset, numInt + 3, offset]); serieTime.Header = LP.Time; typeBuff.YAxis.MajorUnit = time >= 40 ? (double) (time/20)/86400F : 1F/86400F; typeBuff.YAxis.MinValue = 0F; typeBuff.YAxis.MaxValue = (double) time/86400F; typeBuff.XAxis.Orientation = eAxisOrientation.MaxMin; typeBuff.XAxis.MinorTickMark = eAxisTickMark.None; typeBuff.YAxis.Crosses = eCrosses.Max; var typeAxis = buff.PlotArea.ChartTypes.Add(eChartType.BarStacked); typeAxis.UseSecondaryAxis = true; var serieAxis = typeAxis.Series.Add(details.Cells[3, offset + 4, numBuff - 1 + 3, offset + 4], details.Cells[3, offset + 3, numBuff - 1 + 3, offset + 3]); serieAxis.Header = LP.Name; typeAxis.XAxis.Orientation = eAxisOrientation.MaxMin; typeAxis.XAxis.TickLabelPosition = eTickLabelPosition.NextTo; typeAxis.XAxis.MinorTickMark = eAxisTickMark.None; typeAxis.YAxis.Deleted = true; typeAxis.XAxis.Deleted = false; (buff as ExcelBarChart).FirstAxisDate(numBuff); //buff.FixEppPlusBug(); } }
private static ExtendedStats GenerateStats(NpcEntity entity, AbnormalityStorage abnormals) { if (!entity.Info.Boss) return null; var timedEncounter = false; /* modify timedEncounter depending on teradps.io need */ var entityInfo = Database.Database.Instance.GlobalInformationEntity(entity, timedEncounter); var skills = Database.Database.Instance.GetSkills(entityInfo.BeginTime, entityInfo.EndTime); var playersInfo = timedEncounter ? Database.Database.Instance.PlayerDamageInformation(entityInfo.BeginTime, entityInfo.EndTime) : Database.Database.Instance.PlayerDamageInformation(entity); var heals = Database.Database.Instance.PlayerHealInformation(entityInfo.BeginTime, entityInfo.EndTime); playersInfo.RemoveAll(x => x.Amount == 0); var firstTick = entityInfo.BeginTime; var lastTick = entityInfo.EndTime; var interTick = lastTick - firstTick; var interval = interTick/TimeSpan.TicksPerSecond; if (interval == 0) { return null; } var totaldamage = entityInfo.TotalDamage; var partyDps = TimeSpan.TicksPerSecond*totaldamage/interTick; var teradpsData = new EncounterBase(); var extendedStats = new ExtendedStats(); var _abnormals = abnormals.Clone(entity, firstTick, lastTick); teradpsData.encounterUnixEpoch = new DateTimeOffset(new DateTime(lastTick,DateTimeKind.Utc)).ToUnixTimeSeconds(); extendedStats.Entity = entity; extendedStats.BaseStats = teradpsData; extendedStats.FirstTick = firstTick; extendedStats.LastTick = lastTick; teradpsData.areaId = entity.Info.HuntingZoneId + ""; teradpsData.bossId = entity.Info.TemplateId + ""; teradpsData.fightDuration = interval + ""; teradpsData.partyDps = partyDps + ""; extendedStats.Debuffs = _abnormals.Get(entity); foreach (var debuff in extendedStats.Debuffs.OrderByDescending(x => x.Value.Duration(firstTick, lastTick))) { var percentage = debuff.Value.Duration(firstTick, lastTick)*100/interTick; if (percentage == 0) { continue; } teradpsData.debuffUptime.Add(new KeyValuePair<string, string>( debuff.Key.Id + "", percentage + "" )); } foreach (var user in playersInfo.OrderByDescending(x=>x.Amount)) { var teradpsUser = new Members(); var damage = user.Amount; teradpsUser.playerTotalDamage = damage + ""; if (damage <= 0) { continue; } var buffs = _abnormals.Get(user.Source); teradpsUser.playerClass = user.Source.Class.ToString(); teradpsUser.playerName = user.Source.Name; teradpsUser.playerServer = BasicTeraData.Instance.Servers.GetServerName(user.Source.ServerId); teradpsUser.playerAverageCritRate = Math.Round(user.CritRate, 1) + ""; teradpsUser.healCrit = user.Source.IsHealer ? heals.FirstOrDefault(x => x.Source == user.Source)?.CritRate + "" : null; teradpsUser.playerDps = TimeSpan.TicksPerSecond*damage/interTick + ""; teradpsUser.playerTotalDamagePercentage = user.Amount*100/entityInfo.TotalDamage + ""; extendedStats.PlayerReceived.Add(user.Source.Name, Tuple.Create(skills.HitsReceived(user.Source.User, entity, timedEncounter), skills.DamageReceived(user.Source.User, entity, timedEncounter))); var death = buffs.Death; teradpsUser.playerDeaths = death.Count(firstTick, lastTick) + ""; teradpsUser.playerDeathDuration = death.Duration(firstTick, lastTick)/TimeSpan.TicksPerSecond + ""; var aggro = buffs.Aggro(entity); teradpsUser.aggro = 100*aggro.Duration(firstTick, lastTick)/interTick + ""; foreach (var buff in buffs.Times.OrderByDescending(x=>x.Value.Duration(firstTick, lastTick))) { var percentage = buff.Value.Duration(firstTick, lastTick)*100/interTick; if (percentage == 0) { continue; } teradpsUser.buffUptime.Add(new KeyValuePair<string, string>( buff.Key.Id + "", percentage + "" )); } var serverPlayerName = $"{teradpsUser.playerServer}_{teradpsUser.playerName}"; extendedStats.PlayerSkills.Add(serverPlayerName, skills.GetSkillsDealt(user.Source.User, entity, timedEncounter)); extendedStats.PlayerBuffs.Add(serverPlayerName, buffs); var skillsId = SkillAggregate.GetAggregate(user, entityInfo.Entity, skills, timedEncounter, Database.Database.Type.Damage); extendedStats.PlayerSkillsAggregated[teradpsUser.playerServer + "/" + teradpsUser.playerName] = skillsId; foreach (var skill in skillsId.OrderByDescending(x=>x.Amount())) { var skillLog = new SkillLog(); var skilldamage = skill.Amount(); skillLog.skillAverageCrit = Math.Round(skill.AvgCrit()) + ""; skillLog.skillAverageWhite = Math.Round(skill.AvgWhite()) + ""; skillLog.skillCritRate = skill.CritRate() + ""; skillLog.skillDamagePercent = skill.DamagePercent() + ""; skillLog.skillHighestCrit = skill.BiggestCrit() + ""; skillLog.skillHits = skill.Hits() + ""; var skillKey = skill.Skills.First().Key; skillLog.skillId= BasicTeraData.Instance.SkillDatabase.GetSkillByPetName(skillKey.NpcInfo?.Name, user.Source.RaceGenderClass)?.Id.ToString() ?? skillKey.Id.ToString(); skillLog.skillLowestCrit = skill.LowestCrit() + ""; skillLog.skillTotalDamage = skilldamage + ""; if (skilldamage == 0) { continue; } teradpsUser.skillLog.Add(skillLog); } teradpsData.members.Add(teradpsUser); } return extendedStats; }