예제 #1
0
 public static float GetSpellCastsPerSec(CharacterCalculationsHealadin calc)
 {
     return(GetHealingCastsPerSec(calc)
            + (calc.RotationBoL / calc.BoL.CastTime()
               + calc.RotationJotP / calc.JotP.CastTime()
               + calc.RotationSS / calc.SS.CastTime()) / calc.FightLength);
 }
예제 #2
0
        public float ManaPool(CharacterCalculationsHealadin calc)
        {
            DivinePleas = (float)Math.Ceiling((FightLength - 120f) / (120f * CalcOpts.DivinePlea));

            calc.ManaBase          = Stats.Mana;
            calc.ManaLayOnHands    = Stats.Mana * ((Talents.GlyphOfDivinity ? 0.1f : 0) * loh.Casts());
            calc.ManaArcaneTorrent = (Character.Race == CharacterRace.BloodElf ? Stats.Mana * .06f * (float)Math.Ceiling(FightLength / 120f - .25f) : 0);
            calc.ManaDivinePlea    = Stats.Mana * (Talents.GlyphOfDivinePlea ? 0.18f : 0.12f) * DivinePleas;
            calc.ManaMp5           = FightLength * Stats.Mp5 / 5f;
            // this Stats.ManaRestoreFromMaxManaPerSecond is 0 is is messing up the replenishment calculation!
            //calc.ManaReplenishment = Stats.ManaRestoreFromMaxManaPerSecond * Stats.Mana * FightLength * CalcOpts.Replenishment;
            calc.ManaReplenishment = 0.001f * Stats.Mana * FightLength * CalcOpts.Replenishment;
            calc.ManaOther        += Stats.ManaRestore;
            // add calc.ManaJudgements
            calc.ManaJudgements = HealadinConstants.basemana * 0.15f * jotp.Casts();
            if (Stats.HighestStat > 0)
            {
                float greatnessMana = Stats.HighestStat * StatConversion.RATING_PER_MANA;
                calc.ManaReplenishment += Stats.ManaRestoreFromMaxManaPerSecond * FightLength * greatnessMana * CalcOpts.Replenishment; // Replenishment
                calc.ManaDivinePlea    += DivinePleas * greatnessMana * .1f;                                                            // Divine Plea
            }

            // check if this is correct regen per 5 seconds..
            // combat regen = 50% of spirit regen (from Meditation), plus MP5 from gear, plus 5% base mana per 5 secs.  Base mana = 23422 at 85
            float effective_spirit = Stats.Spirit + Stats.BonusCritChanceFrostStrike * 540 * 6 / CalcOpts.HolyShock; // add in bonus spirit from 4T11 procs
            float spirit_regen     = StatConversion.GetSpiritRegenSec(effective_spirit, Stats.Intellect) * 5f;

            calc.CombatRegenRate  = spirit_regen * 0.5f + Stats.Mp5 + HealadinConstants.basemana * 0.05f;
            calc.ManaRegenRate    = spirit_regen + Stats.Mp5 + HealadinConstants.basemana * 0.05f;
            calc.CombatRegenTotal = calc.CombatRegenRate * FightLength / 5f;

            return(calc.ManaBase + calc.ManaDivinePlea + calc.CombatRegenTotal + calc.ManaOther +
                   calc.ManaReplenishment + calc.ManaLayOnHands + calc.ManaJudgements);
        }
예제 #3
0
        public override CharacterCalculationsBase GetCharacterCalculations(Character character, Item additionalItem, bool referenceCalculation, bool significantChange, bool needsDisplayCalculations)
        {
            // First things first, we need to ensure that we aren't using bad data
            CharacterCalculationsHealadin calc = new CharacterCalculationsHealadin();

            if (character == null)
            {
                return(calc);
            }
            CalculationOptionsHealadin calcOpts = character.CalculationOptions as CalculationOptionsHealadin;

            if (calcOpts == null)
            {
                return(calc);
            }
            //
            Stats stats;

            calc = null;
            PaladinTalents talents = character.PaladinTalents;

            for (int i = 0; i < 5; i++)
            {
                float oldBurst = 0;
                if (i > 0)
                {
                    oldBurst = calc.BurstPoints;
                }

                stats = GetCharacterStats(character, additionalItem, true, calc);
                calc  = new CharacterCalculationsHealadin();

                Rotation rot = new Rotation(character, stats);

                if (i > 0)
                {
                    calc.BurstPoints = oldBurst;
                }
                else
                {
                    calc.BurstPoints = rot.CalculateBurstHealing(calc);
                }
                calc.FightPoints   = rot.CalculateFightHealing(calc);
                calc.OverallPoints = calc.BurstPoints + calc.FightPoints;
            }
            calc.BasicStats = GetCharacterStats(character, additionalItem, false, null);

            return(calc);
        }
예제 #4
0
        public float ManaPool(CharacterCalculationsHealadin calc)
        {
            DivinePleas = (float)Math.Ceiling((FightLength - 60f) / (60f * CalcOpts.DivinePlea));

            calc.ManaBase          = Stats.Mana;
            calc.ManaLayOnHands    = 1950 * ((Talents.GlyphOfDivinity ? 1 : 0) + (CalcOpts.LoHSelf ? 1 : 0)) * (Talents.GlyphOfDivinity ? 2f : 1f);
            calc.ManaArcaneTorrent = (Character.Race == CharacterRace.BloodElf ? Stats.Mana * .06f * (float)Math.Ceiling(FightLength / 120f - .25f) : 0);
            calc.ManaDivinePlea    = Stats.Mana * .25f * DivinePleas;
            calc.ManaMp5           = FightLength * Stats.Mp5 / 5f;
            calc.ManaReplenishment = Stats.ManaRestoreFromMaxManaPerSecond * Stats.Mana * FightLength * CalcOpts.Replenishment;
            calc.ManaOther        += Stats.ManaRestore;
            if (Stats.HighestStat > 0)
            {
                float greatnessMana = Stats.HighestStat * StatConversion.RATING_PER_MANA;
                calc.ManaReplenishment += Stats.ManaRestoreFromMaxManaPerSecond * FightLength * greatnessMana * CalcOpts.Replenishment; // Replenishment
                calc.ManaDivinePlea    += DivinePleas * greatnessMana * .25f;                                                           // Divine Plea
            }
            return(calc.ManaBase + calc.ManaDivinePlea + calc.ManaMp5 + calc.ManaOther +
                   calc.ManaReplenishment + calc.ManaLayOnHands);
        }
예제 #5
0
 public float CalculateBurstHealing(CharacterCalculationsHealadin calc)
 {
     return(fol.HPS() * CalcOpts.BurstScale);
 }
