diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 340 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 12 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.cpp | 2 |
4 files changed, 173 insertions, 183 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ce6e795b5c0..0f4e883fac9 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -13731,7 +13731,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool break; case ITEM_MOD_DEFENSE_SKILL_RATING: ApplyRatingMod(CR_DEFENSE_SKILL, enchant_amount, apply); - TC_LOG_DEBUG("entities.player.items", "+ %u DEFENCE", enchant_amount); + TC_LOG_DEBUG("entities.player.items", "+ %u DEFENSE", enchant_amount); break; case ITEM_MOD_DODGE_RATING: ApplyRatingMod(CR_DODGE, enchant_amount, apply); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 998260b80bf..69a1ed7ca1b 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -1325,7 +1325,8 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam int32 leveldif = int32(victim->getLevel()) - int32(getLevel()); if (leveldif > 3) leveldif = 3; - float reducePercent = 1 - leveldif * 0.1f; + + float reducePercent = 1.f - leveldif * 0.1f; damageInfo->cleanDamage += damageInfo->damage - uint32(reducePercent * damageInfo->damage); damageInfo->damage = uint32(reducePercent * damageInfo->damage); break; @@ -2040,132 +2041,99 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackTy return MELEE_HIT_EVADE; // Miss chance based on melee - //float miss_chance = MeleeMissChanceCalc(victim, attType); - int32 miss_chance = int32(MeleeSpellMissChance(victim, attType, 0) * 100); + int32 miss_chance = int32(MeleeSpellMissChance(victim, attType, 0) * 100.0f); // Critical hit chance - int32 crit_chance = int32(GetUnitCriticalChance(attType, victim) * 100); + int32 crit_chance = int32(GetUnitCriticalChance(attType, victim) * 100.0f); + + int32 dodge_chance = int32(GetUnitDodgeChance(attType, victim) * 100.0f); + int32 block_chance = int32(GetUnitBlockChance(attType, victim) * 100.0f); + int32 parry_chance = int32(GetUnitParryChance(attType, victim) * 100.0f); - // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case) - int32 dodge_chance = int32(victim->GetUnitDodgeChanceAgainst(this) * 100); - int32 block_chance = int32(victim->GetUnitBlockChanceAgainst(this) * 100); - int32 parry_chance = int32(victim->GetUnitParryChanceAgainst(this) * 100); + // melee attack table implementation + // outcome priority: + // 1. > 2. > 3. > 4. > 5. > 6. > 7. > 8. + // MISS > DODGE > PARRY > GLANCING > BLOCK > CRIT > CRUSHING > HIT + + int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(victim); + int32 victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this); int32 sum = 0, tmp = 0; - int32 roll = urand (0, 10000); + int32 roll = urand(0, 9999); int32 attackerLevel = getLevelForTarget(victim); int32 victimLevel = getLevelForTarget(this); - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d", - roll, miss_chance, dodge_chance, parry_chance, block_chance, crit_chance); + // check if attack comes from behind, nobody can parry or block if attacker is behind + bool canParryOrBlock = victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION); - tmp = miss_chance; + // only creatures can dodge if attacker is behind + bool canDodge = victim->GetTypeId() != TYPEID_PLAYER || canParryOrBlock; - if (tmp > 0 && roll < (sum += tmp)) + // if victim is casting or cc'd it can't avoid attacks + if (victim->IsNonMeleeSpellCast(false) || victim->HasUnitState(UNIT_STATE_CONTROLLED)) { - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: MISS"); - return MELEE_HIT_MISS; + canDodge = false; + canParryOrBlock = false; } + // 1. MISS + tmp = miss_chance; + if (tmp > 0 && roll < (sum += tmp)) + return MELEE_HIT_MISS; + // always crit against a sitting target (except 0 crit chance) if (victim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !victim->IsStandState()) - { - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRIT (sitting victim)"); return MELEE_HIT_CRIT; - } - - // Dodge chance - // only players can't dodge if attacker is behind - if (victim->GetTypeId() == TYPEID_PLAYER && !victim->HasInArc(float(M_PI), this) && !victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)) - { - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: attack came from behind and victim was a player."); - } - else + // 2. DODGE + if (canDodge) { - // Reduce dodge chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - dodge_chance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100); - else - dodge_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25; - - // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE - dodge_chance += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE) * 100; - dodge_chance = int32(float(dodge_chance) * GetTotalAuraMultiplier(SPELL_AURA_MOD_ENEMY_DODGE)); - tmp = dodge_chance; - if ((tmp > 0) // check if unit _can_ dodge + if (tmp > 0 // check if unit _can_ dodge && roll < (sum += tmp)) - { - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum - tmp, sum); return MELEE_HIT_DODGE; - } } - // parry & block chances - - // check if attack comes from behind, nobody can parry or block if attacker is behind - if (!victim->HasInArc(float(M_PI), this) && !victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)) - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: attack came from behind."); - else + // 3. PARRY + if (canParryOrBlock) { - // Reduce parry chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - parry_chance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100); - else - parry_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25; - - if (victim->GetTypeId() == TYPEID_PLAYER || !(victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY)) - { - int32 tmp2 = int32(parry_chance); - if (tmp2 > 0 // check if unit _can_ parry - && roll < (sum += tmp2)) - { - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp2, sum); - return MELEE_HIT_PARRY; - } - } - - if (victim->GetTypeId() == TYPEID_PLAYER || !(victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK)) - { - tmp = block_chance; - if (tmp > 0 // check if unit _can_ block - && roll < (sum += tmp)) - { - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum); - return MELEE_HIT_BLOCK; - } - } - } - - // Critical chance - tmp = crit_chance; - - if (tmp > 0 && roll < (sum += tmp)) - { - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum); - if (GetTypeId() == TYPEID_UNIT && (ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRIT)) - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRIT DISABLED)"); - else - return MELEE_HIT_CRIT; + tmp = parry_chance; + if (tmp > 0 // check if unit _can_ parry + && roll < (sum += tmp)) + return MELEE_HIT_PARRY; } + // 4. GLANCING // Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon) - if (attType != RANGED_ATTACK && - (GetTypeId() == TYPEID_PLAYER || IsPet()) && + if ((GetTypeId() == TYPEID_PLAYER || IsPet()) && victim->GetTypeId() != TYPEID_PLAYER && !victim->IsPet() && attackerLevel + 3 < victimLevel) { // cap possible value (with bonuses > max skill) tmp = (10 + 10 * (victimLevel - attackerLevel)) * 100; - if (roll < (sum += tmp)) - { - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum); + if (tmp > 0 && roll < (sum += tmp)) return MELEE_HIT_GLANCING; - } } + // 5. BLOCK + if (canParryOrBlock) + { + tmp = block_chance; + if (tmp > 0 // check if unit _can_ block + && roll < (sum += tmp)) + return MELEE_HIT_BLOCK; + } + + // 6.CRIT + tmp = crit_chance; + if (tmp > 0 && roll < (sum += tmp)) + { + if (GetTypeId() != TYPEID_UNIT || !(ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRIT)) + return MELEE_HIT_CRIT; + } + + // 7. CRUSHING // mobs can score crushing blows if they're 4 or more levels above victim if (attackerLevel >= victimLevel + 4 && // can be from by creature (if can) or from controlled player that considered as creature @@ -2181,7 +2149,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackTy } } - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: NORMAL"); + // 8. HIT return MELEE_HIT_NORMAL; } @@ -2274,12 +2242,16 @@ void Unit::SendMeleeAttackStop(Unit* victim) TC_LOG_DEBUG("entities.unit", "%s stopped attacking", GetGUID().ToString().c_str()); } -bool Unit::isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType /*attackType*/) +bool Unit::isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType) { // These spells can't be blocked if (spellProto && spellProto->HasAttribute(SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK)) return false; + // Can't block when casting/controlled + if (victim->IsNonMeleeSpellCast(false) || victim->HasUnitState(UNIT_STATE_CONTROLLED)) + return false; + if (victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION) || victim->HasInArc(float(M_PI), this)) { // Check creatures flags_extra for disable block @@ -2287,9 +2259,11 @@ bool Unit::isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttac victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK) return false; - if (roll_chance_f(victim->GetUnitBlockChanceAgainst(this))) + float blockChance = GetUnitBlockChance(attackType, victim); + if (roll_chance_f(blockChance)) return true; } + return false; } @@ -2319,7 +2293,8 @@ int32 Unit::GetMechanicResistChance(SpellInfo const* spellInfo) const resistMech = temp; } } - return resistMech; + + return std::max(resistMech, 0); } bool Unit::CanUseAttackType(uint8 attacktype) const @@ -2338,7 +2313,7 @@ bool Unit::CanUseAttackType(uint8 attacktype) const } // Melee based spells hit result calculations -SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo) +SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const { // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore // resist and deflect chances @@ -2352,7 +2327,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED) attType = RANGED_ATTACK; - uint32 roll = urand(0, 10000); + uint32 roll = urand(0, 9999); uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, spellInfo->Id) * 100.0f); @@ -2375,6 +2350,14 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo bool canParry = true; bool canBlock = spellInfo->HasAttribute(SPELL_ATTR3_BLOCKABLE_SPELL); + // if victim is casting or cc'd it can't avoid attacks + if (victim->IsNonMeleeSpellCast(false) || victim->HasUnitState(UNIT_STATE_CONTROLLED)) + { + canDodge = false; + canParry = false; + canBlock = false; + } + // Ranged attacks can only miss, resist and deflect if (attType == RANGED_ATTACK) { @@ -2397,10 +2380,10 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo { if (!victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)) { - // Can`t dodge from behind in PvP (but its possible in PvE) + // Can't dodge from behind in PvP (but its possible in PvE) if (victim->GetTypeId() == TYPEID_PLAYER) canDodge = false; - // Can`t parry or block + // Can't parry or block canParry = false; canBlock = false; } @@ -2410,23 +2393,15 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo canParry = false; } } - // Check creatures flags_extra for disable parry - if (victim->GetTypeId() == TYPEID_UNIT) - { - uint32 flagEx = victim->ToCreature()->GetCreatureTemplate()->flags_extra; - if (flagEx & CREATURE_FLAG_EXTRA_NO_PARRY) - canParry = false; - // Check creatures flags_extra for disable block - if (flagEx & CREATURE_FLAG_EXTRA_NO_BLOCK) - canBlock = false; - } + // Ignore combat result aura AuraEffectList const& ignore = GetAuraEffectsByType(SPELL_AURA_IGNORE_COMBAT_RESULT); - for (AuraEffectList::const_iterator i = ignore.begin(); i != ignore.end(); ++i) + for (AuraEffect const* aurEff : ignore) { - if (!(*i)->IsAffectingSpell(spellInfo)) + if (!aurEff->IsAffectingSpell(spellInfo)) continue; - switch ((*i)->GetMiscValue()) + + switch (aurEff->GetMiscValue()) { case MELEE_HIT_DODGE: canDodge = false; @@ -2438,7 +2413,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo canParry = false; break; default: - TC_LOG_DEBUG("entities.unit", "Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT has unhandled state %d", (*i)->GetId(), (*i)->GetMiscValue()); + TC_LOG_DEBUG("entities.unit", "Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT has unhandled state %d", aurEff->GetId(), aurEff->GetMiscValue()); break; } } @@ -2446,15 +2421,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo if (canDodge) { // Roll dodge - int32 dodgeChance = int32(victim->GetUnitDodgeChanceAgainst(this) * 100.0f); - // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE - dodgeChance += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE) * 100; - dodgeChance = int32(float(dodgeChance) * GetTotalAuraMultiplier(SPELL_AURA_MOD_ENEMY_DODGE)); - // Reduce dodge chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - dodgeChance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); - else - dodgeChance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25; + int32 dodgeChance = int32(GetUnitDodgeChance(attType, victim) * 100.0f); if (dodgeChance < 0) dodgeChance = 0; @@ -2465,12 +2432,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo if (canParry) { // Roll parry - int32 parryChance = int32(victim->GetUnitParryChanceAgainst(this) * 100.0f); - // Reduce parry chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - parryChance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); - else - parryChance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25; + int32 parryChance = int32(GetUnitParryChance(attType, victim) * 100.0f); if (parryChance < 0) parryChance = 0; @@ -2481,7 +2443,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo if (canBlock) { - int32 blockChance = int32(victim->GetUnitBlockChanceAgainst(this) * 100.0f); + int32 blockChance = int32(GetUnitBlockChance(attType, victim) * 100.0f); if (blockChance < 0) blockChance = 0; tmp += blockChance; @@ -2494,7 +2456,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo } /// @todo need use unit spell resistances in calculations -SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo) +SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const { // Can`t miss on dead target (on skinning for example) if ((!victim->IsAlive() && victim->GetTypeId() != TYPEID_PLAYER) || spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT)) @@ -2562,7 +2524,7 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo return SPELL_MISS_RESIST; // cast by caster in front of victim - if (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)) + if (!victim->HasUnitState(UNIT_STATE_CONTROLLED) && (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))) { int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100; tmp += deflect_chance; @@ -2632,57 +2594,77 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, boo return SPELL_MISS_NONE; } -float Unit::GetUnitDodgeChanceAgainst(Unit const* attacker) const +float Unit::GetUnitDodgeChance(WeaponAttackType attType, Unit const* victim) const { - if (IsNonMeleeSpellCast(false) || HasUnitState(UNIT_STATE_CONTROLLED)) - return 0.0f; + int32 const levelDiff = victim->getLevelForTarget(this) - getLevelForTarget(victim); - if (GetTypeId() == TYPEID_PLAYER) - return GetFloatValue(PLAYER_DODGE_PERCENTAGE); + float chance = 0.0f; + float levelBonus = 0.0f; + if (victim->GetTypeId() == TYPEID_PLAYER) + chance = victim->GetFloatValue(PLAYER_DODGE_PERCENTAGE); else { - if (IsTotem()) - return 0.0f; - else + if (!victim->IsTotem()) { - float dodge = 3.0f + GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT); - int32 levelDiff = getLevelForTarget(attacker) - attacker->getLevelForTarget(this); + chance = 3.0f; + chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT); + if (levelDiff > 0) - dodge += 1.5f * levelDiff; - return dodge > 0.0f ? dodge : 0.0f; + levelBonus = 1.5f * levelDiff; } } + + chance += levelBonus; + + // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE + chance += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE); + + // reduce dodge by SPELL_AURA_MOD_ENEMY_DODGE + chance += GetTotalAuraModifier(SPELL_AURA_MOD_ENEMY_DODGE); + + // Reduce dodge chance by attacker expertise rating + if (GetTypeId() == TYPEID_PLAYER) + chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType); + else + chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) / 4.0f; + return std::max(chance, 0.0f); } -float Unit::GetUnitParryChanceAgainst(Unit const* attacker) const +float Unit::GetUnitParryChance(WeaponAttackType attType, Unit const* victim) const { - if (IsNonMeleeSpellCast(false) || HasUnitState(UNIT_STATE_CONTROLLED)) - return 0.0f; + int32 const levelDiff = victim->getLevelForTarget(this) - getLevelForTarget(victim); float chance = 0.0f; - - if (Player const* player = ToPlayer()) + float levelBonus = 0.0f; + if (Player const* playerVictim = victim->ToPlayer()) { - if (player->CanParry()) + if (playerVictim->CanParry()) { - Item* tmpitem = player->GetWeaponForAttack(BASE_ATTACK, true); + Item* tmpitem = playerVictim->GetWeaponForAttack(BASE_ATTACK, true); if (!tmpitem) - tmpitem = player->GetWeaponForAttack(OFF_ATTACK, true); + tmpitem = playerVictim->GetWeaponForAttack(OFF_ATTACK, true); if (tmpitem) - chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE); + chance = playerVictim->GetFloatValue(PLAYER_PARRY_PERCENTAGE); } } - else if (GetTypeId() == TYPEID_UNIT) + else if (victim->GetTypeId() == TYPEID_UNIT && !(victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY)) { chance = 6.0f; - int32 levelDiff = getLevelForTarget(attacker) - attacker->getLevelForTarget(this); + chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); + if (levelDiff > 0) - chance += 1.5f * levelDiff; - chance += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); + levelBonus = 1.5f * levelDiff; } - return chance > 0.0f ? chance : 0.0f; + chance += levelBonus; + + // Reduce parry chance by attacker expertise rating + if (GetTypeId() == TYPEID_PLAYER) + chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType); + else + chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) / 4.0f; + return std::max(chance, 0.0f); } float Unit::GetUnitMissChance(WeaponAttackType attType) const @@ -2697,39 +2679,38 @@ float Unit::GetUnitMissChance(WeaponAttackType attType) const return miss_chance; } -float Unit::GetUnitBlockChanceAgainst(Unit const* attacker) const +float Unit::GetUnitBlockChance(WeaponAttackType attType, Unit const* victim) const { - if (IsNonMeleeSpellCast(false) || HasUnitState(UNIT_STATE_CONTROLLED)) - return 0.0f; + int32 const levelDiff = victim->getLevelForTarget(this) - getLevelForTarget(victim); - if (Player const* player = ToPlayer()) + float chance = 0.0f; + float levelBonus = 0.0f; + if (Player const* playerVictim = victim->ToPlayer()) { - if (player->CanBlock()) + if (playerVictim->CanBlock()) { - Item* tmpitem = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); + Item* tmpitem = playerVictim->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); if (tmpitem && !tmpitem->IsBroken() && tmpitem->GetTemplate()->GetInventoryType() == INVTYPE_SHIELD) - return GetFloatValue(PLAYER_BLOCK_PERCENTAGE); + chance = GetFloatValue(PLAYER_BLOCK_PERCENTAGE); } - // is player but has no block ability or no not broken shield equipped - return 0.0f; } else { - if (IsTotem()) - return 0.0f; - else + if (!victim->IsTotem() && !(victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK)) { - float block = 3.0f; - int32 levelDiff = getLevelForTarget(attacker) - attacker->getLevelForTarget(this); + chance = 3.0f; + chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT); + if (levelDiff > 0) - block += 1.5f * levelDiff; - block += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT); - return block > 0.0f ? block : 0.0f; + levelBonus = 1.5f * levelDiff; } } + + chance += levelBonus; + return std::max(chance, 0.0f); } -float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit* victim) const +float Unit::GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victim) const { float crit; @@ -2765,6 +2746,15 @@ float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit* victi else crit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE); + AuraEffectList const& critChanceForCaster = victim->GetAuraEffectsByType(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER); + for (AuraEffect const* aurEff : critChanceForCaster) + { + if (aurEff->GetCasterGUID() != GetGUID()) + continue; + + crit += aurEff->GetAmount(); + } + crit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); if (crit < 0.0f) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 4d9357f3323..2be7745b9d4 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1573,15 +1573,15 @@ class TC_GAME_API Unit : public WorldObject void ApplyResilience(Unit const* victim, int32* damage) const; float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, uint32 spellId) const; - SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo); - SpellMissInfo MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo); + SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const; + SpellMissInfo MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const; SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect = false); - float GetUnitDodgeChanceAgainst(Unit const* attacker) const; - float GetUnitParryChanceAgainst(Unit const* attacker) const; - float GetUnitBlockChanceAgainst(Unit const* attacker) const; + float GetUnitDodgeChance(WeaponAttackType attType, Unit const* victim) const; + float GetUnitParryChance(WeaponAttackType attType, Unit const* victim) const; + float GetUnitBlockChance(WeaponAttackType attType, Unit const* victim) const; float GetUnitMissChance(WeaponAttackType attType) const; - float GetUnitCriticalChance(WeaponAttackType attackType, const Unit* victim) const; + float GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victim) const; int32 GetMechanicResistChance(SpellInfo const* spellInfo) const; bool CanUseAttackType(uint8 attacktype) const; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 705f688db60..350242760ff 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -310,7 +310,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNoImmediateEffect, //248 SPELL_AURA_MOD_COMBAT_RESULT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst &AuraEffect::HandleNULL, //249 SPELL_AURA_CONVERT_RUNE deprecated &AuraEffect::HandleAuraModIncreaseHealth, //250 SPELL_AURA_MOD_INCREASE_HEALTH_2 - &AuraEffect::HandleNoImmediateEffect, //251 SPELL_AURA_MOD_ENEMY_DODGE + &AuraEffect::HandleNoImmediateEffect, //251 SPELL_AURA_MOD_ENEMY_DODGE implemented in Unit::GetUnitDodgeChance &AuraEffect::HandleModCombatSpeedPct, //252 SPELL_AURA_252 Is there any difference between this and SPELL_AURA_MELEE_SLOW ? maybe not stacking mod? &AuraEffect::HandleNoImmediateEffect, //253 SPELL_AURA_MOD_BLOCK_CRIT_CHANCE implemented in Unit::isBlockCritical &AuraEffect::HandleAuraModDisarm, //254 SPELL_AURA_MOD_DISARM_OFFHAND |