예제 #1
0
 public ComputedSpell(SpellData data, TreeStats stats)
 {
     this.Data             = data;
     this.Stats            = stats;
     this.DirectMultiplier = stats.DirectHealMultiplier;
     this.TickMultiplier   = stats.PeriodicHealMultiplier;
 }
 public ComputedSpell(SpellData data, TreeStats stats)
 {
     this.Data = data;
     this.Stats = stats;
     this.DirectMultiplier = stats.DirectHealMultiplier;
     this.TickMultiplier = stats.PeriodicHealMultiplier;
 }
예제 #3
0
 void addPassiveHealing(ActionDistribution dist, TreeStats stats)
 {
     dist.AddPassive((int)TreePassive.HealingTrinkets, stats.Healed * stats.DirectHealMultiplier * getCritMultiplier(stats, 0, 0));
     if (InsectSwarm)
         dist.AddActionOnCooldown((int)TreeAction.InsectSwarm);
 }
예제 #4
0
        void addSpecialDirectHeals(ActionDistribution dist, ComputedSpell[] spells, TreeStats stats, bool onTank, bool useCCs, double minRate, bool htFiller)
        {
            // TODO: possibly make configurable, it's disabled because in practice it's unlikely to have a clearcast exactly when Nature's Grace is to be triggered
            bool procNaturesGraceWithCCs = false;

            bool naturesGraceHandled = false;
            if (InsectSwarm)
                naturesGraceHandled = true;

            double dhrate = 0;

            double ccrate = spells[(int)TreeSpell.Lifebloom].TPS * 0.02f * Talents.MalfurionsGift;
            if (ccrate != 0.0f)
            {
                if (procNaturesGraceWithCCs && Talents.NaturesGrace > 0)
                {
                    naturesGraceHandled = true;
                    dist.AddAction(onTank ? (int)TreeAction.TankClearRegrowth : (int)TreeAction.RaidClearRegrowth, 1.0f / 60.0f * spells[(int)TreeSpell.Regrowth].Action.Time);
                    ccrate -= 1.0f / 60.0f;
                    dhrate += 1.0f / 60.0f;
                }

                if (useCCs)
                {
                    dist.AddAction(onTank ? (int)TreeAction.TankClearHT : (int)TreeAction.RaidClearHT, ccrate * spells[(int)TreeSpell.HealingTouch].Action.Time);
                    dhrate += ccrate;
                }
            }

            if (!naturesGraceHandled && Talents.NaturesGrace > 0)
            {
                dist.AddAction(onTank ? (int)TreeAction.TankRegrowth : (int)TreeAction.RaidRegrowth, 1.0f / 60.0f * spells[(int)TreeSpell.Regrowth].Action.Time);
                dhrate += 1.0f / 60.0f;
            }

            if (dhrate < minRate)
            {
                if (!htFiller)
                    dist.AddAction(onTank ? (int)TreeAction.TankNourish : (int)TreeAction.RaidNourish, (minRate - dhrate) * spells[(int)TreeSpell.Nourish].Action.Time);
                else
                    dist.AddAction(onTank ? (int)TreeAction.TankHealingTouch : (int)TreeAction.RaidHealingTouch, (minRate - dhrate) * spells[(int)TreeSpell.HealingTouch].Action.Time);
            }
        }