예제 #6
0
        public float CalculateFightHealing(CharacterCalculationsHealadin calc)
        {
            #region Copying Stuff to Calc
            calc.FightLength = FightLength;

            calc.HL   = hl;
            calc.FoL  = fol;
            calc.HS   = hs;
            calc.DL   = dl;
            calc.WoG  = wog;
            calc.LoD  = lod;
            calc.HR   = hr;
            calc.JotP = jotp;
            calc.BoL  = bol;
            calc.LoH  = loh;
            calc.PotI = poti;
            calc.EJ   = ej;

            calc.JudgeCasts    = jotp.Casts();
            calc.RotationJudge = jotp.Time() + CalcOpts.Userdelay * calc.JudgeCasts;
            calc.UsageJudge    = jotp.Usage();


            if (Talents.BeaconOfLight > 0)
            {
                calc.RotationBoL = bol.Time();
                calc.UsageBoL    = bol.Usage();
            }

            calc.RotationHS = hs.Time() + hs.Casts() + CalcOpts.Userdelay;
            calc.HealedHS   = hs.Healed();
            calc.UsageHS    = hs.Usage();

            calc.RotationLoH = loh.Casts() * (loh.CastTime() + CalcOpts.Userdelay);
            calc.HealedLoH   = loh.Casts() * loh.AverageHealed();
            calc.UsageLoH    = 0f; // always 0, costs no mana, code was: loh.Casts() * loh.BaseMana;

            calc.UsageCleanse    = CalcOpts.Cleanse * cleanse.BaseMana;
            calc.RotationCleanse = CalcOpts.Cleanse * (cleanse.CastTime() + CalcOpts.Userdelay);
            calc.CleanseCasts    = CalcOpts.Cleanse;
            #endregion

            Stats.BonusCritChanceObliterate = CalcOpts.CritOverheals;  // I really need to put some variables in Stats that are for holy pally
            calc.HasteJotP       = Talents.JudgementsOfThePure * 3f;
            calc.HasteSoL        = Talents.SpeedOfLight * 1f;
            calc.SpellPowerTotal = Stats.Intellect + Stats.SpellPower;

            #region Divine Favor - old code, commented out for now

            /*    if (Talents.DivineFavor > 0)
             *  {
             *      DivineFavor df = new DivineFavor(this);
             *      calc.RotationHL += df.Time();
             *      calc.UsageHL += df.Usage();
             *      calc.HealedHL += df.Healed();
             *  } */
            #endregion

            #region active time, remaining mana / time
            float remainingMana = calc.TotalMana = ManaPool(calc);
            remainingMana -= calc.UsageJudge + calc.UsageBoL + calc.UsageHS + calc.UsageHR + calc.UsageCleanse;

            // start with amount of time you are active in a fight
            calc.ActiveTime = FightLength * CalcOpts.Activity;
            float remainingTime = calc.ActiveTime;
            // now subtract time for lots of stuff we need to cast
            remainingTime -= calc.RotationJudge + calc.RotationBoL + calc.RotationHS + calc.RotationLoH + calc.RotationHR + calc.RotationCleanse;
            float RotationDP = DivinePleas * (calc.HS.CastTime() + CalcOpts.Userdelay);
            remainingTime -= RotationDP; // subtract divine plea cast times.  HS is also a GCD, so I just used that to calculate it
            #endregion

            #region HS and holy power
            calc.HolyPowerCasts = hs.Casts() / 3f;
            if (Talents.LightOfDawn != 0)
            {
                calc.LoDCasts = (float)Math.Floor(calc.HolyPowerCasts * CalcOpts.HolyPoints);
                calc.WoGCasts = (float)Math.Floor(calc.HolyPowerCasts * (1f - CalcOpts.HolyPoints));
            }
            else
            {
                calc.WoGCasts = (float)Math.Floor(calc.HolyPowerCasts);
                calc.LoDCasts = 0;
            }
            calc.RotationWoG = calc.WoGCasts * (wog.CastTime() + CalcOpts.Userdelay);
            calc.UsageWoG    = calc.WoGCasts * wog.BaseMana;
            calc.HealedWoG   = calc.WoGCasts * wog.AverageHealed();
            calc.RotationLoD = calc.LoDCasts * (lod.CastTime() + CalcOpts.Userdelay);
            calc.UsageLoD    = calc.LoDCasts * lod.BaseMana;
            calc.HealedLoD   = calc.LoDCasts * lod.AverageHealed() * CalcOpts.LoDTargets;
            remainingTime   -= calc.RotationWoG + calc.RotationLoD;
            #endregion

            #region Holy Radiance
            calc.HRCasts    = (float)Math.Floor(FightLength / CalcOpts.HRCasts);
            calc.RotationHR = calc.HRCasts * (hr.CastTime() + CalcOpts.Userdelay);
            calc.UsageHR    = calc.HRCasts * hr.BaseMana;
            calc.HealedHR   = calc.HRCasts * hr.AverageHealed() * CalcOpts.HREff;
            remainingTime  -= calc.RotationHR;
            #endregion

            #region Melee mana regen
            // Melee hits generate 4% base mana.  From what I read, this proc has a 4 sec CD.  15ppm max.
            float InstantCastRotationTotal = calc.RotationLoD + calc.RotationWoG + calc.RotationHS + calc.RotationHR + calc.RotationJudge + calc.RotationBoL + calc.RotationLoH + calc.RotationCleanse;
            float MeleeTime = InstantCastRotationTotal * CalcOpts.Melee;
            // Ideally the SwingTime would be the weapon speed, then logic would be added to estimate the # of procs.  As the # of swings increases,
            // the number of procs would have dimishing returns.  (because more frequent swings means more swings happen during the 4 sec CD, and don't proc)
            // For now I am going to fudge it and estimate a proc every 5 secs.  Every 4 is unrealistic since 4 is not divisable by weapon speed,
            // so some time is always wasted.  Also consider when one alternates between swings and casts, then each swing would proc.  Whatever, 5 is good enough for now.
            float SwingTime        = 5f;
            float MeleeManaPerProc = HealadinConstants.basemana * 0.04f;
            // calc.MeleeSwings = MeleeTime / SwingTime;
            calc.MeleeProcs = MeleeTime / SwingTime; // find a way to model this better, as swings approaches MaxMeleeProcs, it should have diminishing returns somehow
            calc.ManaMelee  = calc.MeleeProcs * MeleeManaPerProc;
            remainingMana  += calc.ManaMelee;
            calc.TotalMana += calc.ManaMelee;
            #endregion Melee mana regen

            #region Filler casts
            // now that we did everything from the options panel, fill in the rest of the available cast time
            // we will use Holy Light to fill in the time.  If we still have mana left, we will replace Holy Light casts with Divine Light, until we run out of mana.
            // Note, when I kept the filler casts to whole numbers, Haste was not valued.  Trying the other way to see how haste is valued then.
            // DL and HL have the same casttime, so lets just figure max number of casts with time remaining
            float IoLprocs = hs.Casts() * Talents.InfusionOfLight * hs.ChanceToCrit(); // Infusion of Light procs - -0.75 sec to next HL or DL casttime per point
            remainingTime += IoLprocs * 0.75f;                                         // assuming we will be casting at least a few HL or DL, and can cast them when IoL procs, before next HS cast
            float fill_casts = /*(float)Math.Floor*/ (remainingTime / (hl.CastTime() + CalcOpts.Userdelay));
            calc.HLCasts  = 0;                                                         // Holy Light
            calc.DLCasts  = 0;                                                         // Divine Light
            calc.FoLCasts = 0;
            float mana_fill_hl = fill_casts * hl.BaseMana;
            float mana_fill_dl = fill_casts * dl.BaseMana;
            if (remainingMana < mana_fill_hl) // if you would run out of mana just casting Holy Light
            {                                 // then figure out how many Holy Lights you can cast
                // calc.HLCasts = /*(float)Math.Floor*/(remainingMana / hl.BaseMana);
                float timeleft = calc.HLCasts * (hl.CastTime() + +CalcOpts.Userdelay);
                float MeleeMPS = calc.MeleeProcs / MeleeManaPerProc;
                calc.HLCasts   = ((remainingMana / (hl.MPS() - MeleeMPS) / hl.CastTime())); // use time to spare to melee for more mana, for more HL casts
                remainingTime -= calc.HLCasts * (hl.CastTime() + +CalcOpts.Userdelay);
                float moremeleemana = remainingTime / SwingTime * MeleeManaPerProc;
                calc.RotationMelee = remainingTime;
                calc.MeleeProcs   += remainingTime / SwingTime;
                calc.ManaMelee    += moremeleemana;
                calc.TotalMana    += moremeleemana;
            }
            else if (remainingMana < mana_fill_dl)         // else if you would run out of mana just casting Divine Light
            {
                remainingMana -= fill_casts * hl.BaseMana; // how much mana do we have to spare if we casts all Holy Lights
                calc.DLCasts   = /*(float)Math.Floor*/ (remainingMana / (dl.BaseMana - hl.BaseMana));
                calc.HLCasts   = fill_casts - calc.DLCasts;
            }
            else                                                // my God, you have a crapton of mana, start casting Flash of Light
            {
                calc.DLCasts   = (IoLprocs * 0.75f) / dl.CastTime();
                remainingTime -= IoLprocs * 0.75f;
                remainingMana -= calc.DLCasts * dl.BaseMana;
                remainingMana -= fill_casts * dl.BaseMana;       // how much mana do we have to spare if we casts all Divine Lights
                calc.FoLCasts  = /*(float)Math.Floor*/ ((remainingMana / (fol.MPS() - dl.MPS()) / fol.CastTime()));
                if (calc.FoLCasts > (remainingTime / (fol.CastTime() + CalcOpts.Userdelay)))
                {
                    calc.FoLCasts = remainingTime / (fol.CastTime() + CalcOpts.Userdelay);
                }
                remainingTime -= calc.FoLCasts * (fol.CastTime() + CalcOpts.Userdelay);
                calc.DLCasts  += /*(float)Math.Floor*/ (remainingTime / (dl.CastTime() + CalcOpts.Userdelay));
            }

            calc.RotationHL  = calc.HLCasts * (hl.CastTime() + CalcOpts.Userdelay);
            calc.UsageHL     = calc.HLCasts * hl.BaseMana;
            calc.HealedHL    = calc.HLCasts * hl.AverageHealed();
            calc.RotationDL  = calc.DLCasts * (dl.CastTime() + CalcOpts.Userdelay);
            calc.UsageDL     = calc.DLCasts * dl.BaseMana;
            calc.HealedDL    = calc.DLCasts * dl.AverageHealed();
            calc.RotationFoL = calc.FoLCasts * (fol.CastTime() + CalcOpts.Userdelay);
            calc.UsageFoL    = calc.FoLCasts * fol.BaseMana;
            calc.HealedFoL   = calc.FoLCasts * fol.AverageHealed();
            if (calc.RotationHL > (IoLprocs * 0.75f))
            {
                calc.RotationHL -= IoLprocs * 0.75f;
            }
            else if (calc.RotationDL > (IoLprocs * 0.75f))
            {
                calc.RotationDL -= IoLprocs * 0.75f;
            }
            #endregion Filler Casts

            #region Conviction
            // does enlightened judgements crit seperately from judgement?  does it count towards conviction proc?
            // does Protector of the Innocent crit seperately?  does it count towards conviction proc?
            // I'm assuming yes for all these questions for now.
            // Frankly this was my first pass at modeling Conviction.  It's far from perfect, but the results are
            // in the same ballpark as combatlogs, and should be somewhat accurate in this talent's effect on
            // the value of crit.

            float ConvictionUptime;  // time having 3 stacks up
            float ConvictionCasts = 2f * (calc.HLCasts + calc.DLCasts + calc.FoLCasts +
                                          calc.WoGCasts + calc.JudgeCasts + calc.HSCasts) + calc.LoHCasts +
                                    calc.LoDCasts * CalcOpts.LoDTargets * (5f + (Talents.GlyphOfLightOfDawn ? 1f : 0f)) +
                                    calc.MeleeSwings;
            float CastsPerSec = ConvictionCasts / ActiveTime;
            // Average crit chance is for all spells.  Start with spellcrit, then add extra for each spell.
            float AverageCritChance = Stats.SpellCrit +
                                      (hs.Casts() / ConvictionCasts * (hs.ChanceToCrit() - Stats.SpellCrit)) +
                                      (calc.HLCasts / ConvictionCasts * (hl.ChanceToCrit() - Stats.SpellCrit));
            float ChancePerCastToDrop = (float)Math.Pow((1 - AverageCritChance), (CastsPerSec * 15));

            float FullStackTime =                                         // average time we keep 3 stacks once we have it
                                                                          // might not be the best way, but for now using the time to get to 60% chance the stack has dropped
                                                                          // considering the tail 40% can take very long to drop potentially, pulling the median out past 50%
                                                                          // combat logs show this is the correct ballpark
                                  1f / CastsPerSec * (float)Math.Log(0.4f, (1f - ChancePerCastToDrop));
            float AverageStackBuildTime =                                 // average time to build from 0 to 3 stacks
                                          1f / CastsPerSec *
                                          (3 / AverageCritChance);        // time to get 3 stacks, assuming you dont drop the stack along the way
            // now should add time for if stacks drop along the way
            float StackBuilds =                                           // number of times we will build the stack in the fight
                                1 + (ActiveTime - AverageStackBuildTime) / (AverageStackBuildTime + FullStackTime);
            ConvictionUptime = StackBuilds * AverageStackBuildTime / 3f + // lets count stack builds as having 1 stack on average for now
                               (StackBuilds - 1f) * FullStackTime;
            float ConvictionBuff = 1f + ConvictionUptime / ActiveTime * 0.03f * Talents.Conviction;

            calc.HealedHL  *= ConvictionBuff;
            calc.HealedDL  *= ConvictionBuff;
            calc.HealedFoL *= ConvictionBuff;
            calc.HealedHS  *= ConvictionBuff;
            calc.HealedWoG *= ConvictionBuff;
            calc.HealedLoD *= ConvictionBuff;
            calc.HealedLoH *= ConvictionBuff;

            #endregion Conviction

            #region Talent heals: Enlightened Judgement, Protector of the Innocent, Illuminated healing, Beacon
            // Enlightened Judgement talent heals
            calc.HealedJudge = calc.JudgeCasts * ej.AverageHealed() * ConvictionBuff;

            // Protector of the Innocent
            calc.PotICasts  = fill_casts + calc.WoGCasts + calc.LoDCasts + calc.LoHCasts + calc.HSCasts;
            calc.HealedPotI = calc.PotICasts * poti.AverageHealed() * ConvictionBuff;

            calc.UsageTotal = calc.UsageFoL + calc.UsageDL + calc.UsageHL + calc.UsageLoD + calc.UsageWoG +
                              calc.UsageHS + calc.UsageHR + calc.UsageJudge + calc.UsageBoL + calc.UsageCleanse;
            calc.RotationTotal = calc.RotationFoL + calc.RotationDL + calc.RotationHL + calc.RotationLoD + calc.RotationWoG + calc.RotationHS +
                                 calc.RotationHR + calc.RotationJudge + calc.RotationBoL + calc.RotationLoH + calc.RotationCleanse + calc.RotationMelee
                                 + RotationDP;

            // Illumnated Healing
            calc.HealedIH    = calc.HealedFoL + calc.HealedHL + calc.HealedHS + calc.HealedWoG + calc.HealedLoD + calc.HealedDL;
            calc.TotalHealed = calc.HealedIH + calc.HealedPotI + calc.HealedJudge;
            // BoL doesn't use LoH, but Illuminated healing does - so add LoH to IH and do final IH calcs
            calc.HealedIH += calc.HealedLoH;
            calc.HealedIH *= CalcOpts.IHEff * (0.12f + ((8 + Stats.MasteryRating / 179.28f) * 0.015f));

            // Beacon of Light
            calc.HealedBoL = bol.HealingDone(calc.TotalHealed + calc.HealedHL);   // added HL heals again to reflect 4.2 change, where HL transferes 100% to beacon target, rather than 50% for everything else
            #endregion


            // adding Holy Radiance and LoH after BoL calculation, as they do not count towards BoL heals
            calc.TotalHealed += calc.HealedHR + calc.HealedLoH + calc.HealedIH + calc.HealedBoL;

            calc.HealedOther  = Stats.Healed + Stats.HealedPerSP * calc.SpellPowerTotal;
            calc.HealedOther += calc.TotalHealed * Stats.ShieldFromHealedProc;

            calc.TotalHealed += calc.HealedOther;

            calc.AvgHPS = calc.TotalHealed / FightLength;
            calc.AvgHPM = calc.TotalHealed / calc.TotalMana;

            return(calc.AvgHPS * (1f - CalcOpts.BurstScale));
        }
