protected override void Calculate() { // Hack to not count holy shield when we are trying to calculate crit chance without it if (!UseHolyShield && CalcOpts.UseHolyShield) { Stats.Accumulate(new Stats() { Block = -0.3f }); } float tableSize = 0.0f; #if (RAWR3) int targetLevel = BossOpts.Level; #else int targetLevel = CalcOpts.TargetLevel; #endif // Miss Miss = Math.Min(1.0f - tableSize, Lookup.AvoidanceChance(Character, Stats, HitResult.Miss, targetLevel)); tableSize += Miss; // Dodge Dodge = Math.Min(1.0f - tableSize, Lookup.AvoidanceChance(Character, Stats, HitResult.Dodge, targetLevel)); tableSize += Dodge; // Parry Parry = Math.Min(1.0f - tableSize, Lookup.AvoidanceChance(Character, Stats, HitResult.Parry, targetLevel)); tableSize += Parry; // Block if (Character.OffHand != null && Character.OffHand.Type == ItemType.Shield) { Block = Math.Min(1.0f - tableSize, Lookup.AvoidanceChance(Character, Stats, HitResult.Block, targetLevel)); tableSize += Block; } // Critical Hit Critical = Math.Min(1.0f - tableSize, Lookup.TargetCritChance(Character, Stats, targetLevel)); tableSize += Critical; // Normal Hit Hit = Math.Max(0.0f, 1.0f - tableSize); // Partial Resists don't belong in the combat table Resist = 1.0f - StatConversion.GetResistanceTable(targetLevel, Character.Level, Stats.FrostResistance, 0.0f)[0]; // Hack to put back holy shield when we are trying to calculate crit chance without it if (!UseHolyShield && CalcOpts.UseHolyShield) { Stats.Accumulate(new Stats() { Block = 0.3f }); } }
protected override void Calculate() { float tableSize = 0.0f; int targetLevel = BossOpts.Level; // Miss Miss = Math.Min(1.0f - tableSize, Lookup.AvoidanceChance(Character, Stats, HitResult.Miss, targetLevel)); tableSize += Miss; // Dodge Dodge = Math.Min(1.0f - tableSize, Lookup.AvoidanceChance(Character, Stats, HitResult.Dodge, targetLevel)); tableSize += Dodge; // Parry Parry = Math.Min(1.0f - tableSize, Lookup.AvoidanceChance(Character, Stats, HitResult.Parry, targetLevel)); tableSize += Parry; // Block if (Character.OffHand != null && Character.OffHand.Type == ItemType.Shield) { //Block = Math.Min(1.0f - tableSize, Lookup.AvoidanceChance(Character, Stats, HitResult.Block, targetLevel)); Block = Lookup.AvoidanceChance(Character, Stats, HitResult.Block, targetLevel); if (Block > (1.0f - tableSize)) { BlockOverCap = Block - 1.0f + tableSize; } else { BlockOverCap = 0.0f; } tableSize += Block; } // Critical Hit Critical = Math.Min(1.0f - tableSize, Lookup.TargetCritChance(Character, Stats, targetLevel)); tableSize += Critical; // Normal Hit Hit = Math.Max(0.0f, 1.0f - tableSize); // Partial Resists don't belong in the combat table Resist = 1.0f - StatConversion.GetResistanceTable(targetLevel, Character.Level, Stats.FrostResistance, 0.0f)[0]; }
public static float TargetAvoidanceChance(Character character, Stats stats, HitResult avoidanceType, int targetLevel) { switch (avoidanceType) { case HitResult.Miss: return(StatConversion.WHITE_MISS_CHANCE_CAP[targetLevel - 80]); case HitResult.Dodge: return(StatConversion.WHITE_DODGE_CHANCE_CAP[targetLevel - 80]); case HitResult.Parry: return(StatConversion.WHITE_PARRY_CHANCE_CAP[targetLevel - 80]); case HitResult.Glance: return(StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - 80]); case HitResult.Block: return(StatConversion.WHITE_BLOCK_CHANCE_CAP[targetLevel - 80]); case HitResult.Resist: // Patial resists don't belong in the combat table, they are a damage multiplier (reduction) // The Chance to get any Partial Resist float partialChance = 1.0f - StatConversion.GetResistanceTable(character.Level, targetLevel, 0.0f, stats.SpellPenetration)[0]; return(partialChance); default: return(0.0f); } }
private void CalculateDamage() { float baseDamage = 0.0f; float critMultiplier = 0.0f; float duration = 0.0f; float AP = Stats.AttackPower; float SP = Stats.SpellPower; #if (RAWR3) int targetLevel = BossOpts.Level; #else int targetLevel = CalcOpts.TargetLevel; #endif #region Ability Base Damage switch (Ability) { // White Damage case Ability.None: baseDamage = Stats.WeaponDamage; DamageMultiplier *= (1.0f + Stats.BonusPhysicalDamageMultiplier) * (1.0f - (Lookup.GlancingReduction(Character, targetLevel) * AttackTable.Glance)) * (1.0f - ArmorReduction); critMultiplier = 1.0f; break; case Ability.ShieldOfRighteousness: float blockValue = Stats.BlockValue + Stats.ShieldOfRighteousnessBlockValue + Stats.JudgementBlockValue + Stats.HolyShieldBlockValue; float blockValueDRStart = 30 * Character.Level; if (blockValue < blockValueDRStart) { baseDamage = blockValue; } else if (blockValue < 39.5 * Character.Level) { baseDamage = blockValueDRStart + (0.95f * (blockValue - blockValueDRStart)) - (0.000625f * (float)Math.Pow(blockValue - blockValueDRStart, 2)); } else { baseDamage = blockValueDRStart + (0.95f * 9.5f * Character.Level) - (0.000625f * (float)Math.Pow(9.5 * Character.Level, 2)); } baseDamage += 520f + Stats.BonusShieldOfRighteousnessDamage; DamageMultiplier *= (1.0f + Stats.BonusHolyDamageMultiplier); critMultiplier = 1.0f; break; case Ability.HammerOfTheRighteous: if (Talents.HammerOfTheRighteous == 0 || Character.MainHand == null) { Damage = 0.0f; return; } baseDamage = (Stats.WeaponDamage / Character.MainHand.Speed) * 4.0f; DamageMultiplier *= (1.0f + Stats.BonusHolyDamageMultiplier) * (1.0f + Stats.BonusHammerOfTheRighteousMultiplier); critMultiplier = 1.0f; break; // Seal of Vengeance is the tiny damage that applies on each swing; Holy Vengeance is the DoT // While trivial threat and damage, it's modeled for compatibility with Seal of Righteousness case Ability.SealOfVengeance: baseDamage = Stats.WeaponDamage * 0.33f; DamageMultiplier *= (1.0f + Stats.BonusHolyDamageMultiplier) * (1.0f + 0.03f * Talents.SealsOfThePure) * (1.0f + Stats.BonusSealOfVengeanceDamageMultiplier); critMultiplier = 1.0f; break; // 5 stacks of Holy Vengeance are assumed // TODO: implement stacking mechanic for beginning-of-fight TPS case Ability.HolyVengeance: baseDamage = 5f * (0.016f * SP + 0.032f * AP); DamageMultiplier *= (1.0f + Stats.BonusHolyDamageMultiplier) * (1.0f + 0.03f * Talents.SealsOfThePure) * (1.0f + Stats.BonusSealOfVengeanceDamageMultiplier); critMultiplier = 0.0f; break; // Judgement of Vengeance assumes 5 stacks of Holy Vengeance case Ability.JudgementOfVengeance: float holyVengeanceStacks = 5; baseDamage = (0.22f * SP + 0.14f * AP) * (1.0f + 0.1f * holyVengeanceStacks); DamageMultiplier *= (1.0f + Stats.BonusHolyDamageMultiplier) * (1.0f + 0.03f * Talents.SealsOfThePure) * (Talents.GlyphOfJudgement ? 1.1f : 1.0f); critMultiplier = 1.0f; break; case Ability.SealOfRighteousness: baseDamage = Lookup.WeaponSpeed(Character, Stats) * ((0.022f * AP) + (0.044f * SP)); DamageMultiplier *= (1.0f + Stats.BonusHolyDamageMultiplier) * (1.0f + 0.03f * Talents.SealsOfThePure) * (1.0f + Stats.BonusSealOfRighteousnessDamageMultiplier) * (Talents.GlyphOfSealOfRighteousness ? 1.1f : 1.0f); critMultiplier = 0.0f; break; case Ability.JudgementOfRighteousness: baseDamage = 1.0f + (0.2f * AP) + (0.32f * SP); DamageMultiplier *= (1.0f + Stats.BonusHolyDamageMultiplier) * (1.0f + 0.03f * Talents.SealsOfThePure) * (Talents.GlyphOfJudgement ? 1.1f : 1.0f); critMultiplier = 1.0f; break; case Ability.HolyShield: if (Talents.HolyShield == 0) { Damage = 0.0f; return; } baseDamage = (211f + (0.056f * AP) + (0.09f * SP)) * 1.3f; DamageMultiplier *= (1.0f + Stats.BonusHolyDamageMultiplier); critMultiplier = 0.0f; break; case Ability.Consecration: baseDamage = 113f + (0.04f * (SP + Stats.ConsecrationSpellPower)) + (0.04f * AP); duration = (Talents.GlyphOfConsecration ? 10.0f : 8.0f); DamageMultiplier *= (1.0f + Stats.BonusHolyDamageMultiplier); critMultiplier = 0.0f; break; case Ability.Exorcism: baseDamage = 1087f + (0.15f * SP) + (0.15f * AP); DamageMultiplier *= (1.0f + Stats.BonusHolyDamageMultiplier) * (1.0f + Talents.SanctityOfBattle * 0.05f) * (Talents.GlyphOfExorcism ? 1.2f : 1.0f); critMultiplier = 0.5f; break; case Ability.AvengersShield: baseDamage = 1222f + (0.07f * SP) + (0.07f * AP); DamageMultiplier *= (1.0f + Stats.BonusHolyDamageMultiplier) * (Talents.GlyphOfAvengersShield ? 2.0f : 1.0f); critMultiplier = 1.0f; break; case Ability.HolyWrath: baseDamage = 1142f + (AP * 0.07f) + (SP * 0.07f); DamageMultiplier *= (1.0f + Stats.BonusHolyDamageMultiplier); critMultiplier = 0.5f; break; case Ability.HammerOfWrath: baseDamage = 1198f + (AP * 0.15f) + (SP * 0.15f); DamageMultiplier *= (1.0f + Stats.BonusHolyDamageMultiplier); critMultiplier = 1.0f; break; case Ability.RetributionAura: baseDamage = 112f + (SP * 0.0666f); DamageMultiplier *= (1.0f + Stats.BonusHolyDamageMultiplier) * (1.0f + Talents.SanctifiedRetribution * 0.5f); critMultiplier = 0.0f; break; } #endregion // All damage multipliers, 1HWS, Armor etc...do we need to split buff/debuff ? baseDamage *= DamageMultiplier; #region Miss Chance, Avoidance Chance if (Lookup.IsSpell(Ability)) { if (Ability == Ability.Consecration) { // Probability calculation, since each tick can be resisted individually. baseDamage = Lookup.GetConsecrationTickChances(duration, baseDamage, AttackTable.Miss); } else { // Missed spell attacks // TODO: expand Ability Model to include a check for damage type, not only spell. baseDamage *= (1.0f - AttackTable.Miss); } } else { // Missed attacks if (Lookup.IsAvoidable(Ability)) { baseDamage *= (1.0f - AttackTable.AnyMiss); } else { baseDamage *= (1.0f - AttackTable.Miss); } } #endregion #region Partial Resists // Partial Resists if (Lookup.HasPartials(Ability)) { // Detailed table of Partial slices. float[] partialChanceTable = StatConversion.GetResistanceTable(Character.Level, targetLevel, 0.0f, Stats.SpellPenetration); // Here goes nothing, Damage averaged over the different partial slices that can happen. float partialDamage = 0.0f; for (int i = 0; i < 11; i++) { partialDamage += partialChanceTable[i] * (1.0f - 0.1f * (float)i) * baseDamage; } baseDamage = partialDamage; } #endregion // Average critical strike bonuses if (Lookup.CanCrit(Ability)) { baseDamage += baseDamage * critMultiplier * AttackTable.Critical; } // Final Damage the Ability deals Damage = baseDamage; }