예제 #5
0
        ContinuousAction[] computeDivisionActions(TreeStats stats, TreeComputedData data, ComputedSpell[] spells)
        {
            double healingTouchNSReduction = 0;
            bool swiftmendEatsRejuvenation = true;
            double swiftmendExtraTargets = 0;
            double lifebloomManaPerTick = 0;

            if (T12Count >= 2)
                lifebloomManaPerTick += CalculationsTree.BaseMana * 0.01 * 0.4;

            if (T12Count >= 4)
                swiftmendExtraTargets += opts.SwiftmendExtraHealEH;

            if (Talents.GlyphOfSwiftmend)
                swiftmendEatsRejuvenation = false;

            if (Talents.GlyphOfHealingTouch)
                healingTouchNSReduction = 10;

            data.LifebloomMPSGain = lifebloomManaPerTick * spells[(int)TreeSpell.Lifebloom].TPS;

            DiscreteAction[] actions = new DiscreteAction[(int)TreeAction.Count];

            for (int i = 0; i < spells.Length; ++i)
            {
                actions[i] = spells[i].RaidAction;
                actions[spells.Length + i] = spells[i].TankAction;
            }

            #region Effective healing
            actions[(int)TreeAction.RaidTolLb].Direct *= opts.ToLLifebloomEH;
            actions[(int)TreeAction.RaidTolLb].Periodic *= opts.ToLLifebloomEH;
            actions[(int)TreeAction.RaidRejuvenation].Periodic *= opts.RejuvenationEH;
            actions[(int)TreeAction.RaidHealingTouch].Direct *= opts.HealingTouchEH;
            actions[(int)TreeAction.RaidNourish].Direct *= opts.NourishEH;
            actions[(int)TreeAction.RaidRegrowth].Direct *= opts.NourishEH;
            actions[(int)TreeAction.RaidRegrowth].Periodic *= opts.NourishEH;
            actions[(int)TreeAction.RaidWildGrowth].Periodic *= opts.WildGrowthEH;
            actions[(int)TreeAction.RaidSwiftmend].Periodic *= opts.SwiftmendEH;
            actions[(int)TreeAction.RaidTranquility].Direct *= opts.TranquilityEH;
            actions[(int)TreeAction.RaidTranquility].Periodic *= opts.TranquilityEH;
            #endregion

            #region Targets
            double defaultCritMultiplier = getCritMultiplier(stats, 0, 0);
            double wgTargets = (Talents.GlyphOfWildGrowth ? 6 : 5) + stats.TreeOfLifeUptime * 2;

            actions[(int)TreeAction.TankWildGrowth].Periodic += (wgTargets - 1) * actions[(int)TreeAction.RaidWildGrowth].Periodic * opts.TankRaidHealingWeight;
            actions[(int)TreeAction.RaidWildGrowth].Periodic *= wgTargets;

            actions[(int)TreeAction.TankWildGrowth].Ticks *= wgTargets;
            actions[(int)TreeAction.RaidWildGrowth].Ticks *= wgTargets;

            actions[(int)TreeAction.TankSwiftmend].Direct *= (1 + swiftmendExtraTargets * defaultCritMultiplier * stats.DirectHealMultiplier * opts.TankRaidHealingWeight);
            actions[(int)TreeAction.RaidSwiftmend].Direct *= (1 + swiftmendExtraTargets * defaultCritMultiplier * stats.DirectHealMultiplier);

            actions[(int)TreeAction.TankSwiftmend].Casts *= (1 + swiftmendExtraTargets);
            actions[(int)TreeAction.RaidSwiftmend].Casts *= (1 + swiftmendExtraTargets);

            actions[(int)TreeAction.TankSwiftmend].Periodic *= 1 + opts.TankRaidHealingWeight * Math.Max(3 * opts.EfflorescenceEH - 1.0, 0);
            actions[(int)TreeAction.RaidSwiftmend].Periodic *= 3 * opts.EfflorescenceEH;

            actions[(int)TreeAction.TankSwiftmend].Ticks *= Math.Max(3 * opts.EfflorescenceEH, 1);
            actions[(int)TreeAction.RaidSwiftmend].Ticks *= 3 * opts.EfflorescenceEH;
            #endregion

            #region Swiftmend
            if (swiftmendEatsRejuvenation)
                actions[(int)TreeAction.RaidSwiftmend].Direct -= actions[(int)TreeAction.RaidRejuvenation].Periodic * 0.5f;
            #endregion

            #region Lifebloom
            if (stats.TreeOfLifeUptime > 0)
            {
                // TODO: figure out how 2T12 works in ToL and adjust the code as needed
                //actions[(int)TreeAction.RaidTolLb].Mana -= lifebloomManaPerTick * spells[(int)TreeSpell.Lifebloom].Ticks;
                //actions[(int)TreeAction.TankTolLb].Mana -= lifebloomManaPerTick * spells[(int)TreeSpell.Lifebloom].Ticks;
            }
            else
            {
                actions[(int)TreeAction.RaidTolLb].Direct = 0;
                actions[(int)TreeAction.RaidTolLb].Periodic = 0;
                actions[(int)TreeAction.TankTolLb].Direct = 0;
                actions[(int)TreeAction.TankTolLb].Periodic = 0;
            }
            #endregion

            #region Rejuvenation
            actions[(int)TreeAction.TankRejuvenation].Cooldown = spells[(int)TreeSpell.Rejuvenation].Duration;
            #endregion

            #region Nature's Swiftness
            if (Talents.NaturesSwiftness > 0)
            {
                // Nature's Swiftness is actually additive
                double nshtMultiplier = 1 + 0.5 / (1 + stats.PassiveDirectHealBonus + spells[(int)TreeSpell.HealingTouch].ExtraDirectBonus);

                actions[(int)TreeAction.RaidSwiftHT] = actions[(int)TreeAction.RaidHealingTouch];
                actions[(int)TreeAction.TankSwiftHT] = actions[(int)TreeAction.TankHealingTouch];

                actions[(int)TreeAction.RaidSwiftHT].Time = stats.Haste.HastedGCD;
                actions[(int)TreeAction.TankSwiftHT].Time = stats.Haste.HastedGCD;

                actions[(int)TreeAction.RaidSwiftHT].Cooldown = 180 + opts.NaturesSwiftnessCastDelay;
                actions[(int)TreeAction.TankSwiftHT].Cooldown = 180 + opts.NaturesSwiftnessCastDelay;

                actions[(int)TreeAction.RaidSwiftHT].Direct *= nshtMultiplier;
                actions[(int)TreeAction.TankSwiftHT].Direct *= nshtMultiplier;

                if (healingTouchNSReduction > 0)
                {
                    // add the NS effect as an amortized extra heal to each HT
                    double swiftHtFraction = (healingTouchNSReduction / (180.0 + opts.NaturesSwiftnessCastDelay));
                    double htAddTime = swiftHtFraction * stats.Haste.HastedGCD;
                    double htMulDirect = 1 + swiftHtFraction * nshtMultiplier;
                    double htMulMana = 1 + swiftHtFraction;

                    actions[(int)TreeAction.TankHealingTouch].Time += htAddTime;
                    actions[(int)TreeAction.TankHealingTouch].Mana *= htMulMana;
                    actions[(int)TreeAction.TankHealingTouch].Direct *= htMulDirect;

                    actions[(int)TreeAction.RaidHealingTouch].Time += htAddTime;
                    actions[(int)TreeAction.RaidHealingTouch].Mana *= htMulMana;
                    actions[(int)TreeAction.RaidHealingTouch].Direct *= htMulDirect;
                }
            }
            #endregion

            #region Clearcasting
            actions[(int)TreeAction.RaidClearHT] = applyCC(actions[(int)TreeAction.RaidHealingTouch]);
            actions[(int)TreeAction.TankClearHT] = applyCC(actions[(int)TreeAction.TankHealingTouch]);
            actions[(int)TreeAction.RaidClearRegrowth] = applyCC(actions[(int)TreeAction.RaidRegrowth]);
            actions[(int)TreeAction.TankClearRegrowth] = applyCC(actions[(int)TreeAction.TankRegrowth]);

            if (stats.TreeOfLifeUptime > 0)
            {
                actions[(int)TreeAction.RaidTolLbCcHt] = buildTolLbCcHt(stats, spells[(int)TreeSpell.Lifebloom].Ticks, actions[(int)TreeAction.RaidTolLb], 1, actions[(int)TreeAction.RaidClearHT]);
                actions[(int)TreeAction.TankTolLbCcHt] = buildTolLbCcHt(stats, spells[(int)TreeSpell.Lifebloom].Ticks, actions[(int)TreeAction.RaidTolLb], opts.TankRaidHealingWeight, actions[(int)TreeAction.TankClearHT]);
            }
            #endregion

            #region Nature's Bounty
            actions[(int)TreeAction.RaidRj2NourishNB] = buildNourishNB(stats, actions[(int)TreeAction.RaidRejuvenation], spells[(int)TreeSpell.Rejuvenation].Duration, 2, 1, actions[(int)TreeAction.RaidNourish]);
            actions[(int)TreeAction.RaidRj3NourishNB] = buildNourishNB(stats, actions[(int)TreeAction.RaidRejuvenation], spells[(int)TreeSpell.Rejuvenation].Duration, 3, 1, actions[(int)TreeAction.RaidNourish]);
            actions[(int)TreeAction.TankRj2NourishNB] = buildNourishNB(stats, actions[(int)TreeAction.RaidRejuvenation], spells[(int)TreeSpell.Rejuvenation].Duration, 2, opts.TankRaidHealingWeight, actions[(int)TreeAction.TankNourish]);
            #endregion

            #region Additional actions
            data.LifebloomRefreshInterval = spells[(int)TreeSpell.Lifebloom].Duration - opts.LifebloomWastedDuration * stats.Haste.HastedSecond;
            if (data.LifebloomRefreshInterval < stats.Haste.HastedSecond * 3)
                data.LifebloomRefreshInterval = stats.Haste.HastedSecond * 3;

            actions[(int)TreeAction.ReLifebloom].Time = spells[(int)TreeSpell.Lifebloom].Action.Time;
            actions[(int)TreeAction.ReLifebloom].Mana = spells[(int)TreeSpell.Lifebloom].Action.Mana;
            actions[(int)TreeAction.ReLifebloom].Direct = 0;
            actions[(int)TreeAction.ReLifebloom].Periodic = 0;
            actions[(int)TreeAction.ReLifebloom].Cooldown = data.LifebloomRefreshInterval;

            // TODO: actually compute hit instead of assuming we have 0 hit; also maybe have an option/BossHandler value for the target level (there might a permanent add with lower level than the boss)
            actions[(int)TreeAction.InsectSwarm].Time = stats.Haste.HastedGCD / (1 - StatConversion.GetSpellMiss(character.Level - character.BossOptions.Level, false));
            actions[(int)TreeAction.InsectSwarm].Mana = ((int)Math.Floor(CalculationsTree.BaseMana * 8 / 100f) - stats.SpellsManaCostReduction) * stats.SpellsManaCostMultiplier;
            actions[(int)TreeAction.InsectSwarm].Cooldown = 12 + Talents.Genesis * 2;
            #endregion

            ContinuousAction[] factions = new ContinuousAction[(int)TreeAction.Count];
            for (int i = 0; i < (int)TreeAction.Count; ++i)
                factions[i] = new ContinuousAction(actions[i]);
            return factions;
        }
