Merge pull request #2931 from Chaplain/cleanup
Core/Mechanic: Implement Diminishing Returns for miss\parry\dodge. Original author for parry\dodge case Lynx3d.
This commit is contained in:
@@ -5755,35 +5755,37 @@ float Player::GetMeleeCritFromAgility()
|
|||||||
return crit*100.0f;
|
return crit*100.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Player::GetDodgeFromAgility()
|
void Player::GetDodgeFromAgility(float &diminishing, float &nondiminishing)
|
||||||
{
|
{
|
||||||
// Table for base dodge values
|
// Table for base dodge values
|
||||||
float dodge_base[MAX_CLASSES] = {
|
const float dodge_base[MAX_CLASSES] =
|
||||||
0.0075f, // Warrior
|
{
|
||||||
0.00652f, // Paladin
|
0.036640f, // Warrior
|
||||||
-0.0545f, // Hunter
|
0.034943f, // Paladi
|
||||||
-0.0059f, // Rogue
|
-0.040873f, // Hunter
|
||||||
0.03183f, // Priest
|
0.020957f, // Rogue
|
||||||
0.0114f, // DK
|
0.034178f, // Priest
|
||||||
0.0167f, // Shaman
|
0.036640f, // DK
|
||||||
0.034575f, // Mage
|
0.021080f, // Shaman
|
||||||
0.02011f, // Warlock
|
0.036587f, // Mage
|
||||||
|
0.024211f, // Warlock
|
||||||
0.0f, // ??
|
0.0f, // ??
|
||||||
-0.0187f // Druid
|
0.056097f // Druid
|
||||||
};
|
};
|
||||||
// Crit/agility to dodge/agility coefficient multipliers
|
// Crit/agility to dodge/agility coefficient multipliers; 3.2.0 increased required agility by 15%
|
||||||
float crit_to_dodge[MAX_CLASSES] = {
|
const float crit_to_dodge[MAX_CLASSES] =
|
||||||
1.1f, // Warrior
|
{
|
||||||
1.0f, // Paladin
|
0.85f/1.15f, // Warrior
|
||||||
1.6f, // Hunter
|
1.00f/1.15f, // Paladin
|
||||||
2.0f, // Rogue
|
1.11f/1.15f, // Hunter
|
||||||
1.0f, // Priest
|
2.00f/1.15f, // Rogue
|
||||||
1.0f, // DK?
|
1.00f/1.15f, // Priest
|
||||||
1.0f, // Shaman
|
0.85f/1.15f, // DK
|
||||||
1.0f, // Mage
|
1.60f/1.15f, // Shaman
|
||||||
1.0f, // Warlock
|
1.00f/1.15f, // Mage
|
||||||
0.0f, // ??
|
0.97f/1.15f, // Warlock (?)
|
||||||
1.7f // Druid
|
0.0f, // ??
|
||||||
|
2.00f/1.15f // Druid
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8 level = getLevel();
|
uint8 level = getLevel();
|
||||||
@@ -5792,13 +5794,18 @@ float Player::GetDodgeFromAgility()
|
|||||||
if (level > GT_MAX_LEVEL)
|
if (level > GT_MAX_LEVEL)
|
||||||
level = GT_MAX_LEVEL;
|
level = GT_MAX_LEVEL;
|
||||||
|
|
||||||
// Dodge per agility for most classes equal crit per agility (but for some classes need apply some multiplier)
|
// Dodge per agility is proportional to crit per agility, which is available from DBC files
|
||||||
GtChanceToMeleeCritEntry const *dodgeRatio = sGtChanceToMeleeCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1);
|
GtChanceToMeleeCritEntry const *dodgeRatio = sGtChanceToMeleeCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1);
|
||||||
if (dodgeRatio == NULL || pclass > MAX_CLASSES)
|
if (dodgeRatio == NULL || pclass > MAX_CLASSES)
|
||||||
return 0.0f;
|
return;
|
||||||
|
|
||||||
float dodge=dodge_base[pclass-1] + GetStat(STAT_AGILITY) * dodgeRatio->ratio * crit_to_dodge[pclass-1];
|
// TODO: research if talents/effects that increase total agility by x% should increase non-diminishing part
|
||||||
return dodge*100.0f;
|
float base_agility = GetCreateStat(STAT_AGILITY) * m_auraModifiersGroup[UNIT_MOD_STAT_START + STAT_AGILITY][BASE_PCT];
|
||||||
|
float bonus_agility = GetStat(STAT_AGILITY) - base_agility;
|
||||||
|
|
||||||
|
// calculate diminishing (green in char screen) and non-diminishing (white) contribution
|
||||||
|
diminishing = 100.0f * bonus_agility * dodgeRatio->ratio * crit_to_dodge[pclass-1];
|
||||||
|
nondiminishing = 100.0f * (dodge_base[pclass-1] + base_agility * dodgeRatio->ratio * crit_to_dodge[pclass-1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Player::GetSpellCritFromIntellect()
|
float Player::GetSpellCritFromIntellect()
|
||||||
|
|||||||
@@ -1875,7 +1875,8 @@ class Player : public Unit, public GridObject<Player>
|
|||||||
void UpdateDefenseBonusesMod();
|
void UpdateDefenseBonusesMod();
|
||||||
inline void RecalculateRating(CombatRating cr) { ApplyRatingMod(cr, 0, true);}
|
inline void RecalculateRating(CombatRating cr) { ApplyRatingMod(cr, 0, true);}
|
||||||
float GetMeleeCritFromAgility();
|
float GetMeleeCritFromAgility();
|
||||||
float GetDodgeFromAgility();
|
void GetDodgeFromAgility(float &diminishing, float &nondiminishing);
|
||||||
|
float GetMissPercentageFromDefence() const;
|
||||||
float GetSpellCritFromIntellect();
|
float GetSpellCritFromIntellect();
|
||||||
float OCTRegenHPPerSpirit();
|
float OCTRegenHPPerSpirit();
|
||||||
float OCTRegenMPPerSpirit();
|
float OCTRegenMPPerSpirit();
|
||||||
|
|||||||
@@ -624,20 +624,79 @@ void Player::UpdateAllCritPercentages()
|
|||||||
UpdateCritPercentage(RANGED_ATTACK);
|
UpdateCritPercentage(RANGED_ATTACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const float m_diminishing_k[MAX_CLASSES] =
|
||||||
|
{
|
||||||
|
0.9560f, // Warrior
|
||||||
|
0.9560f, // Paladin
|
||||||
|
0.9880f, // Hunter
|
||||||
|
0.9880f, // Rogue
|
||||||
|
0.9830f, // Priest
|
||||||
|
0.9560f, // DK
|
||||||
|
0.9880f, // Shaman
|
||||||
|
0.9830f, // Mage
|
||||||
|
0.9830f, // Warlock
|
||||||
|
0.0f, // ??
|
||||||
|
0.9720f // Druid
|
||||||
|
};
|
||||||
|
|
||||||
|
float Player::GetMissPercentageFromDefence() const
|
||||||
|
{
|
||||||
|
const float miss_cap[MAX_CLASSES] =
|
||||||
|
{
|
||||||
|
16.00f, // Warrior //correct
|
||||||
|
16.00f, // Paladin //correct
|
||||||
|
16.00f, // Hunter //?
|
||||||
|
16.00f, // Rogue //?
|
||||||
|
16.00f, // Priest //?
|
||||||
|
16.00f, // DK //correct
|
||||||
|
16.00f, // Shaman //?
|
||||||
|
16.00f, // Mage //?
|
||||||
|
16.00f, // Warlock //?
|
||||||
|
0.0f, // ??
|
||||||
|
16.00f // Druid //?
|
||||||
|
};
|
||||||
|
float diminishing = 0.0f, nondiminishing = 0.0f;
|
||||||
|
// Modify value from defense skill (only bonus from defense rating diminishes)
|
||||||
|
nondiminishing += (GetSkillValue(SKILL_DEFENSE) - GetMaxSkillValueForLevel()) * 0.04f;
|
||||||
|
diminishing += (int32(GetRatingBonusValue(CR_DEFENSE_SKILL))) * 0.04f;
|
||||||
|
|
||||||
|
// apply diminishing formula to diminishing miss chance
|
||||||
|
uint32 pclass = getClass()-1;
|
||||||
|
return nondiminishing + (diminishing * miss_cap[pclass] / (diminishing + miss_cap[pclass] * m_diminishing_k[pclass]));
|
||||||
|
}
|
||||||
|
|
||||||
void Player::UpdateParryPercentage()
|
void Player::UpdateParryPercentage()
|
||||||
{
|
{
|
||||||
|
const float parry_cap[MAX_CLASSES] =
|
||||||
|
{
|
||||||
|
47.003525f, // Warrior
|
||||||
|
47.003525f, // Paladin
|
||||||
|
145.560408f, // Hunter
|
||||||
|
145.560408f, // Rogue
|
||||||
|
0.0f, // Priest
|
||||||
|
47.003525f, // DK
|
||||||
|
145.560408f, // Shaman
|
||||||
|
0.0f, // Mage
|
||||||
|
0.0f, // Warlock
|
||||||
|
0.0f, // ??
|
||||||
|
0.0f // Druid
|
||||||
|
};
|
||||||
|
|
||||||
// No parry
|
// No parry
|
||||||
float value = 0.0f;
|
float value = 0.0f;
|
||||||
if (CanParry())
|
uint32 pclass = getClass()-1;
|
||||||
|
if (CanParry() && parry_cap[pclass] > 0.0f)
|
||||||
{
|
{
|
||||||
// Base parry
|
float nondiminishing = 5.0f;
|
||||||
value = 5.0f;
|
|
||||||
// Modify value from defense skill
|
|
||||||
value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
|
|
||||||
// Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
|
|
||||||
value += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
|
|
||||||
// Parry from rating
|
// Parry from rating
|
||||||
value += GetRatingBonusValue(CR_PARRY);
|
float diminishing = GetRatingBonusValue(CR_PARRY);
|
||||||
|
// Modify value from defense skill (only bonus from defense rating diminishes)
|
||||||
|
nondiminishing += (GetSkillValue(SKILL_DEFENSE) - GetMaxSkillValueForLevel()) * 0.04f;
|
||||||
|
diminishing += (int32(GetRatingBonusValue(CR_DEFENSE_SKILL))) * 0.04f;
|
||||||
|
// Parry from SPELL_AURA_MOD_PARRY_PERCENT aura
|
||||||
|
nondiminishing += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
|
||||||
|
// apply diminishing formula to diminishing parry chance
|
||||||
|
value = nondiminishing + diminishing * parry_cap[pclass] / (diminishing + parry_cap[pclass] * m_diminishing_k[pclass]);
|
||||||
value = value < 0.0f ? 0.0f : value;
|
value = value < 0.0f ? 0.0f : value;
|
||||||
}
|
}
|
||||||
SetStatFloatValue(PLAYER_PARRY_PERCENTAGE, value);
|
SetStatFloatValue(PLAYER_PARRY_PERCENTAGE, value);
|
||||||
@@ -645,14 +704,34 @@ void Player::UpdateParryPercentage()
|
|||||||
|
|
||||||
void Player::UpdateDodgePercentage()
|
void Player::UpdateDodgePercentage()
|
||||||
{
|
{
|
||||||
// Dodge from agility
|
const float dodge_cap[MAX_CLASSES] =
|
||||||
float value = GetDodgeFromAgility();
|
{
|
||||||
// Modify value from defense skill
|
88.129021f, // Warrior
|
||||||
value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f;
|
88.129021f, // Paladin
|
||||||
|
145.560408f, // Hunter
|
||||||
|
145.560408f, // Rogue
|
||||||
|
150.375940f, // Priest
|
||||||
|
88.129021f, // DK
|
||||||
|
145.560408f, // Shaman
|
||||||
|
150.375940f, // Mage
|
||||||
|
150.375940f, // Warlock
|
||||||
|
0.0f, // ??
|
||||||
|
116.890707f // Druid
|
||||||
|
};
|
||||||
|
|
||||||
|
float diminishing = 0.0f, nondiminishing = 0.0f;
|
||||||
|
GetDodgeFromAgility(diminishing, nondiminishing);
|
||||||
|
// Modify value from defense skill (only bonus from defense rating diminishes)
|
||||||
|
nondiminishing += (GetSkillValue(SKILL_DEFENSE) - GetMaxSkillValueForLevel()) * 0.04f;
|
||||||
|
diminishing += (int32(GetRatingBonusValue(CR_DEFENSE_SKILL))) * 0.04f;
|
||||||
// Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
|
// Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura
|
||||||
value += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
|
nondiminishing += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
|
||||||
// Dodge from rating
|
// Dodge from rating
|
||||||
value += GetRatingBonusValue(CR_DODGE);
|
diminishing += GetRatingBonusValue(CR_DODGE);
|
||||||
|
// apply diminishing formula to diminishing dodge chance
|
||||||
|
uint32 pclass = getClass()-1;
|
||||||
|
float value = nondiminishing + (diminishing * dodge_cap[pclass] / (diminishing + dodge_cap[pclass] * m_diminishing_k[pclass]));
|
||||||
|
|
||||||
value = value < 0.0f ? 0.0f : value;
|
value = value < 0.0f ? 0.0f : value;
|
||||||
SetStatFloatValue(PLAYER_DODGE_PERCENTAGE, value);
|
SetStatFloatValue(PLAYER_DODGE_PERCENTAGE, value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2011,7 +2011,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* victim, WeaponAttackTy
|
|||||||
|
|
||||||
// Miss chance based on melee
|
// Miss chance based on melee
|
||||||
//float miss_chance = MeleeMissChanceCalc(victim, attType);
|
//float miss_chance = MeleeMissChanceCalc(victim, attType);
|
||||||
float miss_chance = MeleeSpellMissChance(victim, attType, int32(GetWeaponSkillValue(attType, victim)) - int32(victim->GetDefenseSkillValue(this)), 0);
|
float miss_chance = MeleeSpellMissChance(victim, attType, int32(GetWeaponSkillValue(attType, victim)) - int32(GetMaxSkillValueForLevel(this)), 0);
|
||||||
|
|
||||||
// Critical hit chance
|
// Critical hit chance
|
||||||
float crit_chance = GetUnitCriticalChance(attType, victim);
|
float crit_chance = GetUnitCriticalChance(attType, victim);
|
||||||
@@ -2340,11 +2340,10 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spell)
|
|||||||
attackerWeaponSkill = int32(GetWeaponSkillValue(attType, victim));
|
attackerWeaponSkill = int32(GetWeaponSkillValue(attType, victim));
|
||||||
|
|
||||||
int32 skillDiff = attackerWeaponSkill - int32(victim->GetMaxSkillValueForLevel(this));
|
int32 skillDiff = attackerWeaponSkill - int32(victim->GetMaxSkillValueForLevel(this));
|
||||||
int32 fullSkillDiff = attackerWeaponSkill - int32(victim->GetDefenseSkillValue(this));
|
|
||||||
|
|
||||||
uint32 roll = urand (0, 10000);
|
uint32 roll = urand (0, 10000);
|
||||||
|
|
||||||
uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, fullSkillDiff, spell->Id) * 100.0f);
|
uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, skillDiff, spell->Id) * 100.0f);
|
||||||
// Roll miss
|
// Roll miss
|
||||||
uint32 tmp = missChance;
|
uint32 tmp = missChance;
|
||||||
if (roll < tmp)
|
if (roll < tmp)
|
||||||
@@ -2720,6 +2719,21 @@ float Unit::GetUnitParryChance() const
|
|||||||
return chance > 0.0f ? chance : 0.0f;
|
return chance > 0.0f ? chance : 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Unit::GetUnitMissChance(WeaponAttackType attType) const
|
||||||
|
{
|
||||||
|
float miss_chance = 5.00f;
|
||||||
|
|
||||||
|
if (Player const* player = ToPlayer())
|
||||||
|
miss_chance += player->GetMissPercentageFromDefence();
|
||||||
|
|
||||||
|
if (attType == RANGED_ATTACK)
|
||||||
|
miss_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
|
||||||
|
else
|
||||||
|
miss_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
|
||||||
|
|
||||||
|
return miss_chance;
|
||||||
|
}
|
||||||
|
|
||||||
float Unit::GetUnitBlockChance() const
|
float Unit::GetUnitBlockChance() const
|
||||||
{
|
{
|
||||||
if (IsNonMeleeSpellCasted(false) || HasUnitState(UNIT_STAT_CONTROLLED))
|
if (IsNonMeleeSpellCasted(false) || HasUnitState(UNIT_STAT_CONTROLLED))
|
||||||
@@ -16388,51 +16402,43 @@ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool
|
|||||||
// Crit or block - determined on damage calculation phase! (and can be both in some time)
|
// Crit or block - determined on damage calculation phase! (and can be both in some time)
|
||||||
float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const
|
float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const
|
||||||
{
|
{
|
||||||
// Calculate hit chance (more correct for chance mod)
|
//calculate miss chance
|
||||||
int32 HitChance;
|
float missChance = victim->GetUnitMissChance(attType);
|
||||||
|
|
||||||
// PvP - PvE melee chances
|
if (!spellId && haveOffhandWeapon())
|
||||||
if (spellId || attType == RANGED_ATTACK || !haveOffhandWeapon())
|
missChance += 19;
|
||||||
HitChance = 95;
|
|
||||||
else
|
|
||||||
HitChance = 76;
|
|
||||||
|
|
||||||
// Hit chance depends from victim auras
|
|
||||||
if (attType == RANGED_ATTACK)
|
|
||||||
HitChance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
|
|
||||||
else
|
|
||||||
HitChance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
|
|
||||||
|
|
||||||
// Spellmod from SPELLMOD_RESIST_MISS_CHANCE
|
|
||||||
if (spellId)
|
|
||||||
{
|
|
||||||
if (Player* modOwner = GetSpellModOwner())
|
|
||||||
modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, HitChance);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Miss = 100 - hit
|
|
||||||
float miss_chance = 100.0f - HitChance;
|
|
||||||
|
|
||||||
// Bonuses from attacker aura and ratings
|
|
||||||
if (attType == RANGED_ATTACK)
|
|
||||||
miss_chance -= m_modRangedHitChance;
|
|
||||||
else
|
|
||||||
miss_chance -= m_modMeleeHitChance;
|
|
||||||
|
|
||||||
// bonus from skills is 0.04%
|
// bonus from skills is 0.04%
|
||||||
//miss_chance -= skillDiff * 0.04f;
|
//miss_chance -= skillDiff * 0.04f;
|
||||||
int32 diff = -skillDiff;
|
int32 diff = -skillDiff;
|
||||||
if (victim->GetTypeId() == TYPEID_PLAYER)
|
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||||
miss_chance += diff > 0 ? diff * 0.04f : diff * 0.02f;
|
missChance += diff > 0 ? diff * 0.04f : diff * 0.02f;
|
||||||
else
|
else
|
||||||
miss_chance += diff > 10 ? 2 + (diff - 10) * 0.4f : diff * 0.1f;
|
missChance += diff > 10 ? 1 + (diff - 10) * 0.4f : diff * 0.1f;
|
||||||
|
|
||||||
|
// Calculate hit chance
|
||||||
|
float hitChance = 100.0f;
|
||||||
|
|
||||||
|
// Spellmod from SPELLMOD_RESIST_MISS_CHANCE
|
||||||
|
if (spellId)
|
||||||
|
{
|
||||||
|
if (Player* modOwner = GetSpellModOwner())
|
||||||
|
modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, hitChance);
|
||||||
|
}
|
||||||
|
|
||||||
|
missChance += hitChance - 100.0f;
|
||||||
|
|
||||||
|
if (attType == RANGED_ATTACK)
|
||||||
|
missChance -= m_modRangedHitChance;
|
||||||
|
else
|
||||||
|
missChance -= m_modMeleeHitChance;
|
||||||
|
|
||||||
// Limit miss chance from 0 to 60%
|
// Limit miss chance from 0 to 60%
|
||||||
if (miss_chance < 0.0f)
|
if (missChance < 0.0f)
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
if (miss_chance > 60.0f)
|
if (missChance > 60.0f)
|
||||||
return 60.0f;
|
return 60.0f;
|
||||||
return miss_chance;
|
return missChance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
|
void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
|
||||||
|
|||||||
@@ -1479,6 +1479,7 @@ class Unit : public WorldObject
|
|||||||
float GetUnitDodgeChance() const;
|
float GetUnitDodgeChance() const;
|
||||||
float GetUnitParryChance() const;
|
float GetUnitParryChance() const;
|
||||||
float GetUnitBlockChance() const;
|
float GetUnitBlockChance() const;
|
||||||
|
float GetUnitMissChance(WeaponAttackType attType) const;
|
||||||
float GetUnitCriticalChance(WeaponAttackType attackType, const Unit *pVictim) const;
|
float GetUnitCriticalChance(WeaponAttackType attackType, const Unit *pVictim) const;
|
||||||
int32 GetMechanicResistChance(const SpellInfo *spell);
|
int32 GetMechanicResistChance(const SpellInfo *spell);
|
||||||
bool CanUseAttackType(uint8 attacktype) const
|
bool CanUseAttackType(uint8 attacktype) const
|
||||||
|
|||||||
Reference in New Issue
Block a user