示例#1
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));
        }
示例#2
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));
        }