public override ComparisonCalculationBase[] GetCustomChartData(Character character, string chartName) {
            if (character == null) { return null;}
            Character zeOriginal = character.Clone();
            Character zeClone = character.Clone();
            CharacterCalculationsDPSWarr calculations = GetCharacterCalculations(zeOriginal) as CharacterCalculationsDPSWarr;
            CalculationOptionsDPSWarr calcOpts = zeOriginal.CalculationOptions as CalculationOptionsDPSWarr;
            ((CalculationOptionsPanelDPSWarr)CalculationOptionsPanel).IsLoadingCalculationOptions = true;
            bool[] origMaints = (bool[])calcOpts.MaintenanceTree.Clone();
            DPSWarrCharacter dpswarchar = new DPSWarrCharacter() {
                Char = zeOriginal,
                CalcOpts = (CalculationOptionsDPSWarr)zeOriginal.CalculationOptions,
                BossOpts = zeOriginal.BossOptions,
                CombatFactors = null,
                Rot = null,
            };

            switch (chartName) {
                #region Ability DPS
                case "Ability DPS": {
                    List<ComparisonCalculationBase> comparisons = new List<ComparisonCalculationBase>();
                    foreach (AbilityWrapper aw in calculations.Rot.TheAbilityList)
                    {
                        if (aw.Ability.DamageOnUse == 0) { continue; }
                        ComparisonCalculationDPSWarr comparison = new ComparisonCalculationDPSWarr();
                        comparison.Name = aw.Ability.Name;
                        comparison.Description = aw.Ability.Desc;
                        if (aw.Ability is Skills.Rend) {
                            comparison.DPSPoints = (aw.Ability as Skills.Rend).GetDPS(aw.NumActivatesO20, calculations.Rot.GetWrapper<Skills.ThunderClap>().NumActivatesO20, calculations.Rot.TimeOver20Perc) * calculations.Rot.TimeOver20Perc
                                                 + (aw.Ability as Skills.Rend).GetDPS(aw.NumActivatesU20, calculations.Rot.GetWrapper<Skills.ThunderClap>().NumActivatesU20, calculations.Rot.TimeUndr20Perc) * calculations.Rot.TimeUndr20Perc;
                        } else {
                            comparison.DPSPoints = aw.AllDPS;
                        }
                        comparison.SurvPoints = aw.AllHPS;
                        comparison.ImageSource = aw.Ability.Icon;
                        comparisons.Add(comparison);
                    }
                    foreach (ComparisonCalculationDPSWarr comp in comparisons) {
                        comp.OverallPoints = comp.DPSPoints + comp.SurvPoints;
                    }
                    calcOpts.MaintenanceTree = origMaints;
                    ((CalculationOptionsPanelDPSWarr)CalculationOptionsPanel).IsLoadingCalculationOptions = false;
                    return comparisons.ToArray();
                }
                #endregion
                #region Ability Damage per GCD
                case "Ability Damage per GCD":
                    {
                        List<ComparisonCalculationBase> comparisons = new List<ComparisonCalculationBase>();
                        foreach (AbilityWrapper aw in calculations.Rot.TheAbilityList)
                        {
                            if (aw.Ability.DamageOnUse == 0) { continue; }
                            ComparisonCalculationDPSWarr comparison = new ComparisonCalculationDPSWarr();
                            comparison.Name = aw.Ability.Name;
                            comparison.Description = aw.Ability.Desc;
                            comparison.DPSPoints = (
                                ((aw.Ability is Skills.Rend) ? ((aw.Ability as Skills.Rend).TickSize * (aw.Ability as Skills.Rend).NumTicks)
                                : aw.Ability.DamageOnUse)) / (aw.Ability.GCDTime == 0 ? 1f : (aw.Ability.GCDTime / calculations.Rot.LatentGCD));
                            comparison.SurvPoints = aw.Ability.GetAvgHealingOnUse(aw.AllNumActivates);
                            comparison.ImageSource = aw.Ability.Icon;
                            comparisons.Add(comparison);
                        }
                        foreach (ComparisonCalculationDPSWarr comp in comparisons)
                        {
                            comp.OverallPoints = comp.DPSPoints + comp.SurvPoints;
                        }
                        calcOpts.MaintenanceTree = origMaints;
                        ((CalculationOptionsPanelDPSWarr)CalculationOptionsPanel).IsLoadingCalculationOptions = false;
                        return comparisons.ToArray();
                    }
                #endregion
                #region Ability Maintenance Changes
                case "Ability Maintenance Changes": {
                    List<ComparisonCalculationBase> comparisons = new List<ComparisonCalculationBase>();
                    #region Rage Generators
                    comparisons.Add(getComp(dpswarchar, "Berserker Rage", (int)Maintenance.BerserkerRage));
                    comparisons.Add(getComp(dpswarchar, "Deadly Calm", (int)Maintenance.DeadlyCalm));
                    #endregion
                    #region Maintenance
                    comparisons.Add(getComp(dpswarchar, "Battle Shout", (int)Maintenance.BattleShout));
                    comparisons.Add(getComp(dpswarchar, "Commanding Shout", (int)Maintenance.CommandingShout));
                    comparisons.Add(getComp(dpswarchar, "Demoralizing Shout", (int)Maintenance.DemoralizingShout));
                    comparisons.Add(getComp(dpswarchar, "Sunder Armor", (int)Maintenance.SunderArmor));
                    comparisons.Add(getComp(dpswarchar, "Thunder Clap", (int)Maintenance.ThunderClap));
                    comparisons.Add(getComp(dpswarchar, "Hamstring", (int)Maintenance.Hamstring));
                    #endregion
                    #region Periodics
                    comparisons.Add(getComp(dpswarchar, "Shattering Throw", (int)Maintenance.ShatteringThrow));
                    comparisons.Add(getComp(dpswarchar, "Sweeping Strikes", (int)Maintenance.SweepingStrikes));
                    comparisons.Add(getComp(dpswarchar, "Death Wish", (int)Maintenance.DeathWish));
                    comparisons.Add(getComp(dpswarchar, "Recklessness", (int)Maintenance.Recklessness));
                    comparisons.Add(getComp(dpswarchar, "Enraged Regeneration", (int)Maintenance.EnragedRegeneration));
                    #endregion
                    #region Damage Dealers
                    if (calculations.Rot.GetType() == typeof(FuryRotation)) {
                        #region Fury
                        comparisons.Add(getComp(dpswarchar, "Bloodsurge", (int)Maintenance.Bloodsurge));
                        comparisons.Add(getComp(dpswarchar, "Bloodthirst", (int)Maintenance.Bloodthirst));
//                        comparisons.Add(getComp(dpswarchar, "Whirlwind", (int)Maintenance.Whirlwind));
                        comparisons.Add(getComp(dpswarchar, "Raging Blow", (int)Maintenance.RagingBlow));
                        #endregion
                    } else if (calculations.Rot.GetType() == typeof(ArmsRotation)) {
                        #region Arms
                        comparisons.Add(getComp(dpswarchar, "Bladestorm", (int)Maintenance.Bladestorm));
                        comparisons.Add(getComp(dpswarchar, "Mortal Strike", (int)Maintenance.MortalStrike));
                        comparisons.Add(getComp(dpswarchar, "Rend", (int)Maintenance.Rend));
                        comparisons.Add(getComp(dpswarchar, "Overpower", (int)Maintenance.Overpower));
                        comparisons.Add(getComp(dpswarchar, "Taste for Blood", (int)Maintenance.TasteForBlood));
                        comparisons.Add(getComp(dpswarchar, "Colossus Smash", (int)Maintenance.ColossusSmash));
                        comparisons.Add(getComp(dpswarchar, "Slam", (int)Maintenance.Slam));
                        #endregion
                    }
                    comparisons.Add(getComp(dpswarchar, "<20% Execute Spamming", (int)Maintenance.ExecuteSpam));
                    #endregion
                    #region Rage Dumps
                    comparisons.Add(getComp(dpswarchar, "Heroic Strike", (int)Maintenance.HeroicStrike));
                    comparisons.Add(getComp(dpswarchar, "Cleave", (int)Maintenance.Cleave));
                    comparisons.Add(getComp(dpswarchar, "Inner Rage", (int)Maintenance.InnerRage));
                    #endregion
                    foreach (ComparisonCalculationDPSWarr comp in comparisons) {
                        comp.OverallPoints = comp.DPSPoints + comp.SurvPoints;
                    }
                    calcOpts.MaintenanceTree = origMaints;
                    ((CalculationOptionsPanelDPSWarr)CalculationOptionsPanel).IsLoadingCalculationOptions = false;
                    return comparisons.ToArray();
                }
                #endregion
                #region Rage Cost per Damage
                case "Rage Cost per Damage": {
                    List<ComparisonCalculationBase> comparisons = new List<ComparisonCalculationBase>();
                    float DeepWoundsDamage = calculations.Rot.DW.TickSize * 6f;

                    foreach (AbilityWrapper aw in calculations.Rot.TheAbilityList)
                    {
                        if (aw.Ability.DamageOnUse == 0 || aw.Ability.RageCost == -1f) { continue; }
                        ComparisonCalculationDPSWarr comparison = new ComparisonCalculationDPSWarr();
                        comparison.Name = aw.Ability.Name;
                        comparison.Description = string.Format("Costs {0} Rage\r\n{1}", aw.Ability.RageCost, aw.Ability.Desc);
                        float extraRage = (aw.Ability is Skills.Execute) ? (aw.Ability as Skills.Execute).UsedExtraRage : 0f;
                        float val = (((aw.Ability.RageCost + extraRage) != 0) ? (aw.Ability.RageCost < -1f ? aw.Ability.RageCost * -1f : aw.Ability.RageCost) + extraRage : 1f);
                        if (aw.Ability is Skills.Rend) {
                            comparison.SubPoints[0] = ((aw.Ability as Skills.Rend).TickSize * (aw.Ability as Skills.Rend).NumTicks) / val;
                        } else {
                            comparison.SubPoints[0] = aw.Ability.DamageOnUse / val;
                        }
                        comparison.SubPoints[1] = (aw.Ability.MHAtkTable.Crit * DeepWoundsDamage) / val;
                        comparison.ImageSource = aw.Ability.Icon;
                        comparisons.Add(comparison);
                    }
                    foreach (ComparisonCalculationDPSWarr comp in comparisons) {
                        comp.OverallPoints = comp.SubPoints[0] + comp.SubPoints[1];
                    }
                    calcOpts.MaintenanceTree = origMaints;
                    ((CalculationOptionsPanelDPSWarr)CalculationOptionsPanel).IsLoadingCalculationOptions = false;
                    return comparisons.ToArray();
                }
                #endregion
                #region Execute Spam
                case "Execute Spam": {
                    List<ComparisonCalculationBase> comparisons = new List<ComparisonCalculationBase>();
                    {
                        bool orig = ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpam;
                        bool orig2 = ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpamStage2;
                        ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpam = false;
                        ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpamStage2 = false;
                        //CharacterCalculationsDPSWarr bah = GetCharacterCalculations(zeClone) as CharacterCalculationsDPSWarr;
                        ComparisonCalculationDPSWarr comparison = new ComparisonCalculationDPSWarr();
                        comparison.Name = "Without Execute Spam";
                        comparison.Description = "Turning <20% Execute Spam off on the options pane will change your DPS to this";
                        comparison.SubPoints[0] = GetCharacterCalculations(zeClone).SubPoints[0];
                        comparison.SubPoints[1] = GetCharacterCalculations(zeClone).SubPoints[1];
                        comparison.Equipped = orig == false;
                        comparison.ImageSource = Skills.MortalStrike.SIcon;
                        comparisons.Add(comparison);
                        ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpam = orig;
                        ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpamStage2 = orig2;
                    }
                    {
                        bool orig = ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpam;
                        bool orig2 = ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpamStage2;
                        ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpam = true;
                        ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpamStage2 = false;
                        //CharacterCalculationsDPSWarr bah = GetCharacterCalculations(zeClone) as CharacterCalculationsDPSWarr;
                        ComparisonCalculationDPSWarr comparison = new ComparisonCalculationDPSWarr();
                        comparison.Name = "With Execute Spam";
                        comparison.Description = "Turning <20% Execute Spam on on the options pane will change your DPS to this";
                        comparison.SubPoints[0] = GetCharacterCalculations(zeClone).SubPoints[0];
                        comparison.SubPoints[1] = GetCharacterCalculations(zeClone).SubPoints[1];
                        comparison.Equipped = orig == true && orig2 == false;
                        comparison.ImageSource = Skills.Execute.SIcon;
                        comparisons.Add(comparison);
                        ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpam = orig;
                        ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpamStage2 = orig2;
                    }
                    {
                        bool orig = ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpam;
                        bool orig2 = ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpamStage2;
                        ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpam = true;
                        ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpamStage2 = true;
                        CharacterCalculationsDPSWarr bah = GetCharacterCalculations(zeClone) as CharacterCalculationsDPSWarr;
                        ComparisonCalculationDPSWarr comparison = new ComparisonCalculationDPSWarr();
                        comparison.Name = "With Execute Spam Stage 2";
                        comparison.Description = "Turning <20% Execute Spam on on the options pane AND Enforcing Taste for Blood will change your DPS to this";
                        comparison.SubPoints[0] = GetCharacterCalculations(zeClone).SubPoints[0];
                        comparison.SubPoints[1] = GetCharacterCalculations(zeClone).SubPoints[1];
                        comparison.Equipped = orig == true && orig2 == true;
                        comparison.ImageSource = Skills.TasteForBlood.SIcon;
                        comparisons.Add(comparison);
                        ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpam = orig;
                        ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).M_ExecuteSpamStage2 = orig2;
                    }
                    foreach (ComparisonCalculationDPSWarr comp in comparisons)
                    {
                        comp.OverallPoints = comp.SubPoints[0] + comp.SubPoints[1];
                    }
                    calcOpts.MaintenanceTree = origMaints;
                    ((CalculationOptionsPanelDPSWarr)CalculationOptionsPanel).IsLoadingCalculationOptions = false;
                    return comparisons.ToArray();
                }
                #endregion
                #region PTR Testing
                case "PTR Testing":
                    {
                        List<ComparisonCalculationBase> comparisons = new List<ComparisonCalculationBase>();
                        {
                            bool orig = ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).PtrMode;
                            ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).PtrMode = false;
                            CharacterCalculationsDPSWarr bah = GetCharacterCalculations(zeClone) as CharacterCalculationsDPSWarr;
                            ComparisonCalculationDPSWarr comparison = new ComparisonCalculationDPSWarr();
                            comparison.Name = "Live Mode";
                            comparison.Description = "This makes Thunderclap apply Rend's Initial Damage along with its own.";
                            comparison.SubPoints[0] = GetCharacterCalculations(zeClone).SubPoints[0];
                            comparison.SubPoints[1] = GetCharacterCalculations(zeClone).SubPoints[1];
                            comparison.Equipped = orig == false;
                            comparison.ImageSource = "spell_nature_callstorm";
                            comparisons.Add(comparison);
                            ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).PtrMode = orig;
                        }
                        {
                            bool orig = ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).PtrMode;
                            ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).PtrMode = true;
                            CharacterCalculationsDPSWarr bah = GetCharacterCalculations(zeClone) as CharacterCalculationsDPSWarr;
                            ComparisonCalculationDPSWarr comparison = new ComparisonCalculationDPSWarr();
                            comparison.Name = "PTR Mode";
                            comparison.Description = "This makes Thunderclap NOT apply Rend's Initial Damage along with its own.";
                            comparison.SubPoints[0] = GetCharacterCalculations(zeClone).SubPoints[0];
                            comparison.SubPoints[1] = GetCharacterCalculations(zeClone).SubPoints[1];
                            comparison.Equipped = orig == true;
                            comparison.ImageSource = Skills.Rend.SIcon;
                            comparisons.Add(comparison);
                            ((CalculationOptionsDPSWarr)zeClone.CalculationOptions).PtrMode = orig;
                        }
                        foreach (ComparisonCalculationDPSWarr comp in comparisons)
                        {
                            comp.OverallPoints = comp.SubPoints[0] + comp.SubPoints[1];
                        }
                        calcOpts.MaintenanceTree = origMaints;
                        ((CalculationOptionsPanelDPSWarr)CalculationOptionsPanel).IsLoadingCalculationOptions = false;
                        return comparisons.ToArray();
                    }
                #endregion
                default: { calcOpts.MaintenanceTree = origMaints; return new ComparisonCalculationBase[0]; }
            }
        }
 ComparisonCalculationDPSWarr getComp(DPSWarrCharacter dpswarchar, string Name, int Iter) {
     ComparisonCalculationDPSWarr comparison = new ComparisonCalculationDPSWarr();
     comparison.Name = Name;
     comparison.Equipped = dpswarchar.CalcOpts.MaintenanceTree[Iter] == true;
     float with = getDPS(dpswarchar, Iter, true);
     float without = getDPS(dpswarchar, Iter, false);
     comparison.DPSPoints = with - without;
     with = getSurv(dpswarchar, Iter, true) * dpswarchar.CalcOpts.SurvScale;
     without = getSurv(dpswarchar, Iter, false) * dpswarchar.CalcOpts.SurvScale;
     comparison.SurvPoints = with - without;
     //comparison.ImageSource = aw.ability.Icon; // TODO
     //comparison.Description = aw.ability.Desc; // TODO
     return comparison;
 }