예제 #7
0
        public override ComparisonCalculationBase[] GetCustomChartData(Character character, string chartName)
        {
            CharacterCalculationsHealadin calc = GetCharacterCalculations(character) as CharacterCalculationsHealadin;

            if (calc == null)
            {
                calc = new CharacterCalculationsHealadin();
            }
            ComparisonCalculationHealadin FoL  = new ComparisonCalculationHealadin("Flash of Light");
            ComparisonCalculationHealadin HL11 = new ComparisonCalculationHealadin("Holy Light 11");
            ComparisonCalculationHealadin HL10 = new ComparisonCalculationHealadin("Holy Light 10");
            ComparisonCalculationHealadin HL9  = new ComparisonCalculationHealadin("Holy Light 9");
            ComparisonCalculationHealadin HL8  = new ComparisonCalculationHealadin("Holy Light 8");
            ComparisonCalculationHealadin HL7  = new ComparisonCalculationHealadin("Holy Light 7");
            ComparisonCalculationHealadin HL6  = new ComparisonCalculationHealadin("Holy Light 6");
            ComparisonCalculationHealadin HL5  = new ComparisonCalculationHealadin("Holy Light 5");
            ComparisonCalculationHealadin HL4  = new ComparisonCalculationHealadin("Holy Light 4");

            CalculationOptionsHealadin calcOpts = character.CalculationOptions as CalculationOptionsHealadin;

            if (calcOpts == null)
            {
                calcOpts = new CalculationOptionsHealadin();
            }

            calc[0] = new Spell("Flash of Light", 7, calcOpts.BoL);
            calc[1] = new Spell("Holy Light", 11, calcOpts.BoL);
            calc[2] = new Spell("Holy Light", 10, calcOpts.BoL);
            calc[3] = new Spell("Holy Light", 9, calcOpts.BoL);
            calc[4] = new Spell("Holy Light", 8, calcOpts.BoL);
            calc[5] = new Spell("Holy Light", 7, calcOpts.BoL);
            calc[6] = new Spell("Holy Light", 6, calcOpts.BoL);
            calc[7] = new Spell("Holy Light", 5, calcOpts.BoL);
            calc[8] = new Spell("Holy Light", 4, calcOpts.BoL);

            switch (chartName)
            {
            case "Healing per second":
                FoL.OverallPoints  = FoL.ThroughputPoints = calc[0].Hps;
                HL11.OverallPoints = HL11.ThroughputPoints = calc[1].Hps;
                HL10.OverallPoints = HL10.ThroughputPoints = calc[2].Hps;
                HL9.OverallPoints  = HL9.ThroughputPoints = calc[3].Hps;
                HL8.OverallPoints  = HL8.ThroughputPoints = calc[4].Hps;
                HL7.OverallPoints  = HL7.ThroughputPoints = calc[5].Hps;
                HL6.OverallPoints  = HL6.ThroughputPoints = calc[6].Hps;
                HL5.OverallPoints  = HL5.ThroughputPoints = calc[7].Hps;
                HL4.OverallPoints  = HL4.ThroughputPoints = calc[8].Hps;
                break;

            case "Average heal":
                FoL.OverallPoints  = FoL.ThroughputPoints = calc[0].AverageHeal;
                HL11.OverallPoints = HL11.ThroughputPoints = calc[1].AverageHeal;
                HL10.OverallPoints = HL10.ThroughputPoints = calc[2].AverageHeal;
                HL9.OverallPoints  = HL9.ThroughputPoints = calc[3].AverageHeal;
                HL8.OverallPoints  = HL8.ThroughputPoints = calc[4].AverageHeal;
                HL7.OverallPoints  = HL7.ThroughputPoints = calc[5].AverageHeal;
                HL6.OverallPoints  = HL6.ThroughputPoints = calc[6].AverageHeal;
                HL5.OverallPoints  = HL5.ThroughputPoints = calc[7].AverageHeal;
                HL4.OverallPoints  = HL4.ThroughputPoints = calc[8].AverageHeal;
                break;

            case "Healing per mana":
                FoL.OverallPoints  = FoL.LongevityPoints = calc[0].Hpm;
                HL11.OverallPoints = HL11.LongevityPoints = calc[1].Hpm;
                HL10.OverallPoints = HL10.LongevityPoints = calc[2].Hpm;
                HL9.OverallPoints  = HL9.LongevityPoints = calc[3].Hpm;
                HL8.OverallPoints  = HL8.LongevityPoints = calc[4].Hpm;
                HL7.OverallPoints  = HL7.LongevityPoints = calc[5].Hpm;
                HL6.OverallPoints  = HL6.LongevityPoints = calc[6].Hpm;
                HL5.OverallPoints  = HL5.LongevityPoints = calc[7].Hpm;
                HL4.OverallPoints  = HL4.LongevityPoints = calc[8].Hpm;
                break;

            case "Mana per second":
                FoL.OverallPoints  = FoL.LongevityPoints = calc[0].Mps;
                HL11.OverallPoints = HL11.LongevityPoints = calc[1].Mps;
                HL10.OverallPoints = HL10.LongevityPoints = calc[2].Mps;
                HL9.OverallPoints  = HL9.LongevityPoints = calc[3].Mps;
                HL8.OverallPoints  = HL8.LongevityPoints = calc[4].Mps;
                HL7.OverallPoints  = HL7.LongevityPoints = calc[5].Mps;
                HL6.OverallPoints  = HL6.LongevityPoints = calc[6].Mps;
                HL5.OverallPoints  = HL5.LongevityPoints = calc[7].Mps;
                HL4.OverallPoints  = HL4.LongevityPoints = calc[8].Mps;
                break;
            }

            return(new ComparisonCalculationBase[] { FoL, HL11, HL10, HL9, HL8, HL7, HL6, HL5, HL4 });
        }
예제 #8
0
 public float CalculateBurstHealing(CharacterCalculationsHealadin calc)
 {
     return fol.HPS() * CalcOpts.BurstScale;
 }
예제 #9
0
 public static float GetHealingCritsPerSec(CharacterCalculationsHealadin calc)
 {
     return (calc.RotationHL / calc.HL.CastTime() * calc.HL.ChanceToCrit()
         + calc.RotationFoL / calc.FoL.CastTime() * calc.FoL.ChanceToCrit()
         + calc.RotationHS / calc.HS.CastTime() * calc.HS.ChanceToCrit()) / calc.FightLength;
 }
예제 #10
0
 public static float GetSpellCastsPerSec(CharacterCalculationsHealadin calc)
 {
     return GetHealingCastsPerSec(calc)
         + (calc.RotationBoL / calc.BoL.CastTime()
         + calc.RotationJudge / calc.JotP.CastTime()) / calc.FightLength;
 }
예제 #11
0
        public override ComparisonCalculationBase[] GetCustomChartData(Character character, string chartName)

        {
            if (chartName == "Mana Pool Breakdown (needs updating)")
            {
                CharacterCalculationsHealadin calc = GetCharacterCalculations(character) as CharacterCalculationsHealadin;
                if (calc == null) calc = new CharacterCalculationsHealadin();

                ComparisonCalculationHealadin Base = new ComparisonCalculationHealadin("Base");
                ComparisonCalculationHealadin Mp5 = new ComparisonCalculationHealadin("Mp5");
                ComparisonCalculationHealadin Replenishment = new ComparisonCalculationHealadin("Replenishment");
                ComparisonCalculationHealadin ArcaneTorrent = new ComparisonCalculationHealadin("Arcane Torrent");
                ComparisonCalculationHealadin DivinePlea = new ComparisonCalculationHealadin("Divine Plea");
                ComparisonCalculationHealadin LoH = new ComparisonCalculationHealadin("Lay on Hands");
                ComparisonCalculationHealadin Other = new ComparisonCalculationHealadin("Potion & Other");

                Base.OverallPoints = Base.ThroughputPoints = calc.ManaBase;
                Mp5.OverallPoints = Mp5.ThroughputPoints = calc.ManaMp5;
                LoH.OverallPoints = LoH.ThroughputPoints = calc.ManaLayOnHands;
                Replenishment.OverallPoints = Replenishment.ThroughputPoints = calc.ManaReplenishment;
                ArcaneTorrent.OverallPoints = ArcaneTorrent.ThroughputPoints = calc.ManaArcaneTorrent;
                DivinePlea.OverallPoints = DivinePlea.ThroughputPoints = calc.ManaDivinePlea;
                Other.OverallPoints = Other.ThroughputPoints = calc.ManaOther;

                return new ComparisonCalculationBase[] { Base, Mp5, Replenishment, LoH, ArcaneTorrent, DivinePlea, Other };
            }
            else if (chartName == "Mana Usage Breakdown (needs updating)")
            {
                CharacterCalculationsHealadin calc = GetCharacterCalculations(character) as CharacterCalculationsHealadin;
                if (calc == null) calc = new CharacterCalculationsHealadin();

                ComparisonCalculationHealadin FoL = new ComparisonCalculationHealadin("Flash of Light");
                ComparisonCalculationHealadin HL = new ComparisonCalculationHealadin("Holy Light");
                ComparisonCalculationHealadin HS = new ComparisonCalculationHealadin("Holy Shock");
                ComparisonCalculationHealadin JotP = new ComparisonCalculationHealadin("Judgements and Seals");
                ComparisonCalculationHealadin BoL = new ComparisonCalculationHealadin("Beacon of Light");

                FoL.OverallPoints = FoL.ThroughputPoints = calc.UsageFoL;
                HL.OverallPoints = HL.ThroughputPoints = calc.UsageHL;
                HS.OverallPoints = HS.ThroughputPoints = calc.UsageHS;
                JotP.OverallPoints = JotP.ThroughputPoints = calc.UsageJudge;
                BoL.OverallPoints = BoL.ThroughputPoints = calc.UsageBoL;

                return new ComparisonCalculationBase[] { FoL, HL, HS, JotP, BoL };
            }
            else if (chartName == "Healing Breakdown (needs updating)")
            {
                CharacterCalculationsHealadin calc = GetCharacterCalculations(character) as CharacterCalculationsHealadin;
                if (calc == null) calc = new CharacterCalculationsHealadin();

                ComparisonCalculationHealadin FoL = new ComparisonCalculationHealadin("Flash of Light");
                ComparisonCalculationHealadin HL = new ComparisonCalculationHealadin("Holy Light");
                ComparisonCalculationHealadin HS = new ComparisonCalculationHealadin("Holy Shock");
                ComparisonCalculationHealadin GHL = new ComparisonCalculationHealadin("Glyph of Holy Light");
                ComparisonCalculationHealadin BoL = new ComparisonCalculationHealadin("Beacon of Light");

                FoL.OverallPoints = FoL.ThroughputPoints = calc.HealedFoL / calc.FightLength;
                HL.OverallPoints = HL.ThroughputPoints = calc.HealedHL / calc.FightLength;
                HS.OverallPoints = HS.ThroughputPoints = calc.HealedHS / calc.FightLength;
                GHL.OverallPoints = GHL.ThroughputPoints = calc.HealedGHL / calc.FightLength;
                BoL.OverallPoints = BoL.ThroughputPoints = calc.HealedBoL / calc.FightLength;

                return new ComparisonCalculationBase[] { FoL, HL, HS, GHL, BoL };
            }
            else if (chartName == "Rotation Breakdown (needs updating)")
            {
                CharacterCalculationsHealadin calc = GetCharacterCalculations(character) as CharacterCalculationsHealadin;
                if (calc == null) calc = new CharacterCalculationsHealadin();

                ComparisonCalculationHealadin FoL = new ComparisonCalculationHealadin("Flash of Light");
                ComparisonCalculationHealadin HL = new ComparisonCalculationHealadin("Holy Light");
                ComparisonCalculationHealadin HS = new ComparisonCalculationHealadin("Holy Shock");
                ComparisonCalculationHealadin JotP = new ComparisonCalculationHealadin("Judgements and Seals");
                ComparisonCalculationHealadin BoL = new ComparisonCalculationHealadin("Beacon of Light");

                FoL.OverallPoints = FoL.ThroughputPoints = calc.RotationFoL;
                HL.OverallPoints = HL.ThroughputPoints = calc.RotationHL;
                HS.OverallPoints = HS.ThroughputPoints = calc.RotationHS;
                JotP.OverallPoints = JotP.ThroughputPoints = calc.RotationJudge;
                BoL.OverallPoints = BoL.ThroughputPoints = calc.RotationBoL;

                return new ComparisonCalculationBase[] { FoL, HL, HS, JotP, BoL };
            }
            
            return new ComparisonCalculationBase[] {};
        }
