Exemple #1
0
 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;
 }
Exemple #3
0
 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);
    }
Exemple #6
0
 /// <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));
 }
Exemple #14
0
 private bool IsDoublePot(SpecialEffect effect)
 {
     return(effect.Cooldown == 1200f && effect.Duration == 14f);
 }
Exemple #15
0
 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;
 }
Exemple #16
0
    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;
                }
            }
        }
Exemple #18
0
 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);
        }
Exemple #36
0
        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;
        }