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.AddAdditiveMultiplier(Talents.Emberstorm * .03f); if (Pet is Imp) { float bonus = Talents.MasterDemonologist * .01f; modifiers.AddMultiplicativeMultiplier(bonus); modifiers.AddCritChance(bonus); } }
// Kitchen Sink Constructor public Spell( CharacterCalculationsWarlock mommy, MagicSchool magicSchool, SpellTree spellTree, float percentBaseMana, float baseCastTime, float cooldown, float recastPeriod, bool canMiss, float avgDirectDamage, float directCoefficient, float addedDirectMultiplier, float baseTickDamage, float numTicks, float tickCoefficient, float addedTickMultiplier, bool canTickCrit, float bonusCritChance, float bonusCritMultiplier) { Mommy = mommy; MagicSchool = magicSchool; MySpellTree = spellTree; ManaCost = mommy.BaseMana * percentBaseMana; BaseCastTime = baseCastTime; BaseDamage = avgDirectDamage; Cooldown = cooldown; RecastPeriod = recastPeriod; CanMiss = canMiss; DirectCoefficient = directCoefficient; BaseTickDamage = baseTickDamage; NumTicks = numTicks; TickCoefficient = tickCoefficient; CanTickCrit = canTickCrit; SimulatedStats = new Dictionary<string, SimulatedStat>(); WarlockTalents talents = mommy.Talents; SpellModifiers = new SpellModifiers(); SpellModifiers.AddMultiplicativeDirectMultiplier(addedDirectMultiplier); SpellModifiers.AddMultiplicativeTickMultiplier(addedTickMultiplier); SpellModifiers.AddCritChance(bonusCritChance); SpellModifiers.AddCritBonusMultiplier(bonusCritMultiplier); }
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; }