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); } }
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); } }
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); }
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; }