예제 #12
0
        public Stats GetCharacterStats(Character character, Item additionalItem, bool computeAverageStats, CharacterCalculationsHealadin calc)
        {
            PaladinTalents talents = character.PaladinTalents;

            CalculationOptionsHealadin calcOpts = character.CalculationOptions as CalculationOptionsHealadin;

            if (calcOpts == null)
            {
                calcOpts = new CalculationOptionsHealadin();
            }

#if (RAWR3)
            BossOptions bossOpts = character.BossOptions;
            if (bossOpts == null)
            {
                bossOpts = new BossOptions();
            }
#endif

#if (RAWR3)
            float fightLength = bossOpts.BerserkTimer * 60f;
#else
            float fightLength = calcOpts.Length * 60f;
#endif

            Stats statsRace     = BaseStats.GetBaseStats(character.Level, CharacterClass.Paladin, character.Race);
            Stats statsBaseGear = GetItemStats(character, additionalItem);
            Stats statsBuffs    = GetBuffsStats(character, calcOpts);
            Stats stats         = statsBaseGear + statsBuffs + statsRace;

            ConvertRatings(stats, talents, calcOpts);
            if (computeAverageStats)
            {
                Stats statsAverage = new Stats();

                foreach (SpecialEffect effect in stats.SpecialEffects())
                {
                    float trigger = 0f;
                    if (calc == null)
                    {
                        trigger = 1.5f / calcOpts.Activity / (1f + stats.SpellHaste);
                        if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit)
                        {
                            trigger *= stats.SpellCrit;
                        }
                        else if (effect.Trigger == Trigger.HolyShockCast)
                        {
                            trigger = 6f / calcOpts.HolyShock;
                        }
                    }
                    else
                    {
                        if (effect.Trigger == Trigger.HealingSpellCast || effect.Trigger == Trigger.HealingSpellHit)
                        {
                            trigger = 1f / Rotation.GetHealingCastsPerSec(calc);
                        }
                        else if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit)
                        {
                            trigger = 1f / Rotation.GetHealingCritsPerSec(calc);
                        }
                        else if (effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit)
                        {
                            trigger = 1f / Rotation.GetSpellCastsPerSec(calc);
                        }
                        else if (effect.Trigger == Trigger.DamageOrHealingDone)
                        {
                            trigger = 1f / Rotation.GetHealingCastsPerSec(calc);
                        }
                        else if (effect.Trigger == Trigger.HolyShockCast)
                        {
                            trigger = 6f / calcOpts.HolyShock;
                        }
                        else if (effect.Trigger == Trigger.Use)
                        {
                            trigger = 0f;
                            foreach (SpecialEffect childEffect in effect.Stats.SpecialEffects())
                            {
                                float childTrigger = 0f;

                                if (effect.Trigger == Trigger.HealingSpellCast || effect.Trigger == Trigger.HealingSpellHit)
                                {
                                    childTrigger = 1f / Rotation.GetHealingCastsPerSec(calc);
                                }
                                else if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit)
                                {
                                    childTrigger = 1f / Rotation.GetHealingCritsPerSec(calc);
                                }
                                else if (effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit)
                                {
                                    childTrigger = 1f / Rotation.GetSpellCastsPerSec(calc);
                                }

                                statsAverage.Accumulate(childEffect.Stats,
                                                        effect.GetAverageUptime(0.0f, 1.0f)
                                                        * childEffect.GetAverageStackSize(childTrigger, 1f, 1.5f, effect.Duration));
                            }
                        }
                        else if (effect.Trigger == Trigger.HolyLightCast)
                        {
                            trigger = 1f / Rotation.GetHolyLightCastsPerSec(calc);
                        }
                        else
                        {
                            continue;
                        }
                    }
                    statsAverage.Accumulate(effect.GetAverageStats(trigger, 1f, 1.5f, fightLength));
                }
                statsAverage.ManaRestore *= fightLength;
                statsAverage.Healed      *= fightLength;

                stats = statsBaseGear + statsBuffs + statsRace + statsAverage;
                ConvertRatings(stats, talents, calcOpts);
            }

            return(stats);
        }
예제 #13
0
        public Stats GetCharacterStats(Character character, Item additionalItem, bool computeAverageStats, CharacterCalculationsHealadin calc)
        {
            CalculationOptionsHealadin calcOpts = character.CalculationOptions as CalculationOptionsHealadin;
            BossOptions    bossOpts             = character.BossOptions;
            PaladinTalents talents = character.PaladinTalents;

            float fightLength = bossOpts.BerserkTimer;

            Stats statsRace     = BaseStats.GetBaseStats(character.Level, CharacterClass.Paladin, character.Race);
            Stats statsBaseGear = GetItemStats(character, additionalItem);
            Stats statsBuffs    = GetBuffsStats(character, calcOpts);
            Stats stats         = statsBaseGear + statsBuffs + statsRace;

            ConvertRatings(stats, talents, calcOpts);
            if (computeAverageStats)
            {
                Stats statsAverage = new Stats();

                foreach (SpecialEffect effect in stats.SpecialEffects())
                {
                    float trigger = 0f;
                    if (calc == null)
                    {
                        trigger = 1.5f / calcOpts.Activity / (1f + stats.SpellHaste);
                        if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit)
                        {
                            trigger *= stats.SpellCrit;
                        }
                    }
                    else
                    {
                        if (effect.Trigger == Trigger.HealingSpellCast || effect.Trigger == Trigger.HealingSpellHit)
                        {
                            trigger = 1f / Rotation.GetHealingCastsPerSec(calc);
                        }
                        else if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit)
                        {
                            trigger = 1f / Rotation.GetHealingCritsPerSec(calc);
                        }
                        else if (effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit)
                        {
                            trigger = 1f / Rotation.GetSpellCastsPerSec(calc);
                        }
                        else if (effect.Trigger == Trigger.DamageOrHealingDone)
                        {
                            trigger = 1f / Rotation.GetHealingCastsPerSec(calc);
                        }
                        else if (effect.Trigger == Trigger.Use)
                        {
                            trigger = 0f;
                            foreach (SpecialEffect childEffect in effect.Stats.SpecialEffects())
                            {
                                float childTrigger = 0f;

                                if (effect.Trigger == Trigger.HealingSpellCast || effect.Trigger == Trigger.HealingSpellHit)
                                {
                                    childTrigger = 1f / Rotation.GetHealingCastsPerSec(calc);
                                }
                                else if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit)
                                {
                                    childTrigger = 1f / Rotation.GetHealingCritsPerSec(calc);
                                }
                                else if (effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit)
                                {
                                    childTrigger = 1f / Rotation.GetSpellCastsPerSec(calc);
                                }

                                statsAverage.Accumulate(childEffect.Stats,
                                                        effect.GetAverageUptime(0.0f, 1.0f)
                                                        * childEffect.GetAverageStackSize(childTrigger, 1f, 1.5f, effect.Duration));
                            }
                        }
                        else
                        {
                            continue;
                        }
                    }
                    statsAverage.Accumulate(effect.GetAverageStats(trigger, 1f, 1.5f, fightLength));
                }
                statsAverage.ManaRestore *= fightLength;
                statsAverage.Healed      *= fightLength;
                statsAverage.HealedPerSP *= fightLength;

                stats = statsBaseGear + statsBuffs + statsRace + statsAverage;
                ConvertRatings(stats, talents, calcOpts);
            }

            #region Set Bonuses
            int T11Count;
            character.SetBonusCount.TryGetValue("Reinforced Sapphirium Regalia", out T11Count);
            stats.BonusCritChanceDeathCoil   = 0; // using this for Holy Light crit bonus, for now
            stats.BonusCritChanceFrostStrike = 0; // yes, I'm pure evil, using this to track 4T11
            if (T11Count >= 2)
            {
                // T11 Pally 2 piece bonus: add 5% crit to HL
                stats.BonusCritChanceDeathCoil = 0.05f;
            }
            if (T11Count >= 4)
            {
                // T11 Pally 4 piece bonus: 540 spirit buff for 6 secs after HS cast
                stats.BonusCritChanceFrostStrike = 1;
            }
            #endregion Set Bonuses

            return(stats);
        }
