Example #1
0
        public void UpdateGraph(CalculationOptionsMage calculationOptions)
        {
            DisplayCalculations calculations = calculationOptions.Calculations;

            Chart.Series.Clear();
            Chart.Axes.Clear();

            Chart.Text = null;

            if (calculationOptions.SequenceReconstruction == null)
            {
                Chart.Text = "Sequence reconstruction data is not available.";
            }
            else
            {
                List <EffectCooldown> cooldownList = calculationOptions.Calculations.CooldownList;

                /*brushSubPoints = new Brush[cooldownList.Count];
                 * colorSubPointsA = new Color[cooldownList.Count];
                 * colorSubPointsB = new Color[cooldownList.Count];
                 * for (int i = 0; i < cooldownList.Count; i++)
                 * {
                 *  Color baseColor = cooldownList[i].Color;
                 *  brushSubPoints[i] = new SolidBrush(Color.FromArgb(baseColor.R / 2, baseColor.G / 2, baseColor.B / 2));
                 *  colorSubPointsA[i] = Color.FromArgb(baseColor.A / 2, baseColor.R / 2, baseColor.G / 2, baseColor.B / 2);
                 *  colorSubPointsB[i] = Color.FromArgb(baseColor.A / 2, baseColor);
                 * }
                 * StringFormat formatSubPoint = new StringFormat();
                 * formatSubPoint.Alignment = StringAlignment.Center;
                 * formatSubPoint.LineAlignment = StringAlignment.Center;
                 *
                 * int maxWidth = 1;
                 * for (int i = 0; i < cooldownList.Count; i++)
                 * {
                 *  string subPointName = cooldownList[i].Name;
                 *  int widthSubPoint = (int)Math.Ceiling(g.MeasureString(subPointName, fontLegend).Width + 2f);
                 *  if (widthSubPoint > maxWidth) maxWidth = widthSubPoint;
                 * }
                 * for (int i = 0; i < cooldownList.Count; i++)
                 * {
                 *  string cooldownName = cooldownList[i].Name;
                 *  rectSubPoint = new Rectangle(2, legendY, maxWidth, 16);
                 *  blendSubPoint = new System.Drawing.Drawing2D.ColorBlend(3);
                 *  blendSubPoint.Colors = new Color[] { colorSubPointsA[i], colorSubPointsB[i], colorSubPointsA[i] };
                 *  blendSubPoint.Positions = new float[] { 0f, 0.5f, 1f };
                 *  brushSubPointFill = new System.Drawing.Drawing2D.LinearGradientBrush(rectSubPoint, colorSubPointsA[i], colorSubPointsB[i], 67f);
                 *  brushSubPointFill.InterpolationColors = blendSubPoint;
                 *
                 *  g.FillRectangle(brushSubPointFill, rectSubPoint);
                 *  g.DrawRectangle(new Pen(brushSubPointFill), rectSubPoint);
                 *  g.DrawRectangle(new Pen(brushSubPointFill), rectSubPoint);
                 *  g.DrawRectangle(new Pen(brushSubPointFill), rectSubPoint);
                 *
                 *  g.DrawString(cooldownName, fontLegend, brushSubPoints[i], rectSubPoint, formatSubPoint);
                 *  legendY += 16;
                 * }*/

                if (calculationOptions.AdviseAdvancedSolver)
                {
                    Chart.Text = "Sequence Reconstruction was not fully successful, it is recommended that you enable more options in advanced solver (segment cooldowns, integral mana consumables, advanced constraints options)!";
                }

                /*g.DrawLine(Pens.Aqua, new Point(maxWidth + 40, 10), new Point(maxWidth + 80, 10));
                 * g.DrawString("Mana", fontLegend, Brushes.Black, new Point(maxWidth + 90, 2));
                 * g.DrawLine(Pens.Red, new Point(maxWidth + 40, 26), new Point(maxWidth + 80, 26));
                 * g.DrawString("Dps", fontLegend, Brushes.Black, new Point(maxWidth + 90, 18));*/

                List <SequenceItem> sequence = calculationOptions.SequenceReconstruction.sequence;

                List <TimeData> manaList = new List <TimeData>();

                float    mana     = calculations.StartingMana;
                int      gemCount = 0;
                float    time     = 0;
                Color    manaFill = Color.FromArgb(50, 0, 0, 255);
                float    maxMana  = calculations.BaseStats.Mana;
                float    maxDps   = 100;
                DateTime baseTime = new DateTime(2000, 1, 1, 0, 0, 0);
                manaList.Add(new TimeData()
                {
                    Time = baseTime, Value = mana
                });
                for (int i = 0; i < sequence.Count; i++)
                {
                    int          index    = sequence[i].Index;
                    VariableType type     = sequence[i].VariableType;
                    float        duration = (float)sequence[i].Duration;
                    Cycle        cycle    = sequence[i].Cycle;
                    CastingState state    = sequence[i].CastingState;
                    if (cycle != null)
                    {
                        float dps = (float)cycle.GetDamagePerSecond(state.ManaAdeptBonus, 1);
                        if (dps > maxDps)
                        {
                            maxDps = dps;
                        }
                    }
                    float mps = (float)sequence[i].Mps;
                    if (sequence[i].IsManaPotionOrGem)
                    {
                        float value = duration;
                        duration = 0;
                        if (sequence[i].VariableType == VariableType.ManaGem)
                        {
                            mana += (float)((1 + calculations.BaseStats.BonusManaGem) * calculations.ManaGemValue * value);
                            gemCount++;
                        }
                        else if (sequence[i].VariableType == VariableType.ManaPotion)
                        {
                            mana += (float)((1 + calculations.BaseStats.BonusManaPotionEffectMultiplier) * calculations.ManaPotionValue * value);
                        }
                        if (mana < 0)
                        {
                            mana = 0;
                        }
                        if (mana > maxMana)
                        {
                            mana = maxMana;
                        }
                        manaList.Add(new TimeData()
                        {
                            Time = baseTime + TimeSpan.FromSeconds(time) + TimeSpan.FromTicks(1), Value = mana
                        });
                    }
                    else
                    {
                        /*if (sequence[i].IsEvocation)
                         * {
                         *  switch (sequence[i].VariableType)
                         *  {
                         *      case VariableType.Evocation:
                         *          mps = -(float)calculationOptions.Calculations.EvocationRegen;
                         *          break;
                         *      case VariableType.EvocationIV:
                         *          mps = -(float)calculationOptions.Calculations.EvocationRegenIV;
                         *          break;
                         *      case VariableType.EvocationHero:
                         *          mps = -(float)calculationOptions.Calculations.EvocationRegenHero;
                         *          break;
                         *      case VariableType.EvocationIVHero:
                         *          mps = -(float)calculationOptions.Calculations.EvocationRegenIVHero;
                         *          break;
                         *  }
                         * }*/
                        float partTime = duration;
                        if (mana - mps * duration < 0)
                        {
                            partTime = mana / mps;
                        }
                        else if (mana - mps * duration > maxMana)
                        {
                            partTime = (mana - maxMana) / mps;
                        }
                        mana -= mps * duration;
                        if (mana < 0)
                        {
                            mana = 0;
                        }
                        if (mana > maxMana)
                        {
                            mana = maxMana;
                        }
                        manaList.Add(new TimeData()
                        {
                            Time = baseTime + TimeSpan.FromSeconds(time + partTime), Value = mana
                        });
                        if (partTime < duration)
                        {
                            manaList.Add(new TimeData()
                            {
                                Time = baseTime + TimeSpan.FromSeconds(time + duration), Value = mana
                            });
                        }
                    }
                    time += duration;
                }

                Style dateTimeAxisLabelStyle = new Style(typeof(DateTimeAxisLabel));
                dateTimeAxisLabelStyle.Setters.Add(new Setter(DateTimeAxisLabel.MinutesIntervalStringFormatProperty, "{0:m:ss}"));
                dateTimeAxisLabelStyle.Setters.Add(new Setter(DateTimeAxisLabel.SecondsIntervalStringFormatProperty, "{0:m:ss}"));
                DateTimeAxis timeAxis = new DateTimeAxis()
                {
                    //Title = "Time",
                    Minimum        = baseTime,
                    Maximum        = baseTime + TimeSpan.FromSeconds(calculationOptions.FightDuration),
                    IntervalType   = DateTimeIntervalType.Seconds,
                    AxisLabelStyle = dateTimeAxisLabelStyle,
                    Orientation    = AxisOrientation.X,
                    ShowGridLines  = true,
                    Location       = AxisLocation.Top,
                };

                Style hiddenCategoryLabelStyle = new Style(typeof(AxisLabel));
                hiddenCategoryLabelStyle.Setters.Add(new Setter(NumericAxisLabel.VisibilityProperty, Visibility.Collapsed));

                CategoryAxis categoryAxis = new CategoryAxis()
                {
                    AxisLabelStyle     = hiddenCategoryLabelStyle,
                    Orientation        = AxisOrientation.Y,
                    MajorTickMarkStyle = null,
                };

                int barCount = 0;
                for (int cooldown = 0; cooldown < cooldownList.Count; cooldown++)
                {
                    List <TimeIntervalData> data = new List <TimeIntervalData>();
                    //blendSubPoint = new System.Drawing.Drawing2D.ColorBlend(3);
                    //blendSubPoint.Colors = new Color[] { colorSubPointsA[cooldown], colorSubPointsB[cooldown], colorSubPointsA[cooldown] };
                    //blendSubPoint.Positions = new float[] { 0f, 0.5f, 1f };
                    bool  on     = false;
                    float timeOn = 0.0f;
                    time = 0;
                    for (int i = 0; i < sequence.Count; i++)
                    {
                        float duration = (float)sequence[i].Duration;
                        if (sequence[i].IsManaPotionOrGem)
                        {
                            duration = 0;
                        }
                        if (on && !sequence[i].CastingState.EffectsActive(cooldownList[cooldown]) && !sequence[i].IsManaPotionOrGem)
                        {
                            on = false;
                            if (time > timeOn)
                            {
                                data.Add(new TimeIntervalData()
                                {
                                    Start = baseTime + TimeSpan.FromSeconds(timeOn), End = baseTime + TimeSpan.FromSeconds(time), Category = cooldownList[cooldown].Name
                                });
                            }
                        }
                        else if (!on && sequence[i].CastingState.EffectsActive(cooldownList[cooldown]))
                        {
                            on     = true;
                            timeOn = time;
                        }
                        time += duration;
                    }
                    if (on)
                    {
                        if (time - timeOn > 0)
                        {
                            data.Add(new TimeIntervalData()
                            {
                                Start = baseTime + TimeSpan.FromSeconds(timeOn), End = baseTime + TimeSpan.FromSeconds(time), Category = cooldownList[cooldown].Name
                            });
                        }
                    }
                    if (data.Count > 0)
                    {
                        barCount++;
                        Style timeIntervalStyle = new Style(typeof(TimeIntervalDataPoint));
                        timeIntervalStyle.Setters.Add(new Setter(TimeIntervalDataPoint.BackgroundProperty, new SolidColorBrush(cooldownList[cooldown].Color)));
                        Chart.Series.Add(new TimeIntervalSeries()
                        {
                            Title                = cooldownList[cooldown].Name,
                            ItemsSource          = data,
                            IndependentValuePath = "Category",
                            DependentValuePath   = "End",
                            StartTimePath        = "Start",
                            EndTimePath          = "End",
                            DataPointStyle       = timeIntervalStyle,
                            DependentRangeAxis   = timeAxis,
                            IndependentAxis      = categoryAxis
                        });
                    }
                }

                if (calculationOptions.DisplaySegmentCooldowns && calculationOptions.BossHandler)
                {
                    foreach (var buffState in calculationOptions.Character.BossOptions.BuffStates)
                    {
                        if (buffState.Chance > 0 && buffState.Stats.BonusDamageMultiplier > 0)
                        {
                            List <TimeIntervalData> data = new List <TimeIntervalData>();

                            foreach (var phase in buffState.PhaseTimes)
                            {
                                data.Add(new TimeIntervalData()
                                {
                                    Start = baseTime + TimeSpan.FromSeconds(phase.Value[0]), End = baseTime + TimeSpan.FromSeconds(phase.Value[1]), Category = buffState.Name
                                });
                            }
                            if (data.Count > 0)
                            {
                                barCount++;
                                Style timeIntervalStyle = new Style(typeof(TimeIntervalDataPoint));
                                timeIntervalStyle.Setters.Add(new Setter(TimeIntervalDataPoint.BackgroundProperty, new SolidColorBrush(Color.FromArgb(255, 0, 0, 0))));
                                Chart.Series.Add(new TimeIntervalSeries()
                                {
                                    Title                = buffState.Name,
                                    ItemsSource          = data,
                                    IndependentValuePath = "Category",
                                    DependentValuePath   = "End",
                                    StartTimePath        = "Start",
                                    EndTimePath          = "End",
                                    DataPointStyle       = timeIntervalStyle,
                                    DependentRangeAxis   = timeAxis,
                                    IndependentAxis      = categoryAxis
                                });
                            }
                        }
                    }
                }

                Style hiddenNumericLabelStyle = new Style(typeof(NumericAxisLabel));
                hiddenNumericLabelStyle.Setters.Add(new Setter(NumericAxisLabel.VisibilityProperty, Visibility.Collapsed));

                Chart.Series.Add(new AreaSeries()
                {
                    Title                = "Mana",
                    ItemsSource          = manaList,
                    IndependentValuePath = "Time",
                    DependentValuePath   = "Value",
                    DataPointStyle       = (Style)Resources["ManaStyle"],
                    Background           = new SolidColorBrush(Color.FromArgb(0xFF, 0x00, 0xFF, 0xFF)),
                    DependentRangeAxis   = new OffsetLinearAxis()
                    {
                        Minimum            = 0,
                        Offset             = barCount * 10.0,
                        Orientation        = AxisOrientation.Y,
                        AxisLabelStyle     = hiddenNumericLabelStyle,
                        MajorTickMarkStyle = null,
                        MinorTickMarkStyle = null,
                    },
                    IndependentAxis = timeAxis,
                    LegendItemStyle = null,
                });

                maxDps *= 1.1f;
                List <TimeData> list = new List <TimeData>();
                time = 0.0f;
                for (int i = 0; i < sequence.Count; i++)
                {
                    int          index    = sequence[i].Index;
                    VariableType type     = sequence[i].VariableType;
                    float        duration = (float)sequence[i].Duration;
                    Cycle        cycle    = sequence[i].Cycle;
                    CastingState state    = sequence[i].CastingState;
                    float        mps      = (float)sequence[i].Mps;
                    if (sequence[i].IsManaPotionOrGem)
                    {
                        duration = 0;
                    }
                    float dps = 0;
                    if (cycle != null)
                    {
                        dps = (float)cycle.DamagePerSecond;
                    }
                    if (duration > 0)
                    {
                        if (calculations.ManaAdeptBonus > 0)
                        {
                            for (int t = 1; t < 10; t++)
                            {
                                DateTime timet = baseTime + TimeSpan.FromSeconds(time + 0.1f * t * duration);
                                if (cycle != null)
                                {
                                    dps = (float)cycle.GetDamagePerSecond(calculations.ManaAdeptBonus, GetManaAtTime(manaList, timet) / maxMana);
                                }
                                // apply state multipliers
                                if (calculationOptions.DisplaySegmentCooldowns)
                                {
                                    dps *= calculationOptions.GetDamageMultiplier(time, time + duration);
                                }
                                list.Add(new TimeData()
                                {
                                    Time = timet, Value = dps
                                });
                            }
                        }
                        else
                        {
                            // apply state multipliers
                            if (calculationOptions.DisplaySegmentCooldowns)
                            {
                                dps *= calculationOptions.GetDamageMultiplier(time, time + duration);
                            }
                            list.Add(new TimeData()
                            {
                                Time = baseTime + TimeSpan.FromSeconds(time + 0.1f * duration), Value = dps
                            });
                            list.Add(new TimeData()
                            {
                                Time = baseTime + TimeSpan.FromSeconds(time + 0.9f * duration), Value = dps
                            });
                        }
                    }
                    time += duration;
                }

                Chart.Series.Add(new LineSeries()
                {
                    Title                = "Dps",
                    ItemsSource          = list,
                    IndependentValuePath = "Time",
                    DependentValuePath   = "Value",
                    DataPointStyle       = (Style)Resources["DpsStyle"],
                    DependentRangeAxis   = new OffsetLinearAxis()
                    {
                        Offset             = barCount * 10.0,
                        Minimum            = 0,
                        Orientation        = AxisOrientation.Y,
                        AxisLabelStyle     = hiddenNumericLabelStyle,
                        MajorTickMarkStyle = null,
                        MinorTickMarkStyle = null,
                    },
                    IndependentAxis = timeAxis,
                });

                if (zeroLineCanvas == null)
                {
                    zeroLineCanvas          = new ZeroLineCanvas(categoryAxis);
                    zeroLineCanvas.BarCount = barCount;
                }
                else
                {
                    zeroLineCanvas.BarCount = barCount;
                    zeroLineCanvas.Axis     = categoryAxis;
                }

                ISeriesHost host = (ISeriesHost)Chart;
                if (!host.BackgroundElements.Contains(zeroLineCanvas))
                {
                    host.BackgroundElements.Add(zeroLineCanvas);
                }
            }
        }