예제 #6
0
        void computeDivisionSpellActions(TreeStats stats, TreeComputedData data, ComputedSpell[] spells)
        {
            for (int i = 0; i < (int)TreeSpell.Count; ++i)
            {
                spells[i].RaidAction = spells[i].Action;
                spells[i].TankAction = spells[i].Action;
            }

            double lifebloomExtraDirectCrit = 0;
            double lifebloomExtraTickCrit = 0;
            double regrowthExtraCrit = 0;
            double tankLivingSeed, raidLivingSeed;

            #region Talents
            if (T11Count >= 2)
                lifebloomExtraTickCrit += 0.05f;

            tankLivingSeed = raidLivingSeed = 0.1f * Talents.LivingSeed;
            raidLivingSeed *= opts.LivingSeedEH;

            regrowthExtraCrit += 0.2f * Talents.NaturesBounty;

            if (Talents.GlyphOfLifebloom)
            {
                lifebloomExtraDirectCrit += 0.1f;
                lifebloomExtraTickCrit += 0.1f;
            }
            #endregion

            #region Crit
            double defaultCritMultiplier = getCritMultiplier(stats, 0, 0);
            double raidLivingSeedCritMultiplier = getCritMultiplier(stats, 0, raidLivingSeed);
            double tankLivingSeedCritMultiplier = getCritMultiplier(stats, 0, tankLivingSeed);

            spells[(int)TreeSpell.Lifebloom].MultiplyDirect(getCritMultiplier(stats, lifebloomExtraDirectCrit, 0));
            spells[(int)TreeSpell.Lifebloom].MultiplyPeriodic(getCritMultiplier(stats, lifebloomExtraTickCrit, 0));

            spells[(int)TreeSpell.WildGrowth].MultiplyPeriodic(defaultCritMultiplier);

            spells[(int)TreeSpell.Tranquility].Multiply(defaultCritMultiplier);

            // gotem doesn't crit, but is affected by Symbiosis, according to TreeCalcs
            spells[(int)TreeSpell.Rejuvenation].MultiplyPeriodic(defaultCritMultiplier);

            spells[(int)TreeSpell.Swiftmend].RaidAction.Direct *= raidLivingSeedCritMultiplier;
            spells[(int)TreeSpell.Swiftmend].TankAction.Direct *= tankLivingSeedCritMultiplier;
            spells[(int)TreeSpell.Swiftmend].MultiplyPeriodic(defaultCritMultiplier);

            spells[(int)TreeSpell.HealingTouch].RaidAction.Direct *= raidLivingSeedCritMultiplier;
            spells[(int)TreeSpell.HealingTouch].TankAction.Direct *= tankLivingSeedCritMultiplier;

            spells[(int)TreeSpell.Nourish].RaidAction.Direct *= raidLivingSeedCritMultiplier;
            spells[(int)TreeSpell.Nourish].TankAction.Direct *= tankLivingSeedCritMultiplier;

            spells[(int)TreeSpell.Regrowth].RaidAction.Direct *= getCritMultiplier(stats, regrowthExtraCrit, raidLivingSeed);
            spells[(int)TreeSpell.Regrowth].TankAction.Direct *= getCritMultiplier(stats, regrowthExtraCrit, tankLivingSeed);
            spells[(int)TreeSpell.Regrowth].MultiplyPeriodic(getCritMultiplier(stats, regrowthExtraCrit, 0));
            #endregion

            #region Nourish HoTs
            spells[(int)TreeSpell.Nourish].RaidAction.Direct *= 1.0 + opts.NourishHoTRate * 0.2;
            spells[(int)TreeSpell.Nourish].TankAction.Direct *= 1.2;
            #endregion
        }