예제 #14
0
        public float CalculateFightHealing(CharacterCalculationsHealadin calc)
        {
            float fol_BaseHealed = 0f;

            #region Copying Stuff to Calc
            calc.FightLength = FightLength;

            calc.HL   = hl;
            calc.FoL  = fol;
            calc.HS   = hs;
            calc.SS   = ss;
            calc.JotP = jotp;
            calc.BoL  = bol;

            calc.RotationJotP = jotp.Time();
            calc.UsageJotP    = jotp.Usage();

            calc.RotationSS = ss.Time();
            calc.UsageSS    = ss.Usage();
            calc.HealedSS   = ss.TotalAborb();

            calc.RotationBoL = bol.Time();
            calc.UsageBoL    = bol.Usage();

            calc.RotationHS = hs.Time();
            calc.HealedHS   = hs.Healed();
            calc.UsageHS    = hs.Usage();
            #endregion

            #region Divine Illumination
            if (Talents.DivineIllumination > 0)
            {
                DivineIllumination di = new DivineIllumination(this);
                calc.RotationHL += di.Time();
                calc.UsageHL    += di.Usage();
                calc.HealedHL   += di.Healed();
            }
            #endregion

            #region Divine Favor
            if (Talents.DivineFavor > 0)
            {
                DivineFavor df = new DivineFavor(this);
                calc.RotationHL += df.Time();
                calc.UsageHL    += df.Usage();
                calc.HealedHL   += df.Healed();
            }
            #endregion

            #region Infusion of Light

            float iol_hlcasts  = 0;
            float iol_folcasts = 0;
            if (CalcOpts.InfusionOfLight)
            {
                float iol_count = hs.Casts() * hs.ChanceToCrit();

                HolyLight hl_iol = new HolyLight(this)
                {
                    ExtraCritChance = .1f * Talents.InfusionOfLight
                };
                if (Stats.HolyLightCastTimeReductionFromHolyShock > 0)
                {
                    hl_iol.CastTimeReductionFromHolyShock = true;
                }

                iol_hlcasts = hs.Casts() * CalcOpts.IoLHolyLight * hs.ChanceToCrit();

                calc.UsageHL    += iol_hlcasts * hl_iol.AverageCost();
                calc.RotationHL += iol_hlcasts * hl_iol.CastTime();
                calc.HealedHL   += iol_hlcasts * hl_iol.AverageHealed();

                iol_folcasts = hs.Casts() * (1f - CalcOpts.IoLHolyLight) * hs.ChanceToCrit();
            }

            #endregion

            float remainingMana = calc.TotalMana = ManaPool(calc);
            remainingMana -= calc.UsageJotP + calc.UsageBoL + calc.UsageHS + calc.UsageHL + calc.UsageFoL + calc.UsageSS;

            float remainingTime = FightLength * CalcOpts.Activity;
            remainingTime -= calc.RotationJotP + calc.RotationBoL + calc.RotationSS + calc.RotationHS + calc.RotationFoL + calc.RotationHL;

            FoLCasts = 0f;
            if (remainingMana > 0)
            {
                if (Stats.HolyLightCastTimeReductionFromHolyShock > 0) // Calculations for Holy Light with cost reduction from Holy Shock
                {
                    // Get the Holy Light model for cast time reduction from Holy Shock
                    HolyLight hl_hs = new HolyLight(this)
                    {
                        CastTimeReductionFromHolyShock = true
                    };

                    // Calculate how much time we have available to cast Holy Lights after Holy Shock
                    float hl_hs_time_available = Math.Min(remainingTime, Math.Max(0, (remainingMana - (remainingTime * fol.MPS())) / (hl_hs.MPS() - fol.MPS())));

                    // Calculate the maximum number of casts available with the cast time reduction
                    float hs_hlcasts = hs.Casts() - iol_hlcasts;

                    // Calculate the amount of time needed for all of the casts
                    float hl_hs_time_needed = hs_hlcasts * hl_hs.CastTime();

                    float manaCost = 0f;
                    float timeCost = 0f;
                    if (hl_hs_time_available > 0 && hl_hs_time_available < hl_hs_time_needed) // We have enough time to cast the Holy Lights needed, cast them all
                    {
                        // Calculate mana and time cost
                        manaCost = hs_hlcasts * hl_hs.AverageCost();
                        timeCost = hs_hlcasts * hl_hs.CastTime();

                        // Update Holy Light stats
                        calc.UsageHL    += manaCost;
                        calc.RotationHL += timeCost;
                        calc.HealedHL   += hs_hlcasts * hl_hs.AverageHealed();
                    }
                    else if (hl_hs_time_available >= remainingTime) // There's not enough time to cast the Holy Lights needed, so we'll only cast what we can
                    {
                        // Calculate mana and time cost
                        float remainingCasts = remainingTime / hl_hs.CastTime();
                        manaCost = remainingCasts * hl_hs.AverageCost();
                        timeCost = remainingCasts * hl_hs.CastTime();

                        // Update Holy Light stats
                        calc.UsageHL    += manaCost;
                        calc.RotationHL += timeCost;
                        calc.HealedHL   += remainingCasts * hl_hs.AverageHealed();
                    }
                    // Update remaining mana and remaining time
                    remainingMana -= manaCost;
                    remainingTime -= timeCost;
                }

                // Calculate how much time we have available to cast regular Holy Lights
                float hl_time_available = Math.Min(remainingTime, Math.Max(0, (remainingMana - (remainingTime * fol.MPS())) / (hl.MPS() - fol.MPS())));

                // The rest of the time will be for Flash of Light
                float fol_time = remainingTime - hl_time_available;

                if (hl_time_available == 0) // If we didn't have any time available for Holy Lights, check to see when we run out of mana while casting Flash of Light
                {
                    fol_time = Math.Min(remainingTime, remainingMana / fol.MPS());
                }
                else // If we do have time available for Holy Lights, update the Holy Light stats
                {
                    calc.HealedHL   += hl.HPS() * hl_time_available;
                    calc.UsageHL    += hl.MPS() * hl_time_available;
                    calc.RotationHL += hl_time_available;
                }

                // Calculate Flash of Light data
                if (iol_folcasts > 0) // We are using Infusion of Light, so we must calculate it differently than normal
                {
                    // Get the Flash of Light model for Infusion of Light
                    FlashOfLight fol_iol = new FlashOfLight(this)
                    {
                        InfusionOfLight = true
                    };

                    // If there is less time remaining than it would take to cast all of the
                    // Infusion of Light procs, we are forced to drop some of them.  Note
                    // that this should *never* happen, but is here for a sanity check.
                    if (fol_time <= iol_folcasts * fol_iol.CastTime())
                    {
                        // Determine how many total casts we are going to be able to do
                        FoLCasts = fol_time / fol_iol.CastTime();

                        // Adding Flash of Light with Infusion of Light stats
                        calc.UsageFoL    += FoLCasts * fol_iol.AverageCost();
                        calc.RotationFoL += FoLCasts * fol_iol.CastTime();
                        calc.HealedFoL   += FoLCasts * fol_iol.AverageHealed();

                        fol_BaseHealed += FoLCasts * fol_iol.BaseAverageHealed();
                    }
                    else
                    {
                        // Adding Flash of Light with Infusion of Light
                        calc.UsageFoL    += iol_folcasts * fol_iol.AverageCost();
                        calc.RotationFoL += iol_folcasts * fol_iol.CastTime();
                        calc.HealedFoL   += iol_folcasts * fol_iol.AverageHealed();

                        fol_BaseHealed += iol_folcasts * fol_iol.BaseAverageHealed();

                        // Determine how much time we have left to cast Flash of Light without the procs
                        fol_time = fol_time - iol_folcasts * fol.CastTime();

                        // Determine how many total casts, with and without Infusion of Light
                        float remaining_folcasts = fol_time / fol.CastTime();
                        FoLCasts = iol_folcasts + remaining_folcasts;

                        // Adding Flash of Light stats
                        calc.RotationFoL += fol_time;
                        calc.UsageFoL    += fol.MPS() * fol_time;
                        calc.HealedFoL   += fol.HPS() * fol_time;

                        fol_BaseHealed += remaining_folcasts * fol.BaseAverageHealed();
                    }
                }
                else // We don't use Infusion of Light, so just calculate normal data for Flash of Light
                {
                    // Determine how many total casts, with and without Infusion of Light
                    FoLCasts = fol_time / fol.CastTime();

                    // Adding Flash of Light stats
                    calc.RotationFoL += fol_time;
                    calc.UsageFoL    += fol.MPS() * fol_time;
                    calc.HealedFoL   += fol.HPS() * fol_time;

                    fol_BaseHealed += FoLCasts * fol.BaseAverageHealed();
                }
            }

            calc.TotalHealed = calc.HealedFoL + calc.HealedHL + calc.HealedHS;

            if (Talents.BeaconOfLight > 0)
            {
                calc.TotalHealed += calc.HealedBoL = bol.HealingDone(fol_BaseHealed + calc.HealedHL + calc.HealedHS);
            }

            calc.TotalHealed += calc.HealedGHL = hl.GlyphOfHolyLight(calc.HealedHL);

            calc.HealedOther  = Stats.Healed;
            calc.HealedOther += calc.TotalHealed * Stats.ShieldFromHealed;

            calc.TotalHealed += calc.HealedOther;
            calc.TotalHealed += calc.HealedSS;

            calc.AvgHPS = calc.TotalHealed / FightLength;
            calc.AvgHPM = calc.TotalHealed / calc.TotalMana;

            return(calc.AvgHPS * (1f - CalcOpts.BurstScale));
        }
예제 #15
0
        public override CharacterCalculationsBase GetCharacterCalculations(Character character, Item additionalItem, bool referenceCalculation, bool significantChange, bool needsDisplayCalculations)
        {
            // First things first, we need to ensure that we aren't using bad data
            CharacterCalculationsHealadin calc = new CharacterCalculationsHealadin();
            if (character == null) { return calc; }
            CalculationOptionsHealadin calcOpts = character.CalculationOptions as CalculationOptionsHealadin;
            if (calcOpts == null) { return calc; }
            //
            Stats stats;
            calc = null;
            PaladinTalents talents = character.PaladinTalents;

            for (int i = 0; i < 5; i++)
            {
                float oldBurst = 0;
                if (i > 0) oldBurst = calc.BurstPoints;

                stats = GetCharacterStats(character, additionalItem, true, calc);
                calc = new CharacterCalculationsHealadin();

                Rotation rot = new Rotation(character, stats);

                if (i > 0) calc.BurstPoints = oldBurst;
                else calc.BurstPoints = rot.CalculateBurstHealing(calc);
                calc.FightPoints = rot.CalculateFightHealing(calc);
                calc.OverallPoints = calc.BurstPoints + calc.FightPoints;
            }
            calc.BasicStats = GetCharacterStats(character, additionalItem, false, null);

            return calc;
        }
예제 #16
0
        public Stats GetCharacterStats(Character character, Item additionalItem, bool computeAverageStats, CharacterCalculationsHealadin calc)
        {
            CalculationOptionsHealadin calcOpts = character.CalculationOptions as CalculationOptionsHealadin;
            BossOptions bossOpts = character.BossOptions;
            PaladinTalents talents = character.PaladinTalents;
            
            float fightLength = bossOpts.BerserkTimer;

            Stats statsRace = BaseStats.GetBaseStats(character.Level, CharacterClass.Paladin, character.Race);
            Stats statsBaseGear = GetItemStats(character, additionalItem);
            Stats statsBuffs = GetBuffsStats(character, calcOpts);
            Stats stats = statsBaseGear + statsBuffs + statsRace;

            ConvertRatings(stats, talents, calcOpts);
            if (computeAverageStats)
            {
                Stats statsAverage = new Stats();

                foreach (SpecialEffect effect in stats.SpecialEffects())
                {
                    float trigger = 0f;
                    if (calc == null)
                    {
                        trigger = 1.5f / calcOpts.Activity / (1f + stats.SpellHaste);
                        if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit)
                            trigger *= stats.SpellCrit;
                    }
                    else
                    {
                        if (effect.Trigger == Trigger.HealingSpellCast || effect.Trigger == Trigger.HealingSpellHit)
                            trigger = 1f / Rotation.GetHealingCastsPerSec(calc);
                        else if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit)
                            trigger = 1f / Rotation.GetHealingCritsPerSec(calc);
                        else if (effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit)
                            trigger = 1f / Rotation.GetSpellCastsPerSec(calc);
                        else if (effect.Trigger == Trigger.DamageOrHealingDone)
                            trigger = 1f / Rotation.GetHealingCastsPerSec(calc);
                        else if (effect.Trigger == Trigger.Use)
                        {
                            trigger = 0f;
                            foreach (SpecialEffect childEffect in effect.Stats.SpecialEffects())
                            {
                                float childTrigger = 0f;

                                if (effect.Trigger == Trigger.HealingSpellCast || effect.Trigger == Trigger.HealingSpellHit)
                                    childTrigger = 1f / Rotation.GetHealingCastsPerSec(calc);
                                else if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit)
                                    childTrigger = 1f / Rotation.GetHealingCritsPerSec(calc);
                                else if (effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit)
                                    childTrigger = 1f / Rotation.GetSpellCastsPerSec(calc);

                                statsAverage.Accumulate(childEffect.Stats,
                                                        effect.GetAverageUptime(0.0f, 1.0f)
                                                            * childEffect.GetAverageStackSize(childTrigger, 1f, 1.5f, effect.Duration));
                            }
                        }
                        else continue;
                    }
                    statsAverage.Accumulate(effect.GetAverageStats(trigger, 1f, 1.5f, fightLength));
                }
                statsAverage.ManaRestore *= fightLength;
                statsAverage.Healed *= fightLength;
                statsAverage.HealedPerSP *= fightLength;

                stats = statsBaseGear + statsBuffs + statsRace + statsAverage;
                ConvertRatings(stats, talents, calcOpts);
            }

            #region Set Bonuses
            int T11Count;
            character.SetBonusCount.TryGetValue("Reinforced Sapphirium Regalia", out T11Count);
            stats.BonusCritChanceDeathCoil = 0; // using this for Holy Light crit bonus, for now
            stats.BonusCritChanceFrostStrike = 0;  // yes, I'm pure evil, using this to track 4T11 
            if (T11Count >= 2)
            {
               
                // T11 Pally 2 piece bonus: add 5% crit to HL
                stats.BonusCritChanceDeathCoil = 0.05f;
            }
            if (T11Count >= 4)
            {
                // T11 Pally 4 piece bonus: 540 spirit buff for 6 secs after HS cast
                stats.BonusCritChanceFrostStrike = 1; 
            }
            #endregion Set Bonuses

            return stats;
        }
