public Stats getSpecialEffects(SpecialEffect effect) { Stats statsAverage = new Stats(); if (effect == mainHandEnchant || effect == offHandEnchant) { if (mainHandEnchant != null && !mhProcessed) { statsAverage.Accumulate(mainHandEnchant.Stats, GetMHUptime()); mhProcessed = true; } else if (offHandEnchant != null && !ohProcessed) { statsAverage.Accumulate(offHandEnchant.Stats, GetOHUptime()); ohProcessed = true; } } else if (effect.Trigger == Trigger.Use) { effect.AccumulateAverageStats(statsAverage); foreach (SpecialEffect e in effect.Stats.SpecialEffects()) statsAverage.Accumulate(this.getSpecialEffects(e) * (effect.Duration / effect.Cooldown)); } else { SetTriggerChanceAndSpeed(effect); foreach (SpecialEffect e in effect.Stats.SpecialEffects()) // deal with secondary effects { statsAverage.Accumulate(this.getSpecialEffects(e)); } if (effect.MaxStack > 1) { if (effect.Stats.MoteOfAnger > 0) { // When in effect stats, MoteOfAnger is % of melee hits // When in character stats, MoteOfAnger is average procs per second statsAverage.Accumulate(new Stats() { MoteOfAnger = effect.Stats.MoteOfAnger * effect.GetAverageProcsPerSecond(trigger, chance, unhastedAttackSpeed, 0f) / effect.MaxStack }); } else { float timeToMax = (float)Math.Min(_cs.FightLength, effect.GetChance(unhastedAttackSpeed) * trigger * effect.MaxStack); float buffDuration = _cs.FightLength; if (effect.Stats.AttackPower == 250f || effect.Stats.AttackPower == 215f || effect.Stats.HasteRating == 57f || effect.Stats.HasteRating == 64f) { buffDuration = 20f; } if (timeToMax * .5f > buffDuration) { timeToMax = 2 * buffDuration; } statsAverage.Accumulate(effect.Stats * (effect.MaxStack * (((buffDuration) - .5f * timeToMax) / (buffDuration)))); } } else { effect.AccumulateAverageStats(statsAverage, trigger, chance, unhastedAttackSpeed); } } return statsAverage; }
/// <summary> /// With Triggers already setup, just pass into the Accumulate function and return the values /// </summary> /// <param name="effect"></param> /// <returns></returns> public StatsDK getSpecialEffects(SpecialEffect effect) { StatsDK statsAverage = new StatsDK(); triggerIntervals[Trigger.Use] = effect.Cooldown; if (float.IsInfinity(effect.Cooldown)) { triggerIntervals[Trigger.Use] = m_bo.BerserkTimer; } effect.AccumulateAverageStats(statsAverage, triggerIntervals, triggerChances, unhastedAttackSpeed, m_bo.BerserkTimer); return(statsAverage); }
public Stats getSpecialEffects(CalculationOptionsDPSDK calcOpts, SpecialEffect effect) { Stats statsAverage = new Stats(); Rotation rotation = calcOpts.rotation; if (effect.Trigger == Trigger.Use) { effect.AccumulateAverageStats(statsAverage); foreach (SpecialEffect e in effect.Stats.SpecialEffects()) { statsAverage.Accumulate(this.getSpecialEffects(calcOpts, e), (effect.Duration / effect.Cooldown)); } } else { double trigger = 0f; float chance = 0f; float unhastedAttackSpeed = 2f; switch (effect.Trigger) { case Trigger.MeleeCrit: case Trigger.PhysicalCrit: trigger = (1f / ((rotation.getMeleeSpecialsPerSecond() * (combatTable.DW ? 2f : 1f)) + (combatTable.combinedSwingTime != 0 ? 1f / combatTable.combinedSwingTime : 0.5f))); chance = combatTable.physCrits; unhastedAttackSpeed = (combatTable.MH != null ? combatTable.MH.baseSpeed : 2.0f); break; case Trigger.MeleeHit: case Trigger.PhysicalHit: trigger = (1f / ((rotation.getMeleeSpecialsPerSecond() * (combatTable.DW ? 2f : 1f)) + (combatTable.combinedSwingTime != 0 ? 1f / combatTable.combinedSwingTime : 0.5f))); chance = 1f - (combatTable.missedSpecial + combatTable.dodgedSpecial) * (1f - combatTable.totalMHMiss); unhastedAttackSpeed = (combatTable.MH != null ? combatTable.MH.baseSpeed : 2.0f); break; case Trigger.CurrentHandHit: trigger = (1f / ((rotation.getMeleeSpecialsPerSecond()) + (combatTable.combinedSwingTime != 0 ? 1f / combatTable.combinedSwingTime : 0.5f))); chance = 1f - (combatTable.missedSpecial + combatTable.dodgedSpecial) * (1f - combatTable.totalMHMiss); // TODO: need to know if this is MH or OH. unhastedAttackSpeed = (combatTable.MH != null ? combatTable.MH.baseSpeed : 2.0f); break; case Trigger.MainHandHit: trigger = (1f / ((rotation.getMeleeSpecialsPerSecond()) + (combatTable.combinedSwingTime != 0 ? 1f / combatTable.combinedSwingTime : 0.5f))); chance = 1f - (combatTable.missedSpecial + combatTable.dodgedSpecial) * (1f - combatTable.totalMHMiss); unhastedAttackSpeed = (combatTable.MH != null ? combatTable.MH.baseSpeed : 2.0f); break; case Trigger.OffHandHit: trigger = (1f / ((rotation.getMeleeSpecialsPerSecond()) + (combatTable.combinedSwingTime != 0 ? 1f / combatTable.combinedSwingTime : 0.5f))); chance = 1f - (combatTable.missedSpecial + combatTable.dodgedSpecial) * (1f - combatTable.totalMHMiss); unhastedAttackSpeed = (combatTable.OH != null ? combatTable.OH.baseSpeed : 2.0f); break; case Trigger.DamageDone: trigger = 1f / (((rotation.getMeleeSpecialsPerSecond() * (combatTable.DW ? 2f : 1f)) + rotation.getSpellSpecialsPerSecond()) + (combatTable.combinedSwingTime != 0 ? 1f / combatTable.combinedSwingTime: 0.5f)); chance = (1f - (combatTable.missedSpecial + combatTable.dodgedSpecial)) * (1f - combatTable.totalMHMiss); unhastedAttackSpeed = (combatTable.MH != null ? combatTable.MH.baseSpeed : 2.0f); break; case Trigger.DamageOrHealingDone: // Need to add Self Healing trigger = 1f / (((rotation.getMeleeSpecialsPerSecond() * (combatTable.DW ? 2f : 1f)) + rotation.getSpellSpecialsPerSecond()) + (combatTable.combinedSwingTime != 0 ? 1f / combatTable.combinedSwingTime : 0.5f)); chance = (1f - (combatTable.missedSpecial + combatTable.dodgedSpecial)) * (1f - combatTable.totalMHMiss); unhastedAttackSpeed = (combatTable.MH != null ? combatTable.MH.baseSpeed : 2.0f); break; case Trigger.DamageSpellCast: case Trigger.SpellCast: case Trigger.DamageSpellHit: case Trigger.SpellHit: trigger = 1f / rotation.getSpellSpecialsPerSecond(); chance = 1f - combatTable.spellResist; break; case Trigger.DamageSpellCrit: case Trigger.SpellCrit: trigger = 1f / rotation.getSpellSpecialsPerSecond(); chance = combatTable.spellCrits; break; case Trigger.BloodStrikeHit: trigger = rotation.CurRotationDuration / (rotation.BloodStrike * (combatTable.DW ? 2f : 1f)); chance = 1f; break; case Trigger.HeartStrikeHit: trigger = rotation.CurRotationDuration / rotation.HeartStrike; chance = 1f; break; case Trigger.BloodStrikeOrHeartStrikeHit: trigger = rotation.CurRotationDuration / ((rotation.BloodStrike + rotation.HeartStrike) * (combatTable.DW ? 2f : 1f)); chance = 1f; break; case Trigger.ObliterateHit: trigger = rotation.CurRotationDuration / (rotation.Obliterate * (combatTable.DW ? 2f : 1f)); chance = 1f; break; case Trigger.ScourgeStrikeHit: trigger = rotation.CurRotationDuration / rotation.ScourgeStrike; chance = 1f; break; case Trigger.DeathStrikeHit: trigger = rotation.CurRotationDuration / rotation.DeathStrike; chance = 1f; break; case Trigger.PlagueStrikeHit: trigger = rotation.CurRotationDuration / (rotation.PlagueStrike * (combatTable.DW ? 2f : 1f)); chance = 1f; break; case Trigger.DoTTick: trigger = (rotation.BloodPlague + rotation.FrostFever) / 3; chance = 1f; break; } #if false // Pull out the embedded handling in this situation. foreach (SpecialEffect e in effect.Stats.SpecialEffects()) { statsAverage.Accumulate(this.getSpecialEffects(calcOpts, e)); } #endif if (effect.MaxStack > 1) { float timeToMax = (float)Math.Min(calcOpts.FightLength * 60, effect.GetChance(unhastedAttackSpeed) * trigger * effect.MaxStack); float buffDuration = calcOpts.FightLength * 60f; if (effect.Stats.AttackPower == 250f || effect.Stats.AttackPower == 215f || effect.Stats.HasteRating == 57f || effect.Stats.HasteRating == 64f) { buffDuration = 20f; } if (timeToMax * .5f > buffDuration) { timeToMax = 2 * buffDuration; } statsAverage.Accumulate(effect.Stats, effect.GetAverageStackSize((float)trigger, chance, unhastedAttackSpeed, buffDuration)); } else { effect.AccumulateAverageStats(statsAverage, (float)trigger, chance, unhastedAttackSpeed, calcOpts.FightLength * 60); } } return(statsAverage); }
/// <summary> /// With Triggers already setup, just pass into the Accumulate function and return the values /// </summary> /// <param name="effect"></param> /// <returns></returns> public StatsHunter getSpecialEffects(SpecialEffect effect, Dictionary<Trigger, float> triggerIntervals, Dictionary<Trigger, float> triggerChances, Character Char) { StatsHunter statsAverage = new StatsHunter(); triggerIntervals[Trigger.Use] = effect.Cooldown; if (float.IsInfinity(effect.Cooldown)) triggerIntervals[Trigger.Use] = Char.BossOptions.BerserkTimer; ItemInstance RangeWeap = Char.Ranged; float unhastedAttackSpeed = (RangeWeap != null ? RangeWeap.Speed : 2.4f); effect.AccumulateAverageStats(statsAverage, triggerIntervals, triggerChances, unhastedAttackSpeed, Char.BossOptions.BerserkTimer); return statsAverage; }
public Stats getSpecialEffects(CalculationOptionsTankDK calcOpts, SpecialEffect effect) { Stats statsAverage = new Stats(); Rotation rRotation = calcOpts.m_Rotation; if (effect.Trigger == Trigger.Use) { if (calcOpts.bUseOnUseAbilities == true) { statsAverage.Accumulate(effect.GetAverageStats()); } } else { float trigger = 0f; float chance = effect.Chance; float duration = effect.Duration; float unhastedAttackSpeed = 2f; switch (effect.Trigger) { case Trigger.MeleeCrit: case Trigger.PhysicalCrit: trigger = (1f / rRotation.getMeleeSpecialsPerSecond()) + (combatTable.combinedSwingTime != 0 ? 1f / combatTable.combinedSwingTime : 0.5f); chance = combatTable.physCrits * effect.Chance; unhastedAttackSpeed = (combatTable.MH != null ? combatTable.MH.baseSpeed : 2.0f); break; case Trigger.MeleeHit: case Trigger.PhysicalHit: trigger = (1f / (rRotation.getMeleeSpecialsPerSecond() * (combatTable.m_bDW ? 2 : 1))) + (combatTable.combinedSwingTime != 0 ? 1f / combatTable.combinedSwingTime : 0.5f); chance = effect.Chance * (1f - (combatTable.missedSpecial + combatTable.dodgedSpecial)); unhastedAttackSpeed = (combatTable.MH != null ? combatTable.MH.baseSpeed : 2.0f); break; case Trigger.CurrentHandHit: case Trigger.MainHandHit: trigger = (1f / rRotation.getMeleeSpecialsPerSecond()) + (combatTable.MH.hastedSpeed != 0 ? 1f / combatTable.MH.hastedSpeed : 0.5f); chance = effect.Chance * (1f - (combatTable.missedSpecial + combatTable.dodgedSpecial)); unhastedAttackSpeed = (combatTable.MH != null ? combatTable.MH.baseSpeed : 2.0f); break; case Trigger.OffHandHit: trigger = (1f / rRotation.getMeleeSpecialsPerSecond()) + (combatTable.OH.hastedSpeed != 0 ? 1f / combatTable.OH.hastedSpeed : 0.5f); chance = effect.Chance * (1f - (combatTable.missedSpecial + combatTable.dodgedSpecial)); unhastedAttackSpeed = (combatTable.MH != null ? combatTable.MH.baseSpeed : 2.0f); break; case Trigger.DamageDone: case Trigger.DamageOrHealingDone: trigger = (1f / rRotation.getMeleeSpecialsPerSecond()) + (combatTable.combinedSwingTime != 0 ? 1f / combatTable.combinedSwingTime : 0.5f); unhastedAttackSpeed = (combatTable.MH != null ? combatTable.MH.baseSpeed : 2.0f); chance = effect.Chance * (1f - (combatTable.missedSpecial + combatTable.dodgedSpecial)); break; case Trigger.DamageSpellCast: case Trigger.SpellCast: case Trigger.DamageSpellHit: case Trigger.SpellHit: trigger = 1f / rRotation.getSpellSpecialsPerSecond(); chance = 1f - combatTable.spellResist; break; case Trigger.DamageSpellCrit: case Trigger.SpellCrit: trigger = 1f / rRotation.getSpellSpecialsPerSecond(); chance = combatTable.spellCrits * effect.Chance; break; case Trigger.DoTTick: trigger = (rRotation.BloodPlague + rRotation.FrostFever) / 3; break; case Trigger.DamageTaken: case Trigger.DamageTakenPhysical: trigger = calcOpts.BossAttackSpeed; chance *= 1f - (stats.Dodge + stats.Parry + stats.Miss); unhastedAttackSpeed = calcOpts.BossAttackSpeed; break; case Trigger.DamageTakenMagical: trigger = calcOpts.IncomingFromMagicFrequency; break; ////////////////////////////////// // DK specific triggers: case Trigger.BloodStrikeHit: case Trigger.HeartStrikeHit: trigger = rRotation.curRotationDuration / (rRotation.BloodStrike + rRotation.HeartStrike); break; case Trigger.PlagueStrikeHit: trigger = rRotation.curRotationDuration / rRotation.PlagueStrike; break; case Trigger.RuneStrikeHit: trigger = rRotation.curRotationDuration / rRotation.RuneStrike; break; case Trigger.IcyTouchHit: trigger = rRotation.curRotationDuration / rRotation.IcyTouch; break; case Trigger.DeathStrikeHit: trigger = rRotation.curRotationDuration / rRotation.DeathStrike; break; case Trigger.ObliterateHit: trigger = rRotation.curRotationDuration / rRotation.Obliterate; break; case Trigger.ScourgeStrikeHit: trigger = rRotation.curRotationDuration / rRotation.ScourgeStrike; break; case Trigger.FrostFeverHit: // Icy Talons triggers off this. trigger = rRotation.curRotationDuration / rRotation.IcyTouch; if (character.DeathKnightTalents.GlyphofHowlingBlast) { trigger += rRotation.curRotationDuration / rRotation.HowlingBlast; } break; } if (!float.IsInfinity(trigger) && !float.IsNaN(trigger)) { if (effect.UsesPPM()) { // If effect.chance < 0 , then it's using PPM. // Let's get the duration * how many times it procs per min: float UptimePerMin = 0; float fWeight = 0; if (duration == 0) // Duration of 0 means that it's a 1 time effect that procs every time the proc comes up. { fWeight = Math.Abs(effect.Chance) / 60; } else { UptimePerMin = duration * Math.Abs(effect.Chance); fWeight = UptimePerMin / 60; } statsAverage.Accumulate(effect.Stats, fWeight); } else { effect.AccumulateAverageStats(statsAverage, trigger, chance, unhastedAttackSpeed, calcOpts.FightLength * 60); } } } return(statsAverage); }
/// <summary> /// With Triggers already setup, just pass into the Accumulate function and return the values /// </summary> /// <param name="effect"></param> /// <returns></returns> public StatsDK getSpecialEffects(SpecialEffect effect) { StatsDK statsAverage = new StatsDK(); triggerIntervals[Trigger.Use] = effect.Cooldown; if (float.IsInfinity(effect.Cooldown)) triggerIntervals[Trigger.Use] = m_bo.BerserkTimer; effect.AccumulateAverageStats(statsAverage, triggerIntervals, triggerChances, unhastedAttackSpeed, m_bo.BerserkTimer); return statsAverage; }
public Stats getSpecialEffects(SpecialEffect effect) { Stats statsAverage = new Stats(); if (effect == mainHandEnchant || effect == offHandEnchant) { if (mainHandEnchant != null && !mhProcessed) { statsAverage.Accumulate(mainHandEnchant.Stats, GetMHUptime()); mhProcessed = true; } else if (offHandEnchant != null && !ohProcessed) { statsAverage.Accumulate(offHandEnchant.Stats, GetOHUptime()); ohProcessed = true; } } else if (effect.Trigger == Trigger.Use) { effect.AccumulateAverageStats(statsAverage); foreach (SpecialEffect e in effect.Stats.SpecialEffects()) { statsAverage.Accumulate(this.getSpecialEffects(e) * (effect.Duration / effect.Cooldown)); } } else { SetTriggerChanceAndSpeed(effect); foreach (SpecialEffect e in effect.Stats.SpecialEffects()) // deal with secondary effects { statsAverage.Accumulate(this.getSpecialEffects(e)); } if (effect.MaxStack > 1) { if (effect.Stats.MoteOfAnger > 0) { // When in effect stats, MoteOfAnger is % of melee hits // When in character stats, MoteOfAnger is average procs per second statsAverage.Accumulate(new Stats() { MoteOfAnger = effect.Stats.MoteOfAnger * effect.GetAverageProcsPerSecond(trigger, chance, unhastedAttackSpeed, 0f) / effect.MaxStack }); } else { float timeToMax = (float)Math.Min(_cs.FightLength, effect.GetChance(unhastedAttackSpeed) * trigger * effect.MaxStack); float buffDuration = _cs.FightLength; if (effect.Stats.AttackPower == 250f || effect.Stats.AttackPower == 215f || effect.Stats.HasteRating == 57f || effect.Stats.HasteRating == 64f) { buffDuration = 20f; } if (timeToMax * .5f > buffDuration) { timeToMax = 2 * buffDuration; } statsAverage.Accumulate(effect.Stats * (effect.MaxStack * (((buffDuration) - .5f * timeToMax) / (buffDuration)))); } } else { effect.AccumulateAverageStats(statsAverage, trigger, chance, unhastedAttackSpeed); } } return(statsAverage); }