예제 #7
0
        /* Spell data is computed in the following stages:
         * 1. SpellData with constants
         * 2. ComputedSpell containing computed data for a generic target (thus excluding crit, mastery, targets, effective healing)
         * 3. ComputedSpell with RaidAction and TankAction filled with information except effective healing and multiplication by number of targets
         * 4. SpellAction adding effective healing, targets and strange options, plus special SpellActions containing combination of spells
         * 5. Actions containing the SpellActions converted to EPS/MPS/time format
         * 
         * Note that Tank mostly means "target always with hots, hit frequently" while Raid means "target which might have hots (from wild growth), hit rarely"
         */

        ComputedSpell[] computeDivisionSpells(TreeStats stats, TreeComputedData data)
        {
            ComputedSpell[] spells = new ComputedSpell[(int)TreeSpell.Count];
            for (int i = 0; i < (int)TreeSpell.Count; ++i)
            {
                SpellData spdata = CalculationsTree.SpellData[i];
                if(i == (int)TreeSpell.WildGrowth && opts.WildGrowthNerf)
                    spdata = CalculationsTree.NerfedWildGrowthSpellData;
                spells[i] = new ComputedSpell(spdata, stats);
            }

            spells[(int)TreeSpell.Tranquility].DirectMultiplier *= 4 * 5;
            spells[(int)TreeSpell.Tranquility].TickMultiplier *= 4 * 5;

            #region Talents
            double rejuvenationInstantTicks = 0;

            spells[(int)TreeSpell.Swiftmend].ExtraDirectBonus += 0.02f * Talents.Genesis;

            spells[(int)TreeSpell.Rejuvenation].ExtraTickBonus += Talents.BlessingOfTheGrove * 0.02f;

            spells[(int)TreeSpell.Nourish].TimeReductionMS += 250 * Talents.Naturalist;
            spells[(int)TreeSpell.HealingTouch].TimeReductionMS += 250 * Talents.Naturalist;

            spells[(int)TreeSpell.Rejuvenation].ExtraTickBonus += 0.05f * Talents.ImprovedRejuvenation;
            spells[(int)TreeSpell.Swiftmend].ExtraTickBonus += 0.05f * Talents.ImprovedRejuvenation;
            spells[(int)TreeSpell.Swiftmend].ExtraDirectBonus += 0.05f * Talents.ImprovedRejuvenation;

            // according to Paragon's Anaram posting on ElitistJerks, Efflorescence double-dips Master Shapeshifter and Harmony
            spells[(int)TreeSpell.Swiftmend].TickMultiplier *= 0.04f * Talents.Efflorescence * (1.0f + Talents.MasterShapeshifter * 0.04f) * (1.0f + stats.Harmony);

            spells[(int)TreeSpell.Nourish].ExtraDirectBonus += 0.05f * Talents.EmpoweredTouch;
            spells[(int)TreeSpell.HealingTouch].ExtraDirectBonus += 0.05f * Talents.EmpoweredTouch;
            spells[(int)TreeSpell.Regrowth].ExtraDirectBonus += 0.05f * Talents.EmpoweredTouch;

            // formula from TreeCalcs
            // TODO: test this in-game
            rejuvenationInstantTicks = Talents.GiftOfTheEarthmother * 0.05f * Math.Floor(4.0f * (1 + StatConversion.GetSpellHasteFromRating((float)stats.Haste.HasteRating)) + 0.5f) * 1.0135f;
            spells[(int)TreeSpell.Lifebloom].DirectMultiplier *= 1 + Talents.GiftOfTheEarthmother * 0.05f;

            if (Talents.SwiftRejuvenation > 0)
                spells[(int)TreeSpell.Rejuvenation].TimeReductionMS = 500;
            #endregion

            #region Glyphs
            if (Talents.GlyphOfRejuvination)
                spells[(int)TreeSpell.Rejuvenation].ExtraTickBonus += 0.1f;

            if (Talents.GlyphOfRegrowth)
                spells[(int)TreeSpell.Regrowth].ExtraDurationMS += (Talents.GlyphOfRegrowth ? (int)(Math.Min(opts.GlyphOfRegrowthExtraDuration, calc.FightLength) * 1000.0) : 0);
            #endregion

            for (int i = 0; i < (int)TreeSpell.Count; ++i)
            {
                if (i != (int)TreeSpell.HealingTouch && i != (int)TreeSpell.WildGrowth)
                    spells[i].ComputeTiming();
            }

            if (T13Count >= 4)
            {
                // here we assume that the tick structure is computed as if the spell just had double duration
                // this is NOT the same as doubling the amount of ticks, due to rounding

                // also we assume that overhealing ratio doesn't depend on duration in our model
                // if the model is changed to do that, then this averaging will need to be done much later

                for (int i = 0; i < CalculationsTree.T13Spells.Length; ++i)
                {
                    ComputedSpell extspell = new ComputedSpell(CalculationsTree.T13SpellData[i], stats);
                    extspell.ComputeTiming();

                    ComputedSpell spell = spells[(int)CalculationsTree.T13Spells[i]];
                    spell.Ticks = 0.9 * spell.Ticks + 0.1 * extspell.Ticks;
                    spell.TPS = 0.9 * spell.TPS + 0.1 * extspell.TPS;
                    spell.Duration = 0.9 * spell.Duration + 0.1 * extspell.Duration;
                }
            }

            // optimization to avoid duplicating computations
            spells[(int)TreeSpell.HealingTouch].Action.Time = spells[(int)TreeSpell.Nourish].Action.Time;
            spells[(int)TreeSpell.WildGrowth].Action.Time = spells[(int)TreeSpell.Swiftmend].Action.Time;
            spells[(int)TreeSpell.WildGrowth].Ticks = spells[(int)TreeSpell.Swiftmend].Ticks;
            spells[(int)TreeSpell.WildGrowth].Duration = spells[(int)TreeSpell.Swiftmend].Duration;
            spells[(int)TreeSpell.WildGrowth].TPS = spells[(int)TreeSpell.Swiftmend].TPS;

            for (int i = 0; i < (int)TreeSpell.Count; ++i)
                spells[i].ComputeRest();

            if (rejuvenationInstantTicks > 0)
            {
                spells[(int)TreeSpell.Rejuvenation].Action.Direct += rejuvenationInstantTicks * spells[(int)TreeSpell.Rejuvenation].Tick;
                ++spells[(int)TreeSpell.Rejuvenation].Action.Ticks;
            }

            #region Cooldowns
            spells[(int)TreeSpell.WildGrowth].Action.Cooldown = 8 + opts.WildGrowthCastDelay;
            spells[(int)TreeSpell.Tranquility].Action.Cooldown = 8 * 60 - (150 * Talents.MalfurionsGift) + opts.TranquilityCastDelay;
            spells[(int)TreeSpell.Swiftmend].Action.Cooldown = 15 + opts.SwiftmendCastDelay;

            if (opts.GlyphOfWildGrowthCDIncrease && character.DruidTalents.GlyphOfWildGrowth)
                spells[(int)TreeSpell.WildGrowth].Action.Cooldown += 2;
            #endregion

            return spells;
        }
