public DefendModel(Player player) { Player = player; AttackSpeed = Lookup.TargetWeaponSpeed(Player); DefendTable = new DefendTable(Player); Calculate(); }
public static float TargetAvoidanceChance(Player player, HitResult avoidanceType) { switch (avoidanceType) { case HitResult.Miss: return StatConversion.WHITE_MISS_CHANCE_CAP[player.BossOpts.Level - 85]; case HitResult.Dodge: return StatConversion.YELLOW_DODGE_CHANCE_CAP[player.BossOpts.Level - 85]; case HitResult.Parry: return StatConversion.YELLOW_PARRY_CHANCE_CAP[player.BossOpts.Level - 85]; case HitResult.Glance: return 0.06f + ((player.BossOpts.Level - player.Character.Level) * 0.06f); case HitResult.Crit: return -StatConversion.NPC_LEVEL_CRIT_MOD[player.BossOpts.Level - player.Character.Level]; // StatConversion returns as negative default: return 0.0f; } }
/// <summary> /// This should be a positive number factoring your Defensive Stance (-10% damage taken) /// and your stats.DamageTakenReductionMultiplier /// </summary> /// <returns>A Percentage (1f - (1f - 0.10f) * (1f - player.Stats.DamageTakenReductionMultiplier))</returns> public static float StanceDamageReduction(Player player, DamageType damageType) { // In Defensive Stance float damageTaken = (1.0f - 0.10f) * (1.0f - player.Stats.DamageTakenReductionMultiplier); switch (damageType) { case DamageType.Arcane: case DamageType.Fire: case DamageType.Frost: case DamageType.Nature: case DamageType.Shadow: case DamageType.Holy: return (1.0f - damageTaken); default: return (1.0f - damageTaken); } }
public static float TargetWeaponSpeed(Player player) { return player.BossOpts.DefaultMeleeAttack.AttackSpeed / (1f - player.Stats.BossAttackSpeedReductionMultiplier); }
public static float BonusExpertisePercentage(Player player) { return StatConversion.GetDodgeParryReducFromExpertise(player.Stats.Expertise + StatConversion.GetExpertiseFromRating(player.Stats.ExpertiseRating), CharacterClass.Warrior); }
public AttackModel(Player player, AttackModelMode attackModelMode, RageModelMode rageModelMode) { Player = player; DefendTable = new DefendTable(Player); _attackModelMode = attackModelMode; _rageModelMode = rageModelMode; Abilities.Add(Ability.None, Player); Abilities.Add(Ability.Cleave, Player); Abilities.Add(Ability.ConcussionBlow, Player); Abilities.Add(Ability.DeepWounds, Player); Abilities.Add(Ability.Devastate, Player); Abilities.Add(Ability.HeroicStrike, Player); Abilities.Add(Ability.HeroicThrow, Player); Abilities.Add(Ability.Rend, Player); Abilities.Add(Ability.Revenge, Player); Abilities.Add(Ability.ShieldSlam, Player); Abilities.Add(Ability.Shockwave, Player); Abilities.Add(Ability.Slam, Player); Abilities.Add(Ability.SunderArmor, Player); Abilities.Add(Ability.ThunderClap, Player); Calculate(); }
protected void Initialize(Player player, Ability ability) { Player = player; Ability = ability; Calculate(); }
public AttackTable(Player player) { Initialize(player, Ability.None); }
public static float MaxEffectiveMasteryRating(Player player) { if (player.DefendModel != null) return ((1.0f - player.DefendModel.DefendTable.BaseAnyAvoid) / 0.015f) * StatConversion.RATING_PER_MASTERY; else return float.MaxValue; }
public static float StanceDamageReduction(Player player) { return StanceDamageReduction(player, DamageType.Physical); }
public static float WeaponSpeed(Player player) { if (player.Character.MainHand != null) return Math.Max(1.0f, player.Character.MainHand.Speed / (1.0f + BonusHastePercentage(player))); else return 1.0f; }
public static float TargetArmorReduction(Player player) { return StatConversion.GetArmorDamageReduction(player.Character.Level, player.BossOpts.Armor, player.Stats.TargetArmorReduction, 0.0f); }
public static float WeaponDamage(Player player, bool normalized) { float weaponDamage = 1.0f; if (player.Character.MainHand != null) { float weaponSpeed = player.Character.MainHand.Speed; float weaponMinDamage = player.Character.MainHand.MinDamage; float weaponMaxDamage = player.Character.MainHand.MaxDamage; float normalizedSpeed = 1.0f; if (player.Character.MainHand.Type == ItemType.Dagger) normalizedSpeed = 1.7f; else normalizedSpeed = 2.4f; // Non-Normalized Hits if (!normalized) weaponDamage = ((weaponMinDamage + weaponMaxDamage) / 2.0f + (weaponSpeed * player.Stats.AttackPower / 14.0f)) + player.Stats.WeaponDamage; // Normalized Hits else weaponDamage = ((weaponMinDamage + weaponMaxDamage) / 2.0f + (normalizedSpeed * player.Stats.AttackPower / 14.0f)) + player.Stats.WeaponDamage; } return weaponDamage; }
public static float BonusCritPercentage(Player player, Ability ability) { // Grab base melee crit chance before adding ability-specific crit chance float abilityCritChance = BonusCritPercentage(player); switch (ability) { case Ability.Devastate: abilityCritChance += (player.Talents.SwordAndBoard * 0.05f); break; case Ability.HeroicStrike: abilityCritChance += player.Talents.Incite * 0.05f; break; case Ability.ShieldSlam: abilityCritChance += player.Talents.Cruelty * 0.05f; break; case Ability.DeepWounds: case Ability.Rend: case Ability.ShieldBash: case Ability.SunderArmor: abilityCritChance = 0.0f; break; } return Math.Min(1.0f, abilityCritChance); }
public static float BonusCritPercentage(Player player) { return Math.Max(0.0f, Math.Min(1.0f, StatConversion.GetPhysicalCritFromRating(player.Stats.CritRating, CharacterClass.Warrior) + StatConversion.GetPhysicalCritFromAgility(player.Stats.Agility, CharacterClass.Warrior) + player.Stats.PhysicalCrit)); }
public static float BonusCritMultiplier(Player player, Ability ability) { return (2.0f * (1.0f + player.Stats.BonusCritDamageMultiplier) - 1.0f); }
public static float BonusHitPercentage(Player player) { return StatConversion.GetPhysicalHitFromRating(player.Stats.HitRating, CharacterClass.Warrior) + player.Stats.PhysicalHit; }
public static float StanceDamageMultipler(Player player) { // In Defensive Stance return (1.0f * (1.0f + player.Stats.BonusDamageMultiplier) * (1.0f + player.Stats.BonusPhysicalDamageMultiplier)); }
public static float StanceThreatMultipler(Player player) { // In Defensive Stance return (3.0f * (1.0f + player.Stats.ThreatIncreaseMultiplier)); }
public static float GlancingReduction(Player player) { return (Math.Min(0.91f, 1.3f - (0.05f * (player.BossOpts.Level - player.Character.Level) * 5.0f)) + Math.Max(0.99f, 1.2f - (0.03f * (player.BossOpts.Level - player.Character.Level) * 5.0f))) / 2; }
public static float ArmorReduction(Player player) { return StatConversion.GetArmorDamageReduction(player.BossOpts.Level, player.Stats.Armor, 0f, 0f); }
public static float MagicReduction(Player player, DamageType school) { float totalResist = 0.0f; switch (school) { case DamageType.Arcane: totalResist = player.Stats.ArcaneResistance; break; case DamageType.Fire: totalResist = player.Stats.FireResistance; break; case DamageType.Frost: totalResist = player.Stats.FrostResistance; break; case DamageType.Nature: totalResist = player.Stats.NatureResistance; break; case DamageType.Shadow: totalResist = player.Stats.ShadowResistance; break; } float damageReduction = Lookup.StanceDamageReduction(player, school); float averageResistance = StatConversion.GetAverageResistance(player.BossOpts.Level, player.Character.Level, totalResist, 0.0f); return Math.Max(0.0f, (1.0f - averageResistance) * (1f - damageReduction)); }
public DefendTable(Player player) { Initialize(player, Ability.None); }
public static float AvoidanceChance(Player player, HitResult avoidanceType) { switch (avoidanceType) { case HitResult.Crit: return StatConversion.GetDRAvoidanceChance(player.Character, player.Stats, avoidanceType, player.BossOpts.Level) + (player.Talents.BastionOfDefense * 0.03f); case HitResult.CritBlock: return Lookup.BonusMasteryBlockPercentage(player) + player.Stats.CriticalBlock; default: return Math.Max(0.0f, StatConversion.GetDRAvoidanceChance(player.Character, player.Stats, avoidanceType, player.BossOpts.Level)); } }
public AttackTable(Player player, Ability ability) { Initialize(player, ability); }
private StatsWarrior GetSpecialEffectStats(Player player) { StatsWarrior statsSpecialEffects = new StatsWarrior(); Dictionary<Trigger, float> triggerIntervals = new Dictionary<Trigger, float>(); Dictionary<Trigger, float> triggerChances = new Dictionary<Trigger, float>(); player.DefendModel = new DefendModel(player); player.AttackModel = new AttackModel(player, AttackModelMode.Optimal); float effectiveMasteryRating = Lookup.MaxEffectiveMasteryRating(player); float effectiveBuffedMasteryRating = effectiveMasteryRating * (1.0f - 10.0f / player.CalcOpts.ShieldBlockInterval) + Lookup.MaxEffectiveBuffedMasteryRating(player) * (10.0f / player.CalcOpts.ShieldBlockInterval); triggerIntervals[Trigger.Use] = 0.0f; triggerIntervals[Trigger.MeleeAttack] = player.AttackModel.WeaponAttacksPerSecond; triggerIntervals[Trigger.MeleeHit] = triggerIntervals[Trigger.MeleeAttack]; triggerIntervals[Trigger.MeleeCrit] = triggerIntervals[Trigger.MeleeAttack]; triggerIntervals[Trigger.PhysicalHit] = triggerIntervals[Trigger.MeleeAttack]; triggerIntervals[Trigger.PhysicalAttack] = triggerIntervals[Trigger.MeleeAttack]; triggerIntervals[Trigger.PhysicalCrit] = triggerIntervals[Trigger.MeleeAttack]; triggerIntervals[Trigger.ExecuteHit] = triggerIntervals[Trigger.MeleeAttack]; triggerIntervals[Trigger.DoTTick] = (player.Talents.DeepWounds > 0) ? 2.0f : 0.0f; triggerIntervals[Trigger.DamageDone] = triggerIntervals[Trigger.MeleeAttack] + triggerIntervals[Trigger.DoTTick]; triggerIntervals[Trigger.DamageOrHealingDone] = triggerIntervals[Trigger.DamageDone]; triggerIntervals[Trigger.DamageTaken] = 1.0f / player.DefendModel.AttackerSwingsPerSecond; triggerIntervals[Trigger.DamageAvoided] = triggerIntervals[Trigger.DamageTaken]; triggerIntervals[Trigger.DamageParried] = triggerIntervals[Trigger.DamageTaken]; triggerIntervals[Trigger.DamageTakenPutsMeBelow35PercHealth] = triggerIntervals[Trigger.DamageTaken]; triggerIntervals[Trigger.ShieldBlock] = 60f - (player.Talents.ShieldMastery * 10f); triggerChances[Trigger.Use] = 1.0f; triggerChances[Trigger.MeleeAttack] = 1.0f; triggerChances[Trigger.MeleeHit] = player.AttackModel.HitsPerSecond / player.AttackModel.WeaponAttacksPerSecond; triggerChances[Trigger.MeleeCrit] = player.AttackModel.CritsPerSecond / player.AttackModel.WeaponAttacksPerSecond; triggerChances[Trigger.PhysicalAttack] = 1.0f; triggerChances[Trigger.PhysicalHit] = triggerChances[Trigger.MeleeHit]; triggerChances[Trigger.PhysicalCrit] = triggerChances[Trigger.MeleeCrit]; triggerChances[Trigger.ExecuteHit] = triggerChances[Trigger.MeleeHit]; triggerChances[Trigger.DoTTick] = (player.Talents.DeepWounds > 0) ? 1.0f : 0.0f; triggerChances[Trigger.DamageDone] = (player.AttackModel.HitsPerSecond + ((player.Talents.DeepWounds > 0) ? 2.0f : 0.0f)) / (player.AttackModel.WeaponAttacksPerSecond + ((player.Talents.DeepWounds > 0) ? 1.0f : 0.0f)); triggerChances[Trigger.DamageOrHealingDone] = triggerChances[Trigger.DamageDone]; triggerChances[Trigger.DamageTaken] = player.DefendModel.AttackerHitsPerSecond / player.DefendModel.AttackerSwingsPerSecond; triggerChances[Trigger.DamageAvoided] = player.DefendModel.DefendTable.AnyAvoid; triggerChances[Trigger.DamageParried] = player.DefendModel.DefendTable.Parry; triggerChances[Trigger.DamageTakenPutsMeBelow35PercHealth] = triggerChances[Trigger.DamageTaken] * 0.35f; triggerChances[Trigger.ShieldBlock] = 1.0f; foreach (SpecialEffect effect in player.Stats.SpecialEffects()) { if (RelevantTriggers.Contains(effect.Trigger)) { // Effective Mastery Capping on Large Proc Effects if ((effect.Trigger == Trigger.Use && effect.Stats.MasteryRating > effectiveMasteryRating) || effect.Stats.MasteryRating > effectiveBuffedMasteryRating) { Stats cappedStats = new Stats(); cappedStats.Accumulate(effect.Stats); // Assume Use Effects Bypass Shield Block Collision if (effect.Trigger == Trigger.Use) cappedStats.MasteryRating = effectiveMasteryRating; else cappedStats.MasteryRating = effectiveBuffedMasteryRating; // calculate average up-time of this trinket float averageUpTime = 0.0f; if (effect.Trigger == Trigger.ExecuteHit) averageUpTime = effect.GetAverageFactor(triggerIntervals[effect.Trigger], triggerChances[effect.Trigger], player.AttackModel.WeaponSpeed, player.BossOpts.BerserkTimer * (float)player.BossOpts.Under20Perc); else averageUpTime = effect.GetAverageFactor(triggerIntervals[effect.Trigger], triggerChances[effect.Trigger], player.AttackModel.WeaponSpeed, player.BossOpts.BerserkTimer); // accumulate the capped stats from the trinket into our final stats statsSpecialEffects.Accumulate(cappedStats, averageUpTime); } else { if (effect.Trigger == Trigger.ExecuteHit) effect.AccumulateAverageStats(statsSpecialEffects, triggerIntervals, triggerChances, player.AttackModel.WeaponSpeed, player.BossOpts.BerserkTimer * (float)player.BossOpts.Under20Perc); else effect.AccumulateAverageStats(statsSpecialEffects, triggerIntervals, triggerChances, player.AttackModel.WeaponSpeed, player.BossOpts.BerserkTimer); } } } // Base Stats statsSpecialEffects.Stamina = (float)Math.Floor(statsSpecialEffects.Stamina * (1.0f + player.Stats.BonusStaminaMultiplier)); statsSpecialEffects.Strength = (float)Math.Floor(statsSpecialEffects.Strength * (1.0f + player.Stats.BonusStrengthMultiplier)); statsSpecialEffects.Agility = (float)Math.Floor(statsSpecialEffects.Agility * (1.0f + player.Stats.BonusAgilityMultiplier)); return statsSpecialEffects; }
public AttackModel(Player player, AttackModelMode attackModelMode) : this(player, attackModelMode, RageModelMode.Infinite) { }
public static float TargetCritChance(Player player) { return Math.Max(0.0f, 0.05f - AvoidanceChance(player, HitResult.Crit)); }
public StatsWarrior GetBuffsStats(Player player) { Base.StatsWarrior statsBuffs = new Base.StatsWarrior(); statsBuffs.Accumulate(GetBuffsStats(player.Character.ActiveBuffs, player.Character.SetBonusCount)); if (player.Character.ActiveBuffs.Find<Buff>(x => x.SpellId == 22738) != null) { statsBuffs.BonusWarrior_PvP_4P_InterceptCDReduc = 5f; } if (player.Character.ActiveBuffs.Find<Buff>(x => x.SpellId == 70843) != null) { statsBuffs.BonusShieldSlamDamageMultiplier = 0.20f; statsBuffs.BonusShockwaveDamageMultiplier = 0.20f; } if (player.Character.ActiveBuffs.Find<Buff>(x => x.SpellId == 70844) != null) { //Your Battle Shout and Commanding Shout abilities now cause you to absorb damage equal to 20% of your maximum health. Lasts 10 sec. //statsBuffs.BonusWarrior_PvP_4P_InterceptCDReduc = 5f; } if (player.Character.ActiveBuffs.Find<Buff>(x => x.SpellId == 90296) != null) { statsBuffs.BonusShieldSlamDamageMultiplier = 0.05f; } if (player.Character.ActiveBuffs.Find<Buff>(x => x.SpellId == 90296) != null) { statsBuffs.BonusShieldWallDurMultiplier = 0.50f; } int T12count; player.Character.SetBonusCount.TryGetValue("Molten Giant Battleplate", out T12count); if (T12count >= 2) { statsBuffs.BonusShieldSlamDamageMultiplier = 0.20f; } if (T12count >= 4) { statsBuffs.AddSpecialEffect(_SE_4T12[player.Talents.ShieldMastery]); } return statsBuffs; }
public static float BonusMasteryBlockPercentage(Player player) { return 0.015f * (8.0f + StatConversion.GetMasteryFromRating(player.Stats.MasteryRating, CharacterClass.Warrior)); }