예제 #17
0
        public override ComparisonCalculationBase[] GetCustomChartData(Character character, string chartName)
        {
            if (chartName == "Mana Pool Breakdown")
            {
                CharacterCalculationsHealadin calc = GetCharacterCalculations(character) as CharacterCalculationsHealadin;
                if (calc == null)
                {
                    calc = new CharacterCalculationsHealadin();
                }

                ComparisonCalculationHealadin Base          = new ComparisonCalculationHealadin("Base");
                ComparisonCalculationHealadin Mp5           = new ComparisonCalculationHealadin("Mp5");
                ComparisonCalculationHealadin Replenishment = new ComparisonCalculationHealadin("Replenishment");
                ComparisonCalculationHealadin ArcaneTorrent = new ComparisonCalculationHealadin("Arcane Torrent");
                ComparisonCalculationHealadin DivinePlea    = new ComparisonCalculationHealadin("Divine Plea");
                ComparisonCalculationHealadin LoH           = new ComparisonCalculationHealadin("Lay on Hands");
                ComparisonCalculationHealadin Other         = new ComparisonCalculationHealadin("Potion & Other");

                Base.OverallPoints          = Base.ThroughputPoints = calc.ManaBase;
                Mp5.OverallPoints           = Mp5.ThroughputPoints = calc.ManaMp5;
                LoH.OverallPoints           = LoH.ThroughputPoints = calc.ManaLayOnHands;
                Replenishment.OverallPoints = Replenishment.ThroughputPoints = calc.ManaReplenishment;
                ArcaneTorrent.OverallPoints = ArcaneTorrent.ThroughputPoints = calc.ManaArcaneTorrent;
                DivinePlea.OverallPoints    = DivinePlea.ThroughputPoints = calc.ManaDivinePlea;
                Other.OverallPoints         = Other.ThroughputPoints = calc.ManaOther;

                return(new ComparisonCalculationBase[] { Base, Mp5, Replenishment, LoH, ArcaneTorrent, DivinePlea, Other });
            }
            else if (chartName == "Mana Usage Breakdown")
            {
                CharacterCalculationsHealadin calc = GetCharacterCalculations(character) as CharacterCalculationsHealadin;
                if (calc == null)
                {
                    calc = new CharacterCalculationsHealadin();
                }

                ComparisonCalculationHealadin FoL  = new ComparisonCalculationHealadin("Flash of Light");
                ComparisonCalculationHealadin HL   = new ComparisonCalculationHealadin("Holy Light");
                ComparisonCalculationHealadin HS   = new ComparisonCalculationHealadin("Holy Shock");
                ComparisonCalculationHealadin JotP = new ComparisonCalculationHealadin("Judgements and Seals");
                ComparisonCalculationHealadin BoL  = new ComparisonCalculationHealadin("Beacon of Light");
                ComparisonCalculationHealadin SS   = new ComparisonCalculationHealadin("Sacred Shield");

                FoL.OverallPoints  = FoL.ThroughputPoints = calc.UsageFoL;
                HL.OverallPoints   = HL.ThroughputPoints = calc.UsageHL;
                HS.OverallPoints   = HS.ThroughputPoints = calc.UsageHS;
                JotP.OverallPoints = JotP.ThroughputPoints = calc.UsageJotP;
                BoL.OverallPoints  = BoL.ThroughputPoints = calc.UsageBoL;
                SS.OverallPoints   = SS.ThroughputPoints = calc.UsageSS;

                return(new ComparisonCalculationBase[] { FoL, HL, HS, JotP, BoL, SS });
            }
            else if (chartName == "Healing Breakdown")
            {
                CharacterCalculationsHealadin calc = GetCharacterCalculations(character) as CharacterCalculationsHealadin;
                if (calc == null)
                {
                    calc = new CharacterCalculationsHealadin();
                }

                ComparisonCalculationHealadin FoL = new ComparisonCalculationHealadin("Flash of Light");
                ComparisonCalculationHealadin HL  = new ComparisonCalculationHealadin("Holy Light");
                ComparisonCalculationHealadin HS  = new ComparisonCalculationHealadin("Holy Shock");
                ComparisonCalculationHealadin GHL = new ComparisonCalculationHealadin("Glyph of Holy Light");
                ComparisonCalculationHealadin BoL = new ComparisonCalculationHealadin("Beacon of Light");
                ComparisonCalculationHealadin SS  = new ComparisonCalculationHealadin("Sacred Shield");

                FoL.OverallPoints = FoL.ThroughputPoints = calc.HealedFoL / calc.FightLength;
                HL.OverallPoints  = HL.ThroughputPoints = calc.HealedHL / calc.FightLength;
                HS.OverallPoints  = HS.ThroughputPoints = calc.HealedHS / calc.FightLength;
                GHL.OverallPoints = GHL.ThroughputPoints = calc.HealedGHL / calc.FightLength;
                BoL.OverallPoints = BoL.ThroughputPoints = calc.HealedBoL / calc.FightLength;
                SS.OverallPoints  = SS.ThroughputPoints = calc.HealedSS / calc.FightLength;

                return(new ComparisonCalculationBase[] { FoL, HL, HS, GHL, BoL, SS });
            }
            else if (chartName == "Rotation Breakdown")
            {
                CharacterCalculationsHealadin calc = GetCharacterCalculations(character) as CharacterCalculationsHealadin;
                if (calc == null)
                {
                    calc = new CharacterCalculationsHealadin();
                }

                ComparisonCalculationHealadin FoL  = new ComparisonCalculationHealadin("Flash of Light");
                ComparisonCalculationHealadin HL   = new ComparisonCalculationHealadin("Holy Light");
                ComparisonCalculationHealadin HS   = new ComparisonCalculationHealadin("Holy Shock");
                ComparisonCalculationHealadin JotP = new ComparisonCalculationHealadin("Judgements and Seals");
                ComparisonCalculationHealadin BoL  = new ComparisonCalculationHealadin("Beacon of Light");
                ComparisonCalculationHealadin SS   = new ComparisonCalculationHealadin("Sacred Shield");

                FoL.OverallPoints  = FoL.ThroughputPoints = calc.RotationFoL;
                HL.OverallPoints   = HL.ThroughputPoints = calc.RotationHL;
                HS.OverallPoints   = HS.ThroughputPoints = calc.RotationHS;
                JotP.OverallPoints = JotP.ThroughputPoints = calc.RotationJotP;
                BoL.OverallPoints  = BoL.ThroughputPoints = calc.RotationBoL;
                SS.OverallPoints   = SS.ThroughputPoints = calc.RotationSS;

                return(new ComparisonCalculationBase[] { FoL, HL, HS, JotP, BoL, SS });
            }
            return(new ComparisonCalculationBase[] {});
        }
예제 #18
0
 public static float GetHolyLightCastsPerSec(CharacterCalculationsHealadin calc)
 {
     return (calc.RotationHL / calc.HL.CastTime()) / calc.FightLength;
 }
예제 #19
0
 public static float GetHolyLightCastsPerSec(CharacterCalculationsHealadin calc)
 {
     return((calc.RotationHL / calc.HL.CastTime()) / calc.FightLength);
 }
예제 #20
0
 public static float GetSpellCritsPerSec(CharacterCalculationsHealadin calc) { return GetHealingCritsPerSec(calc); }
예제 #21
0
 public static float GetSpellCritsPerSec(CharacterCalculationsHealadin calc)
 {
     return(GetHealingCritsPerSec(calc));
 }
