diff options
author | Shauren <shauren.trinity@gmail.com> | 2015-11-10 17:33:36 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2015-11-10 17:33:36 +0100 |
commit | 61c7161a1069f93948b8b4d80b501d9358b4844c (patch) | |
tree | 58447e68471aa0682b22b5b8b69f844960484fe9 /src | |
parent | e2e8a0d1bce717c0da0fc0a6d7ffb3f44e3c15ea (diff) |
Core/Units: Updated melee/spell hit chance calculation
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 5 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/StatSystem.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 152 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 11 | ||||
-rw-r--r-- | src/server/scripts/World/npcs_special.cpp | 1 |
5 files changed, 86 insertions, 89 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 83218f40951..e244db0940f 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -5318,12 +5318,13 @@ float Player::GetRatingBonusValue(CombatRating cr) const float Player::GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const { + float baseExpertise = 7.5f; switch (attType) { case BASE_ATTACK: - return GetUInt32Value(PLAYER_EXPERTISE) / 4.0f; + return baseExpertise + GetUInt32Value(PLAYER_EXPERTISE) / 4.0f; case OFF_ATTACK: - return GetUInt32Value(PLAYER_OFFHAND_EXPERTISE) / 4.0f; + return baseExpertise + GetUInt32Value(PLAYER_OFFHAND_EXPERTISE) / 4.0f; default: break; } diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index f85860dfde3..1451b018a39 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -681,19 +681,19 @@ void Player::UpdateArmorPenetration(int32 amount) void Player::UpdateMeleeHitChances() { - m_modMeleeHitChance = (float)GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE); + m_modMeleeHitChance = 7.5f + (float)GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE); m_modMeleeHitChance += GetRatingBonusValue(CR_HIT_MELEE); } void Player::UpdateRangedHitChances() { - m_modRangedHitChance = (float)GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE); + m_modRangedHitChance = 7.5f + (float)GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE); m_modRangedHitChance += GetRatingBonusValue(CR_HIT_RANGED); } void Player::UpdateSpellHitChances() { - m_modSpellHitChance = (float)GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE); + m_modSpellHitChance = 15.0f + (float)GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE); m_modSpellHitChance += GetRatingBonusValue(CR_HIT_SPELL); } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index c15fe26f60e..803ffc06114 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -263,9 +263,18 @@ Unit::Unit(bool isWorldObject) : m_createStats[i] = 0.0f; m_attacking = NULL; - m_modMeleeHitChance = 0.0f; - m_modRangedHitChance = 0.0f; - m_modSpellHitChance = 0.0f; + if (GetTypeId() == TYPEID_PLAYER) + { + m_modMeleeHitChance = 7.5f; + m_modRangedHitChance = 7.5f; + m_modSpellHitChance = 15.0f; + } + else + { + m_modMeleeHitChance = 0.0f; + m_modRangedHitChance = 0.0f; + m_modSpellHitChance = 0.0f; + } m_baseSpellCritChance = 5; m_CombatTimer = 0; @@ -1055,7 +1064,6 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama { damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT; damage = SpellCriticalDamageBonus(spellInfo, damage, victim); - } ApplyResilience(victim, &damage); @@ -1912,42 +1920,29 @@ void Unit::HandleProcExtraAttackFor(Unit* victim) } } -MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* victim, WeaponAttackType attType) const +MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackType attType) const { - // This is only wrapper + if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()) + return MELEE_HIT_EVADE; // Miss chance based on melee //float miss_chance = MeleeMissChanceCalc(victim, attType); - float miss_chance = MeleeSpellMissChance(victim, attType, 0); + int32 miss_chance = int32(MeleeSpellMissChance(victim, attType, 0) * 100); // Critical hit chance - float crit_chance = GetUnitCriticalChance(attType, victim); + int32 crit_chance = int32(GetUnitCriticalChance(attType, victim) * 100); // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case) - float dodge_chance = victim->GetUnitDodgeChance(); - float block_chance = victim->GetUnitBlockChance(); - float parry_chance = victim->GetUnitParryChance(); + int32 dodge_chance = int32(victim->GetUnitDodgeChanceAgainst(this) * 100); + int32 block_chance = int32(victim->GetUnitBlockChanceAgainst(this) * 100); + int32 parry_chance = int32(victim->GetUnitParryChanceAgainst(this) * 100); - // Useful if want to specify crit & miss chances for melee, else it could be removed - TC_LOG_DEBUG("entities.unit", "MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance, crit_chance, dodge_chance, parry_chance, block_chance); - - return RollMeleeOutcomeAgainst(victim, attType, int32(crit_chance*100), int32(miss_chance*100), int32(dodge_chance*100), int32(parry_chance*100), int32(block_chance*100)); -} - -MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const -{ - if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()) - return MELEE_HIT_EVADE; - - int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(victim); - int32 victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this); - - // bonus from skills is 0.04% - int32 skillBonus = 4 * (attackerMaxSkillValueForLevel - victimMaxSkillValueForLevel); int32 sum = 0, tmp = 0; int32 roll = urand (0, 10000); - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus); + 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); @@ -1982,15 +1977,14 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackT 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)); + 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 - && ((tmp -= skillBonus) > 0) && roll < (sum += tmp)) { - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum); + TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum - tmp, sum); return MELEE_HIT_DODGE; } } @@ -2012,7 +2006,6 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackT { int32 tmp2 = int32(parry_chance); if (tmp2 > 0 // check if unit _can_ parry - && (tmp2 -= skillBonus) > 0 && roll < (sum += tmp2)) { TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp2, sum); @@ -2024,7 +2017,6 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackT { tmp = block_chance; if (tmp > 0 // check if unit _can_ block - && (tmp -= skillBonus) > 0 && roll < (sum += tmp)) { TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum); @@ -2049,13 +2041,10 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackT if (attType != RANGED_ATTACK && (GetTypeId() == TYPEID_PLAYER || IsPet()) && victim->GetTypeId() != TYPEID_PLAYER && !victim->IsPet() && - getLevel() < victim->getLevelForTarget(this)) + attackerLevel + 3 < victimLevel) { // cap possible value (with bonuses > max skill) - int32 skill = attackerMaxSkillValueForLevel; - - tmp = (10 + (victimMaxSkillValueForLevel - skill)) * 100; - tmp = tmp > 4000 ? 4000 : tmp; + tmp = (10 + 10 * (victimLevel - attackerLevel)) * 100; if (roll < (sum += tmp)) { TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum); @@ -2064,24 +2053,17 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackT } // mobs can score crushing blows if they're 4 or more levels above victim - if (getLevelForTarget(victim) >= victim->getLevelForTarget(this) + 4 && + if (attackerLevel >= victimLevel + 4 && // can be from by creature (if can) or from controlled player that considered as creature !IsControlledByPlayer() && !(GetTypeId() == TYPEID_UNIT && ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH)) { - // when their weapon skill is 15 or more above victim's defense skill - tmp = victimMaxSkillValueForLevel; - // tmp = mob's level * 5 - player's current defense skill - tmp = attackerMaxSkillValueForLevel - tmp; - if (tmp >= 15) + // add 2% chance per level, min. is 15% + tmp = attackerLevel - victimLevel * 1000 - 1500; + if (roll < (sum += tmp)) { - // add 2% chance per lacking skill point, min. is 15% - tmp = tmp * 200 - 1500; - if (roll < (sum += tmp)) - { - TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum); - return MELEE_HIT_CRUSHING; - } + TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum); + return MELEE_HIT_CRUSHING; } } @@ -2176,7 +2158,7 @@ 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->GetUnitBlockChance())) + if (roll_chance_f(victim->GetUnitBlockChanceAgainst(this))) return true; } return false; @@ -2353,7 +2335,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo if (canDodge) { // Roll dodge - int32 dodgeChance = int32(victim->GetUnitDodgeChance() * 100.0f); + 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)); @@ -2372,7 +2354,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo if (canParry) { // Roll parry - int32 parryChance = int32(victim->GetUnitParryChance() * 100.0f); + 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); @@ -2388,7 +2370,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo if (canBlock) { - int32 blockChance = int32(victim->GetUnitBlockChance() * 100.0f); + int32 blockChance = int32(victim->GetUnitBlockChanceAgainst(this) * 100.0f); if (blockChance < 0) blockChance = 0; tmp += blockChance; @@ -2414,11 +2396,27 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsTrigger()) thisLevel = std::max<int32>(thisLevel, spellInfo->SpellLevel); int32 leveldif = int32(victim->getLevelForTarget(this)) - thisLevel; + int32 levelBasedHitDiff = leveldif; // Base hit chance from attacker and victim levels int32 modHitChance = 100; - if (leveldif > 3) - modHitChance -= (leveldif - 3) * lchance; + if (levelBasedHitDiff >= 0) + { + if (victim->GetTypeId() != TYPEID_PLAYER) + { + modHitChance = 94 - 3 * std::min(levelBasedHitDiff, 3); + levelBasedHitDiff -= 3; + } + else + { + modHitChance = 96 - std::min(levelBasedHitDiff, 2); + levelBasedHitDiff -= 2; + } + if (levelBasedHitDiff > 0) + modHitChance -= lchance * std::min(levelBasedHitDiff, 7); + } + else + modHitChance = 97 - levelBasedHitDiff; // Spellmod from SPELLMOD_RESIST_MISS_CHANCE if (Player* modOwner = GetSpellModOwner()) @@ -2523,12 +2521,7 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, boo return SPELL_MISS_NONE; } -uint32 Unit::GetUnitMeleeSkill(Unit const* target) const -{ - return (target ? getLevelForTarget(target) : getLevel()) * 5; -} - -float Unit::GetUnitDodgeChance() const +float Unit::GetUnitDodgeChanceAgainst(Unit const* attacker) const { if (IsNonMeleeSpellCast(false) || HasUnitState(UNIT_STATE_CONTROLLED)) return 0.0f; @@ -2541,14 +2534,16 @@ float Unit::GetUnitDodgeChance() const return 0.0f; else { - float dodge = 5.0f; - dodge += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT); + float dodge = 3.0f + GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT); + int32 levelDiff = getLevelForTarget(attacker) - attacker->getLevelForTarget(this); + if (levelDiff > 0) + dodge += 1.5f * levelDiff; return dodge > 0.0f ? dodge : 0.0f; } } } -float Unit::GetUnitParryChance() const +float Unit::GetUnitParryChanceAgainst(Unit const* attacker) const { if (IsNonMeleeSpellCast(false) || HasUnitState(UNIT_STATE_CONTROLLED)) return 0.0f; @@ -2569,11 +2564,11 @@ float Unit::GetUnitParryChance() const } else if (GetTypeId() == TYPEID_UNIT) { - if (GetCreatureType() == CREATURE_TYPE_HUMANOID) - { - chance = 5.0f; - chance += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); - } + chance = 6.0f; + int32 levelDiff = getLevelForTarget(attacker) - attacker->getLevelForTarget(this); + if (levelDiff > 0) + chance += 1.5f * levelDiff; + chance += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); } return chance > 0.0f ? chance : 0.0f; @@ -2591,7 +2586,7 @@ float Unit::GetUnitMissChance(WeaponAttackType attType) const return miss_chance; } -float Unit::GetUnitBlockChance() const +float Unit::GetUnitBlockChanceAgainst(Unit const* attacker) const { if (IsNonMeleeSpellCast(false) || HasUnitState(UNIT_STATE_CONTROLLED)) return 0.0f; @@ -2601,7 +2596,7 @@ float Unit::GetUnitBlockChance() const if (player->CanBlock()) { Item* tmpitem = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); - if (tmpitem && !tmpitem->IsBroken()) + if (tmpitem && !tmpitem->IsBroken() && tmpitem->GetTemplate()->GetInventoryType() == INVTYPE_SHIELD) return GetFloatValue(PLAYER_BLOCK_PERCENTAGE); } // is player but has no block ability or no not broken shield equipped @@ -2613,7 +2608,10 @@ float Unit::GetUnitBlockChance() const return 0.0f; else { - float block = 5.0f; + float block = 3.0f; + int32 levelDiff = getLevelForTarget(attacker) - attacker->getLevelForTarget(this); + if (levelDiff > 0) + block += 1.5f * levelDiff; block += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT); return block > 0.0f ? block : 0.0f; } @@ -14557,8 +14555,8 @@ float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, u // Limit miss chance from 0 to 60% if (missChance < 0.0f) return 0.0f; - if (missChance > 60.0f) - return 60.0f; + if (missChance > 77.0f) + return 77.0f; return missChance; } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 5124513e8ad..88b1dde518c 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1535,9 +1535,9 @@ class Unit : public WorldObject SpellMissInfo MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo); SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect = false); - float GetUnitDodgeChance() const; - float GetUnitParryChance() const; - float GetUnitBlockChance() const; + float GetUnitDodgeChanceAgainst(Unit const* attacker) const; + float GetUnitParryChanceAgainst(Unit const* attacker) const; + float GetUnitBlockChanceAgainst(Unit const* attacker) const; float GetUnitMissChance(WeaponAttackType attType) const; float GetUnitCriticalChance(WeaponAttackType attackType, const Unit* victim) const; int32 GetMechanicResistChance(SpellInfo const* spellInfo) const; @@ -1545,13 +1545,10 @@ class Unit : public WorldObject virtual uint32 GetBlockPercent() const { return 30; } - uint32 GetUnitMeleeSkill(Unit const* target = NULL) const; - float GetWeaponProcChance() const; float GetPPMProcChance(uint32 WeaponSpeed, float PPM, const SpellInfo* spellProto) const; - MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackType attType) const; - MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const; + MeleeHitOutcome RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackType attType) const; bool IsVendor() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_VENDOR); } bool IsTrainer() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_TRAINER); } diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index e72e094ea06..964e69874c3 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -1422,6 +1422,7 @@ public: void Reset() override { + // TODO: solve this in a different way! setting them as stunned prevents dummies from parrying me->SetControlled(true, UNIT_STATE_STUNNED);//disable rotate me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);//imune to knock aways like blast wave |