예제 #8
0
        // cast Lifebloom on raid during ToL, then an amortized Healing Touch using the average number of clearcasts from the Lifebloom
        DiscreteAction buildTolLbCcHt(TreeStats stats, double lifebloomTicks, DiscreteAction tollb, double tollbWeight, DiscreteAction ccht)
        {
            double cchtsPerLifebloom = lifebloomTicks * 0.02f * Talents.MalfurionsGift;

            DiscreteAction action = new DiscreteAction();
            action.Time = tollb.Time + cchtsPerLifebloom * ccht.Time;
            action.Direct = tollb.Direct * tollbWeight + cchtsPerLifebloom * ccht.Direct;
            action.Periodic = tollb.Periodic * tollbWeight;
            action.Mana = tollb.Mana;
            action.Casts = cchtsPerLifebloom;
            action.Ticks = lifebloomTicks + cchtsPerLifebloom;
            return action;
        }
예제 #9
0
 // cast Rejuvenation rjn times to get Nature's Bounty, then cast Nourish until it drops off
 // TODO: do we have some extra time before it drops off?
 DiscreteAction buildNourishNB(TreeStats stats, DiscreteAction rj, double rjduration, int rjn, double rjWeight, DiscreteAction nourish)
 {
     DiscreteAction action = new DiscreteAction();
     double nourishCasts = (rjduration - rj.Time * rjn) / ((1.0f - 0.1f * Talents.NaturesBounty) * nourish.Time);
     action.Time = rjduration;
     action.Periodic = rj.Periodic * rjn * rjWeight;
     action.Direct = rj.Direct * rjn * rjWeight + nourishCasts * nourish.Direct;
     action.Mana = rj.Mana * rjn + nourishCasts * nourish.Mana;
     action.Casts = rj.Casts * rjn + nourishCasts;
     action.Ticks = rj.Ticks * rjn;
     return action;
 }
예제 #10
0
 double getCritMultiplier(TreeStats stats, double extraCritChance, double livingSeed)
 {
     double crit = Math.Min(1, stats.SpellCrit + extraCritChance);
     return crit * 2.0 * (1.0 + stats.BonusCritHealMultiplier) * (1 + livingSeed) + (1 - crit);
 }