예제 #22
0
        public float CalculateFightHealing(CharacterCalculationsHealadin calc)
        {
            #region Copying Stuff to Calc
            calc.FightLength = FightLength;

            calc.HL = hl;
            calc.FoL = fol;
            calc.HS = hs;
            calc.DL = dl;  
            calc.WoG = wog;  
            calc.LoD = lod;
            calc.HR = hr; 
            calc.JotP = jotp;
            calc.BoL = bol;
            calc.LoH = loh;
            calc.PotI = poti;
            calc.EJ = ej;

            calc.JudgeCasts = jotp.Casts();
            calc.RotationJudge = jotp.Time() + CalcOpts.Userdelay * calc.JudgeCasts;
            calc.UsageJudge = jotp.Usage();
            

            if (Talents.BeaconOfLight > 0)
            {
                calc.RotationBoL = bol.Time();
                calc.UsageBoL = bol.Usage();
            }

            calc.RotationHS = hs.Time() + hs.Casts() + CalcOpts.Userdelay;
            calc.HealedHS = hs.Healed();
            calc.UsageHS = hs.Usage();

            calc.RotationLoH = loh.Casts() * (loh.CastTime() + CalcOpts.Userdelay);
            calc.HealedLoH = loh.Casts() * loh.AverageHealed();
            calc.UsageLoH = 0f; // always 0, costs no mana, code was: loh.Casts() * loh.BaseMana;

            calc.UsageCleanse = CalcOpts.Cleanse * cleanse.BaseMana;
            calc.RotationCleanse = CalcOpts.Cleanse * ( cleanse.CastTime() + CalcOpts.Userdelay);
            calc.CleanseCasts = CalcOpts.Cleanse;
            #endregion

            Stats.BonusCritChanceObliterate = CalcOpts.CritOverheals;  // I really need to put some variables in Stats that are for holy pally
            calc.HasteJotP = Talents.JudgementsOfThePure * 3f;
            calc.HasteSoL = Talents.SpeedOfLight * 1f;
            calc.SpellPowerTotal = Stats.Intellect + Stats.SpellPower;

            #region Divine Favor - old code, commented out for now
        /*    if (Talents.DivineFavor > 0)
            {
                DivineFavor df = new DivineFavor(this);
                calc.RotationHL += df.Time();
                calc.UsageHL += df.Usage();
                calc.HealedHL += df.Healed();
            } */
            #endregion

            #region active time, remaining mana / time
            float remainingMana = calc.TotalMana = ManaPool(calc);
            remainingMana -= calc.UsageJudge + calc.UsageBoL + calc.UsageHS + calc.UsageHR + calc.UsageCleanse;

            // start with amount of time you are active in a fight
            calc.ActiveTime = FightLength * CalcOpts.Activity;
            float remainingTime = calc.ActiveTime;
            // now subtract time for lots of stuff we need to cast  
            remainingTime -= calc.RotationJudge + calc.RotationBoL + calc.RotationHS + calc.RotationLoH + calc.RotationHR + calc.RotationCleanse;
            float RotationDP = DivinePleas * (calc.HS.CastTime() + CalcOpts.Userdelay);
            remainingTime -= RotationDP; // subtract divine plea cast times.  HS is also a GCD, so I just used that to calculate it
            #endregion

            #region HS and holy power
            calc.HolyPowerCasts = hs.Casts() / 3f;
            if (Talents.LightOfDawn != 0)
            {
              calc.LoDCasts = (float)Math.Floor(calc.HolyPowerCasts * CalcOpts.HolyPoints);
              calc.WoGCasts = (float)Math.Floor(calc.HolyPowerCasts * (1f - CalcOpts.HolyPoints));
            }
            else {
                calc.WoGCasts = (float)Math.Floor(calc.HolyPowerCasts);
                calc.LoDCasts = 0;
            }
            calc.RotationWoG = calc.WoGCasts * (wog.CastTime() + CalcOpts.Userdelay);
            calc.UsageWoG = calc.WoGCasts * wog.BaseMana;
            calc.HealedWoG = calc.WoGCasts * wog.AverageHealed();
            calc.RotationLoD = calc.LoDCasts * (lod.CastTime() + CalcOpts.Userdelay);
            calc.UsageLoD = calc.LoDCasts * lod.BaseMana;
            calc.HealedLoD = calc.LoDCasts * lod.AverageHealed() * CalcOpts.LoDTargets;
            remainingTime -= calc.RotationWoG + calc.RotationLoD;
            #endregion

            #region Holy Radiance
            calc.HRCasts = (float)Math.Floor(FightLength / CalcOpts.HRCasts);
            calc.RotationHR = calc.HRCasts * (hr.CastTime() + CalcOpts.Userdelay);
            calc.UsageHR = calc.HRCasts * hr.BaseMana;
            calc.HealedHR = calc.HRCasts * hr.AverageHealed() * CalcOpts.HREff;
            remainingTime -= calc.RotationHR;
            #endregion

            #region Melee mana regen
            // Melee hits generate 4% base mana.  From what I read, this proc has a 4 sec CD.  15ppm max.
            float InstantCastRotationTotal = calc.RotationLoD + calc.RotationWoG + calc.RotationHS + calc.RotationHR + calc.RotationJudge + calc.RotationBoL + calc.RotationLoH + calc.RotationCleanse;
            float MeleeTime = InstantCastRotationTotal * CalcOpts.Melee;
            // Ideally the SwingTime would be the weapon speed, then logic would be added to estimate the # of procs.  As the # of swings increases, 
            // the number of procs would have dimishing returns.  (because more frequent swings means more swings happen during the 4 sec CD, and don't proc)
            // For now I am going to fudge it and estimate a proc every 5 secs.  Every 4 is unrealistic since 4 is not divisable by weapon speed,
            // so some time is always wasted.  Also consider when one alternates between swings and casts, then each swing would proc.  Whatever, 5 is good enough for now.
            float SwingTime = 5f; 
            float MeleeManaPerProc = HealadinConstants.basemana * 0.04f;
            // calc.MeleeSwings = MeleeTime / SwingTime;
            calc.MeleeProcs = MeleeTime / SwingTime; // find a way to model this better, as swings approaches MaxMeleeProcs, it should have diminishing returns somehow
            calc.ManaMelee = calc.MeleeProcs * MeleeManaPerProc;
            remainingMana += calc.ManaMelee;
            calc.TotalMana += calc.ManaMelee;
            #endregion Melee mana regen

            #region Filler casts
            // now that we did everything from the options panel, fill in the rest of the available cast time
            // we will use Holy Light to fill in the time.  If we still have mana left, we will replace Holy Light casts with Divine Light, until we run out of mana.
            // Note, when I kept the filler casts to whole numbers, Haste was not valued.  Trying the other way to see how haste is valued then.
            // DL and HL have the same casttime, so lets just figure max number of casts with time remaining
            float IoLprocs = hs.Casts() * Talents.InfusionOfLight * hs.ChanceToCrit();  // Infusion of Light procs - -0.75 sec to next HL or DL casttime per point
            remainingTime += IoLprocs * 0.75f;  // assuming we will be casting at least a few HL or DL, and can cast them when IoL procs, before next HS cast
            float fill_casts = /*(float)Math.Floor*/(remainingTime / (hl.CastTime() + CalcOpts.Userdelay));
            calc.HLCasts = 0; // Holy Light
            calc.DLCasts = 0; // Divine Light
            calc.FoLCasts = 0;
            float mana_fill_hl = fill_casts * hl.BaseMana;
            float mana_fill_dl = fill_casts * dl.BaseMana;
            if (remainingMana < mana_fill_hl)       // if you would run out of mana just casting Holy Light
            {     // then figure out how many Holy Lights you can cast
                // calc.HLCasts = /*(float)Math.Floor*/(remainingMana / hl.BaseMana);
                float timeleft = calc.HLCasts * (hl.CastTime() + + CalcOpts.Userdelay);
                float MeleeMPS = calc.MeleeProcs / MeleeManaPerProc;
                calc.HLCasts = ((remainingMana / (hl.MPS() - MeleeMPS) / hl.CastTime()));  // use time to spare to melee for more mana, for more HL casts
                remainingTime -= calc.HLCasts * (hl.CastTime() + + CalcOpts.Userdelay);
                float moremeleemana = remainingTime / SwingTime * MeleeManaPerProc;
                calc.RotationMelee = remainingTime;
                calc.MeleeProcs += remainingTime / SwingTime;
                calc.ManaMelee += moremeleemana;
                calc.TotalMana += moremeleemana;
            }
            else if (remainingMana < mana_fill_dl)  // else if you would run out of mana just casting Divine Light
            {
                remainingMana -= fill_casts * hl.BaseMana;       // how much mana do we have to spare if we casts all Holy Lights
                calc.DLCasts = /*(float)Math.Floor*/(remainingMana / (dl.BaseMana - hl.BaseMana));
                calc.HLCasts = fill_casts - calc.DLCasts;
            }
            else                                                // my God, you have a crapton of mana, start casting Flash of Light
            {
                calc.DLCasts = (IoLprocs * 0.75f) / dl.CastTime();
                remainingTime -= IoLprocs * 0.75f;
                remainingMana -= calc.DLCasts * dl.BaseMana;
                remainingMana -= fill_casts * dl.BaseMana;       // how much mana do we have to spare if we casts all Divine Lights
                calc.FoLCasts = /*(float)Math.Floor*/((remainingMana / (fol.MPS() - dl.MPS()) / fol.CastTime()));
                if (calc.FoLCasts > (remainingTime / (fol.CastTime() + CalcOpts.Userdelay)))
                    calc.FoLCasts = remainingTime / (fol.CastTime() + CalcOpts.Userdelay);
                remainingTime -= calc.FoLCasts * (fol.CastTime() + CalcOpts.Userdelay);
                calc.DLCasts += /*(float)Math.Floor*/(remainingTime / (dl.CastTime() + CalcOpts.Userdelay));
            }

            calc.RotationHL = calc.HLCasts * (hl.CastTime() + CalcOpts.Userdelay);
            calc.UsageHL = calc.HLCasts * hl.BaseMana;
            calc.HealedHL = calc.HLCasts * hl.AverageHealed();
            calc.RotationDL = calc.DLCasts * (dl.CastTime() + CalcOpts.Userdelay);
            calc.UsageDL = calc.DLCasts * dl.BaseMana;
            calc.HealedDL = calc.DLCasts * dl.AverageHealed();
            calc.RotationFoL = calc.FoLCasts * (fol.CastTime() + CalcOpts.Userdelay);
            calc.UsageFoL = calc.FoLCasts * fol.BaseMana;
            calc.HealedFoL = calc.FoLCasts * fol.AverageHealed();
            if (calc.RotationHL > (IoLprocs * 0.75f))
                calc.RotationHL -= IoLprocs * 0.75f;
            else if (calc.RotationDL > (IoLprocs * 0.75f))
                calc.RotationDL -= IoLprocs * 0.75f;
            #endregion Filler Casts

            #region Conviction
            // does enlightened judgements crit seperately from judgement?  does it count towards conviction proc?
            // does Protector of the Innocent crit seperately?  does it count towards conviction proc?
            // I'm assuming yes for all these questions for now.
            // Frankly this was my first pass at modeling Conviction.  It's far from perfect, but the results are
            // in the same ballpark as combatlogs, and should be somewhat accurate in this talent's effect on
            // the value of crit.

            float ConvictionUptime;  // time having 3 stacks up
            float ConvictionCasts = 2f * (calc.HLCasts + calc.DLCasts + calc.FoLCasts +
                                 calc.WoGCasts + calc.JudgeCasts + calc.HSCasts) + calc.LoHCasts +
                                  calc.LoDCasts * CalcOpts.LoDTargets * (5f + (Talents.GlyphOfLightOfDawn ? 1f : 0f)) + 
                                  calc.MeleeSwings;
            float CastsPerSec = ConvictionCasts / ActiveTime;
            // Average crit chance is for all spells.  Start with spellcrit, then add extra for each spell.
            float AverageCritChance = Stats.SpellCrit +
                  (hs.Casts() / ConvictionCasts * (hs.ChanceToCrit() - Stats.SpellCrit)) +
                  (calc.HLCasts / ConvictionCasts * (hl.ChanceToCrit() - Stats.SpellCrit));
            float ChancePerCastToDrop = (float)Math.Pow((1 - AverageCritChance), (CastsPerSec * 15));

            float FullStackTime =   // average time we keep 3 stacks once we have it
                // might not be the best way, but for now using the time to get to 60% chance the stack has dropped
                // considering the tail 40% can take very long to drop potentially, pulling the median out past 50%
                // combat logs show this is the correct ballpark
                  1f / CastsPerSec * (float)Math.Log(0.4f, (1f - ChancePerCastToDrop));
            float AverageStackBuildTime = // average time to build from 0 to 3 stacks
                  1f / CastsPerSec *
                  (3 / AverageCritChance);  // time to get 3 stacks, assuming you dont drop the stack along the way
            // now should add time for if stacks drop along the way
            float StackBuilds = // number of times we will build the stack in the fight
                    1 + (ActiveTime - AverageStackBuildTime) / (AverageStackBuildTime + FullStackTime);
            ConvictionUptime = StackBuilds * AverageStackBuildTime / 3f +  // lets count stack builds as having 1 stack on average for now 
                               (StackBuilds - 1f) * FullStackTime;
            float ConvictionBuff = 1f + ConvictionUptime / ActiveTime * 0.03f * Talents.Conviction;

            calc.HealedHL *= ConvictionBuff;
            calc.HealedDL *= ConvictionBuff;
            calc.HealedFoL *= ConvictionBuff;
            calc.HealedHS  *= ConvictionBuff;
            calc.HealedWoG  *= ConvictionBuff;
            calc.HealedLoD  *= ConvictionBuff;
            calc.HealedLoH *= ConvictionBuff; 

            #endregion Conviction

            #region Talent heals: Enlightened Judgement, Protector of the Innocent, Illuminated healing, Beacon
            // Enlightened Judgement talent heals
            calc.HealedJudge = calc.JudgeCasts * ej.AverageHealed() * ConvictionBuff;

            // Protector of the Innocent
            calc.PotICasts = fill_casts + calc.WoGCasts + calc.LoDCasts + calc.LoHCasts + calc.HSCasts;
            calc.HealedPotI = calc.PotICasts * poti.AverageHealed() * ConvictionBuff;

            calc.UsageTotal = calc.UsageFoL + calc.UsageDL + calc.UsageHL + calc.UsageLoD + calc.UsageWoG +
                                 calc.UsageHS + calc.UsageHR + calc.UsageJudge + calc.UsageBoL + calc.UsageCleanse;
            calc.RotationTotal = calc.RotationFoL + calc.RotationDL + calc.RotationHL + calc.RotationLoD + calc.RotationWoG + calc.RotationHS +
                                 calc.RotationHR + calc.RotationJudge + calc.RotationBoL + calc.RotationLoH + calc.RotationCleanse + calc.RotationMelee
                                 + RotationDP;  

            // Illumnated Healing
            calc.HealedIH = calc.HealedFoL + calc.HealedHL + calc.HealedHS + calc.HealedWoG + calc.HealedLoD + calc.HealedDL;
            calc.TotalHealed = calc.HealedIH + calc.HealedPotI + calc.HealedJudge;
            // BoL doesn't use LoH, but Illuminated healing does - so add LoH to IH and do final IH calcs
            calc.HealedIH += calc.HealedLoH;
            calc.HealedIH *= CalcOpts.IHEff * (0.12f + ((8 + Stats.MasteryRating / 179.28f) * 0.015f));                   
            
            // Beacon of Light
            calc.HealedBoL =  bol.HealingDone(calc.TotalHealed + calc.HealedHL);  // added HL heals again to reflect 4.2 change, where HL transferes 100% to beacon target, rather than 50% for everything else
            #endregion


            // adding Holy Radiance and LoH after BoL calculation, as they do not count towards BoL heals
            calc.TotalHealed += calc.HealedHR + calc.HealedLoH + calc.HealedIH + calc.HealedBoL; 

            calc.HealedOther = Stats.Healed + Stats.HealedPerSP * calc.SpellPowerTotal;
            calc.HealedOther += calc.TotalHealed * Stats.ShieldFromHealedProc;

            calc.TotalHealed += calc.HealedOther;

            calc.AvgHPS = calc.TotalHealed / FightLength;
            calc.AvgHPM = calc.TotalHealed / calc.TotalMana;

            return calc.AvgHPS * (1f - CalcOpts.BurstScale);
        }
