public void AddShadowModifiers(SpellModifiers modifiers)
 {
     modifiers.AddMultiplicativeMultiplier(
         Stats.BonusShadowDamageMultiplier);
     modifiers.AddAdditiveMultiplier(
         Talents.ShadowMastery * .03f);
     if (Options.GetActiveRotation().Contains("Shadow Bolt") ||
         (Options.GetActiveRotation().Contains("Haunt") &&
          Talents.Haunt > 0))
     {
         modifiers.AddMultiplicativeTickMultiplier(
             Talents.ShadowEmbrace * .01f * 3f);
     }
     if (CastSpells.ContainsKey("Haunt"))
     {
         modifiers.AddMultiplicativeTickMultiplier(
             ((Haunt)CastSpells["Haunt"]).GetAvgTickBonus());
     }
     if (Pet is Succubus)
     {
         float bonus = Talents.MasterDemonologist * .01f;
         modifiers.AddMultiplicativeMultiplier(bonus);
         modifiers.AddCritChance(bonus);
     }
 }
Example #2
0
 public void AddFireModifiers(SpellModifiers modifiers)
 {
     modifiers.AddMultiplicativeMultiplier(Stats.BonusFireDamageMultiplier);
     modifiers.AddMultiplicativeMultiplier(Demonology ? .15f : 0f);
     modifiers.AddMultiplicativeMultiplier(Destruction ? .25f : 0f);
     if (Destruction)
     {
         // Fiery Apocalypse
         modifiers.AddMultiplicativeMultiplier(.108f + .0135f * (CalcMastery() - 8f));
     }
 }
 public void AddFireModifiers(SpellModifiers modifiers)
 {
     modifiers.AddMultiplicativeMultiplier(
         Stats.BonusFireDamageMultiplier);
     modifiers.AddAdditiveMultiplier(Talents.Emberstorm * .03f);
     if (Pet is Imp)
     {
         float bonus = Talents.MasterDemonologist * .01f;
         modifiers.AddMultiplicativeMultiplier(bonus);
         modifiers.AddCritChance(bonus);
     }
 }
        public void Add4pT10(SpellModifiers modifiers)
        {
            if (Stats.Warlock4T10 == 0)
            {
                return;
            }

            Spell trigger = null;

            if (CastSpells.ContainsKey("Immolate"))
            {
                trigger = CastSpells["Immolate"];
            }
            else if (CastSpells.ContainsKey("Unstable Affliction"))
            {
                trigger = CastSpells["Unstable Affliction"];
            }
            if (trigger != null)
            {
                float numTicks
                    = HitChance * trigger.GetNumCasts() * trigger.NumTicks;
                float uprate
                    = Spell.CalcUprate(
                          .15f, 10f, Options.Duration / numTicks);
                modifiers.AddMultiplicativeMultiplier(.1f * uprate);
            }
        }
