Beispiel #1
0
        private void Calculate()
        {
            float globalCooldownSpeed = Lookup.GlobalCooldownSpeed(Character, true);
            float baseBossAttackSpeed = Options.BossAttackSpeed * (1.0f - Stats.BossAttackSpeedMultiplier);
            float baseWeaponSpeed     = Lookup.WeaponSpeed(Character, Stats);
            float bossAttackHaste     = 0.0f;
            float weaponHaste         = 0.0f;

            BossAttackSpeed = baseBossAttackSpeed;
            WeaponSpeed     = baseWeaponSpeed;

            if (Options.UseParryHaste)
            {
                // Iterate on this a few times to get a 'stable' result
                for (int j = 0; j < 4; j++)
                {
                    weaponHaste     = DefendTable.Parry * 0.24f * (WeaponSpeed / BossAttackSpeed);
                    bossAttackHaste = AttackTable.Parry * 0.24f * ((BossAttackSpeed / WeaponSpeed) + (BossAttackSpeed / globalCooldownSpeed));

                    WeaponSpeed     = baseWeaponSpeed / (1.0f + weaponHaste);
                    BossAttackSpeed = baseBossAttackSpeed / (1.0f + bossAttackHaste);
                }
            }
            else
            {
                // Simple adjust to the defender's speed if the attacker isn't parry hasted
                WeaponSpeed /= (1.0f + (DefendTable.Parry * 0.24f * (WeaponSpeed / BossAttackSpeed)));
            }
        }
Beispiel #2
0
        private void Calculate()
        {
            float baseBossAttackSpeed = Options.BossAttackSpeed;
            float baseWeaponSpeed     = Lookup.WeaponSpeed(Character, Stats);
            float bossAttackHaste     = 0.0f;
            float weaponHaste         = 0.0f;

            BossAttackSpeed = baseBossAttackSpeed;
            WeaponSpeed     = baseWeaponSpeed;

            if (Options.UseParryHaste)
            {
                // Iterate on this a few times to get a 'stable' result
                for (int j = 0; j < 4; j++)
                {
                    weaponHaste = DefendTable.Parry * 0.24f * (WeaponSpeed / BossAttackSpeed);
                    // Unrelenting Assault 'Revenge Spam' builds have 1.0s GCD instead of 1.5s
                    if (Character.WarriorTalents.UnrelentingAssault == 2)
                    {
                        bossAttackHaste = AttackTable.Parry * 0.24f * ((BossAttackSpeed / WeaponSpeed) + (BossAttackSpeed / 1.0f));
                    }
                    else
                    {
                        bossAttackHaste = AttackTable.Parry * 0.24f * ((BossAttackSpeed / WeaponSpeed) + (BossAttackSpeed / 1.5f));
                    }

                    WeaponSpeed     = baseWeaponSpeed / (1.0f + weaponHaste);
                    BossAttackSpeed = baseBossAttackSpeed / (1.0f + bossAttackHaste);
                }
            }
            else
            {
                // Simple adjust to the defender's speed if the attacker isn't parry hasted
                WeaponSpeed /= (1.0f + (DefendTable.Parry * 0.24f * (WeaponSpeed / BossAttackSpeed)));
            }
        }
