예제 #1
0
파일: Actions.cs 프로젝트: rakot/rawr
 public ContinuousAction(DiscreteAction pa)
 {
     Time  = pa.Time;
     MPS   = pa.Mana;
     EPS   = pa.Direct + pa.Periodic;
     CPS   = pa.Casts;
     TPS   = pa.Ticks;
     Limit = Time / pa.Cooldown;
     if (!(Limit >= 0 && Limit <= 1))
     {
         Limit = 1;
     }
     if (Time != 0)
     {
         MPS /= Time;
         EPS /= Time;
         CPS /= Time;
         TPS /= Time;
     }
 }
예제 #2
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;
        }
예제 #3
0
 DiscreteAction applyCC(DiscreteAction action)
 {
     action.Mana = 0;
     return action;
 }
예제 #4
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;
        }
예제 #5
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;
 }
예제 #6
0
 public ContinuousAction(DiscreteAction pa)
 {
     Time = pa.Time;
     MPS = pa.Mana;
     EPS = pa.Direct + pa.Periodic;
     CPS = pa.Casts;
     TPS = pa.Ticks;
     Limit = Time / pa.Cooldown;
     if(!(Limit >= 0 && Limit <= 1))
         Limit = 1;
     if (Time != 0)
     {
         MPS /= Time;
         EPS /= Time;
         CPS /= Time;
         TPS /= Time;
     }
 }