Example #5
0
 public void AddShadowModifiers(SpellModifiers modifiers)
 {
     modifiers.AddMultiplicativeMultiplier(Stats.BonusShadowDamageMultiplier);
     modifiers.AddMultiplicativeMultiplier(Affliction ? .3f : 0f); // Shadow Mastery
     modifiers.AddMultiplicativeMultiplier(Demonology ? .15f : 0f);
     if (Affliction)
     {
         modifiers.AddAdditiveTickMultiplier(.1304f + (CalcMastery() - 8f) * .0163f);
     }
     if (CalcOpts.GetActiveRotation().Contains("Shadow Bolt") || (CalcOpts.GetActiveRotation().Contains("Haunt") && Talents.Haunt > 0))
     {
         // we assume a steady state of 3 stacks
         float[] talentEffects = { 0f, .03f, .04f, .05f };
         modifiers.AddMultiplicativeTickMultiplier(talentEffects[Talents.ShadowEmbrace] * 3f);
     }
     if (CastSpells.ContainsKey("Haunt"))
     {
         modifiers.AddMultiplicativeTickMultiplier(((Haunt)CastSpells["Haunt"]).GetAvgTickBonus());
     }
 }
        private float CalcRemainingProcs()
        {
            if (Options.NoProcs)
            {
                return(0f);
            }

            Dictionary <int, float> periods = new Dictionary <int, float>();
            Dictionary <int, float> chances = new Dictionary <int, float>();

            PopulateTriggers(periods, chances);

            float procdDamage = 0f;
            Stats procStats   = new Stats();

            foreach (SpecialEffect effect in Stats.SpecialEffects())
            {
                if (!periods.ContainsKey((int)effect.Trigger))
                {
                    continue;
                }

                Stats effectStats = effect.Stats;
                if (effectStats.ValkyrDamage > 0)
                {
                    SpellModifiers mods = new SpellModifiers();
                    mods.AddCritChance(.05f + Stats.SpellCritOnTarget);
                    mods.AddMultiplicativeMultiplier(
                        Stats.BonusHolyDamageMultiplier);
                    procdDamage
                        += CalcDamageProc(
                               effect,
                               effect.Stats.ValkyrDamage,
                               periods,
                               chances,
                               mods);
                }
                else if (
                    effectStats.ShadowDamage > 0 ||
                    effectStats.FireDamage > 0 ||
                    effectStats.NatureDamage > 0 ||
                    effectStats.HolyDamage > 0 ||
                    effectStats.FrostDamage > 0)
                {
                    SpellModifiers mods = new SpellModifiers();
                    mods.Accumulate(SpellModifiers);
                    if (Options.Imbue.Equals("Grand Firestone"))
                    {
                        mods.AddAdditiveDirectMultiplier(.01f);
                    }
                    if (effectStats.ShadowDamage > 0)
                    {
                        AddShadowModifiers(mods);
                    }
                    else if (effectStats.FireDamage > 0)
                    {
                        AddFireModifiers(mods);
                    }
                    procdDamage
                        += CalcDamageProc(
                               effect,
                               effectStats.ShadowDamage
                               + effectStats.FireDamage
                               + effectStats.NatureDamage
                               + effectStats.HolyDamage
                               + effectStats.FrostDamage,
                               periods,
                               chances,
                               mods);
                }
                else
                {
                    procStats.Accumulate(
                        CalcNormalProc(effect, periods, chances));
                }
            }

            procStats.HasteRating
                                    = procStats.SpellHaste
                                    = procStats.Mana
                                    = procStats.ManaRestore
                                    = procStats.ManaRestoreFromBaseManaPPM
                                    = procStats.ManaRestoreFromMaxManaPerSecond
                                    = procStats.Mp5
                                    = procStats.CritRating
                                    = procStats.SpellCrit
                                    = procStats.SpellCritOnTarget
                                    = procStats.PhysicalCrit
                                    = 0;
            Stats.Accumulate(procStats);

            return(procdDamage);
        }
        private float CalcPersonalDps()
        {
            // SP & Crit: lock before pet (both affected by procs)
            // Procs after crit

            if (Options.GetActiveRotation().GetError() != null)
            {
                return(0f);
            }

            CalcHasteAndManaProcs();
            AvgTimeUsed
                = Spell.GetTimeUsed(
                      CalculationsWarlock.AVG_UNHASTED_CAST_TIME,
                      0f,
                      Haste,
                      Options.Latency);

            float timeRemaining   = Options.Duration;
            float totalMana       = CalcUsableMana(timeRemaining);
            float maxMana         = StatUtils.CalcMana(PreProcStats);
            float manaFromEffects = totalMana - maxMana;
            float manaUsed        = 0f;

            #region Calculate NumCasts for each spell

            // execute stage collision delays
            Spell  execute        = null;
            float  executePercent = GetExecutePercentage();
            string executeName    = Options.GetActiveRotation().Execute;
            if (executePercent > 0)
            {
                execute = GetSpell(executeName);
                SetupSpells(true);
                RecordCollisionDelays(
                    new CastingState(this, execute, executePercent));
            }

            // normal collision delays
            Spell filler = GetSpell(Options.GetActiveRotation().Filler);
            SetupSpells(false);
            RecordCollisionDelays(new CastingState(this, filler, 1f - executePercent));

            // calc numcasts
            foreach (Spell spell in Priorities)
            {
                float numCasts = spell.GetNumCasts();
                timeRemaining -= numCasts * spell.GetAvgTimeUsed();
                manaUsed      += numCasts * spell.ManaCost;
            }
            LifeTap lifeTap = (LifeTap)GetSpell("Life Tap");
            if (executePercent > 0)
            {
                float executeTime = executePercent * timeRemaining;
                float taps
                    = lifeTap.AddCastsForRegen(
                          timeRemaining * executePercent,
                          maxMana + (manaFromEffects - manaUsed) * executePercent,
                          execute);
                executeTime -= taps * lifeTap.GetAvgTimeUsed();
                manaUsed    += taps * lifeTap.ManaCost;
                execute.Spam(executeTime);
                timeRemaining -= executeTime;
                manaUsed      += execute.ManaCost * execute.GetNumCasts();
                CastSpells.Add(Options.GetActiveRotation().Execute, execute);
            }
            timeRemaining
                -= lifeTap.GetAvgTimeUsed()
                   * lifeTap.AddCastsForRegen(
                       timeRemaining, totalMana - manaUsed, filler);
            filler.Spam(timeRemaining);
            CastSpells.Add(Options.GetActiveRotation().Filler, filler);

            foreach (Spell spell in CastSpells.Values)
            {
                spell.AdjustAfterCastingIsSet();
            }

            #endregion

            #region Calculate spell modifiers, Part 1

            // add procs to RawStats
            if (CastSpells.ContainsKey("Curse Of The Elements"))
            {
                // If the raid is already providing this debuff, the curse will
                // not actually end up casting, so this will not double-count
                // the debuff.
                Stats.BonusFireDamageMultiplier
                                      = Stats.BonusShadowDamageMultiplier
                                      = Stats.BonusHolyDamageMultiplier
                                      = Stats.BonusFrostDamageMultiplier
                                      = Stats.BonusNatureDamageMultiplier
                                      = PetBuffs.BonusFireDamageMultiplier
                                      = PetBuffs.BonusShadowDamageMultiplier
                                      = PetBuffs.BonusHolyDamageMultiplier
                                      = PetBuffs.BonusFrostDamageMultiplier
                                      = PetBuffs.BonusNatureDamageMultiplier
                                      = .13f;
            }
            float critBuff = CalcAddedCritBuff();
            Stats.SpellCritOnTarget    += critBuff;
            PetBuffs.SpellCritOnTarget += critBuff;
            Stats.SpellPower           += lifeTap.GetAvgBonusSpellPower();

            // create the SpellModifiers object
            SpellModifiers = new SpellModifiers();
            SpellModifiers.AddMultiplicativeMultiplier(
                Stats.BonusDamageMultiplier);
            SpellModifiers.AddMultiplicativeMultiplier(
                Talents.Malediction * .01f);
            SpellModifiers.AddMultiplicativeMultiplier(
                Talents.DemonicPact * .02f);
            SpellModifiers.AddCritOverallMultiplier(
                Stats.BonusCritMultiplier);
            if (Talents.Metamorphosis > 0)
            {
                SpellModifiers.AddMultiplicativeMultiplier(
                    GetMetamorphosisBonus());
            }
            if (Pet is Felguard)
            {
                SpellModifiers.AddMultiplicativeMultiplier(
                    Talents.MasterDemonologist * .01f);
            }
            Add4pT10(SpellModifiers);

            Stats critProcs = CalcCritProcs();
            Stats.CritRating        += critProcs.CritRating;
            Stats.SpellCrit         += critProcs.SpellCrit;
            Stats.SpellCritOnTarget += critProcs.SpellCritOnTarget;
            SpellModifiers.AddCritChance(CalcSpellCrit());

            if (Pet != null)
            {
                Pet.CalcStats1();
                Stats.SpellPower
                    += Talents.DemonicKnowledge
                       * .04f
                       * (Pet.CalcStamina() + Pet.CalcIntellect());
            }

            #endregion

            float damageDone = CalcRemainingProcs();

            #region Calculate Spell Modifiers, Part 2

            if (Pet != null)
            {
                Pet.CalcStats2();
                Stats.SpellPower += Pet.ApplyPactProcBenefit();
            }

            // finilize each spell's modifiers.
            // Start with Conflagrate, since pyroclasm depends on its results.
            if (CastSpells.ContainsKey("Conflagrate"))
            {
                CastSpells["Conflagrate"].FinalizeSpellModifiers();
            }
            foreach (Spell spell in CastSpells.Values)
            {
                if (!(spell is Conflagrate))
                {
                    spell.FinalizeSpellModifiers();
                }
            }

            #endregion

            #region Calculate damage done for each spell
            Spell conflagrate = null;
            float spellPower  = CalcSpellPower();
            foreach (KeyValuePair <string, Spell> pair in CastSpells)
            {
                Spell spell = pair.Value;
                if (pair.Key.Equals("Conflagrate"))
                {
                    conflagrate = spell;
                    continue; // save until we're sure immolate is done
                }
                spell.SetDamageStats(spellPower);
                damageDone += spell.GetNumCasts() * spell.AvgDamagePerCast;
            }
            if (conflagrate != null)
            {
                conflagrate.SetDamageStats(spellPower);
                damageDone
                    += conflagrate.GetNumCasts() * conflagrate.AvgDamagePerCast;
            }
            #endregion

            return(damageDone / Options.Duration);
        }
 public void AddFireModifiers(SpellModifiers modifiers)
 {
     modifiers.AddMultiplicativeMultiplier(Stats.BonusFireDamageMultiplier);
     modifiers.AddMultiplicativeMultiplier(Demonology ? .15f : 0f);
     modifiers.AddMultiplicativeMultiplier(Destruction ? .25f : 0f);
     if (Destruction)
     {
         // Fiery Apocalypse
         modifiers.AddMultiplicativeMultiplier(.108f + .0135f * (CalcMastery() - 8f));
     }
 }
 public void AddShadowModifiers(SpellModifiers modifiers)
 {
     modifiers.AddMultiplicativeMultiplier(Stats.BonusShadowDamageMultiplier);
     modifiers.AddMultiplicativeMultiplier(Affliction ? .3f : 0f); // Shadow Mastery
     modifiers.AddMultiplicativeMultiplier(Demonology ? .15f : 0f);
     if (Affliction)
     {
         modifiers.AddAdditiveTickMultiplier(.1304f + (CalcMastery() - 8f) * .0163f);
     }
     if (CalcOpts.GetActiveRotation().Contains("Shadow Bolt") || (CalcOpts.GetActiveRotation().Contains("Haunt") && Talents.Haunt > 0))
     {
         // we assume a steady state of 3 stacks
         float[] talentEffects = { 0f, .03f, .04f, .05f };
         modifiers.AddMultiplicativeTickMultiplier(talentEffects[Talents.ShadowEmbrace] * 3f);
     }
     if (CastSpells.ContainsKey("Haunt"))
     {
         modifiers.AddMultiplicativeTickMultiplier(((Haunt)CastSpells["Haunt"]).GetAvgTickBonus());
     }
 }
        private float CalcRemainingProcs()
        {
            if (CalcOpts.NoProcs)
            {
                return 0f;
            }

            Dictionary<int, float> periods = new Dictionary<int, float>();
            Dictionary<int, float> chances = new Dictionary<int, float>();
            PopulateTriggers(periods, chances);

            float procdDamage = 0f;
            Stats procStats = new Stats();
            foreach (SpecialEffect effect in Stats.SpecialEffects())
            {
                if (!periods.ContainsKey((int)effect.Trigger))
                {
                    continue;
                }

                Stats effectStats = effect.Stats;
                if (effectStats.HolySummonedDamage > 0)
                {
                    SpellModifiers mods = new SpellModifiers();
                    mods.AddCritChance(.05f + Stats.SpellCritOnTarget);
                    mods.AddMultiplicativeMultiplier(Stats.BonusHolyDamageMultiplier);
                    procdDamage += CalcDamageProc(effect, effect.Stats.HolySummonedDamage, periods, chances, mods);
                }
                else if (
                         effectStats.ShadowDamage > 0
                      || effectStats.FireDamage > 0
                      || effectStats.NatureDamage > 0
                      || effectStats.HolyDamage > 0
                      || effectStats.FrostDamage > 0)
                {
                    SpellModifiers mods = new SpellModifiers();
                    mods.Accumulate(SpellModifiers);

                    if (effectStats.ShadowDamage > 0)
                    {
                        AddShadowModifiers(mods);
                    }
                    else if (effectStats.FireDamage > 0)
                    {
                        AddFireModifiers(mods);
                    }
                    procdDamage += CalcDamageProc(
                            effect,
                              effectStats.ShadowDamage
                            + effectStats.FireDamage
                            + effectStats.NatureDamage
                            + effectStats.HolyDamage
                            + effectStats.FrostDamage,
                            periods,
                            chances,
                            mods);
                }
                else
                {
                    procStats.Accumulate(CalcNormalProc(effect, periods, chances));
                }
            }

            procStats.HasteRating
                = procStats.SpellHaste
                = procStats.Mana
                = procStats.ManaRestore
                = procStats.ManaRestoreFromMaxManaPerSecond
                = procStats.Mp5
                = procStats.CritRating
                = procStats.SpellCrit
                = procStats.SpellCritOnTarget
                = procStats.PhysicalCrit
                = 0;
            Stats.Accumulate(procStats);

            return procdDamage;
        }
        private float CalcPersonalDps()
        {
            // SP & Crit: lock before pet (both affected by procs)
            // Procs after crit

            if (CalcOpts.GetActiveRotation().GetError() != null)
            {
                return 0f;
            }

            CalcHasteAndManaProcs();
            AvgTimeUsed = Spell.GetTimeUsed(CalculationsWarlock.AVG_UNHASTED_CAST_TIME, 0f, Haste, CalcOpts.Latency);

            float timeRemaining = BossOpts.BerserkTimer;
            float totalMana = CalcUsableMana(timeRemaining);
            float maxMana = StatUtils.CalcMana(PreProcStats, BaseIntellect, CalcOpts.PlayerLevel);
            float manaFromEffects = totalMana - maxMana;
            float manaUsed = 0f;

            // Calculate NumCasts for each spell

            // execute stage collision delays
            Spell execute = null;
            float executePercent = GetExecutePercentage();
            string executeName = CalcOpts.GetActiveRotation().Execute;
            if (executePercent > 0)
            {
                execute = GetSpell(executeName);
                SetupSpells(true);
                RecordCollisionDelays(new CastingState(this, execute, executePercent));
            }

            // normal collision delays
            Spell filler = GetSpell(CalcOpts.GetActiveRotation().Filler);
            SetupSpells(false);
            RecordCollisionDelays(new CastingState(this, filler, 1f - executePercent));

            // calc numcasts
            foreach (Spell spell in Priorities)
            {
                float numCasts = spell.GetNumCasts();
                timeRemaining -= numCasts * spell.GetAvgTimeUsed();
                manaUsed += numCasts * spell.ManaCost;
            }
            LifeTap lifeTap = (LifeTap)GetSpell("Life Tap");
            if (executePercent > 0)
            {
                float executeTime = executePercent * timeRemaining;
                float taps = lifeTap.AddCastsForRegen(timeRemaining * executePercent, maxMana + (manaFromEffects - manaUsed) * executePercent, execute);
                executeTime -= taps * lifeTap.GetAvgTimeUsed();
                manaUsed += taps * lifeTap.ManaCost;
                execute.Spam(executeTime);
                timeRemaining -= executeTime;
                manaUsed += execute.ManaCost * execute.GetNumCasts();
                CastSpells.Add(CalcOpts.GetActiveRotation().Execute, execute);
            }
            timeRemaining -= lifeTap.GetAvgTimeUsed() * lifeTap.AddCastsForRegen(timeRemaining, totalMana - manaUsed, filler);
            filler.Spam(timeRemaining);
            if (!CastSpells.ContainsKey(CalcOpts.GetActiveRotation().Filler))
            {
                CastSpells.Add(CalcOpts.GetActiveRotation().Filler, filler);
            }

            foreach (Spell spell in CastSpells.Values)
            {
                spell.AdjustAfterCastingIsSet();
            }

            // add procs to RawStats
            if (CastSpells.ContainsKey("Curse Of The Elements"))
            {
                // If the raid is already providing this debuff, the curse will
                // not actually end up casting, so this will not double-count
                // the debuff.
                Stats.BonusFireDamageMultiplier
                    = Stats.BonusShadowDamageMultiplier
                    = Stats.BonusHolyDamageMultiplier
                    = Stats.BonusFrostDamageMultiplier
                    = Stats.BonusNatureDamageMultiplier
                    = PetBuffs.BonusFireDamageMultiplier
                    = PetBuffs.BonusShadowDamageMultiplier
                    = PetBuffs.BonusHolyDamageMultiplier
                    = PetBuffs.BonusFrostDamageMultiplier
                    = PetBuffs.BonusNatureDamageMultiplier
                    = .08f;
            }
            float critBuff = CalcAddedCritBuff();
            Stats.SpellCritOnTarget += critBuff;
            PetBuffs.SpellCritOnTarget += critBuff;

            // create the SpellModifiers object
            SpellModifiers = new SpellModifiers();
            SpellModifiers.AddMultiplicativeMultiplier(Stats.BonusDamageMultiplier);
            SpellModifiers.AddMultiplicativeMultiplier(Talents.DemonicPact * .02f);
            SpellModifiers.AddCritOverallMultiplier(Stats.BonusCritDamageMultiplier);
            if (Talents.Metamorphosis > 0)
            {
                SpellModifiers.AddMultiplicativeMultiplier(
                    GetMetamorphosisBonus());
            }

            Stats critProcs = CalcCritProcs();
            Stats.CritRating += critProcs.CritRating;
            Stats.SpellCrit += critProcs.SpellCrit;
            Stats.SpellCritOnTarget += critProcs.SpellCritOnTarget;
            SpellModifiers.AddCritChance(CalcSpellCrit());

            if (Pet != null)
            {
                Pet.CalcStats1();
            }

            float damageDone = CalcRemainingProcs();
                        
            if (Pet != null)
            {
                Pet.CalcStats2();
            }

            // TODO: Mana Feed talent: You gain 4% total mana whenever your demon critically hits with its Basic Attack.
            // (PTR: 16% if your pet is a Felguard or Felhunter)

            // finilize each spell's modifiers.
            // Start with Conflagrate, since pyroclasm depends on its results.
            if (CastSpells.ContainsKey("Conflagrate"))
            {
                CastSpells["Conflagrate"].FinalizeSpellModifiers();
            }
            foreach (Spell spell in CastSpells.Values)
            {
                if (!(spell is Conflagrate))
                {
                    spell.FinalizeSpellModifiers();
                }
            }

            Spell conflagrate = null;
            float spellPower = CalcSpellPower();
            foreach (KeyValuePair<string, Spell> pair in CastSpells)
            {
                Spell spell = pair.Value;
                if (pair.Key.Equals("Conflagrate"))
                {
                    conflagrate = spell;
                    continue; // save until we're sure immolate is done
                }
                spell.SetDamageStats(spellPower);
                damageDone += spell.GetNumCasts() * spell.AvgDamagePerCast;
            }
            if (conflagrate != null)
            {
                conflagrate.SetDamageStats(spellPower);
                damageDone += conflagrate.GetNumCasts() * conflagrate.AvgDamagePerCast;
            }

            return damageDone / BossOpts.BerserkTimer;
        }