private void btnGraph_Click(object sender, EventArgs e) { CalculationsRetribution retCalc = new CalculationsRetribution(); CharacterCalculationsRetribution baseCalc = retCalc.GetCharacterCalculations(Character) as CharacterCalculationsRetribution; Bitmap _prerenderedGraph = global::Rawr.Retribution.Properties.Resources.GraphBase; Graphics g = Graphics.FromImage(_prerenderedGraph); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; float graphHeight = 700f, graphStart = 100f; Color[] colors = new Color[] { Color.FromArgb(127, 202, 180, 96), // Strength Color.FromArgb(127, 101, 225, 240), // Agility Color.FromArgb(127, 0, 4, 3), // Attack Power Color.FromArgb(127, 123, 238, 199), // Crit Rating Color.FromArgb(127, 45, 112, 63), // Hit Rating Color.FromArgb(127, 121, 72, 210), //Expertise Rating Color.FromArgb(127, 217, 100, 54), // Haste Rating Color.FromArgb(127, 210, 72, 195), // Armor Penetration Color.FromArgb(127, 206, 189, 191), // Spell Damage }; Stats[] statsList = new Stats[] { new Stats() { Strength = 10 }, new Stats() { Agility = 10 }, new Stats() { AttackPower = 20 }, new Stats() { CritRating = 10 }, new Stats() { HitRating = 10 }, new Stats() { ExpertiseRating = 10 }, new Stats() { HasteRating = 10 }, new Stats() { ArmorPenetration = 66.667f }, new Stats() { SpellDamageRating = 11.17f }, }; for (int index = 0; index < statsList.Length; index++) { Stats newStats = new Stats(); Point[] points = new Point[100]; for (int count = 0; count < 100; count++) { newStats = newStats + statsList[index]; CharacterCalculationsRetribution currentCalc = retCalc.GetCharacterCalculations(Character, new Item() { Stats = newStats }) as CharacterCalculationsRetribution; float overallPoints = currentCalc.DPSPoints - baseCalc.DPSPoints; if ((graphHeight - overallPoints) > 16) { points[count] = new Point(Convert.ToInt32(graphStart + count * 5), (Convert.ToInt32(graphHeight - overallPoints))); } else { points[count] = points[count - 1]; } } Brush statBrush = new SolidBrush(colors[index]); g.DrawLines(new Pen(statBrush, 3), points); } #region Graph Ticks float graphWidth = 500f;// this.Width - 150f; float graphEnd = graphStart + graphWidth; //float graphStartY = 16f; float maxScale = 100f; float[] ticks = new float[] { (float)Math.Round(graphStart + graphWidth * 0.5f), (float)Math.Round(graphStart + graphWidth * 0.75f), (float)Math.Round(graphStart + graphWidth * 0.25f), (float)Math.Round(graphStart + graphWidth * 0.125f), (float)Math.Round(graphStart + graphWidth * 0.375f), (float)Math.Round(graphStart + graphWidth * 0.625f), (float)Math.Round(graphStart + graphWidth * 0.875f) }; Pen black200 = new Pen(Color.FromArgb(200, 0, 0, 0)); Pen black150 = new Pen(Color.FromArgb(150, 0, 0, 0)); Pen black75 = new Pen(Color.FromArgb(75, 0, 0, 0)); Pen black50 = new Pen(Color.FromArgb(50, 0, 0, 0)); Pen black25 = new Pen(Color.FromArgb(25, 0, 0, 0)); StringFormat formatTick = new StringFormat(); formatTick.LineAlignment = StringAlignment.Far; formatTick.Alignment = StringAlignment.Center; Brush black200brush = new SolidBrush(Color.FromArgb(200, 0, 0, 0)); Brush black150brush = new SolidBrush(Color.FromArgb(150, 0, 0, 0)); Brush black75brush = new SolidBrush(Color.FromArgb(75, 0, 0, 0)); Brush black50brush = new SolidBrush(Color.FromArgb(50, 0, 0, 0)); Brush black25brush = new SolidBrush(Color.FromArgb(25, 0, 0, 0)); g.DrawLine(black200, graphStart - 4, 20, graphEnd + 4, 20); g.DrawLine(black200, graphStart, 16, graphStart, _prerenderedGraph.Height - 16); g.DrawLine(black200, graphEnd, 16, graphEnd, 19); g.DrawLine(black200, ticks[0], 16, ticks[0], 19); g.DrawLine(black150, ticks[1], 16, ticks[1], 19); g.DrawLine(black150, ticks[2], 16, ticks[2], 19); g.DrawLine(black75, ticks[3], 16, ticks[3], 19); g.DrawLine(black75, ticks[4], 16, ticks[4], 19); g.DrawLine(black75, ticks[5], 16, ticks[5], 19); g.DrawLine(black75, ticks[6], 16, ticks[6], 19); g.DrawLine(black75, graphEnd, 21, graphEnd, _prerenderedGraph.Height - 4); g.DrawLine(black75, ticks[0], 21, ticks[0], _prerenderedGraph.Height - 4); g.DrawLine(black50, ticks[1], 21, ticks[1], _prerenderedGraph.Height - 4); g.DrawLine(black50, ticks[2], 21, ticks[2], _prerenderedGraph.Height - 4); g.DrawLine(black25, ticks[3], 21, ticks[3], _prerenderedGraph.Height - 4); g.DrawLine(black25, ticks[4], 21, ticks[4], _prerenderedGraph.Height - 4); g.DrawLine(black25, ticks[5], 21, ticks[5], _prerenderedGraph.Height - 4); g.DrawLine(black25, ticks[6], 21, ticks[6], _prerenderedGraph.Height - 4); g.DrawLine(black200, graphStart - 4, _prerenderedGraph.Height - 20, graphEnd + 4, _prerenderedGraph.Height - 20); Font tickFont = new Font("Calibri", 11); g.DrawString((0f).ToString(), tickFont, black200brush, graphStart, 16, formatTick); g.DrawString((maxScale).ToString(), tickFont, black200brush, graphEnd, 16, formatTick); g.DrawString((maxScale * 0.5f).ToString(), tickFont, black200brush, ticks[0], 16, formatTick); g.DrawString((maxScale * 0.75f).ToString(), tickFont, black150brush, ticks[1], 16, formatTick); g.DrawString((maxScale * 0.25f).ToString(), tickFont, black150brush, ticks[2], 16, formatTick); g.DrawString((maxScale * 0.125f).ToString(), tickFont, black75brush, ticks[3], 16, formatTick); g.DrawString((maxScale * 0.375f).ToString(), tickFont, black75brush, ticks[4], 16, formatTick); g.DrawString((maxScale * 0.625f).ToString(), tickFont, black75brush, ticks[5], 16, formatTick); g.DrawString((maxScale * 0.875f).ToString(), tickFont, black75brush, ticks[6], 16, formatTick); g.DrawString((0f).ToString(), tickFont, black200brush, graphStart, _prerenderedGraph.Height - 16, formatTick); g.DrawString((maxScale).ToString(), tickFont, black200brush, graphEnd, _prerenderedGraph.Height - 16, formatTick); g.DrawString((maxScale * 0.5f).ToString(), tickFont, black200brush, ticks[0], _prerenderedGraph.Height - 16, formatTick); g.DrawString((maxScale * 0.75f).ToString(), tickFont, black150brush, ticks[1], _prerenderedGraph.Height - 16, formatTick); g.DrawString((maxScale * 0.25f).ToString(), tickFont, black150brush, ticks[2], _prerenderedGraph.Height - 16, formatTick); g.DrawString((maxScale * 0.125f).ToString(), tickFont, black75brush, ticks[3], _prerenderedGraph.Height - 16, formatTick); g.DrawString((maxScale * 0.375f).ToString(), tickFont, black75brush, ticks[4], _prerenderedGraph.Height - 16, formatTick); g.DrawString((maxScale * 0.625f).ToString(), tickFont, black75brush, ticks[5], _prerenderedGraph.Height - 16, formatTick); g.DrawString((maxScale * 0.875f).ToString(), tickFont, black75brush, ticks[6], _prerenderedGraph.Height - 16, formatTick); #endregion Graph graph = new Graph(_prerenderedGraph); graph.Show(); }
public GraphForm(Character character, bool bStats) { InitializeComponent(); if (!bStats) { Text = "Effective Cooldown Graph"; } // Create ARGB bitmap matching the size of the picturebox and associate with picturebox bmp = new Bitmap(pictureBoxGraph.Size.Width, pictureBoxGraph.Size.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); pictureBoxGraph.Image = bmp; // Greate & initialise GDI+ graphics object via bitmap gfx = Graphics.FromImage(bmp); gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; #region Coordinates and scaling. /* * +-----------------------------------------------------+-rcBmp --- * | | |EndY * | ^ | --- * | | | * | | | * | | | * | | | * | | | * | | | * | | | * | | | * | | | * | | | * | | | * | | | * | | | * | +---------------------------------------------> | --- * | | | OrgY * +-----------------------------------------------------+ --- * * |----|OrgX |--|EndX * * * */ // Apply a translateion transformation. We'll move the 0,0 to the 0,0 of the chart we want to display // This will make most of the rest of the charting easier since all translation are then done by GDI+ // It also makes working with 'y' a bit easier as it's just flipped in sign rather than translated also. int OrgX = 50; // Leftmost edge of char int OrgY = 50; // Bottom edge of char int EndX = 15; // Margin right of chart int EndY = 15; // Margin top of chart gfx.TranslateTransform(OrgX, pictureBoxGraph.Size.Height - OrgY); // Bitmap coordinates translated back into transform Rectangle rcBmp = new Rectangle(0, 0, pictureBoxGraph.Size.Width, pictureBoxGraph.Size.Height); rcBmp.Offset(-OrgX, -(pictureBoxGraph.Size.Height - OrgY)); // rcChart is image rectangle, watch out, Y has positive value ! Rectangle rcChart = new Rectangle(0, 0, pictureBoxGraph.Size.Width - OrgX - EndX, pictureBoxGraph.Size.Height - OrgY - EndY); int YAxisValueX = -5; // Right alignment of values on the Y axis int XAxisValueY = +5; // Top margin of values on the X axis int YChartMargin = 5; #endregion #region Define and calculate charts ChartData[] aCharts; float DpsMax; float DpsMin; float DpsScaling; if (bStats) { aCharts = new ChartData[] { new ChartData(rcChart.Width, Color.FromArgb(255, 192, 0, 0), "1 Strength", new Stats() { Strength = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 192, 192, 96), "1.167 Spell Power", new Stats() { SpellPower = 7 / 6 }), new ChartData(rcChart.Width, Color.FromArgb(255, 0, 0, 192), "1 Armor Pen.", new Stats() { ArmorPenetrationRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 192, 0, 192), "1 Hit Rating", new Stats() { HitRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 0, 192, 0), "1 Expertise Rating", new Stats() { ExpertiseRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 192, 127, 96), "1 Agility", new Stats() { Agility = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 192, 127, 0), "2 Attack Power", new Stats() { AttackPower = 2 }), new ChartData(rcChart.Width, Color.FromArgb(255, 96, 127, 192), "1 Crit Rating", new Stats() { CritRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 0, 0, 0), "1 Haste Rating", new Stats() { HasteRating = 1 }), }; // Calculate charts CalculationsRetribution Calc = new CalculationsRetribution(); DpsMax = 0; DpsMin = 999999999; foreach (ChartData cd in aCharts) { for (int count = 0; count < rcChart.Width; count++) { Stats chartstats = cd.stats.Clone(); chartstats *= count - (rcChart.Width / 2); CharacterCalculationsRetribution chartCalc = Calc.GetCharacterCalculations(character, new Item() { Stats = chartstats }) as CharacterCalculationsRetribution; float Dps = chartCalc.DPSPoints; if (Dps > DpsMax) { DpsMax = Dps; } if (Dps < DpsMin) { DpsMin = Dps; } cd.dps[count] = Dps; } } DpsScaling = (rcChart.Height - 2 * YChartMargin /* some extra margin*/) / (DpsMax - DpsMin); } else { aCharts = new ChartData[] { new ChartData(rcChart.Width, Color.FromArgb(255, 192, 0, 0), "White", new Stats() { HasteRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 192, 192, 96), "CS", new Stats() { HasteRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 0, 0, 192), "J", new Stats() { HasteRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 192, 0, 192), "DS", new Stats() { HasteRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 0, 192, 0), "Cons", new Stats() { HasteRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 192, 127, 96), "Exo", new Stats() { HasteRating = 1 }), //new ChartData(rcChart.Width, Color.FromArgb(255, 192, 127, 0), "HoW", new Stats() { HasteRating = 1 }), }; // Calculate charts CalculationsRetribution Calc = new CalculationsRetribution(); DpsMax = 0; DpsMin = 999999999; Stats stats = new Stats() { HasteRating = 1 }; for (int count = 0; count < rcChart.Width; count++) { Stats chartstats = stats.Clone(); chartstats *= count - (rcChart.Width / 2); CharacterCalculationsRetribution chartCalc = Calc.GetCharacterCalculations(character, new Item() { Stats = chartstats }) as CharacterCalculationsRetribution; float Ecd; Ecd = chartCalc.AttackSpeed; if (Ecd > DpsMax) { DpsMax = Ecd; } if (Ecd < DpsMin) { DpsMin = Ecd; } aCharts[0].dps[count] = Ecd; Ecd = 1 / chartCalc.Solution.GetAbilityUsagePerSecond(Ability.CrusaderStrike); if (Ecd > 50) // infinity fix { Ecd = 0; } if (Ecd > DpsMax) { DpsMax = Ecd; } if (Ecd < DpsMin) { DpsMin = Ecd; } aCharts[1].dps[count] = Ecd; Ecd = 1 / chartCalc.Solution.GetAbilityUsagePerSecond(Ability.Judgement); if (Ecd > 50) { Ecd = 0; } if (Ecd > DpsMax) { DpsMax = Ecd; } if (Ecd < DpsMin) { DpsMin = Ecd; } aCharts[2].dps[count] = Ecd; Ecd = 1 / chartCalc.Solution.GetAbilityUsagePerSecond(Ability.DivineStorm); if (Ecd > 50) { Ecd = 0; } if (Ecd > DpsMax) { DpsMax = Ecd; } if (Ecd < DpsMin) { DpsMin = Ecd; } aCharts[3].dps[count] = Ecd; Ecd = 1 / chartCalc.Solution.GetAbilityUsagePerSecond(Ability.Consecration); if (Ecd > 50) { Ecd = 0; } if (Ecd > DpsMax) { DpsMax = Ecd; } if (Ecd < DpsMin) { DpsMin = Ecd; } aCharts[4].dps[count] = Ecd; Ecd = 1 / chartCalc.Solution.GetAbilityUsagePerSecond(Ability.Exorcism); if (Ecd > 50) { Ecd = 0; } if (Ecd > DpsMax) { DpsMax = Ecd; } if (Ecd < DpsMin) { DpsMin = Ecd; } aCharts[5].dps[count] = Ecd; /*Ecd = 1 / chartCalc.Solution.GetAbilityUsagePerSecond(Ability.HammerOfWrath); * if (Ecd > 50) * Ecd = 0; * if (Ecd > DpsMax) * DpsMax = Ecd; * if (Ecd < DpsMin) * DpsMin = Ecd; * aCharts[6].dps[count] = Ecd; */ } DpsScaling = (rcChart.Height - 2 * YChartMargin /* some extra margin*/) / (DpsMax - DpsMin); } #endregion #region Fonts, Pens, Brushes and other helper variables Font fntValue = new Font("Arial", 8); Font fntTitle = new Font("Arial", 16); Pen penBlack = new Pen(Color.FromArgb(255, 0, 0, 0)); Pen penGray50 = new Pen(Color.FromArgb(255, 127, 127, 127)); Pen penGray75 = new Pen(Color.FromArgb(255, 196, 196, 196)); Pen penGray90 = new Pen(Color.FromArgb(255, 230, 230, 230)); Pen penRed = new Pen(Color.FromArgb(255, 255, 0, 0)); Brush brBlack = new SolidBrush(Color.FromArgb(255, 0, 0, 0)); Brush brWhite = new SolidBrush(Color.FromArgb(255, 255, 255, 255)); Brush brRed = new SolidBrush(Color.FromArgb(255, 255, 0, 0)); StringFormat fmtRAlignCenter = new StringFormat(); fmtRAlignCenter.Alignment = StringAlignment.Far; fmtRAlignCenter.LineAlignment = StringAlignment.Center; StringFormat fmtRAlignBottom = new StringFormat(); fmtRAlignBottom.Alignment = StringAlignment.Far; fmtRAlignBottom.LineAlignment = StringAlignment.Far; StringFormat fmtLAlignTop = new StringFormat(); fmtLAlignTop.Alignment = StringAlignment.Near; fmtLAlignTop.LineAlignment = StringAlignment.Near; StringFormat fmtCAlignTop = new StringFormat(); fmtCAlignTop.Alignment = StringAlignment.Center; fmtCAlignTop.LineAlignment = StringAlignment.Near; #endregion // Clear bitmap to all white. gfx.FillRectangle(brWhite, rcBmp); #region Draw Axis and titles // Stats ticks (draw this first, so other axis information is drawn on top) const int Steps = 10; // Chart is per 1 stat, typically, 20 stats go in a iLevel. for (int i = 1; i < (rcChart.Width / 2) / Steps; i++) { Pen pen; if (i % 5 == 0) { pen = penGray75; gfx.DrawString((-i * 10).ToString(), fntValue, brBlack, rcChart.Width / 2 - i * 10, XAxisValueY, fmtCAlignTop); gfx.DrawString((i * 10).ToString(), fntValue, brBlack, rcChart.Width / 2 + i * 10, XAxisValueY, fmtCAlignTop); } else { pen = penGray90; } gfx.DrawLine(pen, rcChart.Width / 2 - i * 10, 0, rcChart.Width / 2 - i * 10, -rcChart.Height); gfx.DrawLine(pen, rcChart.Width / 2 + i * 10, 0, rcChart.Width / 2 + i * 10, -rcChart.Height); } // DPS ticks (Draw this first, so other axis information is drawn on top) const int MaxDpsLines = 25; float DpsDelta = DpsMax - DpsMin; int[] Ranges = { 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000, 25000, 50000, }; int Range = 1; foreach (int r in Ranges) { if (MaxDpsLines * r > DpsDelta) { Range = r; break; } } int Y = (int)(Math.Floor(DpsMin / Range) * Range); do { float Y2 = (Y - DpsMin) * DpsScaling; if (Y2 > 0) { gfx.DrawLine(penGray75, 0, -Y2, rcChart.Width - 5, -Y2); gfx.DrawString(Y.ToString(), fntValue, brBlack, YAxisValueX, -Y2, fmtRAlignCenter); } Y += Range; }while (Y < DpsMax); // Y Axis gfx.DrawLine(penBlack, 0, 0, 0, -rcChart.Height); gfx.DrawString(bStats ? "DPS" : "ECD", fntTitle, brBlack, 5, -(rcChart.Height - 5), fmtLAlignTop); // X-axis gfx.DrawLine(penBlack, 0, 0, rcChart.Width, 0); gfx.DrawString(bStats ? "Stats" : "Haste Rating", fntTitle, brBlack, rcChart.Width - 5, -5, fmtRAlignBottom); // Center Y Axis. gfx.DrawLine(penBlack, rcChart.Width / 2, 0, rcChart.Width / 2, -rcChart.Height); gfx.DrawString("0", fntValue, brBlack, rcChart.Width / 2, XAxisValueY, fmtCAlignTop); // "Experimental" text gfx.DrawString("Experimental", fntTitle, brRed, rcChart.Width - 5, OrgY, fmtRAlignBottom); #endregion // Draw charts int l = 0; foreach (ChartData cd in aCharts) { for (int count = 0; count < rcChart.Width - 1; count++) { gfx.DrawLine(cd.pen, count, -(cd.dps[count] - DpsMin) * DpsScaling - YChartMargin, count + 1, -(cd.dps[count + 1] - DpsMin) * DpsScaling - YChartMargin); } gfx.DrawString(cd.name, fntValue, cd.brush, 5, -(rcChart.Height - fntTitle.GetHeight() - 5 - l * fntValue.GetHeight())); l++; } Invalidate(); Update(); }
public GraphForm(Character character, bool bStats) { InitializeComponent(); if (!bStats) Text = "Effective Cooldown Graph"; // Create ARGB bitmap matching the size of the picturebox and associate with picturebox bmp = new Bitmap(pictureBoxGraph.Size.Width, pictureBoxGraph.Size.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); pictureBoxGraph.Image = bmp; // Greate & initialise GDI+ graphics object via bitmap gfx = Graphics.FromImage(bmp); gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; #region Coordinates and scaling. /* * +-----------------------------------------------------+-rcBmp --- * | | |EndY * | ^ | --- * | | | * | | | * | | | * | | | * | | | * | | | * | | | * | | | * | | | * | | | * | | | * | | | * | | | * | +---------------------------------------------> | --- * | | | OrgY * +-----------------------------------------------------+ --- * * |----|OrgX |--|EndX * * * */ // Apply a translateion transformation. We'll move the 0,0 to the 0,0 of the chart we want to display // This will make most of the rest of the charting easier since all translation are then done by GDI+ // It also makes working with 'y' a bit easier as it's just flipped in sign rather than translated also. int OrgX = 50; // Leftmost edge of char int OrgY = 50; // Bottom edge of char int EndX = 15; // Margin right of chart int EndY = 15; // Margin top of chart gfx.TranslateTransform(OrgX, pictureBoxGraph.Size.Height - OrgY); // Bitmap coordinates translated back into transform Rectangle rcBmp = new Rectangle(0, 0, pictureBoxGraph.Size.Width, pictureBoxGraph.Size.Height); rcBmp.Offset(-OrgX, -(pictureBoxGraph.Size.Height - OrgY)); // rcChart is image rectangle, watch out, Y has positive value ! Rectangle rcChart = new Rectangle(0, 0, pictureBoxGraph.Size.Width - OrgX - EndX, pictureBoxGraph.Size.Height - OrgY - EndY); int YAxisValueX = - 5; // Right alignment of values on the Y axis int XAxisValueY = + 5; // Top margin of values on the X axis int YChartMargin = 5; #endregion #region Define and calculate charts ChartData[] aCharts; float DpsMax; float DpsMin; float DpsScaling; if (bStats) { aCharts = new ChartData[] { new ChartData(rcChart.Width, Color.FromArgb(255, 192, 0, 0), "1 Strength", new Stats() { Strength = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 192, 192, 96), "1.167 Spell Power", new Stats() { SpellPower = 7/6 }), new ChartData(rcChart.Width, Color.FromArgb(255, 0, 0, 192), "1 Armor Pen.", new Stats() { ArmorPenetrationRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 192, 0, 192), "1 Hit Rating", new Stats() { HitRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 0, 192, 0), "1 Expertise Rating", new Stats() { ExpertiseRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 192, 127, 96), "1 Agility", new Stats() { Agility = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 192, 127, 0), "2 Attack Power", new Stats() { AttackPower = 2 }), new ChartData(rcChart.Width, Color.FromArgb(255, 96, 127, 192), "1 Crit Rating", new Stats() { CritRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 0, 0, 0), "1 Haste Rating", new Stats() { HasteRating = 1 }), }; // Calculate charts CalculationsRetribution Calc = new CalculationsRetribution(); DpsMax = 0; DpsMin = 999999999; foreach (ChartData cd in aCharts) { for (int count = 0; count < rcChart.Width; count++) { Stats chartstats = cd.stats.Clone(); chartstats *= count - (rcChart.Width / 2); CharacterCalculationsRetribution chartCalc = Calc.GetCharacterCalculations(character, new Item() { Stats = chartstats }) as CharacterCalculationsRetribution; float Dps = chartCalc.DPSPoints; if (Dps > DpsMax) DpsMax = Dps; if (Dps < DpsMin) DpsMin = Dps; cd.dps[count] = Dps; } } DpsScaling = (rcChart.Height - 2 * YChartMargin/* some extra margin*/) / (DpsMax - DpsMin); } else { aCharts = new ChartData[] { new ChartData(rcChart.Width, Color.FromArgb(255, 192, 0, 0), "White", new Stats() { HasteRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 192, 192, 96), "CS", new Stats() { HasteRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 0, 0, 192), "J", new Stats() { HasteRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 192, 0, 192), "DS", new Stats() { HasteRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 0, 192, 0), "Cons", new Stats() { HasteRating = 1 }), new ChartData(rcChart.Width, Color.FromArgb(255, 192, 127, 96), "Exo", new Stats() { HasteRating = 1 }), //new ChartData(rcChart.Width, Color.FromArgb(255, 192, 127, 0), "HoW", new Stats() { HasteRating = 1 }), }; // Calculate charts CalculationsRetribution Calc = new CalculationsRetribution(); DpsMax = 0; DpsMin = 999999999; Stats stats = new Stats() { HasteRating = 1 }; for (int count = 0; count < rcChart.Width; count++) { Stats chartstats = stats.Clone(); chartstats *= count - (rcChart.Width / 2); CharacterCalculationsRetribution chartCalc = Calc.GetCharacterCalculations(character, new Item() { Stats = chartstats }) as CharacterCalculationsRetribution; float Ecd; Ecd = chartCalc.AttackSpeed; if (Ecd > DpsMax) DpsMax = Ecd; if (Ecd < DpsMin) DpsMin = Ecd; aCharts[0].dps[count] = Ecd; Ecd = 1 / chartCalc.Solution.GetAbilityUsagePerSecond(Ability.CrusaderStrike); if (Ecd > 50) // infinity fix Ecd = 0; if (Ecd > DpsMax) DpsMax = Ecd; if (Ecd < DpsMin) DpsMin = Ecd; aCharts[1].dps[count] = Ecd; Ecd = 1 / chartCalc.Solution.GetAbilityUsagePerSecond(Ability.Judgement); if (Ecd > 50) Ecd = 0; if (Ecd > DpsMax) DpsMax = Ecd; if (Ecd < DpsMin) DpsMin = Ecd; aCharts[2].dps[count] = Ecd; Ecd = 1 / chartCalc.Solution.GetAbilityUsagePerSecond(Ability.DivineStorm); if (Ecd > 50) Ecd = 0; if (Ecd > DpsMax) DpsMax = Ecd; if (Ecd < DpsMin) DpsMin = Ecd; aCharts[3].dps[count] = Ecd; Ecd = 1 / chartCalc.Solution.GetAbilityUsagePerSecond(Ability.Consecration); if (Ecd > 50) Ecd = 0; if (Ecd > DpsMax) DpsMax = Ecd; if (Ecd < DpsMin) DpsMin = Ecd; aCharts[4].dps[count] = Ecd; Ecd = 1 / chartCalc.Solution.GetAbilityUsagePerSecond(Ability.Exorcism); if (Ecd > 50) Ecd = 0; if (Ecd > DpsMax) DpsMax = Ecd; if (Ecd < DpsMin) DpsMin = Ecd; aCharts[5].dps[count] = Ecd; /*Ecd = 1 / chartCalc.Solution.GetAbilityUsagePerSecond(Ability.HammerOfWrath); if (Ecd > 50) Ecd = 0; if (Ecd > DpsMax) DpsMax = Ecd; if (Ecd < DpsMin) DpsMin = Ecd; aCharts[6].dps[count] = Ecd; */ } DpsScaling = (rcChart.Height - 2 * YChartMargin/* some extra margin*/) / (DpsMax - DpsMin); } #endregion #region Fonts, Pens, Brushes and other helper variables Font fntValue = new Font("Arial", 8); Font fntTitle = new Font("Arial", 16); Pen penBlack = new Pen(Color.FromArgb(255, 0, 0, 0)); Pen penGray50 = new Pen(Color.FromArgb(255, 127, 127, 127)); Pen penGray75 = new Pen(Color.FromArgb(255, 196, 196, 196)); Pen penGray90 = new Pen(Color.FromArgb(255, 230, 230, 230)); Pen penRed = new Pen(Color.FromArgb(255, 255, 0, 0)); Brush brBlack = new SolidBrush(Color.FromArgb(255, 0, 0, 0)); Brush brWhite = new SolidBrush(Color.FromArgb(255, 255, 255, 255)); Brush brRed = new SolidBrush(Color.FromArgb(255, 255, 0, 0)); StringFormat fmtRAlignCenter = new StringFormat(); fmtRAlignCenter.Alignment = StringAlignment.Far; fmtRAlignCenter.LineAlignment = StringAlignment.Center; StringFormat fmtRAlignBottom = new StringFormat(); fmtRAlignBottom.Alignment = StringAlignment.Far; fmtRAlignBottom.LineAlignment = StringAlignment.Far; StringFormat fmtLAlignTop = new StringFormat(); fmtLAlignTop.Alignment = StringAlignment.Near; fmtLAlignTop.LineAlignment = StringAlignment.Near; StringFormat fmtCAlignTop = new StringFormat(); fmtCAlignTop.Alignment = StringAlignment.Center; fmtCAlignTop.LineAlignment = StringAlignment.Near; #endregion // Clear bitmap to all white. gfx.FillRectangle(brWhite, rcBmp); #region Draw Axis and titles // Stats ticks (draw this first, so other axis information is drawn on top) const int Steps=10; // Chart is per 1 stat, typically, 20 stats go in a iLevel. for (int i = 1; i < (rcChart.Width / 2) / Steps; i++) { Pen pen; if (i % 5 == 0) { pen = penGray75; gfx.DrawString((-i * 10).ToString(), fntValue, brBlack, rcChart.Width / 2 - i * 10, XAxisValueY, fmtCAlignTop); gfx.DrawString((i * 10).ToString(), fntValue, brBlack, rcChart.Width / 2 + i * 10, XAxisValueY, fmtCAlignTop); } else pen = penGray90; gfx.DrawLine(pen, rcChart.Width / 2 - i * 10, 0, rcChart.Width / 2 - i * 10, -rcChart.Height); gfx.DrawLine(pen, rcChart.Width / 2 + i * 10, 0, rcChart.Width / 2 + i * 10, -rcChart.Height); } // DPS ticks (Draw this first, so other axis information is drawn on top) const int MaxDpsLines = 25; float DpsDelta = DpsMax - DpsMin; int[] Ranges = { 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000, 25000, 50000, }; int Range = 1; foreach (int r in Ranges) { if (MaxDpsLines * r > DpsDelta) { Range = r; break; } } int Y = (int)(Math.Floor(DpsMin / Range) * Range); do { float Y2 = (Y - DpsMin) * DpsScaling; if (Y2 > 0) { gfx.DrawLine(penGray75, 0, -Y2, rcChart.Width - 5, -Y2); gfx.DrawString(Y.ToString(), fntValue, brBlack, YAxisValueX, -Y2, fmtRAlignCenter); } Y += Range; } while (Y < DpsMax); // Y Axis gfx.DrawLine(penBlack, 0, 0, 0, -rcChart.Height); gfx.DrawString(bStats ? "DPS" : "ECD", fntTitle, brBlack, 5, -(rcChart.Height - 5), fmtLAlignTop); // X-axis gfx.DrawLine(penBlack, 0, 0, rcChart.Width, 0); gfx.DrawString(bStats ? "Stats" : "Haste Rating", fntTitle, brBlack, rcChart.Width - 5, -5, fmtRAlignBottom); // Center Y Axis. gfx.DrawLine(penBlack, rcChart.Width / 2, 0, rcChart.Width / 2, -rcChart.Height); gfx.DrawString("0", fntValue, brBlack, rcChart.Width / 2, XAxisValueY, fmtCAlignTop); // "Experimental" text gfx.DrawString("Experimental", fntTitle, brRed, rcChart.Width-5, OrgY, fmtRAlignBottom); #endregion // Draw charts int l = 0; foreach (ChartData cd in aCharts) { for (int count = 0; count < rcChart.Width - 1; count++) gfx.DrawLine(cd.pen, count, -(cd.dps[count] - DpsMin) * DpsScaling - YChartMargin, count + 1, -(cd.dps[count + 1] - DpsMin) * DpsScaling - YChartMargin); gfx.DrawString(cd.name, fntValue, cd.brush, 5, -(rcChart.Height - fntTitle.GetHeight() - 5 - l*fntValue.GetHeight())); l++; } Invalidate(); Update(); }