Example #2
0
        public void UpdateGraph(DisplayCalculations calculations)
        {
            Chart.Series.Clear();
            Chart.Axes.Clear();

            DateTime baseTime = new DateTime(2000, 1, 1, 0, 0, 0);

            List <SpecialEffect> effectList = new List <SpecialEffect>();

            effectList.AddRange(calculations.SpellPowerEffects);
            effectList.AddRange(calculations.IntellectEffects);
            effectList.AddRange(calculations.HasteRatingEffects);
            effectList.AddRange(calculations.MasteryRatingEffects);

            Color[] colors = new Color[] {
                Color.FromArgb(255, 202, 180, 96),
                Color.FromArgb(255, 101, 225, 240),
                Color.FromArgb(255, 0, 4, 3),
                Color.FromArgb(255, 238, 238, 30),
                Color.FromArgb(255, 45, 112, 63),
                Color.FromArgb(255, 121, 72, 210),
                Color.FromArgb(255, 217, 100, 54),
                Color.FromArgb(255, 210, 72, 195),
                Color.FromArgb(255, 206, 189, 191),
                Color.FromArgb(255, 255, 0, 0),
                Color.FromArgb(255, 0, 255, 0),
                Color.FromArgb(255, 0, 0, 255),
            };

            Style dateTimeAxisLabelStyle = new Style(typeof(DateTimeAxisLabel));

            dateTimeAxisLabelStyle.Setters.Add(new Setter(DateTimeAxisLabel.MinutesIntervalStringFormatProperty, "{0:m:ss}"));
            dateTimeAxisLabelStyle.Setters.Add(new Setter(DateTimeAxisLabel.SecondsIntervalStringFormatProperty, "{0:m:ss}"));
            DateTimeAxis timeAxis = new DateTimeAxis()
            {
                //Title = "Time",
                Minimum        = baseTime,
                Maximum        = baseTime + TimeSpan.FromSeconds(calculations.CalculationOptions.FightDuration),
                IntervalType   = DateTimeIntervalType.Seconds,
                AxisLabelStyle = dateTimeAxisLabelStyle,
                Orientation    = AxisOrientation.X,
                ShowGridLines  = true,
                Location       = AxisLocation.Top,
            };

            for (int i = 0; i < effectList.Count; i++)
            {
                float procs    = 0.0f;
                float triggers = 0.0f;
                for (int j = 0; j < calculations.SolutionVariable.Count; j++)
                {
                    if (calculations.Solution[j] > 0)
                    {
                        Cycle c = calculations.SolutionVariable[j].Cycle;
                        if (c != null)
                        {
                            switch (effectList[i].Trigger)
                            {
                            case Trigger.DamageSpellCrit:
                            case Trigger.SpellCrit:
                                triggers += (float)(calculations.Solution[j] * c.Ticks / c.CastTime);
                                procs    += (float)(calculations.Solution[j] * c.CritProcs / c.CastTime);
                                break;

                            case Trigger.DamageSpellHit:
                            case Trigger.SpellHit:
                                triggers += (float)(calculations.Solution[j] * c.Ticks / c.CastTime);
                                procs    += (float)(calculations.Solution[j] * c.HitProcs / c.CastTime);
                                break;

                            case Trigger.SpellMiss:
                                triggers += (float)(calculations.Solution[j] * c.Ticks / c.CastTime);
                                procs    += (float)(calculations.Solution[j] * (1 - c.HitProcs) / c.CastTime);
                                break;

                            case Trigger.DamageSpellCast:
                            case Trigger.SpellCast:
                                if (effectList[i].Stats.HolySummonedDamage > 0)
                                {
                                    triggers += (float)(calculations.Solution[j] * c.CastProcs2 / c.CastTime);
                                    procs    += (float)(calculations.Solution[j] * c.CastProcs2 / c.CastTime);
                                }
                                else
                                {
                                    triggers += (float)(calculations.Solution[j] * c.CastProcs / c.CastTime);
                                    procs    += (float)(calculations.Solution[j] * c.CastProcs / c.CastTime);
                                }
                                break;

                            case Trigger.MageNukeCast:
                                triggers += (float)(calculations.Solution[j] * c.NukeProcs / c.CastTime);
                                procs    += (float)(calculations.Solution[j] * c.NukeProcs / c.CastTime);
                                break;

                            case Trigger.DamageDone:
                            case Trigger.DamageOrHealingDone:
                                triggers += (float)(calculations.Solution[j] * c.DamageProcs / c.CastTime);
                                procs    += (float)(calculations.Solution[j] * c.DamageProcs / c.CastTime);
                                break;

                            case Trigger.DoTTick:
                                triggers += (float)(calculations.Solution[j] * c.DotProcs / c.CastTime);
                                procs    += (float)(calculations.Solution[j] * c.DotProcs / c.CastTime);
                                break;
                            }
                        }
                    }
                }
                float triggerInterval = calculations.CalculationOptions.FightDuration / triggers;
                float triggerChance   = Math.Min(1.0f, procs / triggers);

                int        steps = 200;
                TimeData[] plot  = new TimeData[steps + 1];
                for (int tick = 0; tick <= steps; tick++)
                {
                    float time = tick / (float)steps * calculations.CalculationOptions.FightDuration;
                    plot[tick] = new TimeData()
                    {
                        Time = baseTime + TimeSpan.FromSeconds(time), Value = effectList[i].GetUptimePlot(triggerInterval, triggerChance, 3.0f, time)
                    };
                }

                Style style = new Style(typeof(LineDataPoint));
                style.Setters.Add(new Setter(LineDataPoint.TemplateProperty, Resources["LineDataPointTemplate"]));
                style.Setters.Add(new Setter(LineDataPoint.BackgroundProperty, new SolidColorBrush(colors[i])));
                Chart.Series.Add(new LineSeries()
                {
                    Title                = effectList[i].ToString(),
                    ItemsSource          = plot,
                    IndependentValuePath = "Time",
                    DependentValuePath   = "Value",
                    DataPointStyle       = style,
                    IndependentAxis      = timeAxis,
                });
            }
        }
        public void UpdateGraph(DisplayCalculations calculations)
        {
            Chart.Series.Clear();
            Chart.Axes.Clear();

            DateTime baseTime = new DateTime(2000, 1, 1, 0, 0, 0);

            List<SpecialEffect> effectList = new List<SpecialEffect>();
            effectList.AddRange(calculations.SpellPowerEffects);
            effectList.AddRange(calculations.IntellectEffects);
            effectList.AddRange(calculations.HasteRatingEffects);
            effectList.AddRange(calculations.MasteryRatingEffects);

            Color[] colors = new Color[] {
                        Color.FromArgb(255,202,180,96), 
                        Color.FromArgb(255,101,225,240),
                        Color.FromArgb(255,0,4,3), 
                        Color.FromArgb(255,238,238,30),
                        Color.FromArgb(255,45,112,63), 
                        Color.FromArgb(255,121,72,210), 
                        Color.FromArgb(255,217,100,54), 
                        Color.FromArgb(255,210,72,195), 
                        Color.FromArgb(255,206,189,191), 
                        Color.FromArgb(255,255,0,0), 
                        Color.FromArgb(255,0,255,0), 
                        Color.FromArgb(255,0,0,255), 
                    };

            Style dateTimeAxisLabelStyle = new Style(typeof(DateTimeAxisLabel));
            dateTimeAxisLabelStyle.Setters.Add(new Setter(DateTimeAxisLabel.MinutesIntervalStringFormatProperty, "{0:m:ss}"));
            dateTimeAxisLabelStyle.Setters.Add(new Setter(DateTimeAxisLabel.SecondsIntervalStringFormatProperty, "{0:m:ss}"));
            DateTimeAxis timeAxis = new DateTimeAxis()
            {
                //Title = "Time",
                Minimum = baseTime,
                Maximum = baseTime + TimeSpan.FromSeconds(calculations.CalculationOptions.FightDuration),
                IntervalType = DateTimeIntervalType.Seconds,
                AxisLabelStyle = dateTimeAxisLabelStyle,
                Orientation = AxisOrientation.X,
                ShowGridLines = true,
                Location = AxisLocation.Top,
            };

            for (int i = 0; i < effectList.Count; i++)
            {
                float procs = 0.0f;
                float triggers = 0.0f;
                for (int j = 0; j < calculations.SolutionVariable.Count; j++)
                {
                    if (calculations.Solution[j] > 0)
                    {
                        Cycle c = calculations.SolutionVariable[j].Cycle;
                        if (c != null)
                        {
                            switch (effectList[i].Trigger)
                            {
                                case Trigger.DamageSpellCrit:
                                case Trigger.SpellCrit:
                                    triggers += (float)(calculations.Solution[j] * c.Ticks / c.CastTime);
                                    procs += (float)(calculations.Solution[j] * c.CritProcs / c.CastTime);
                                    break;
                                case Trigger.DamageSpellHit:
                                case Trigger.SpellHit:
                                    triggers += (float)(calculations.Solution[j] * c.Ticks / c.CastTime);
                                    procs += (float)(calculations.Solution[j] * c.HitProcs / c.CastTime);
                                    break;
                                case Trigger.SpellMiss:
                                    triggers += (float)(calculations.Solution[j] * c.Ticks / c.CastTime);
                                    procs += (float)(calculations.Solution[j] * (1 - c.HitProcs) / c.CastTime);
                                    break;
                                case Trigger.DamageSpellCast:
                                case Trigger.SpellCast:
                                    if (effectList[i].Stats.HolySummonedDamage > 0)
                                    {
                                        triggers += (float)(calculations.Solution[j] * c.CastProcs2 / c.CastTime);
                                        procs += (float)(calculations.Solution[j] * c.CastProcs2 / c.CastTime);
                                    }
                                    else
                                    {
                                        triggers += (float)(calculations.Solution[j] * c.CastProcs / c.CastTime);
                                        procs += (float)(calculations.Solution[j] * c.CastProcs / c.CastTime);
                                    }
                                    break;
                                case Trigger.MageNukeCast:
                                    triggers += (float)(calculations.Solution[j] * c.NukeProcs / c.CastTime);
                                    procs += (float)(calculations.Solution[j] * c.NukeProcs / c.CastTime);
                                    break;
                                case Trigger.DamageDone:
                                case Trigger.DamageOrHealingDone:
                                    triggers += (float)(calculations.Solution[j] * c.DamageProcs / c.CastTime);
                                    procs += (float)(calculations.Solution[j] * c.DamageProcs / c.CastTime);
                                    break;
                                case Trigger.DoTTick:
                                    triggers += (float)(calculations.Solution[j] * c.DotProcs / c.CastTime);
                                    procs += (float)(calculations.Solution[j] * c.DotProcs / c.CastTime);
                                    break;
                            }
                        }
                    }
                }
                float triggerInterval = calculations.CalculationOptions.FightDuration / triggers;
                float triggerChance = Math.Min(1.0f, procs / triggers);

                int steps = 200;
                TimeData[] plot = new TimeData[steps + 1];
                for (int tick = 0; tick <= steps; tick++)
                {
                    float time = tick / (float)steps * calculations.CalculationOptions.FightDuration;
                    plot[tick] = new TimeData() { Time = baseTime + TimeSpan.FromSeconds(time), Value = effectList[i].GetUptimePlot(triggerInterval, triggerChance, 3.0f, time) };
                }

                Style style = new Style(typeof(LineDataPoint));
                style.Setters.Add(new Setter(LineDataPoint.TemplateProperty, Resources["LineDataPointTemplate"]));
                style.Setters.Add(new Setter(LineDataPoint.BackgroundProperty, new SolidColorBrush(colors[i])));
                Chart.Series.Add(new LineSeries()
                {
                    Title = effectList[i].ToString(),
                    ItemsSource = plot,
                    IndependentValuePath = "Time",
                    DependentValuePath = "Value",
                    DataPointStyle = style,
                    IndependentAxis = timeAxis,
                });
            }
        }