예제 #23
0
 public static float GetHealingCritsPerSec(CharacterCalculationsHealadin calc)
 {
     return((calc.RotationHL / calc.HL.CastTime() * calc.HL.ChanceToCrit()
             + calc.RotationFoL / calc.FoL.CastTime() * calc.FoL.ChanceToCrit()
             + calc.RotationHS / calc.HS.CastTime() * calc.HS.ChanceToCrit()) / calc.FightLength);
 }
예제 #24
0
        public float ManaPool(CharacterCalculationsHealadin calc)
        {
            DivinePleas = (float)Math.Ceiling((FightLength - 120f) / (120f * CalcOpts.DivinePlea));

            calc.ManaBase = Stats.Mana;
            calc.ManaLayOnHands = Stats.Mana * ((Talents.GlyphOfDivinity ? 0.1f : 0) * loh.Casts());
            calc.ManaArcaneTorrent = (Character.Race == CharacterRace.BloodElf ? Stats.Mana * .06f * (float)Math.Ceiling(FightLength / 120f - .25f) : 0);
            calc.ManaDivinePlea = Stats.Mana * (Talents.GlyphOfDivinePlea ? 0.18f : 0.12f) * DivinePleas;
            calc.ManaMp5 = FightLength * Stats.Mp5 / 5f;
            // this Stats.ManaRestoreFromMaxManaPerSecond is 0 is is messing up the replenishment calculation!
            //calc.ManaReplenishment = Stats.ManaRestoreFromMaxManaPerSecond * Stats.Mana * FightLength * CalcOpts.Replenishment;
            calc.ManaReplenishment = 0.001f * Stats.Mana * FightLength * CalcOpts.Replenishment;
            calc.ManaOther += Stats.ManaRestore;
            // add calc.ManaJudgements
            calc.ManaJudgements = HealadinConstants.basemana * 0.15f * jotp.Casts();
            if (Stats.HighestStat > 0)
            {
                float greatnessMana = Stats.HighestStat * StatConversion.RATING_PER_MANA;
                calc.ManaReplenishment += Stats.ManaRestoreFromMaxManaPerSecond * FightLength * greatnessMana * CalcOpts.Replenishment; // Replenishment
                calc.ManaDivinePlea += DivinePleas * greatnessMana * .1f; // Divine Plea
            }

            // check if this is correct regen per 5 seconds..  
            // combat regen = 50% of spirit regen (from Meditation), plus MP5 from gear, plus 5% base mana per 5 secs.  Base mana = 23422 at 85
            float effective_spirit = Stats.Spirit + Stats.BonusCritChanceFrostStrike * 540 * 6 / CalcOpts.HolyShock; // add in bonus spirit from 4T11 procs
            float spirit_regen = StatConversion.GetSpiritRegenSec(effective_spirit, Stats.Intellect) * 5f;
            calc.CombatRegenRate = spirit_regen * 0.5f + Stats.Mp5 + HealadinConstants.basemana * 0.05f;
            calc.ManaRegenRate = spirit_regen + Stats.Mp5 + HealadinConstants.basemana * 0.05f;
            calc.CombatRegenTotal = calc.CombatRegenRate * FightLength / 5f;

            return calc.ManaBase + calc.ManaDivinePlea + calc.CombatRegenTotal + calc.ManaOther +
                calc.ManaReplenishment + calc.ManaLayOnHands + calc.ManaJudgements;
        }
예제 #25
0
        public override CharacterCalculationsBase GetCharacterCalculations(Character character, Item additionalItem)
        {
            //_cachedCharacter = character;
            Stats stats = GetCharacterStats(character, additionalItem);
            CharacterCalculationsHealadin calculatedStats = new CharacterCalculationsHealadin();

            //CharacterCalculationsHealadin oldStats = _cachedCharacterStatsWithSlotEmpty as CharacterCalculationsHealadin;
            calculatedStats.BasicStats = stats;

            CalculationOptionsHealadin calcOpts = character.CalculationOptions as CalculationOptionsHealadin;

            if (calcOpts == null)
            {
                calcOpts = new CalculationOptionsHealadin();
            }
            float activity  = calcOpts.Activity / 100f;
            float time      = calcOpts.Length * 60;
            float length    = time * activity;
            float totalMana = stats.Mana + (time * stats.Mp5 / 5) + (calcOpts.Spriest * time / 5) +
                              ((1 + stats.BonusManaPotion) * calcOpts.ManaAmt * (float)Math.Ceiling((time / 60 - 1) / calcOpts.ManaTime))
                              + calcOpts.Spiritual;

            if (stats.MementoProc > 0)
            {
                totalMana += (float)Math.Ceiling(time / 60 - .25) * stats.MementoProc * 3;
            }

            calculatedStats[0] = new Spell("Flash of Light", 7, calcOpts.BoL);
            calculatedStats[1] = new Spell("Holy Light", 11, calcOpts.BoL);
            calculatedStats[2] = new Spell("Holy Light", 10, calcOpts.BoL);
            calculatedStats[3] = new Spell("Holy Light", 9, calcOpts.BoL);
            calculatedStats[4] = new Spell("Holy Light", 8, calcOpts.BoL);
            calculatedStats[5] = new Spell("Holy Light", 7, calcOpts.BoL);
            calculatedStats[6] = new Spell("Holy Light", 6, calcOpts.BoL);
            calculatedStats[7] = new Spell("Holy Light", 5, calcOpts.BoL);
            calculatedStats[8] = new Spell("Holy Light", 4, calcOpts.BoL);

            #region Divine Illumination
            Spell hl1_di = new Spell("Holy Light", 11, calcOpts.BoL);
            hl1_di.Calculate(stats, true);
            Spell hl2_di = new Spell("Holy Light", 9, calcOpts.BoL);
            hl2_di.Calculate(stats, true);
            Spell fol_di = new Spell("Flash of Light", 7, calcOpts.BoL);
            fol_di.Calculate(stats, true);
            float hl1_dimana = calculatedStats[1].Mps - hl1_di.Mps;
            float hl2_dimana = calculatedStats[3].Mps - hl2_di.Mps;
            float fol_dimana = calculatedStats[0].Mps - fol_di.Mps;
            float di_mana    = (hl1_dimana * 6 + hl2_dimana * 3 + fol_dimana * 6) * activity * (float)Math.Ceiling((time - 1) / 180);
            totalMana += di_mana;
            #endregion

            #region Divine Favor
            totalMana += (float)Math.Ceiling((time - 30) / 120f) * calculatedStats[1].DFMana();
            calculatedStats.Healed = (float)Math.Ceiling((time - 30) / 120f) * calculatedStats[1].DFHeal();
            #endregion

            Spell FoL   = calculatedStats[0];
            int   rank1 = 12 - calcOpts.Rank1;
            int   rank2 = 12 - calcOpts.Rank2;

            float HL_Mps = calculatedStats[rank1].Mps * (1f - calcOpts.Ratio) + calculatedStats[rank2].Mps * calcOpts.Ratio;
            float HL_Hps = calculatedStats[rank1].Hps * (1f - calcOpts.Ratio) + calculatedStats[rank2].Hps * calcOpts.Ratio;


            float time_hl  = Math.Min(length, Math.Max(0, (totalMana - (length * FoL.Mps)) / (HL_Mps - FoL.Mps)));
            float time_fol = length - time_hl;
            if (time_hl == 0)
            {
                time_fol = Math.Min(length, totalMana / FoL.Mps);
            }
            calculatedStats.TimeHL = time_hl / length;

            float healing_fol = time_fol * FoL.Hps;
            float healing_hl  = time_hl * HL_Hps;

            calculatedStats.Healed += healing_fol + healing_hl;
            calculatedStats.HLHPS   = HL_Hps;
            calculatedStats.FoLHPS  = FoL.Hps;

            calculatedStats.ThroughputPoints = calculatedStats.Healed / time;// FoL.Hps* activity;
            //calculatedStats.LongevityPoints = calculatedStats.Healed / time - FoL.Hps;

            /*if (oldStats == null)
             * {
             *  calculatedStats.ThroughputPoints = FoL.Hps * length;
             *  calculatedStats.LongevityPoints = calculatedStats.Healed - calculatedStats.ThroughputPoints;
             * }
             * else
             * {
             *  float otime = Math.Max(oldStats.TimeHL * length, time_hl);
             *  calculatedStats.LongevityPoints = (length-otime) * oldStats.FoLHPS + otime * oldStats.HLHPS;
             *  calculatedStats.ThroughputPoints = calculatedStats.Healed - calculatedStats.LongevityPoints;
             * }*/

            calculatedStats.OverallPoints = calculatedStats.ThroughputPoints;// +calculatedStats.LongevityPoints;

            calculatedStats.HealHL = healing_hl / calculatedStats.Healed;
            calculatedStats.AvgHPS = calculatedStats.Healed / length * activity;
            calculatedStats.AvgHPM = calculatedStats.Healed / totalMana;

            return(calculatedStats);
        }