Index: game/Player.cpp =================================================================== --- game/Player.cpp (revision 5306) +++ game/Player.cpp (working copy) @@ -4532,6 +4532,7 @@ case MELEE_HIT_DODGE: case MELEE_HIT_PARRY: case MELEE_HIT_BLOCK: + case MELEE_HIT_BLOCK_CRIT: return; default: Index: game/Unit.cpp =================================================================== --- game/Unit.cpp (revision 5306) +++ game/Unit.cpp (working copy) @@ -1107,6 +1107,7 @@ // Classify outcome switch (outcome) { + case MELEE_HIT_BLOCK_CRIT: case MELEE_HIT_CRIT: { uint32 bonusDmg = *damage; @@ -1137,18 +1138,30 @@ StartReactiveTimer( REACTIVE_HUNTER_CRIT ); } + if ( outcome == MELEE_HIT_BLOCK_CRIT ) + { + blocked_amount = uint32(pVictim->GetShieldBlockValue()); + if (blocked_amount >= *damage) + { + hitInfo |= HITINFO_SWINGNOHITSOUND; + victimState = VICTIMSTATE_BLOCKS; + cleanDamage->damage += *damage; // To Help Calculate Rage + *damage = 0; + } + else + { + // To Help Calculate Rage + cleanDamage->damage += blocked_amount; + *damage = *damage - blocked_amount; + } + + pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); + pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); + } break; } case MELEE_HIT_PARRY: { - // this special attack can't be parryed - if ( spellInfo->Attributes & 0x200000 ) - { - outcome = MELEE_HIT_NORMAL; - cleanDamage->hitOutCome = MELEE_HIT_NORMAL; - break; - } - cleanDamage->damage += *damage; // To Help Calculate Rage *damage = 0; victimState = VICTIMSTATE_PARRY; @@ -1212,14 +1225,6 @@ } case MELEE_HIT_DODGE: { - // this special attack can't be dodged - if ( spellInfo->Attributes & 0x200000 ) - { - outcome = MELEE_HIT_NORMAL; - cleanDamage->hitOutCome = MELEE_HIT_NORMAL; - break; - } - if(pVictim->GetTypeId() == TYPEID_PLAYER) ((Player*)pVictim)->UpdateDefense(); @@ -1248,14 +1253,6 @@ } case MELEE_HIT_BLOCK: { - // this special attack can't be blocked - if ( spellInfo->Attributes & 0x200000 ) - { - outcome = MELEE_HIT_NORMAL; - cleanDamage->hitOutCome = MELEE_HIT_NORMAL; - break; - } - blocked_amount = uint32(pVictim->GetShieldBlockValue()); if (blocked_amount >= *damage) { @@ -1940,13 +1937,12 @@ void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchools damageType, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted, bool isTriggeredSpell) { - bool unavoidable = spellCasted && (spellCasted->Attributes & 0x200000); MeleeHitOutcome outcome; // If is casted Melee spell, calculate like physical if(!spellCasted) - outcome = RollMeleeOutcomeAgainst (pVictim, attType); + outcome = RollMeleeOutcomeAgainst (pVictim, attType, NULL); else outcome = RollPhysicalOutcomeAgainst (pVictim, attType, spellCasted); @@ -2010,6 +2006,7 @@ switch (outcome) { + case MELEE_HIT_BLOCK_CRIT: case MELEE_HIT_CRIT: { //*hitInfo = 0xEA; @@ -2063,11 +2060,35 @@ StartReactiveTimer( REACTIVE_HUNTER_CRIT ); } + if ( outcome == MELEE_HIT_BLOCK_CRIT ) + { + *blocked_amount = pVictim->GetShieldBlockValue(); + + if (pVictim->GetUnitBlockChance()) + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD); + else + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); + + //Only set VICTIMSTATE_BLOCK on a full block + if (*blocked_amount >= uint32(*damage)) + { + *victimState = VICTIMSTATE_BLOCKS; + *blocked_amount = uint32(*damage); + } + + if(pVictim->GetTypeId() == TYPEID_PLAYER) + ((Player*)pVictim)->UpdateDefense(); + + pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true); + pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); + break; + } + pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL); break; } case MELEE_HIT_PARRY: - if(attType == RANGED_ATTACK || unavoidable) //range attack - no parry + if(attType == RANGED_ATTACK) //range attack - no parry { outcome = MELEE_HIT_NORMAL; break; @@ -2140,7 +2161,7 @@ return; case MELEE_HIT_DODGE: - if(attType == RANGED_ATTACK || unavoidable ) //range attack - no dodge + if(attType == RANGED_ATTACK) //range attack - no dodge { outcome = MELEE_HIT_NORMAL; break; @@ -2172,12 +2193,6 @@ return; case MELEE_HIT_BLOCK: - if( unavoidable ) - { - outcome = MELEE_HIT_NORMAL; - break; - } - *blocked_amount = pVictim->GetShieldBlockValue(); if (pVictim->GetUnitBlockChance()) @@ -2474,10 +2489,10 @@ DEBUG_LOG("PHYSICAL OUTCOME: hit %f crit %f miss %u",modHitChance,crit_chance,miss_chance); - return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance * 100 ), miss_chance, int32(modHitChance)); + return RollMeleeOutcomeAgainst(pVictim, attType, spellInfo, int32(crit_chance * 100 ), miss_chance, int32(modHitChance)); } -MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType) const +MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo) const { // This is only wrapper @@ -2494,10 +2509,10 @@ // Useful if want to specify crit & miss chances for melee, else it could be removed DEBUG_LOG("MELEE OUTCOME: hit %f crit %u miss %u", modHitChance,crit_chance,miss_chance); - return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance * 100 ), miss_chance, int32(modHitChance)); + return RollMeleeOutcomeAgainst(pVictim, attType, spellInfo, int32(crit_chance * 100 ), miss_chance, int32(modHitChance)); } -MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 hit_chance) const +MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo, int32 crit_chance, int32 miss_chance, int32 hit_chance) const { if(pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) return MELEE_HIT_EVADE; @@ -2560,6 +2575,9 @@ // stunned target cannot dodge and this is check in GetUnitDodgeChance() float dodge = pVictim->GetUnitDodgeChance(); + if ( spellInfo && spellInfo->Attributes & 0x200000 ) + dodge = 0; + // Reduce dodge chance by attacker expertise rating if (GetTypeId() == TYPEID_PLAYER) dodge-=((Player*)this)->GetExpertiseDodgeOrParryReduction(); @@ -2573,13 +2591,23 @@ } int32 modCrit = 0; + // reduce crit chance from Rating for players + if (pVictim->GetTypeId()==TYPEID_PLAYER) + { + if (attType==RANGED_ATTACK) + modCrit -= int32(((Player*)pVictim)->GetRatingBonusValue(PLAYER_FIELD_CRIT_TAKEN_RANGED_RATING)*100); + else + modCrit -= int32(((Player*)pVictim)->GetRatingBonusValue(PLAYER_FIELD_CRIT_TAKEN_MELEE_RATING)*100); + } // check if attack comes from behind if (!pVictim->HasInArc(M_PI,this)) { - // ASSUME +10% crit from behind DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind."); - modCrit += 1000; + } + else if ( spellInfo && (spellInfo->Attributes & 0x200000)) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: melee spell that cannot be evaded."); } else { @@ -2602,20 +2630,21 @@ && ((tmp -= skillBonus2) > 0) && (roll < (sum += tmp))) { + // Critical chance + tmp = crit_chance + skillBonus + modCrit; + if ( GetTypeId() == TYPEID_PLAYER && spellInfo && tmp > 0 ) + { + if ( roll_chance_f(tmp/100)) + { + DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT"); + return MELEE_HIT_BLOCK_CRIT; + } + } DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum); return MELEE_HIT_BLOCK; } } - // reduce crit chance from Rating for players - if (pVictim->GetTypeId()==TYPEID_PLAYER) - { - if (attType==RANGED_ATTACK) - modCrit -= int32(((Player*)pVictim)->GetRatingBonusValue(PLAYER_FIELD_CRIT_TAKEN_RANGED_RATING)*100); - else - modCrit -= int32(((Player*)pVictim)->GetRatingBonusValue(PLAYER_FIELD_CRIT_TAKEN_MELEE_RATING)*100); - } - // Critical chance tmp = crit_chance + skillBonus + modCrit; @@ -2626,7 +2655,10 @@ } // 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 || ((Creature*)this)->isPet()) && pVictim->GetTypeId() != TYPEID_PLAYER && getLevel() < pVictim->getLevel() ) + if( attType != RANGED_ATTACK && !spellInfo && + (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet()) && + pVictim->GetTypeId() != TYPEID_PLAYER && !((Creature*)pVictim)->isPet() && + getLevel() < pVictim->getLevel() ) { // cap possible value (with bonuses > max skill) int32 skill = GetWeaponSkillValue(attType); @@ -2650,7 +2682,7 @@ tmp = tmp > tmpmax ? tmpmax : tmp; // tmp = mob's level * 5 - player's current defense skill tmp = GetMaxSkillValueForLevel() - tmp; - if (GetTypeId() != TYPEID_PLAYER && (tmp >= 15)) + if (GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->isPet() && (tmp >= 15)) { // add 2% chance per lacking skill point, min. is 15% tmp = tmp * 200 - 1500; @@ -4193,11 +4225,17 @@ procAttacker = PROC_FLAG_MISS; } break; + case MELEE_HIT_BLOCK_CRIT: case MELEE_HIT_CRIT: if(spellCasted && attType == BASE_ATTACK) { procAttacker |= PROC_FLAG_CRIT_SPELL; procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL; + if ( outcome == MELEE_HIT_BLOCK_CRIT ) + { + procVictim |= PROC_FLAG_BLOCK; + procAttacker |= PROC_FLAG_TARGET_BLOCK; + } } else if(attType == BASE_ATTACK || attType == OFF_ATTACK) { Index: game/Unit.h =================================================================== --- game/Unit.h (revision 5306) +++ game/Unit.h (working copy) @@ -419,7 +419,7 @@ enum MeleeHitOutcome { MELEE_HIT_EVADE, MELEE_HIT_MISS, MELEE_HIT_DODGE, MELEE_HIT_BLOCK, MELEE_HIT_PARRY, - MELEE_HIT_GLANCING, MELEE_HIT_CRIT, MELEE_HIT_CRUSHING, MELEE_HIT_NORMAL + MELEE_HIT_GLANCING, MELEE_HIT_CRIT, MELEE_HIT_CRUSHING, MELEE_HIT_NORMAL, MELEE_HIT_BLOCK_CRIT }; struct CleanDamage { @@ -698,8 +698,8 @@ float GetWeaponProcChance() const; float GetPPMProcChance(uint32 WeaponSpeed, float PPM) const; MeleeHitOutcome RollPhysicalOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo); - MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType) const; - MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 hit_chance) const; + MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo) const; + MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo, int32 crit_chance, int32 miss_chance, int32 hit_chance) const; bool isVendor() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_VENDOR ); } bool isTrainer() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_TRAINER ); }