Beispiel #3
0
        private void Calculate()
        {
            Dictionary <Ability, float> modelAbilities = new Dictionary <Ability, float>();
            float modelLength        = 0.0f;
            float modelThreat        = 0.0f;
            float modelDamage        = 0.0f;
            float modelCrits         = 0.0f;
            float modelHits          = 0.0f;
            float modelWeaponAttacks = 0.0f;

            WeaponSpeed = 1.0f;
            if (Player.Character.MainHand != null)
            {
                WeaponSpeed = Player.Character.MainHand.Speed;
            }

            // Rotation Auto-Detection
            if (AttackModelMode == AttackModelMode.Optimal)
            {
                if (Player.Talents.Shockwave == 1 && Player.Talents.SwordAndBoard == 3 && Player.Talents.Devastate == 1)
                {
                    if (Player.Talents.ImprovedRevenge > 0)
                    {
                        AttackModelMode = AttackModelMode.FullProtectionRevenge;
                    }
                    else
                    {
                        AttackModelMode = AttackModelMode.FullProtection;
                    }
                }
                else if (Player.Talents.SwordAndBoard == 3 && Player.Talents.Devastate == 1)
                {
                    if (Player.Talents.ImprovedRevenge > 0)
                    {
                        AttackModelMode = AttackModelMode.SwordAndBoardRevenge;
                    }
                    else
                    {
                        AttackModelMode = AttackModelMode.SwordAndBoard;
                    }
                }
                else if (Player.Talents.Devastate == 1)
                {
                    if (Player.Talents.ImprovedRevenge > 0)
                    {
                        AttackModelMode = AttackModelMode.DevastateRevenge;
                    }
                    else
                    {
                        AttackModelMode = AttackModelMode.Devastate;
                    }
                }
                else
                {
                    AttackModelMode = AttackModelMode.Basic;
                }
            }

            switch (AttackModelMode)
            {
            case AttackModelMode.Basic:
            {
                // Basic Rotation
                // Shield Slam -> Revenge -> Sunder Armor -> Sunder Armor
                Name        = "Basic Cycle";
                Description = "Shield Slam -> Revenge -> Sunder Armor -> Sunder Armor";
                modelLength = 6.0f;
                modelAbilities.Add(Ability.ShieldSlam, 1.0f);
                modelAbilities.Add(Ability.Revenge, 1.0f);
                modelAbilities.Add(Ability.SunderArmor, 2.0f);
                break;
            }

            case AttackModelMode.Devastate:
            {
                // Devastate Rotation
                // Shield Slam -> Devastate -> Devastate -> Devastate
                Name        = "Devastate";
                Description = "Shield Slam -> Devastate -> Devastate -> Devastate";
                modelLength = 6.0f;
                modelAbilities.Add(Ability.ShieldSlam, 1.0f);
                modelAbilities.Add(Ability.Devastate, 3.0f);
                break;
            }

            case AttackModelMode.DevastateRevenge:
            {
                // Devastate + Revenge Rotation
                // Shield Slam -> Revenge -> Devastate -> Devastate
                Name        = "Devastate + Revenge";
                Description = "Shield Slam -> Revenge -> Devastate -> Devastate";
                modelLength = 6.0f;
                modelAbilities.Add(Ability.ShieldSlam, 1.0f);
                modelAbilities.Add(Ability.Revenge, 1.0f);
                modelAbilities.Add(Ability.Devastate, 2.0f);
                break;
            }

            case AttackModelMode.SwordAndBoard:
            case AttackModelMode.SwordAndBoardRevenge:
            case AttackModelMode.FullProtection:
            case AttackModelMode.FullProtectionRevenge:
            {
                // Sword And Board Rotation
                // Shield Slam > Revenge > Devastate
                // The distribution of abilities in the model is as follows:
                // 1.0 * Shield Slam + 0.73 * Revenge + 1.4596 * Devastate
                // -or-
                // Shield Slam > Revenge > Devastate @ 3s Shield Slam Cooldown > Shockwave > Devastate
                // The distribution of abilities in the model is as follows:
                // 1.0 * Shield Slam + 0.73 * Revenge + 1.133 * Devastate + 0.3266 * (Concussion Blow/Shockwave/Devastate)
                // The cycle length is 4.7844s, abilities per cycle is 3.1896
                Name        = "Sword and Board";
                Description = "Shield Slam > ";
                if (AttackModelMode == AttackModelMode.SwordAndBoardRevenge || AttackModelMode == AttackModelMode.FullProtectionRevenge)
                {
                    Name        += " + Revenge";
                    Description += "Revenge > Devastate";
                }
                else
                {
                    Description += "Devastate";
                }
                if (AttackModelMode == AttackModelMode.FullProtection || AttackModelMode == AttackModelMode.FullProtectionRevenge)
                {
                    Name        += " + Shockwave";
                    Description += "\n@ 1.5s Shield Slam Cooldown: Shockwave > Devastate";
                }

                modelLength = 4.7844f;
                modelAbilities.Add(Ability.ShieldSlam, 1.0f);
                modelAbilities.Add(Ability.Devastate, 1.133f);

                // Add Revenge, if applicable
                if (AttackModelMode == AttackModelMode.SwordAndBoardRevenge || AttackModelMode == AttackModelMode.FullProtectionRevenge)
                {
                    modelAbilities.Add(Ability.Revenge, 0.73f);
                }
                else
                {
                    modelAbilities[Ability.Devastate] += 0.73f;
                }

                // Add Shockwave, if applicable
                if (AttackModelMode == AttackModelMode.FullProtection || AttackModelMode == AttackModelMode.FullProtectionRevenge)
                {
                    modelAbilities.Add(Ability.Shockwave, (0.3266f / 3.0f));
                    modelAbilities[Ability.Devastate] += (0.3266f / 3.0f) * 2.0f;
                }
                else
                {
                    modelAbilities[Ability.Devastate] += 0.3266f;
                }

                break;
            }
            }

            // Accumulate base model statistics
            foreach (KeyValuePair <Ability, float> modelAbility in modelAbilities)
            {
                AbilityModel ability = Abilities[modelAbility.Key];
                modelThreat += ability.Threat * modelAbility.Value;
                modelDamage += ability.Damage * modelAbility.Value;
                if (ability.Damage > 0.0f)
                {
                    modelHits  += ability.HitPercentage * modelAbility.Value;
                    modelCrits += ability.CritPercentage * modelAbility.Value;
                }
                if (ability.IsWeaponAttack)
                {
                    modelWeaponAttacks += modelAbility.Value;
                }
            }

            // Heroic Strike
            float heroicStrikePercentage = Math.Max(0.0f, Math.Min(1.0f, Player.CalcOpts.HeroicStrikeFrequency));
            float heroicStrikeCount      = (modelLength / 3.0f) * heroicStrikePercentage;

            modelThreat        += Abilities[Ability.HeroicStrike].Threat * heroicStrikeCount;
            modelDamage        += Abilities[Ability.HeroicStrike].Damage * heroicStrikeCount;
            modelHits          += Abilities[Ability.HeroicStrike].HitPercentage * heroicStrikeCount;
            modelCrits         += Abilities[Ability.HeroicStrike].CritPercentage * heroicStrikeCount;
            modelWeaponAttacks += heroicStrikeCount;

            // Simple GCD-Based Latency Adjustment
            // modelLength *= Lookup.GlobalCooldownSpeed(true) / Lookup.GlobalCooldownSpeed(false);
            // Note: Removed due to action queue in Cataclysm--should no longer be needed

            // Weapon Damage Swings
            float weaponSwings = modelLength / Lookup.WeaponSpeed(Player);

            modelThreat        += Abilities[Ability.None].Threat * weaponSwings;
            modelDamage        += Abilities[Ability.None].Damage * weaponSwings;
            modelCrits         += Abilities[Ability.None].CritPercentage * weaponSwings;
            modelHits          += Abilities[Ability.None].HitPercentage * weaponSwings;
            modelWeaponAttacks += weaponSwings;

            // Deep Wounds
            AbilityModel deepWounds = Abilities[Ability.DeepWounds];

            modelThreat += deepWounds.Threat * modelCrits;
            modelDamage += deepWounds.Damage * modelCrits;

            // Misc. Power Gains
            modelThreat += DefendTable.AnyBlock * (modelLength / Lookup.TargetWeaponSpeed(Player)) * 25.0f * Player.Talents.ShieldSpecialization;

            // Final Per-Second Calculations
            ThreatPerSecond        = modelThreat / modelLength;
            DamagePerSecond        = modelDamage / modelLength;
            WeaponAttacksPerSecond = modelWeaponAttacks / modelLength;
            HitsPerSecond          = modelHits / modelLength;
            CritsPerSecond         = modelCrits / modelLength;
        }