Пример #1
0
        public float GetExecutePercentage()
        {
            string executeName = CalcOpts.GetActiveRotation().Execute;

            if (executeName == null || executeName == "")
            {
                return(0f);
            }

            Spell execute = GetSpell(executeName);

            if (!execute.IsCastable())
            {
                return(0f);
            }

            if (execute is SoulFire)
            {
                return(CalcOpts.ThirtyFive);
            }
            else
            {
                return(CalcOpts.TwentyFive);
            }
        }
Пример #2
0
 private void SetupSpells(bool execute)
 {
     Priorities = new List <Spell>();
     foreach (string spellName in CalcOpts.GetActiveRotation().GetPrioritiesForCalcs(Talents, execute))
     {
         Spell spell = GetSpell(spellName);
         if (spell.IsCastable() && (!execute || spell.IsCastDuringExecute()))
         {
             Priorities.Add(spell);
             if (!CastSpells.ContainsKey(spellName))
             {
                 CastSpells.Add(spellName, spell);
             }
         }
     }
 }
Пример #3
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());
     }
 }
Пример #4
0
        private void CalcHasteAndManaProcs()
        {
            float nonProcHaste = StatUtils.CalcSpellHaste(PreProcStats, CalcOpts.PlayerLevel);

            if (CalcOpts.NoProcs)
            {
                WeightedStat staticHaste = new WeightedStat();
                staticHaste.Chance = 1f;
                staticHaste.Value  = nonProcHaste;
                Haste = new List <WeightedStat> {
                    staticHaste
                };
                AvgHaste = nonProcHaste;
                return;
            }

            // the trigger rates are all guestimates at this point, since the
            // real values depend on haste (which obviously has not been
            // finalized yet)
            Dictionary <int, float> periods = new Dictionary <int, float>();
            Dictionary <int, float> chances = new Dictionary <int, float>();
            float corruptionPeriod          = 0f;

            if (CalcOpts.GetActiveRotation().Contains("Corruption"))
            {
                corruptionPeriod = 3.1f / nonProcHaste;
            }
            PopulateTriggers(periods, chances, CalculationsWarlock.AVG_UNHASTED_CAST_TIME / nonProcHaste + CalcOpts.Latency, 1 / 1.5f, corruptionPeriod, 1f);

            // calculate the haste procs
            Haste = new List <WeightedStat>();
            WeightedStat[] percentages = GetUptimes(Stats, periods, chances, s => s.SpellHaste,
                                                    (a, b, c, d, e, f, g, h) => SpecialEffect.GetAverageCombinedUptimeCombinationsMultiplicative(a, b, c, d, e, f, g, h));
            WeightedStat[] ratings = GetUptimes(Stats, periods, chances, s => s.HasteRating,
                                                (a, b, c, d, e, f, g, h) => SpecialEffect.GetAverageCombinedUptimeCombinations(a, b, c, d, e, f, g, h));
            for (int p = percentages.Length, f = 0; --p >= 0;)
            {
                if (percentages[p].Chance == 0)
                {
                    continue;
                }

                for (int r = ratings.Length; --r >= 0; ++f)
                {
                    if (ratings[r].Chance == 0)
                    {
                        continue;
                    }
                    WeightedStat s = new WeightedStat();
                    s.Chance = percentages[p].Chance * ratings[r].Chance;
                    s.Value  = (1 + percentages[p].Value)
                               * (1 + StatUtils.GetSpellHasteFromRating(ratings[r].Value + Stats.HasteRating, CalcOpts.PlayerLevel))
                               * (1 + Stats.SpellHaste);
                    Haste.Add(s);
                    AvgHaste += s.Chance * s.Value;
                }
            }

            // calculate mana procs
            Stats procStats = new Stats();

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

                Stats proc = effect.GetAverageStats(periods[(int)effect.Trigger], chances[(int)effect.Trigger], CalculationsWarlock.AVG_UNHASTED_CAST_TIME, BossOpts.BerserkTimer);
                if (proc.ManaRestore > 0)
                {
                    proc.ManaRestore *= BossOpts.BerserkTimer;
                }
                procStats.Accumulate(proc);
            }
            Stats.Mana        += procStats.Mana;
            Stats.ManaRestore += procStats.ManaRestore;
            Stats.ManaRestoreFromMaxManaPerSecond += procStats.ManaRestoreFromMaxManaPerSecond;
            Stats.Mp5 += procStats.Mp5;
        }
Пример #5
0
        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);
        }