Beispiel #1
0
        private float CalcAddedCritBuff()
        {
            // If the 5% crit debuff is not already being maintained by
            // somebody else (i.e. it's not selected in the buffs tab), we
            // may supply it via Improved Shadow Bolt.
            if (Talents.ShadowAndFlame == 0 || StatUtils.GetActiveBuff(Character.ActiveBuffs, "Spell Critical Strike Taken", s => s.SpellCritOnTarget) > 0)
            {
                return(0f);
            }

            float casts = 0f;

            if (CastSpells.ContainsKey("Shadow Bolt"))
            {
                casts += CastSpells["Shadow Bolt"].GetNumCasts();
            }
            if (CastSpells.ContainsKey("Shadow Bolt (Instant)"))
            {
                casts += CastSpells["Shadow Bolt (Instant)"].GetNumCasts();
            }
            if (casts == 0)
            {
                return(0f);
            }

            float uprate = Spell.CalcUprate(
                Talents.ShadowAndFlame * .33f,  // proc rate
                30f,                            // duration
                BossOpts.BerserkTimer / casts); // trigger period
            float benefit = .05f - Stats.SpellCritOnTarget;

            return(benefit * uprate);
        }
Beispiel #2
0
        private float CalcRaidBuff()
        {
            float raidBuff = 0f;
            float perSP    = CalcOpts.PerSP;

            if (perSP > 0 && Pet != null)
            {
                if (CalcOpts.ConvertTotem)
                {
                    float curTotem = StatUtils.GetActiveBuff(Character.ActiveBuffs, "Spell Power", s => s.SpellPower);
                    if (curTotem == 144f || curTotem == 165f)
                    {
                        raidBuff += CalcOpts.PerFlametongue;
                    }
                }
            }

            if (CastSpells.ContainsKey("Curse Of The Elements"))
            {
                raidBuff += CalcOpts.PerMagicBuff;
            }

            raidBuff += CalcOpts.PerCritBuff * (CalcAddedCritBuff() / .05f);
            raidBuff += CalcOpts.PerHealth * CalculationsWarlock.CalcPetHealthBuff(CalcOpts.Pet, Talents, Character.ActiveBuffs, CalcOpts);

            return(raidBuff);
        }
Beispiel #3
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);
             }
         }
     }
 }
Beispiel #4
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());
     }
 }
Beispiel #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);
        }
