public RandomIntellectEffect(double manaIncrease, SpecialEffect effect, double interval, double chance) { this.ManaIncrease = manaIncrease; this.Effect = effect; this.Interval = interval; this.Chance = chance; }
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; }
public static float getProcsPerSecond(bool glyphed, int fightDuration) { if (glyphed) { if (manaRestoreGlyphed == null) manaRestoreGlyphed = new SpecialEffect(Trigger.Use, new Stats { }, 0f, 35f, 1f); return manaRestoreGlyphed.GetAverageProcsPerSecond(35f, 1f, 1f, fightDuration); } else { if (manaRestoreUnglyphed == null) manaRestoreUnglyphed = new SpecialEffect(Trigger.Use, new Stats { }, 0f, 45f, 1f); return manaRestoreUnglyphed.GetAverageProcsPerSecond(45f, 1f, 1f, fightDuration); } }
public StatsSpecialEffects(Character character, Stats stats, CalculationOptionsEnhance calcOpts, BossOptions bossOpts) { _character = character; _stats = stats; _cs = new CombatStats(_character, _stats, calcOpts, bossOpts); if (character.MainHandEnchant != null) { Stats.SpecialEffectEnumerator mhEffects = character.MainHandEnchant.Stats.SpecialEffects(); if (mhEffects.MoveNext()) { mainHandEnchant = mhEffects.Current; } } if (character.OffHandEnchant != null) { Stats.SpecialEffectEnumerator ohEffects = character.OffHandEnchant.Stats.SpecialEffects(); if (ohEffects.MoveNext()) { offHandEnchant = ohEffects.Current; } } }
public void PlayEffectAt(SpecialEffect i_effectName, Vector3 i_position) { GameObject effect = null; switch (i_effectName) { case SpecialEffect.MatchedEffect: effect = Instantiate(MatchEffect) as GameObject; break; case SpecialEffect.CrashedEffect: effect = Instantiate(CrashedEffect) as GameObject; break; } effect.transform.parent = m_Transform; effect.transform.localPosition = i_position; Destroy(effect,3); }
/// <summary> /// <b>Bestial Wrath</b>, Instant, 2 min cooldown /// <para>Send your pet into a rage causing 20% additional damage for 10 sec. The beast does not feel pity or remorse or fear and it cannot be stopped unless killed.</para> /// </summary> /// <TalentsAffecting> /// Longevity - Reduces the cooldown of your Bestial Wrath, Intimidation and Pet Special Abilities by 10/20/30%. /// The Beast Within - While your pet is under the effects of Bestial Wrath, you also go into a rage causing 10% additional damage and reducing the focus cost of all shots and abilities by 50% for 10 sec. /// </TalentsAffecting> /// <GlyphsAffecting>Glyph of Bestial Wrath - Decreases the cooldown of Bestial Wrath by 20 sec.</GlyphsAffecting> public BestialWrath(Character c, StatsHunter s, CombatFactors cf, WhiteAttacks wa, CalculationOptionsHunter co) { Char = c; StatS = s; combatFactors = cf; Whiteattacks = wa; CalcOpts = co; // Name = "Bestial Wrath"; Cd = ((2f * 60f) * (1f - Talents.Longevity)) - (Talents.GlyphOfBestialWrath ? 20f : 0f); // In Seconds Duration = 10f; UseHitTable = false; ReqTalent = true; Talent2ChksValue = Talents.BestialWrath; // TODO: Move these to static SEs. Effect = new SpecialEffect(Trigger.Use, new Stats() { BonusPetDamageMultiplier = 0.20f }, Duration, Cd); if (Talents.TheBeastWithin > 0f) { Effect = new SpecialEffect(Trigger.Use, new Stats() { BonusDamageMultiplier = 0.10f }, Duration, Cd); } Initialize(); }
private void SetTriggerChanceAndSpeed(SpecialEffect effect) { trigger = 0f; chance = 1f; unhastedAttackSpeed = 3f; switch (effect.Trigger) { case Trigger.DamageDone: trigger = (_cs.HastedMHSpeed + 1f / _cs.GetSpellAttacksPerSec()) / 2f; chance = (float)Math.Min(1.0f, _cs.AverageWhiteHitChance + _cs.ChanceSpellHit); // limit to 100% chance unhastedAttackSpeed = _cs.UnhastedMHSpeed; break; case Trigger.DamageOrHealingDone: // Need to add Self Heals trigger = (_cs.HastedMHSpeed + 1f / _cs.GetSpellAttacksPerSec()) / 2f; chance = (float)Math.Min(1.0f, _cs.AverageWhiteHitChance + _cs.ChanceSpellHit); // limit to 100% chance unhastedAttackSpeed = _cs.UnhastedMHSpeed; break; case Trigger.MeleeCrit: case Trigger.PhysicalCrit: trigger = _cs.HastedMHSpeed; chance = _cs.AverageWhiteCritChance; unhastedAttackSpeed = _cs.UnhastedMHSpeed; break; case Trigger.MeleeHit: trigger = _cs.HastedMHSpeed; chance = _cs.AverageWhiteHitChance; unhastedAttackSpeed = _cs.UnhastedMHSpeed; break; case Trigger.PhysicalHit: trigger = _cs.HastedMHSpeed; chance = _cs.AverageWhiteHitChance; unhastedAttackSpeed = _cs.UnhastedMHSpeed; break; case Trigger.PhysicalAttack: case Trigger.MeleeAttack: if (_cs.UnhastedOHSpeed != 0) { trigger = (_cs.HastedMHSpeed + _cs.HastedOHSpeed) / 2; chance = 1f; unhastedAttackSpeed = (_cs.UnhastedMHSpeed + _cs.UnhastedOHSpeed) / 2; } else { trigger = _cs.HastedMHSpeed; chance = 1f; unhastedAttackSpeed = _cs.UnhastedMHSpeed; } break; case Trigger.DamageSpellCast: case Trigger.SpellCast: trigger = 1f / _cs.GetSpellCastsPerSec(); chance = 1f; break; case Trigger.DamageSpellHit: case Trigger.SpellHit: trigger = 1f / _cs.GetSpellAttacksPerSec(); chance = _cs.ChanceSpellHit; break; case Trigger.DamageSpellCrit: case Trigger.SpellCrit: trigger = 1f / _cs.GetSpellCritsPerSec(); chance = _cs.ChanceSpellCrit; break; case Trigger.SpellMiss: trigger = 1f / _cs.GetSpellMissesPerSec(); chance = 1 - _cs.ChanceSpellHit; break; case Trigger.ShamanLightningBolt: trigger = 1f / _cs.AbilityCooldown(EnhanceAbility.LightningBolt); chance = _cs.ChanceSpellHit; break; case Trigger.ShamanStormStrike: trigger = 1f / _cs.AbilityCooldown(EnhanceAbility.StormStrike); chance = _cs.ChanceYellowHitMH; break; case Trigger.ShamanShock: trigger = 1f / _cs.AbilityCooldown(EnhanceAbility.EarthShock); chance = _cs.ChanceSpellHit; break; case Trigger.ShamanLavaLash: trigger = 1f / _cs.AbilityCooldown(EnhanceAbility.LavaLash); chance = _cs.ChanceYellowHitOH; unhastedAttackSpeed = _cs.UnhastedOHSpeed; break; case Trigger.ShamanShamanisticRage: trigger = 1f / _cs.AbilityCooldown(EnhanceAbility.ShamanisticRage); chance = 1f; break; case Trigger.ShamanFlameShockDoTTick: case Trigger.DoTTick: trigger = 1f / _cs.AbilityCooldown(EnhanceAbility.FlameShock); chance = 1f; break; } }
public static SpecialEffect GetDeathWishWithMastery(float masteryVal, DPSWarrCharacter dpswarrchar) { SpecialEffect retVal = new SpecialEffect(Trigger.Use, new Stats() { BonusDamageMultiplier = 0.20f * (1f + masteryVal), DamageTakenReductionMultiplier = (dpswarrchar.Talents.GlyphOfDeathWish ? 0f : -0.05f), }, 30f, 3f * 60f * (1f - 0.10f * dpswarrchar.Talents.IntensifyRage)); return retVal; }
public static bool IsSupportedEffect(SpecialEffect effect) { return IsSupportedUseEffect(effect) || IsSupportedSpellPowerProc(effect) || IsSupportedMasteryProc(effect) || IsSupportedIntellectProc(effect) || IsSupportedDamageProc(effect) || IsSupportedHasteProc(effect) || IsSupportedManaRestoreProc(effect) || IsSupportedMp5Proc(effect) || IsSupportedStackingEffect(effect) || IsSupportedDotTickStackingEffect(effect) || IsSupportedResetStackingEffect(effect) || IsDarkIntentEffect(effect); }
public static bool IsSupportedResetStackingEffect(SpecialEffect effect) { if (effect.MaxStack == 1 && effect.Chance == 1 && (effect.Trigger == Trigger.DamageSpellCast || effect.Trigger == Trigger.DamageSpellHit || effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit)) { Stats effectStats = effect.Stats; for (int i = 0; i < effectStats._rawSpecialEffectDataSize; i++) { SpecialEffect e = effectStats._rawSpecialEffectData[i]; if (e.Chance == 1f && e.Cooldown == 0f && e.MaxStack > 1 && (e.Trigger == Trigger.DamageSpellCast || e.Trigger == Trigger.DamageSpellHit || e.Trigger == Trigger.SpellCast || e.Trigger == Trigger.SpellHit)) { if (e.Stats.SpellPower > 0) { return true; } } } } return false; }
public static bool IsSupportedStackingEffect(SpecialEffect effect) { if (effect.MaxStack > 1 && effect.Chance == 1f && effect.Cooldown == 0f && (effect.Trigger == Trigger.DamageSpellCast || effect.Trigger == Trigger.DamageSpellHit || effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit)) { if (HasEffectStats(effect.Stats)) { return true; } } return false; }
public static bool IsSupportedHasteProc(SpecialEffect effect) { if (effect.MaxStack == 1 && effect.Stats.HasteRating > 0) { if (effect.Cooldown >= effect.Duration && (effect.Trigger == Trigger.DamageSpellCrit || effect.Trigger == Trigger.SpellCrit || effect.Trigger == Trigger.DamageSpellHit || effect.Trigger == Trigger.SpellHit || effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.DamageSpellCast)) { return true; } if (effect.Cooldown == 0 && (effect.Trigger == Trigger.SpellCrit || effect.Trigger == Trigger.DamageSpellCrit)) { return true; } } return false; }
public static bool IsSupportedIntellectProc(SpecialEffect effect) { return (effect.MaxStack == 1 && (effect.Stats.Intellect + effect.Stats.HighestStat) > 0 && IsSupportedProc(effect.Trigger)); }
private bool IsDoublePot(SpecialEffect effect) { return(effect.Cooldown == 1200f && effect.Duration == 14f); }
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; }
public void SetBlock(int tileID, GameObject prefab, Vector3 position, Quaternion quaternion, SpecialEffect se) { TileID = tileID; go = GameObject.Instantiate(prefab, position, quaternion); go.name = TileID.ToString(); switch (se) { case SpecialEffect.DROPFASTER: go.GetComponent <Renderer> ().material = PrefabManager.cubeDropFaster; break; case SpecialEffect.BLOCKROTATION: go.GetComponent <Renderer> ().material = PrefabManager.cubeBlockRotation; break; case SpecialEffect.SWITCHMOVEMENT: go.GetComponent <Renderer> ().material = PrefabManager.cubeSwitchMovement; break; } }
public override void Update(GameTime gameTime) { base.Update(gameTime); if (currentState != CharacterState.None) { if (currentState != CharacterState.Dead) { float basicHorizontalVelocity; if (currentEffect == SpecialEffect.Haste) { basicHorizontalVelocity = 25; } else { basicHorizontalVelocity = 15; } Keys keyRight, keyLeft; if (currentEffect == SpecialEffect.Reverse) { keyRight = this.keyLeft; keyLeft = this.keyRight; } else { keyRight = this.keyRight; keyLeft = this.keyLeft; } if (Global.gKeyboardHelper.IsKeyPressed(keyRight)) { horizontalDirection = 1; lastKeyPressed = keyRight; this.reverse = false; } if (Global.gKeyboardHelper.IsKeyPressed(keyLeft)) { horizontalDirection = -1; lastKeyPressed = keyLeft; this.reverse = true; } if (Global.gKeyboardHelper.IsKeyPressed(keyDown)) { if (this.Distances.W == 0) { if (Global.gMap.HasNextBottomEdge(this.BoundingBox)) { verticalVelocity = 1; } } } if (Global.gKeyboardHelper.IsKeyReleased(lastKeyPressed)) { horizontalDirection = 0; } if (this.currentState == CharacterState.Jump) { verticalVelocity += gravityAcceleration; if (verticalVelocity >= 0) { this.CurrentState = CharacterState.Fall; } } if (distances.X < basicHorizontalVelocity && horizontalDirection == -1) { basicHorizontalVelocity = distances.X; } else if (distances.Z < basicHorizontalVelocity && horizontalDirection == 1) { basicHorizontalVelocity = distances.Z; } this.ActualLeft += horizontalDirection * basicHorizontalVelocity; this.Distances = Global.gMap.GetDistance(this.BoundingBox); if (this.currentState != CharacterState.Jump && this.currentState != CharacterState.Fall && distances.W > 0) { this.CurrentState = CharacterState.Fall; } if (this.currentState == CharacterState.Fall) { if (distances.W > 0) { verticalVelocity += gravityAcceleration; if (distances.W < verticalVelocity) { verticalVelocity = distances.W; } } else { this.CurrentState = CharacterState.Idle; if (Global.gKeyboardHelper.IsKeyDown(lastKeyPressed)) { this.CurrentState = CharacterState.Run; if (lastKeyPressed == keyLeft) { this.reverse = true; } else { this.reverse = false; } } verticalVelocity = 0; } } if (currentState != CharacterState.Jump && currentState != CharacterState.Fall) { if (Global.gKeyboardHelper.IsKeyPressed(keyLeft) || Global.gKeyboardHelper.IsKeyPressed(keyRight)) { this.CurrentState = CharacterState.Run; } if (Global.gKeyboardHelper.IsKeyReleased(lastKeyPressed)) { this.CurrentState = CharacterState.Idle; } if (Global.gKeyboardHelper.IsKeyPressed(keyUp) && this.currentEffect != SpecialEffect.NoJump) { this.CurrentState = CharacterState.Jump; } } } else { if (distances.W >= 15) { verticalVelocity = 15; } else { verticalVelocity = distances.W; } if (verticalVelocity == 0) { if (delayRespawn-- == 0) { OnRespawn(); } } } if (this.ActualBottom == 720 && this.CurrentState != CharacterState.Dead) { this.CurrentState = CharacterState.Dead; this.point--; } if (this.ActualBottom > 720 - 128) { this.characterSprites[this.CurrentState].Depth = 0.05f; } else { if (Global.gMap.isFront(this.BoundingBox)) { this.characterSprites[currentState].Depth = 0.9f; } else { this.characterSprites[currentState].Depth = 0.8f; } } this.ActualBottom += verticalVelocity; this.characterSprites[this.CurrentState].Reverse = this.reverse; this.characterSprites[this.CurrentState].Left = this.left; this.characterSprites[this.CurrentState].Top = this.top; this.characterSprites[this.CurrentState].Update(gameTime); if (this.effectDuration-- == 0) { this.CurrentEffect = SpecialEffect.None; } if (this.CurrentEffect == SpecialEffect.SuperJump || this.CurrentEffect == SpecialEffect.Haste) { characterSprites[currentState].Color = Color.FromNonPremultiplied(255, 255, 255, 255); } else if (this.CurrentEffect == SpecialEffect.NoJump || this.CurrentEffect == SpecialEffect.Reverse) { characterSprites[currentState].Color = Color.FromNonPremultiplied(255, 255, 255, 255); } else { characterSprites[currentState].Color = Color.White; } } }
public SpecialCard(SpecialType type, SpecialEffect effect) { Type = type; Effect = effect; }
public static bool IsSupportedMasteryProc(SpecialEffect effect) { return (effect.MaxStack == 1 && effect.Stats.MasteryRating > 0 && IsSupportedProc(effect.Trigger)); }
private float CalcDamageProc(SpecialEffect effect, float damagePerProc, Dictionary<int, float> periods, Dictionary<int, float> chances, SpellModifiers modifiers) { damagePerProc *= modifiers.GetFinalDirectMultiplier() * (1 + (modifiers.GetFinalCritMultiplier() - 1) * modifiers.CritChance) * (1 - StatConversion.GetAverageResistance(CalcOpts.PlayerLevel, CalcOpts.TargetLevel, 0f, 0f)); float numProcs = BossOpts.BerserkTimer * effect.GetAverageProcsPerSecond( periods[(int)effect.Trigger], chances[(int)effect.Trigger], CalculationsWarlock.AVG_UNHASTED_CAST_TIME, BossOpts.BerserkTimer); return numProcs * damagePerProc; }
public static bool IsSupportedDamageProc(SpecialEffect effect) { return (effect.MaxStack == 1 && (effect.Stats.ArcaneDamage + effect.Stats.FireDamage + effect.Stats.FrostDamage + effect.Stats.NatureDamage + effect.Stats.ShadowDamage + effect.Stats.HolyDamage + effect.Stats.ValkyrDamage > 0) && (IsSupportedProc(effect.Trigger) || effect.Trigger == Trigger.Use)); }
private bool IsDoublePot(SpecialEffect effect) { return effect.Cooldown == 1200f && effect.Duration == 14f; }
public static bool IsSupportedMp5Proc(SpecialEffect effect) { return (effect.MaxStack == 1 && effect.Stats.Mp5 > 0 && (IsSupportedProc(effect.Trigger) || effect.Trigger == Trigger.Use)); }
public float EffectiveEffectFightDuration(SpecialEffect effect) { if (effect.LimitedToExecutePhase) { return FightDuration * MoltenFuryPercentage; } return FightDuration; }
public static bool IsSupportedDotTickStackingEffect(SpecialEffect effect) { if (effect.MaxStack > 1 && effect.Chance == 1f && effect.Cooldown == 0f && effect.Trigger == Trigger.DoTTick && effect.Stats.SpellPower > 0) { return true; } return false; }
private float CalculateTotalDamagePerSecond(SpecialEffect effect, float baseDamage, ItemDamageType type) { float totalDamage = 0f; float totalDamagePerSec = 0f; float totalNumProcs = 0f; float totalNumProcsPerSec = 0f; try { float triggerInterval = TriggerIntervals[effect.Trigger]; float triggerChance = TriggerChances[effect.Trigger]; if (TriggerChances.ContainsKey(Trigger.MainHandHit) && MainHandEffects.Contains(effect) && (!OffHandEffects.Contains(effect) || !dualWieldProcs)) { triggerInterval = TriggerIntervals[Trigger.MainHandHit]; triggerChance = TriggerChances[Trigger.MainHandHit]; if (OffHandEffects.Contains(effect)) dualWieldProcs = true; } else if (TriggerChances.ContainsKey(Trigger.OffHandHit) && OffHandEffects.Contains(effect)) { triggerInterval = TriggerIntervals[Trigger.OffHandHit]; triggerChance = TriggerChances[Trigger.OffHandHit]; } // Process the Effects totalNumProcsPerSec = effect.GetAverageProcsPerSecond(triggerInterval, triggerChance, Char.MainHand.Speed, FightDuration); totalNumProcs = totalNumProcsPerSec * FightDuration; totalDamage = totalNumProcs * CalculateThisDamage(type, baseDamage); totalDamagePerSec = totalDamage / FightDuration; // Set our Results into the Dictionaries TotalDamage[type] += totalDamage; TotalDamagePerSec[type] += totalDamagePerSec; TotalNumProcs[type] += totalNumProcs; TotalNumProcsPerSec[type] += totalNumProcsPerSec; } catch (Exception ex) { new Base.ErrorBox() { Title = "Error calculating special proc DPS", Function = "CalculateTotalDamagePerSecond(...)", TheException = ex, }.Show(); } return totalDamagePerSec; }
public static bool IsDarkIntentEffect(SpecialEffect effect) { if (effect.MaxStack > 1 && effect.Chance == 1 && effect.Trigger == Trigger.DarkIntentCriticalPeriodicDamageOrHealing && effect.Cooldown == 0) { return true; } return false; }
protected bool RelevantTrinket(SpecialEffect effect) { if ( effect.Trigger == Trigger.Use || effect.Trigger == Trigger.DamageSpellCast || effect.Trigger == Trigger.DamageSpellCrit || effect.Trigger == Trigger.DamageSpellHit || effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellCrit || effect.Trigger == Trigger.SpellHit || effect.Trigger == Trigger.SpellMiss || effect.Trigger == Trigger.DoTTick || effect.Trigger == Trigger.DamageDone || effect.Trigger == Trigger.DamageOrHealingDone) { // This properly handles the case where the effect.Stats itself has a SpecialEffect with relevant stats // e.g. Heart of Ignacious return HasRelevantStats(effect.Stats); } return false; }
/// <summary> /// Gets the total Stats of the Character /// </summary> /// <param name="character">The Character to get the total Stats of</param> /// <param name="additionalItem">An additional item to grant the Character the stats of (as if it were worn)</param> /// <returns>The total stats for the Character</returns> public override Stats GetCharacterStats(Character character, Item additionalItem) { CalculationOptionsBear calcOpts = character.CalculationOptions as CalculationOptionsBear ?? new CalculationOptionsBear(); DruidTalents talents = character.DruidTalents; bool hasCritBuff = false; foreach (Buff buff in character.ActiveBuffs) { if (buff.Group == "Critical Strike Chance") { hasCritBuff = true; break; } } StatsBear statsTotal = new StatsBear() { BonusAttackPowerMultiplier = 0.25f, BonusBleedDamageMultiplier = (character.ActiveBuffsContains("Mangle") || character.ActiveBuffsContains("Trauma") ? 0f : 0.3f), Dodge = 0.02f * talents.FeralSwiftness + 0.03f * talents.NaturalReaction, FurySwipesChance = 0.05f * talents.FurySwipes, BonusEnrageDamageMultiplier = 0.05f * talents.KingOfTheJungle, HasteOnFeralCharge = 0.15f * talents.Stampede, BaseArmorMultiplier = 2.2f * (1f + 0.10f * talents.ThickHide / 3f) * (1f + 0.26f * talents.ThickHide) - 1f, CritChanceReduction = 0.02f * talents.ThickHide, PhysicalCrit = (hasCritBuff ? 0f : 0.05f * talents.LeaderOfThePack) + (talents.Pulverize > 0 ? 0.09f: 0f), SpellCrit = (hasCritBuff ? 0f : 0.05f * talents.LeaderOfThePack), BonusPulverizeDuration = 4f * talents.EndlessCarnage, DamageTakenReductionMultiplier = 0.09f * talents.NaturalReaction, BonusMaulDamageMultiplier = 0.04f * talents.RendAndTear, BonusStaminaMultiplier = (1f + 0.02f * talents.HeartOfTheWild) * (Character.ValidateArmorSpecialization(character, ItemType.Leather) ? 1.05f : 1f) - 1f, BonusPhysicalDamageMultiplier = 0.04f * talents.MasterShapeshifter, BonusMangleDamageMultiplier = talents.GlyphOfMangle ? 0.1f : 0f, BonusLacerateCritChance = talents.GlyphOfLacerate ? 0.05f : 0f, BonusFaerieFireStacks = talents.FeralAggression, BerserkDuration = (talents.GlyphOfBerserk ? 10f : 0f), }; #region Set Bonuses int PvPCount; character.SetBonusCount.TryGetValue("Gladiator's Sanctuary", out PvPCount); if (PvPCount >= 2) { statsTotal.Agility += 70f; statsTotal.Resilience += 400f; } if (PvPCount >= 4) { // the 15% movement speed is only outdoors which most dungeons are not statsTotal.Agility += 90f; } int T11Count; character.SetBonusCount.TryGetValue("Stormrider's Battlegarb", out T11Count); if (T11Count >= 2) { //statsTotal.BonusDamageMultiplierRakeTick = (1f + statsTotal.BonusDamageMultiplierRakeTick) * (1f + 0.10f) - 1f; statsTotal.BonusDamageMultiplierLacerate = (1f + statsTotal.BonusDamageMultiplierLacerate) * (1f + 0.10f) - 1f; } if (T11Count >= 4) { /*statsBuffs.AddSpecialEffect(new SpecialEffect(Trigger.MangleCatHit, new Stats() { BonusAttackPowerMultiplier = 0.01f, }, 30, 0, 1f, 3));*/ statsTotal.BonusSurvivalInstinctsDurationMultiplier = 0.5f; } int T12Count; character.SetBonusCount.TryGetValue("Obsidian Arborweave Battlegarb", out T12Count); if (T12Count >= 2) { statsTotal.BonusMangleDamageMultiplier = (1f + statsTotal.BonusMangleDamageMultiplier) * (1f + 0.10f) - 1f; statsTotal.BonusMaulDamageMultiplier = (1f + statsTotal.BonusMaulDamageMultiplier) * (1f + 0.10f) - 1f; } if (T12Count >= 4) { statsTotal.AddSpecialEffect(SpecialEffect4T12); } int T13Count; character.SetBonusCount.TryGetValue("Deep Earth Battlegarb", out T13Count); if (T13Count >= 2) { statsTotal.Tier_13_2_piece = true; } if (T13Count >= 4) { statsTotal.Tier_13_4_piece = (10f + 25f)/2; } #endregion // Leader of the Pack self-heal statsTotal.AddSpecialEffect(LeaderOfThePackSpecialEffect); // Survival Instincts SpecialEffect SurvivalInstinctsSpecialEffect = new SpecialEffect(Trigger.Use, new Stats() { DamageTakenReductionMultiplier = 0.50f, }, 12f * (1f + statsTotal.BonusSurvivalInstinctsDurationMultiplier), 180f, 1f); statsTotal.AddSpecialEffect(SurvivalInstinctsSpecialEffect); // Barkskin SpecialEffect BarkskinSpecialEffect = new SpecialEffect(Trigger.Use, new Stats() { DamageTakenReductionMultiplier = 0.20f, CritChanceReduction = (talents.GlyphOfBarkskin ? 0.25f : 0f), }, 12f, 60f, 1f); statsTotal.AddSpecialEffect(BarkskinSpecialEffect); // Frenzied Regeneration SpecialEffect FrenziedRegenerationSpecialEffect = new SpecialEffect(Trigger.Use, new Stats() { BonusHealthMultiplier = 0.15f, HealthRestoreFromMaxHealth = (talents.GlyphOfFrenziedRegeneration ? 0f : (0.015f * (1f + statsTotal.Tier_13_4_piece))), HealingReceivedMultiplier = (talents.GlyphOfFrenziedRegeneration ? (0.30f * (1f + statsTotal.Tier_13_4_piece)) : 0f) }, 20f, 180f, 1f); statsTotal.AddSpecialEffect(FrenziedRegenerationSpecialEffect); // Berserk StatsBear tempBear = new StatsBear(); tempBear.AddSpecialEffect(new SpecialEffect(Trigger.LacerateTick, new StatsBear() { MangleCooldownReduction = 6f, MangleCostReduction = 1f }, float.PositiveInfinity, 0, 0.5f)); SpecialEffect BerserkSpecialEffect = new SpecialEffect(Trigger.Use, tempBear, 15f + statsTotal.BerserkDuration, 180f, 1f); statsTotal.AddSpecialEffect(BerserkSpecialEffect); // Enrage SpecialEffect EnrageSpecialEffect = new SpecialEffect(Trigger.Use, new StatsBear() { BonusDamageMultiplier = (0.05f * talents.KingOfTheJungle) }, 10f, 60f, 1f); statsTotal.AddSpecialEffect(EnrageSpecialEffect); statsTotal.Accumulate(BaseStats.GetBaseStats(character.Level, character.Class, character.Race, BaseStats.DruidForm.Bear)); statsTotal.Accumulate(GetItemStats(character, additionalItem)); statsTotal.Accumulate(GetBuffsStats(character, calcOpts)); statsTotal.Stamina = (float)Math.Floor(statsTotal.Stamina * (1f + statsTotal.BonusStaminaMultiplier)); statsTotal.Strength = (float)Math.Floor(statsTotal.Strength * (1f + statsTotal.BonusStrengthMultiplier)); statsTotal.Agility = (float)Math.Floor(statsTotal.Agility * (1f + statsTotal.BonusAgilityMultiplier)); statsTotal.AttackPower += (float)Math.Floor(statsTotal.Strength); statsTotal.AttackPower += (float)Math.Floor(statsTotal.Agility - 20f) * 2f + 20f; statsTotal.AttackPower = (float)Math.Floor(statsTotal.AttackPower * (1f + statsTotal.BonusAttackPowerMultiplier)); statsTotal.Health += ((statsTotal.Stamina - 20f) * 14f) + 20f; statsTotal.Health *= (1f + statsTotal.BonusHealthMultiplier); statsTotal.Armor *= 1f + statsTotal.BaseArmorMultiplier; statsTotal.Armor += statsTotal.BonusArmor; statsTotal.Armor = (float)Math.Floor(statsTotal.Armor * (1f + statsTotal.BonusArmorMultiplier)); statsTotal.NatureResistance += statsTotal.NatureResistanceBuff; statsTotal.FireResistance += statsTotal.FireResistanceBuff; statsTotal.FrostResistance += statsTotal.FrostResistanceBuff; statsTotal.ShadowResistance += statsTotal.ShadowResistanceBuff; statsTotal.ArcaneResistance += statsTotal.ArcaneResistanceBuff; AccumulateProcs(character, statsTotal); return statsTotal; }
public void GenPetStats() { // Initial Variables int levelDiff = BossOpts.Level - character.Level; StatsHunter petStatsBase = BasePetStats; #region From Hunter StatsHunter petStatsFromHunter = new StatsHunter() { AttackPower = (HunterStats.RangedAttackPower * 0.424f), SpellPower = HunterStats.RangedAttackPower * 0.211807381f, Stamina = HunterStats.Stamina, Agility = HunterStats.Agility, CritRating = HunterStats.CritRating, Strength = HunterStats.Strength, Spirit = HunterStats.PetSpirit, PhysicalHaste = HunterStats.PhysicalHaste, ArcaneResistance = HunterStats.ArcaneResistance * 0.4f, FireResistance = HunterStats.FireResistance * 0.4f, NatureResistance = HunterStats.NatureResistance * 0.4f, ShadowResistance = HunterStats.ShadowResistance * 0.4f, FrostResistance = HunterStats.FrostResistance * 0.4f, Armor = HunterStats.Armor * 0.7f, SpellPenetration = HunterStats.SpellPenetration, Resilience = HunterStats.Resilience, BonusDamageMultiplier = ((HunterStats.BonusDamageMultiplier /* / (1f + Talents.TheBeastWithin * 0.10f)*/)) * ((character.Race == CharacterRace.Orc ? 0.05f : 0f)), BonusPetDamageMultiplier = HunterStats.BonusPetDamageMultiplier, BonusBleedDamageMultiplier = HunterStats.BonusBleedDamageMultiplier, BonusPetAttackPowerMultiplier = HunterStats.BonusPetAttackPowerMultiplier, // PetAttackPower = HunterStats.PetAttackPower, }; #endregion #region From Talents (Pet or Hunter) Stats petStatsTalents = new Stats() { BonusStaminaMultiplier = PetTalents.GreatStamina * 0.04f, MovementSpeed = PetTalents.BoarsSpeed * 0.30f, PhysicalHaste = PetTalents.SerpentSwiftness * 0.05f, PhysicalCrit = PetTalents.SpidersBite * 0.03f , BaseArmorMultiplier = (1f + PetTalents.NaturalArmor * 0.05f) * (1f + PetTalents.PetBarding * 0.05f) * (1.05f) // Base 5% Armor Bonus - 1f, Dodge = PetTalents.PetBarding * 0.01f, CritChanceReduction = PetTalents.GraceOfTheMantis * 0.03f, ArcaneResistance = PetTalents.GreatResistance * 0.05f, FireResistance = PetTalents.GreatResistance * 0.05f, NatureResistance = PetTalents.GreatResistance * 0.05f, ShadowResistance = PetTalents.GreatResistance * 0.05f, FrostResistance = PetTalents.GreatResistance * 0.05f, FearDurReduc = PetTalents.Lionhearted * 0.15f, StunDurReduc = PetTalents.Lionhearted * 0.15f, BonusDamageMultiplier = (1 + (PetTalents.SharkAttack * 0.03f)) * (1.05f) - 1f, // Base 5% Damage //BonusAttackPowerMultiplier = calculatedStats.aspectBonusAPBeast, BonusHealthMultiplier = 0.05f, // Base 5% Health }; float LongevityCdAdjust = 1f - Talents.Longevity * 0.10f; if (PetTalents.Rabid > 0) { float rabidCooldown = 45f * LongevityCdAdjust; SpecialEffect primary = new SpecialEffect(Trigger.Use, new Stats() { }, 20f, rabidCooldown); SpecialEffect secondary = new SpecialEffect(Trigger.MeleeHit, new Stats() { BonusAttackPowerMultiplier = 0.05f }, 20f, 0f, 0.50f, 5); primary.Stats.AddSpecialEffect(secondary); petStatsTalents.AddSpecialEffect(primary); } if (Talents.Frenzy > 0) { if (frenzy == null) { frenzy = new SpecialEffect(Trigger.MeleeCrit, new Stats() { PhysicalHaste = 0.30f, }, 8f, 1f, Talents.Frenzy * 0.20f); } petStatsTalents.AddSpecialEffect(frenzy); } if (PetTalents.LastStand > 0) { SpecialEffect laststand = new SpecialEffect(Trigger.Use, new Stats() { BonusHealthMultiplier = 0.30f, }, 20f, (1f * 60f) * LongevityCdAdjust); petStatsTalents.AddSpecialEffect(laststand); } #endregion #region From Options Stats petStatsOptionsPanel = new Stats() { PhysicalCrit = StatConversion.NPC_LEVEL_CRIT_MOD[levelDiff], //BonusStaminaMultiplier = 0.05f, }; CalculateTimings(); if(priorityRotation.getSkillFrequency(PetAttacks.SerenityDust) > 0){ // TODO: Need to make sure this freq actually works float freq = priorityRotation.getSkillFrequency(PetAttacks.SerenityDust); SpecialEffect serenitydust = new SpecialEffect(Trigger.Use, new Stats() { BonusAttackPowerMultiplier = 0.10f, }, 15f, BossOpts.BerserkTimer / freq); petStatsOptionsPanel.AddSpecialEffect(serenitydust); petStatsOptionsPanel.HealthRestore += (BossOpts.BerserkTimer / freq) * 825f; } #endregion // Totals // Stats petStatsGearEnchantsBuffs = new Stats(); // petStatsGearEnchantsBuffs.Accumulate(petStatsBuffs); StatsHunter petStatsTotal = new StatsHunter(); petStatsTotal.Accumulate(petStatsBase); petStatsTotal.Accumulate(petStatsFromHunter); // petStatsTotal.Accumulate(petStatsBuffs); petStatsTotal.Accumulate(petStatsTalents); petStatsTotal.Accumulate(petStatsOptionsPanel); StatsHunter petStatsProcs = new StatsHunter(); Dictionary<Trigger, float> triggerIntervals = new Dictionary<Trigger, float>(); Dictionary<Trigger, float> triggerChances = new Dictionary<Trigger, float>(); #region Stamina & Health float totalBSTAM = petStatsTotal.BonusStaminaMultiplier; //calculatedStats.petBaseHealth = BasePetStats.Health; //calculatedStats.petHealthfromStamina = (petStatsFromHunter.Stamina) * 10.4173919f; petStatsTotal.Stamina = (float)Math.Floor((1f + totalBSTAM) * petStatsTotal.Stamina); // Health | all pets have a 5% Bonus Stam petStatsTotal.Health += (petStatsTotal.Stamina) * 10.4173919f; petStatsTotal.Health *= 1f + petStatsTotal.BonusHealthMultiplier; //calculatedStats.petBonusHealth = petStatsTotal.Health - calculatedStats.petBaseHealth - calculatedStats.petHealthfromStamina; if (PetTalents.Bloodthirsty > 0) { SpecialEffect bloodthirsty = new SpecialEffect(Trigger.MeleeHit, new Stats() { HealthRestore = petStatsTotal.Health * 0.05f }, 0f, 0f, PetTalents.Bloodthirsty * 0.10f); petStatsTotal.AddSpecialEffect(bloodthirsty); } #endregion #region Strength float totalBSTRM = petStatsTotal.BonusStrengthMultiplier; petStatsTotal.Strength = /*(float)Math.Floor(*/(1f + totalBSTRM) * petStatsTotal.Strength/*)*/; #endregion #region Agility float totalBAGIM = petStatsTotal.BonusAgilityMultiplier; petStatsTotal.Agility = /*(float)Math.Floor(*/(1f + totalBAGIM) * petStatsTotal.Agility/*)*/; #endregion #region Attack Power petStatsTotal.BonusAttackPowerMultiplier *= (1f + petStatsTotal.BonusPetAttackPowerMultiplier); float totalBAPM = petStatsTotal.BonusAttackPowerMultiplier; float apFromBase = (1f + totalBAPM) * BasePetStats.PetAttackPower; // float apFromBonus = (1f + totalBAPM) * (petStatsTotal.PetAttackPower - BasePetStats.PetAttackPower); float apFromHunter = ((1f + totalBAPM) * petStatsFromHunter.AttackPower); // float apFromSTR = ((1f + totalBAPM) * (petStatsFromHunter.Strength)) * 0.85f;//(petStatsTotal.Strength - 10f) * 2f; // float apFromHvW = 0f; //(1f + totalBAPM) * (HunterStats.Stamina * 0.10f * Talents.HunterVsWild); petStatsTotal.AttackPower = apFromBase /*+ apFromBonus*/ + apFromHunter /*+ apFromSTR + apFromHvW*/; #endregion #region Haste /*if (StatsPetBuffs._rawSpecialEffectData != null && StatsPetBuffs._rawSpecialEffectData.Length > 0) { Stats add = StatsPetBuffs._rawSpecialEffectData[0].GetAverageStats(); StatsPetBuffs.PhysicalHaste *= (1f + add.PhysicalHaste); }*/ #endregion #region Armor petStatsTotal.Armor = (float)Math.Floor((petStatsTotal.Armor - petStatsFromHunter.Armor) * (1f + petStatsTotal.BaseArmorMultiplier) + petStatsFromHunter.Armor); // petStatsTotal.BonusArmor += petStatsTotal.Agility * 2f; petStatsTotal.BonusArmor = (float)Math.Floor(petStatsTotal.BonusArmor * (1f + petStatsTotal.BonusArmorMultiplier)); petStatsTotal.Armor += petStatsTotal.BonusArmor; #endregion #region Hit/Dodge Chances // This is tied directly to the Hunter's chance to miss PetChanceToMiss = Math.Max(0f, StatConversion.YELLOW_MISS_CHANCE_CAP[levelDiff] - HunterStats.PhysicalHit); PetChanceToSpellMiss = -1f * Math.Min(0f, StatConversion.GetSpellMiss(levelDiff, false) - HunterStats.SpellHit); //calculatedStats.petHitTotal = HunterStats.PhysicalHit; //calculatedStats.petHitSpellTotal = HunterStats.PhysicalHit * 17f / 8f; //petStatsTotal.PhysicalHit = calculatedStats.petHitTotal; //petStatsTotal.SpellHit = calculatedStats.petHitSpellTotal; // If the Hunter is Hit Capped, the pet is also Exp Capped // If not, Pet is proportionately lower based on Hunter's Hit // Expertise itself doesn't factor in at all PetChanceToBeDodged = StatConversion.YELLOW_DODGE_CHANCE_CAP[levelDiff] * Math.Min(1f, (PetChanceToMiss / StatConversion.YELLOW_MISS_CHANCE_CAP[levelDiff])); //calculatedStats.petTargetDodge = PetChanceToBeDodged; float[] avoidChances = { PetChanceToMiss, PetChanceToSpellMiss, PetChanceToBeDodged }; #endregion #region Crit Chance petStatsTotal.PhysicalCrit += StatConversion.GetCritFromAgility(petStatsTotal.Agility, CharacterClass.Warrior) + StatConversion.GetCritFromRating(petStatsTotal.CritRating); //calculatedStats.petCritTotalMelee = petStatsTotal.PhysicalCrit; // Cobra Strikes //calculatedStats.petCritFromCobraStrikes = 0; float cobraStrikesProc = Talents.CobraStrikes * 0.2f; if (cobraStrikesProc > 0) { #if FALSE float cobraStrikesCritFreqSteady = calculatedStats.steadyShot.Freq * (1f / calculatedStats.steadyShot.CritChance); float cobraStrikesCritFreqArcane = calculatedStats.arcaneShot.Freq * (1f / calculatedStats.arcaneShot.CritChance); float cobraStrikesCritFreqKill = calculatedStats.killShot.Freq * (1f / calculatedStats.killShot.CritChance); float cobraStrikesCritFreqSteadyInv = cobraStrikesCritFreqSteady > 0 ? 1f / cobraStrikesCritFreqSteady : 0; float cobraStrikesCritFreqArcaneInv = cobraStrikesCritFreqArcane > 0 ? 1f / cobraStrikesCritFreqArcane : 0; float cobraStrikesCritFreqKillInv = cobraStrikesCritFreqKill > 0 ? 1f / cobraStrikesCritFreqKill : 0; float cobraStrikesCritFreqInv = cobraStrikesCritFreqSteadyInv + cobraStrikesCritFreqArcaneInv + cobraStrikesCritFreqKillInv; float cobraStrikesCritFreq = cobraStrikesCritFreqInv > 0 ? 1f / cobraStrikesCritFreqInv : 0; float cobraStrikesProcAdjust = cobraStrikesCritFreq / cobraStrikesProc; float cobraStrikesFreqSteadyInv = calculatedStats.steadyShot.Freq > 0 ? 1f / calculatedStats.steadyShot.Freq : 0; float cobraStrikesFreqArcaneInv = calculatedStats.arcaneShot.Freq > 0 ? 1f / calculatedStats.arcaneShot.Freq : 0; float cobraStrikesFreqKillInv = calculatedStats.killShot.Freq > 0 ? 1f / calculatedStats.killShot.Freq : 0; float cobraStrikesFreqInv = cobraStrikesFreqSteadyInv + cobraStrikesFreqArcaneInv + cobraStrikesFreqKillInv; float cobraStrikesTwoSpecials = 2f * priorityRotation.petSpecialFrequency; float cobraStrikesUptime = 1f - (float)Math.Pow(1f - calculatedStats.steadyShot.CritChance * cobraStrikesProc, cobraStrikesFreqInv * cobraStrikesTwoSpecials); //calculatedStats.petCritFromCobraStrikes = (cobraStrikesUptime + (1f - cobraStrikesUptime) * calculatedStats.petCritTotalMelee) - calculatedStats.petCritTotalMelee; #endif } //calculatedStats.petCritTotalSpecials = petStatsTotal.PhysicalCrit + calculatedStats.petCritFromCobraStrikes; // PetCritChance //critSpecialsAdjust = calculatedStats.petCritTotalSpecials * 1.5f + 1f; #endregion #region Handle Special Effects CalculateTimings(); WhAtkTable = new PetAttackTable(character, petStatsTotal, CalcOpts, avoidChances, false, false); YwAtkTable = new PetAttackTable(character, petStatsTotal, CalcOpts, avoidChances, PetAttacks.Claw, false, false); float AllAttemptedAtksInterval = GenPetFullAttackSpeed(petStatsTotal); float WhtAttemptedAtksInterval = PetAttackSpeed(petStatsTotal); float YlwAttemptedAtksInterval = AllAttemptedAtksInterval - WhtAttemptedAtksInterval; float[] hitRates = { WhAtkTable.AnyLand, // Whites YwAtkTable.AnyLand }; // Yellows float[] critRates = { WhAtkTable.Crit, // Whites YwAtkTable.Crit /*+ calculatedStats.petCritFromCobraStrikes*/ }; // Yellows float bleedHitInterval = 0f; float rakefreq = priorityRotation.getSkillFrequency(PetAttacks.Rake ); if (rakefreq > 0) { bleedHitInterval += rakefreq; } float dmgDoneInterval = 1f; // Need to Fix this float clawbitesmackinterval = 0f; float clawfreq = priorityRotation.getSkillFrequency(PetAttacks.Claw ); if (clawfreq > 0) { clawbitesmackinterval += clawfreq; } float bitefreq = priorityRotation.getSkillFrequency(PetAttacks.Bite ); if (bitefreq > 0) { clawbitesmackinterval += bitefreq; } float smakfreq = priorityRotation.getSkillFrequency(PetAttacks.Smack); if (smakfreq > 0) { clawbitesmackinterval += smakfreq; } PetClawBiteSmackInterval = clawbitesmackinterval; float[] AttemptedAtkIntervals = { AllAttemptedAtksInterval, // All WhtAttemptedAtksInterval, // Whites YlwAttemptedAtksInterval, // Yellows PetClawBiteSmackInterval, // ClawBiteSmack }; petStatsProcs.Accumulate(GetSpecialEffectsStats(character, triggerIntervals, triggerChances, AttemptedAtkIntervals, hitRates, critRates, bleedHitInterval, dmgDoneInterval, petStatsTotal, null) as StatsHunter); #region Stat Results of Special Effects // Base Stats petStatsProcs.Stamina = (float)Math.Floor(petStatsProcs.Stamina * (1f + totalBSTAM) * (1f + petStatsProcs.BonusStaminaMultiplier)); petStatsProcs.Strength = (float)Math.Floor(petStatsProcs.Strength * (1f + totalBSTRM) * (1f + petStatsProcs.BonusStrengthMultiplier)); petStatsProcs.Agility = (float)Math.Floor(petStatsProcs.Agility * (1f + totalBAGIM) * (1f + petStatsProcs.BonusAgilityMultiplier)); petStatsProcs.Health += (float)Math.Floor(petStatsProcs.Stamina * 10f); petStatsProcs.Health += (float)Math.Floor((petStatsProcs.Health + petStatsTotal.Health) * petStatsProcs.BonusHealthMultiplier); // Armor petStatsProcs.Armor = (float)Math.Floor(petStatsProcs.Armor * (1f + petStatsTotal.BaseArmorMultiplier + petStatsProcs.BaseArmorMultiplier)); petStatsProcs.BonusArmor += petStatsProcs.Agility * 2f; petStatsProcs.BonusArmor = (float)Math.Floor(petStatsProcs.BonusArmor * (1f + petStatsTotal.BonusArmorMultiplier + petStatsProcs.BonusArmorMultiplier)); petStatsProcs.Armor += petStatsProcs.BonusArmor; petStatsProcs.BonusArmor = 0; //it's been added to Armor so kill it // Attack Power petStatsProcs.BonusAttackPowerMultiplier *= (1f + petStatsProcs.BonusPetAttackPowerMultiplier); float totalBAPMProcs = (1f + totalBAPM) * (1f + petStatsProcs.BonusAttackPowerMultiplier) - 1f; float apFromSTRProcs = (1f + totalBAPMProcs) * (petStatsProcs.Strength * 2f); float apBonusOtherProcs = (1f + totalBAPMProcs) * (petStatsProcs.AttackPower + petStatsProcs.PetAttackPower); float apBonusFromBasetoNewMulti = (petStatsProcs.BonusAttackPowerMultiplier) * (petStatsTotal.AttackPower); petStatsProcs.AttackPower = (float)Math.Floor(apFromSTRProcs + apBonusOtherProcs + apBonusFromBasetoNewMulti); // Crit petStatsProcs.PhysicalCrit += StatConversion.GetCritFromAgility(petStatsProcs.Agility, CharacterClass.Warrior); //petStatsProcs.PhysicalCrit += StatConversion.GetCritFromRating(petStatsProcs.CritRating, CharacterClass.Warrior); #endregion petStatsTotal.Accumulate(petStatsProcs); GenPetFullAttackSpeed(petStatsTotal); CalculateTimings(); clawbitesmackinterval = 0f; clawfreq = priorityRotation.getSkillFrequency(PetAttacks.Claw); if (clawfreq > 0) { clawbitesmackinterval += clawfreq; } bitefreq = priorityRotation.getSkillFrequency(PetAttacks.Bite); if (bitefreq > 0) { clawbitesmackinterval += bitefreq; } smakfreq = priorityRotation.getSkillFrequency(PetAttacks.Smack); if (smakfreq > 0) { clawbitesmackinterval += smakfreq; } PetClawBiteSmackInterval = clawbitesmackinterval; #endregion PetStats = petStatsTotal; #region Special Abilities Priority Rotation CalculateTimings(); #endregion #region Kill Command MPS //calculatedStats.petKillCommandMPS = 0; killCommandCooldown = 0; if (CalcOpts.useKillCommand) { float killCommandManaCost = 40f /* * calculatedStats.baseMana*/; // float killCommandReadinessFactor = calculatedStats.priorityRotation.containsShot(Shots.Readiness) ? 1.0f / 180f : 0f; float killCommandCooldownBase = 1.0f; // killCommandCooldown = 1.0f / (killCommandCooldownBase + killCommandReadinessFactor); //calculatedStats.petKillCommandMPS = killCommandCooldown > 0 ? killCommandManaCost / killCommandCooldown : 0; } #endregion #region Target Debuffs float armorDebuffSporeCloud = 0; float sporeCloudFrequency = priorityRotation.getSkillFrequency(PetAttacks.SporeCloud); if (sporeCloudFrequency > 0) { float sporeCloudDuration = 9f; float sporeCloudUptime = sporeCloudDuration > sporeCloudFrequency ? 1f : sporeCloudDuration / sporeCloudFrequency; armorDebuffSporeCloud = sporeCloudUptime * 0.03f; } float armorDebuffAcidSpit = 0; float acidSpitFrequency = priorityRotation.getSkillFrequency(PetAttacks.AcidSpit); // AcidSpitEffectiveRate if (acidSpitFrequency > 0) { float acidSpitCalcFreq = priorityRotation.getSkillCooldown(PetAttacks.AcidSpit); float acidSpitDuration = 30; float acidSpitChanceToApply = 1f - PetChanceToMiss - PetChanceToBeDodged; // V45 float acidSpitChancesToMaintain = (float)Math.Floor((acidSpitDuration - 1f) / acidSpitFrequency); // V46 float acidSpitChanceToApplyFirst = acidSpitChancesToMaintain == 0 ? 0 : acidSpitChanceToApply; // V47 float acidSpitChanceToStop = 1f - acidSpitChanceToApplyFirst; // AcidSpitChanceToStop float acidSpitAverageTimeToInc = acidSpitChanceToApplyFirst > 0 ? acidSpitFrequency : 0; // AcidSpitTimeToInc float acidSpitTimeSpentAtMax = acidSpitAverageTimeToInc + (acidSpitDuration * acidSpitChanceToStop); // AcidSpitAverageStackTime PetSkillStack[] stacks = new PetSkillStack[3]; stacks[0] = new PetSkillStack(); stacks[1] = new PetSkillStack(); stacks[2] = new PetSkillStack(); stacks[0].time_to_reach = 0; stacks[1].time_to_reach = acidSpitAverageTimeToInc * 1; stacks[2].time_to_reach = acidSpitAverageTimeToInc * 2; stacks[0].chance_to_max = 0; stacks[1].chance_to_max = acidSpitChanceToStop == 1 ? 0 : acidSpitChanceToStop; stacks[2].chance_to_max = acidSpitChanceToStop == 1 ? 0 : 1 - (stacks[0].chance_to_max + stacks[1].chance_to_max); stacks[0].time_spent = stacks[1].time_to_reach; stacks[1].time_spent = stacks[1].time_to_reach == 0 ? 0 : acidSpitTimeSpentAtMax * (1 - stacks[0].chance_to_max); stacks[2].time_spent = stacks[1].time_to_reach == 0 ? 0 : acidSpitChanceToStop == 0 ? 1 : 1 / acidSpitChanceToStop * acidSpitCalcFreq * (1-(stacks[0].chance_to_max + stacks[1].chance_to_max)); float acidSpitTotalTime = stacks[0].time_spent + stacks[1].time_spent + stacks[2].time_spent; stacks[0].percent_time = acidSpitTotalTime == 0 ? 1 : stacks[0].time_spent / acidSpitTotalTime; stacks[1].percent_time = acidSpitTotalTime == 0 ? 1 : stacks[1].time_spent / acidSpitTotalTime; stacks[2].percent_time = acidSpitTotalTime == 0 ? 1 : stacks[2].time_spent / acidSpitTotalTime; stacks[0].total = stacks[0].percent_time * 0.0f; stacks[1].total = stacks[0].percent_time * 0.1f; stacks[2].total = stacks[0].percent_time * 0.2f; armorDebuffAcidSpit = stacks[0].total + stacks[1].total + stacks[2].total; } float armorDebuffSting = 0; float stingFrequency = priorityRotation.getSkillFrequency(PetAttacks.Sting); if (stingFrequency > 0) { float stingUseFreq = priorityRotation.getSkillFrequency(PetAttacks.Sting); float stingDuration = 20; float stingUptime = stingDuration > stingUseFreq ? 1 : stingDuration / stingUseFreq; armorDebuffSting = stingUptime * 0.05f; } // these local buffs can be overridden if (character.ActiveBuffsConflictingBuffContains("Sting")) { armorDebuffSporeCloud = 0; armorDebuffSting = 0; } if (character.ActiveBuffsConflictingBuffContains("Acid Spit")) { armorDebuffAcidSpit = 0; } //calculatedStats.petArmorDebuffs = 0f - (1f - armorDebuffSporeCloud) * (1f - armorDebuffAcidSpit) * (1f - armorDebuffSting) + 1; #endregion #region Hunter Effects // Ferocious Inspiraion // (Same as above) //calculatedStats.ferociousInspirationDamageAdjust = 1; if (character.HunterTalents.FerociousInspiration > 0) { if (CalcOpts.PetFamily != PETFAMILY.None) { float ferociousInspirationSpecialsEffect = priorityRotation.petSpecialFrequency == 0 ? 0 : 10f / priorityRotation.petSpecialFrequency; //float ferociousInspirationUptime = 1f - (float)Math.Pow(1f - calculatedStats.petCritTotalSpecials, (10f / attackSpeedEffective) + ferociousInspirationSpecialsEffect); float ferociousInspirationEffect = 0.01f * character.HunterTalents.FerociousInspiration; //calculatedStats.ferociousInspirationDamageAdjust = 1.0f + ferociousInspirationUptime * ferociousInspirationEffect; } } // Roar of Recovery //calculatedStats.manaRegenRoarOfRecovery = 0; float roarOfRecoveryFreq = priorityRotation.getSkillFrequency(PetAttacks.RoarOfRecovery); if (roarOfRecoveryFreq > 0) { float roarOfRecoveryUseCount = (float)Math.Ceiling(BossOpts.BerserkTimer / roarOfRecoveryFreq); float roarOfRecoveryManaRestored = HunterStats.Mana * 0.30f * roarOfRecoveryUseCount; // E129 //calculatedStats.manaRegenRoarOfRecovery = roarOfRecoveryUseCount > 0 ? roarOfRecoveryManaRestored / BossOpts.BerserkTimer : 0; } //Invigoration //calculatedStats.manaRegenInvigoration = 0; float invigorationProcChance = Talents.Invigoration * 0.50f; // C32 if (invigorationProcChance > 0) { float invigorationProcFreq = (priorityRotation.petSpecialFrequency /*/ calculatedStats.petCritTotalSpecials*/) / invigorationProcChance; //C35 float invigorationEffect = Talents.Invigoration > 0 ? 0.01f : 0; float invigorationManaGainedPercent = invigorationProcFreq > 0 ? 60f / invigorationProcFreq * invigorationEffect : 0; // C36 float invigorationManaPerMinute = invigorationProcFreq > 0 ? 60f / invigorationProcFreq * invigorationEffect * HunterStats.Mana : 0; // C37 //calculatedStats.manaRegenInvigoration = invigorationManaPerMinute / 60f; } #endregion #region Target Armor Effect //31-10-2009 Drizz: added Armor effect #if RAWR3 || RAWR4 || SILVERLIGHT //double petEffectiveArmor = BossOpts.Armor * (1f - calculatedStats.petArmorDebuffs); //calculatedStats.petTargetArmorReduction = StatConversion.GetArmorDamageReduction(character.Level, BossOpts.Armor, calculatedStats.petArmorDebuffs, 0, 0); #else double petEffectiveArmor = CalcOpts.TargetArmor * (1f - calculatedStats.petArmorDebuffs); calculatedStats.petTargetArmorReduction = StatConversion.GetArmorDamageReduction(character.Level, CalcOpts.TargetArmor, calculatedStats.petArmorDebuffs, 0, 0); #endif //petEffectiveArmor/(petEffectiveArmor - 22167.5f + (467.5f*80f)); #endregion }
public static SpecialEffect GetEnragedRegenerationWithMastery(float masteryVal, DPSWarrCharacter dpswarrchar) { SpecialEffect retVal = new SpecialEffect(Trigger.MeleeHit, new Stats() { BonusDamageMultiplier = 0.10f / 3f * dpswarrchar.Talents.Enrage * (1f + masteryVal), }, 9f, 0f, 0.03f * 3f); return retVal; }
public static bool IsSupportedUseEffect(SpecialEffect effect) { bool hasteEffect; bool stackingEffect; return IsSupportedUseEffect(effect, out hasteEffect, out stackingEffect); }
public static bool IsSupportedUseEffect(SpecialEffect effect, out bool hasteEffect, out bool stackingEffect) { stackingEffect = false; hasteEffect = false; if (effect.MaxStack == 1 && effect.Trigger == Trigger.Use) { // check if it is a stacking use effect Stats effectStats = effect.Stats; for (int i = 0; i < effectStats._rawSpecialEffectDataSize; i++) { SpecialEffect e = effectStats._rawSpecialEffectData[i]; if (e.Chance == 1f && e.Cooldown == 0f && (e.Trigger == Trigger.DamageSpellCast || e.Trigger == Trigger.DamageSpellHit || e.Trigger == Trigger.SpellCast || e.Trigger == Trigger.SpellHit)) { if (e.Stats.HasteRating > 0) { hasteEffect = true; stackingEffect = true; break; } } if (e.Chance == 1f && e.Cooldown == 0f && (e.Trigger == Trigger.DamageSpellCrit || e.Trigger == Trigger.SpellCrit)) { if (e.Stats.CritRating < 0 && effect.Stats.CritRating > 0) { stackingEffect = true; break; } } } if (stackingEffect) { return true; } if (effect.Stats.HasteRating > 0) { hasteEffect = true; } return effect.Stats.SpellPower + effect.Stats.HasteRating + effect.Stats.Intellect + effect.Stats.HighestStat > 0; } return false; }
public static bool IsSupportedSpellPowerProc(SpecialEffect effect) { return (effect.MaxStack == 1 && effect.Stats.SpellPower > 0 && IsSupportedProc(effect.Trigger)); }
/// <summary> /// Get Character Stats for multiple calls. Allowing means by which to stack different sets/Special effects. /// </summary> /// <param name="character"></param> /// <param name="additionalItem"></param> /// <param name="sType">Enum describing which set of stats we want.</param> /// <returns></returns> private StatsDK GetCharacterStats(Character character, Item additionalItem, StatType sType, TankDKChar TDK, Rotation rot = null) { StatsDK statsTotal = new StatsDK(); if (null == character.CalculationOptions) { // Possibly put some error text here. return statsTotal; } // Warning TDK can be blank at this point. TDK.Char = character; TDK.calcOpts = character.CalculationOptions as CalculationOptionsTankDK; TDK.bo = character.BossOptions; // Start populating data w/ Basic racial & class baseline. Stats BStats = BaseStats.GetBaseStats(character); statsTotal.Accumulate(BStats); statsTotal.BaseAgility = BStats.Agility; AccumulateItemStats(statsTotal, character, additionalItem); // Stack only the info we care about. statsTotal = GetRelevantStatsLocal(statsTotal); AccumulateBuffsStats(statsTotal, character.ActiveBuffs); AccumulateSetBonusStats(statsTotal, character.SetBonusCount); #region Tier Bonuses: Tank #region T11 int tierCount; if (character.SetBonusCount.TryGetValue("Magma Plated Battlearmor", out tierCount)) { if (tierCount >= 2) { statsTotal.b2T11_Tank = true; } if (tierCount >= 4) { statsTotal.b4T11_Tank = true; } } if (statsTotal.b4T11_Tank) statsTotal.AddSpecialEffect(_SE_IBF[1]); else statsTotal.AddSpecialEffect(_SE_IBF[0]); #endregion #region T12 if (character.SetBonusCount.TryGetValue("Elementium Deathplate Battlearmor", out tierCount)) { if (tierCount >= 2) { statsTotal.b2T12_Tank = true; } if (tierCount >= 4) { statsTotal.b4T12_Tank = true; } } if (statsTotal.b2T12_Tank) { // Your melee attacks cause Burning Blood on your target, // which deals 800 Fire damage every 2 for 6 sec and // causes your abilities to behave as if you had 2 diseases // present on the target. // Implemented in CombatState DiseaseCount statsTotal.FireDamage = 800 / 2; } if (statsTotal.b4T12_Tank) { // Your when your Dancing Rune Weapon expires, it grants 15% additional parry chance for 12 sec. // Implemented in DRW talent Static Special Effect. } #endregion #region T13 if (character.SetBonusCount.TryGetValue("Necrotic Boneplate Armor", out tierCount)) { if (tierCount >= 2) { statsTotal.b2T13_Tank = true; } if (tierCount >= 4) { statsTotal.b4T13_Tank = true; } } if (statsTotal.b2T13_Tank) { // When an attack drops your health below 35%, one of your Blood Runes // will immediately activate and convert into a Death Rune for the next // 20 sec. This effect cannot occur more than once every 45 sec. } if (statsTotal.b4T13_Tank) { // Your Vampiric Blood ability also affects all party and raid members // for 50% of the effect it has on you. } #endregion #endregion Rawr.DPSDK.CalculationsDPSDK.RemoveDuplicateRunes(statsTotal, character, true/*statsTotal.bDW*/); Rawr.DPSDK.CalculationsDPSDK.AccumulateTalents(statsTotal, character); Rawr.DPSDK.CalculationsDPSDK.AccumulatePresenceStats(statsTotal, Presence.Blood, character.DeathKnightTalents); statsTotal.ArcaneResistance += statsTotal.ArcaneResistanceBuff; statsTotal.ArcaneResistanceBuff = 0f; statsTotal.FireResistance += statsTotal.FireResistanceBuff; statsTotal.FireResistanceBuff = 0f; statsTotal.FrostResistance += statsTotal.FrostResistanceBuff; statsTotal.FrostResistanceBuff = 0f; statsTotal.NatureResistance += statsTotal.NatureResistanceBuff; statsTotal.NatureResistanceBuff = 0f; statsTotal.ShadowResistance += statsTotal.ShadowResistanceBuff; statsTotal.ShadowResistanceBuff = 0f; /* At this point, we're combined all the data from gear and talents and all that happy jazz. * However, we haven't applied any special effects nor have we applied any multipliers. * Many special effects are now getting dependant upon combat info (rotations). */ StatsDK PreRatingsBase = statsTotal.Clone() as StatsDK; // Apply the ratings to actual stats. ProcessRatings(statsTotal); ProcessAvoidance(statsTotal, TDK.bo.Level, TDK.Char, PreRatingsBase); statsTotal.EffectiveParry = 0; if (character.MainHand != null) { statsTotal.EffectiveParry = statsTotal.Parry; } float fChanceToGetHit = 1f - Math.Min(1f, statsTotal.Miss + statsTotal.Dodge + statsTotal.EffectiveParry); // Now comes the special handling for secondary stats passes that are dependant upon Boss & Rotation values. if (sType != StatType.Unbuffed && (null != TDK.bo && null != rot)) // Make sure we have the rotation and Boss info. { #region Special Effects #region Talent: Bone Shield if (character.DeathKnightTalents.BoneShield > 0) { int BSStacks = 4; // The number of bones by default. if (Rawr.Properties.GeneralSettings.Default.PTRMode) BSStacks = 6; // The number of bones by default. float BoneLossRate = Math.Max(2f, TDK.bo.DynamicCompiler_Attacks.AttackSpeed / fChanceToGetHit); // 2 sec internal cooldown on loosing bones so the DK can't get spammed to death. float moveVal = character.DeathKnightTalents.GlyphofBoneShield ? 0.15f : 0f; SpecialEffect primary = new SpecialEffect(Trigger.Use, new Stats() { DamageTakenReductionMultiplier = 0.20f, BonusDamageMultiplier = 0.02f, MovementSpeed = moveVal, }, BoneLossRate * BSStacks, 60) {BypassCache = true,}; statsTotal.AddSpecialEffect(primary); } #endregion #region Vengeance // Vengence has the chance to increase AP. int iVengenceMax = (int)(statsTotal.Stamina + (BaseStats.GetBaseStats(character).Health) * .1); int iAttackPowerMax = (int)statsTotal.AttackPower + iVengenceMax; float mitigatedDPS = TDK.bo.GetDPSByType(TDK.role, 0, statsTotal.DamageTakenReductionMultiplier, 0, .14f, statsTotal.Miss, statsTotal.Dodge, statsTotal.EffectiveParry, 0, 0, 0, 0, 0, 0, 0); //statsTotal.ArcaneResistance, statsTotal.FireResistance, statsTotal.FrostResistance, statsTotal.NatureResistance, statsTotal.ShadowResistance); mitigatedDPS = mitigatedDPS * (1 - (float)StatConversion.GetArmorDamageReduction(TDK.bo.Level, statsTotal.Armor, 0f, 0f)); float APStackSingle = mitigatedDPS * 0.05f * TDK.bo.DynamicCompiler_Attacks.AttackSpeed; int APStackCountMax = (int)Math.Floor(iVengenceMax / APStackSingle); SpecialEffect seVeng = new SpecialEffect(Trigger.DamageTaken, new Stats() { AttackPower = APStackSingle }, 2 * 10, 0, 1, APStackCountMax) { BypassCache = true, }; Dictionary<Trigger, float> triggerInterval = new Dictionary<Trigger,float>(); Dictionary<Trigger, float> triggerChance = new Dictionary<Trigger,float>(); triggerInterval.Add(Trigger.DamageTaken, TDK.bo.DynamicCompiler_Attacks.AttackSpeed); triggerChance.Add(Trigger.DamageTaken, 1f); // MitigatedDPS already factors in avoidance. statsTotal.VengenceAttackPower = seVeng.GetAverageStats(triggerInterval, triggerChance).AttackPower; statsTotal.AttackPower += statsTotal.VengenceAttackPower * TDK.calcOpts.VengeanceWeight; #endregion statsTotal.AddSpecialEffect(_SE_DeathPact); // For now we just factor them in once. Rawr.DPSDK.StatsSpecialEffects se = new Rawr.DPSDK.StatsSpecialEffects(rot.m_CT, rot, TDK.bo); StatsDK statSE = new StatsDK(); foreach (SpecialEffect effect in statsTotal.SpecialEffects()) { if (HasRelevantStats(effect.Stats)) { statSE.Accumulate(se.getSpecialEffects(effect)); // statsTotal.Accumulate(se.getSpecialEffects(effect)); // This is done further down. } } // Darkmoon card greatness procs if (statSE.HighestStat > 0 || statSE.Paragon > 0) { if (statSE.Strength >= statSE.Agility) { statSE.Strength += statSE.HighestStat + statSE.Paragon; } else if (statSE.Agility > statSE.Strength) { statSE.Agility += statSE.HighestStat + statSE.Paragon; } statSE.HighestStat = 0; statSE.Paragon = 0; } // Any Modifiers from stats need to be applied to statSE statSE.Strength = StatConversion.ApplyMultiplier(statSE.Strength, statsTotal.BonusStrengthMultiplier); statSE.Agility = StatConversion.ApplyMultiplier(statSE.Agility, statsTotal.BonusAgilityMultiplier); statSE.Stamina = StatConversion.ApplyMultiplier(statSE.Stamina, statsTotal.BonusStaminaMultiplier); // statSE.Stamina = (float)Math.Floor(statSE.Stamina); statSE.Armor = StatConversion.ApplyMultiplier(statSE.Armor, statsTotal.BaseArmorMultiplier); statSE.AttackPower = StatConversion.ApplyMultiplier(statSE.AttackPower, statsTotal.BonusAttackPowerMultiplier); statSE.BonusArmor = StatConversion.ApplyMultiplier(statSE.BonusArmor, statsTotal.BonusArmorMultiplier); statSE.Armor += statSE.BonusArmor; statSE.Health += StatConversion.GetHealthFromStamina(statSE.Stamina) + statSE.BattlemasterHealthProc; statSE.Health = statSE.Health * (1 + statSE.BonusHealthMultiplier); statsTotal.BonusHealthMultiplier = ((1 + statsTotal.BonusHealthMultiplier) * (1 + statSE.BonusHealthMultiplier)) - 1 ; if (character.DeathKnightTalents.BladedArmor > 0) { statSE.AttackPower += (statSE.Armor / 180f) * (float)character.DeathKnightTalents.BladedArmor; } statSE.AttackPower += StatConversion.ApplyMultiplier((statSE.Strength * 2), statsTotal.BonusAttackPowerMultiplier); statSE.ParryRating += statSE.Strength * 0.27f; // Any Modifiers from statSE need to be applied to stats statsTotal.Strength = StatConversion.ApplyMultiplier(statsTotal.Strength, statSE.BonusStrengthMultiplier); statsTotal.Agility = StatConversion.ApplyMultiplier(statsTotal.Agility, statSE.BonusAgilityMultiplier); statsTotal.Stamina = StatConversion.ApplyMultiplier(statsTotal.Stamina, statSE.BonusStaminaMultiplier); // stats.Stamina = (float)Math.Floor(stats.Stamina); statsTotal.Armor = StatConversion.ApplyMultiplier(statsTotal.Armor, statSE.BaseArmorMultiplier); statsTotal.AttackPower = StatConversion.ApplyMultiplier(statsTotal.AttackPower, statSE.BonusAttackPowerMultiplier); statsTotal.BonusArmor = StatConversion.ApplyMultiplier(statsTotal.BonusArmor, statSE.BonusArmorMultiplier); statsTotal.Accumulate(statSE); PreRatingsBase.Miss += statSE.Miss; PreRatingsBase.Dodge += statSE.Dodge; PreRatingsBase.Parry += statSE.Parry; #if DEBUG if (float.IsNaN(statsTotal.Stamina)) throw new Exception("Something very wrong in stats."); #endif #endregion // Special effects } // Apply the Multipliers ProcessStatModifiers(statsTotal, character.DeathKnightTalents.BladedArmor, character); ProcessAvoidance(statsTotal, TDK.bo.Level, TDK.Char, PreRatingsBase); if (character.MainHand != null) { statsTotal.EffectiveParry = statsTotal.Parry; } return (statsTotal); }
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; }