Beispiel #6
0
        /// <summary>
        /// Builds a dictionary containing the values to display for each of the
        /// calculations defined in CharacterDisplayCalculationLabels. The key
        /// should be the Label of each display calculation, and the value
        /// should be the value to display, optionally appended with '*'
        /// followed by any string you'd like displayed as a tooltip on the
        /// value.
        /// </summary>
        /// <returns>
        /// A Dictionary<string, string> containing the values to display for
        /// each of the calculations defined in
        /// CharacterDisplayCalculationLabels.
        /// </returns>
        public override Dictionary <string, string> GetCharacterDisplayCalculationValues()
        {
            Dictionary <string, string> dictValues = new Dictionary <string, string>();

            dictValues.Add("Personal DPS", string.Format("{0:0}", PersonalDps));
            dictValues.Add("Pet DPS", string.Format("{0:0}", PetDps));
            dictValues.Add("Total DPS", string.Format("{0:0}", OverallPoints));

            dictValues.Add("Health", string.Format("{0:0}*{1:0} stamina", CalcHealth(), CalcStamina()));
            dictValues.Add("Mana", string.Format("{0:0}*{1:0} intellect", CalcMana(), CalcIntellect()));

            dictValues.Add("Spell Power", string.Format("{0:0.0}*{1:0.0}\tBefore Procs", CalcSpellPower(), StatUtils.CalcSpellPower(PreProcStats, BaseIntellect, CalcOpts.PlayerLevel)));

            #region Hit Rating
            float onePercentOfHitRating = (1 / StatUtils.GetSpellHitFromRating(1, CalcOpts.PlayerLevel));
            float hitFromRating         = StatUtils.GetSpellHitFromRating(Stats.HitRating, CalcOpts.PlayerLevel);
            float hitFromBuffs          = (CalcSpellHit() - hitFromRating);
            float targetHit             = CalcOpts.GetBaseHitRate() / 100f;
            float totalHit   = targetHit + CalcSpellHit();
            float missChance = totalHit > 1 ? 0 : (1 - totalHit);
            dictValues.Add(
                "Hit Rating",
                string.Format(
                    "{0}*{1:0.00%} Hit Chance (max 100%) | {2:0.00%} Miss Chance \r\n\r\n"
                    + "{3:0.00%}\t Base Hit Chance on a Level {4:0} target\r\n"
                    + "{5:0.00%}\t from {6:0} Hit Rating [gear, food and/or flasks]\r\n"
                    + "{7:0.00%}\t from Buffs: Racial and/or Spell Hit Chance Taken\r\n\r\n"
                    + "You are {8} hit rating {9} the hard cap [no hit from gear, talents or buffs]\r\n\r\n",
                    Stats.HitRating,
                    totalHit,
                    missChance,
                    targetHit,
                    CalcOpts.TargetLevel,
                    hitFromRating,
                    Stats.HitRating,
                    hitFromBuffs,
                    Math.Ceiling(Math.Abs((totalHit - 1) * onePercentOfHitRating)),
                    (totalHit > 1) ? "above" : "below"));
            #endregion

            dictValues.Add("Crit Chance", string.Format("{0:0.00%}*{1:0.00%}\tBefore Procs", CalcSpellCrit(), StatUtils.CalcSpellCrit(PreProcStats, BaseIntellect, CalcOpts.PlayerLevel)));
            dictValues.Add("Average Haste",
                           string.Format(
                               "{0:0.00}%*"
                               + "{1:0.00}%\tfrom {2:0.0} Haste rating\r\n"
                               + "{3:0.00}%\tfrom Buffs\r\n"
                               + "{4:0.0}ish%\tfrom Procs\r\n"
                               + "\r\n"
                               + "{5:0.00}s\tGlobal Cooldown\r\n",
                               (AvgHaste - 1f) * 100f,
                               StatUtils.GetSpellHasteFromRating(Stats.HasteRating, CalcOpts.PlayerLevel) * 100f,
                               Stats.HasteRating,
                               Stats.SpellHaste * 100f,
                               (AvgHaste - StatUtils.CalcSpellHaste(PreProcStats, CalcOpts.PlayerLevel)) * 100f,
                               Math.Max(1.0f, 1.5f / AvgHaste)));
            dictValues.Add("Mastery", string.Format("{0:0.0}*from {1:0.0} Mastery Rating", CalcMastery(), Stats.MasteryRating));

            if (Pet == null)
            {
                dictValues.Add("Pet Mana", "-");
                dictValues.Add("Basic Melee Damage", "-");
                dictValues.Add("Basic Melee DPS", "-");
                dictValues.Add("Attack Power", "-");
                dictValues.Add("Basic Melee Speed", "-");
                dictValues.Add("Spell Damage", "-");
            }
            else
            {
                dictValues.Add("Pet Mana", string.Format("{0:0.0}", Pet.CalcMana()));
                dictValues.Add("Basic Melee Damage", string.Format("{0:0.0}", Pet.CalcMeleeDamage()));
                dictValues.Add("Basic Melee DPS", string.Format("{0:0.0}", Pet.CalcMeleeDps()));
                dictValues.Add("Attack Power", string.Format("{0:0.0}", Pet.CalcAttackPower()));
                dictValues.Add("Basic Melee Speed", string.Format("{0:0.0}", Pet.CalcMeleeSpeed()));
                dictValues.Add("Spell Damage", string.Format("{0:0.0}", Pet.CalcSpellPower()));
            }

            if (Pet is Felhunter)
            {
                dictValues.Add("Shadow Bite (Fel Hunter)", string.Format("{0:0.0}", Pet.GetSpecialDamage()));
            }
            else
            {
                dictValues.Add("Shadow Bite (Fel Hunter)", "-");
            }

            if (Pet is Imp)
            {
                dictValues.Add("Fire Bolt (Imp)", string.Format("{0:0.0}", Pet.GetSpecialDamage()));
            }
            else
            {
                dictValues.Add("Fire Bolt (Imp)", "-");
            }

            if (Pet is Succubus)
            {
                dictValues.Add("Lash of Pain (Succubus)", string.Format("{0:0.0}", Pet.GetSpecialDamage()));
            }
            else
            {
                dictValues.Add("Lash of Pain (Succubus)", "-");
            }

            if (Pet is Felguard)
            {
                dictValues.Add("Legion Strike (Felguard)", string.Format("{0:0.0}", Pet.GetSpecialDamage()));
            }
            else
            {
                dictValues.Add("Legion Strike (Felguard)", "-");
            }

            // Spell Stats
            foreach (string spellName in Spell.ALL_SPELLS)
            {
                if (CastSpells.ContainsKey(spellName))
                {
                    dictValues.Add(spellName, CastSpells[spellName].GetToolTip());
                }
                else
                {
                    dictValues.Add(spellName, "-");
                }
            }

            return(dictValues);
        }