diff options
author | Shauren <shauren.trinity@gmail.com> | 2023-02-11 16:54:46 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2023-02-11 16:54:46 +0100 |
commit | 9f088c2e04cba1f1870c6d9da1b16e9593430c54 (patch) | |
tree | 4c18a7cf6f89c3716afcd826191abd84afbc53d5 | |
parent | 38097e0f37b500c8f5928bfeb5518f8d3941389d (diff) |
Core/Units: Pass real damage taken after level scaling calculations to DamageDone and DamageTaken script hooks
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 84 |
1 files changed, 51 insertions, 33 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 35c7da03d82..cb2d7b0c8df 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -743,14 +743,35 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons /*static*/ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss) { - if (UnitAI* victimAI = victim->GetAI()) - victimAI->DamageTaken(attacker, damage, damagetype, spellProto); + uint32 damageDone = damage; + uint32 damageTaken = damage; + if (attacker) + damageTaken = damage / victim->GetHealthMultiplierForTarget(attacker); + + // call script hooks + { + uint32 tmpDamage = damageTaken; - if (UnitAI* attackerAI = attacker ? attacker->GetAI() : nullptr) - attackerAI->DamageDealt(victim, damage, damagetype); + if (UnitAI* victimAI = victim->GetAI()) + victimAI->DamageTaken(attacker, tmpDamage, damagetype, spellProto); - // Hook for OnDamage Event - sScriptMgr->OnDamage(attacker, victim, damage); + if (UnitAI* attackerAI = attacker ? attacker->GetAI() : nullptr) + attackerAI->DamageDealt(victim, tmpDamage, damagetype); + + // Hook for OnDamage Event + sScriptMgr->OnDamage(attacker, victim, tmpDamage); + + // if any script modified damage, we need to also apply the same modification to unscaled damage value + if (tmpDamage != damageTaken) + { + if (attacker) + damageDone = tmpDamage * victim->GetHealthMultiplierForTarget(attacker); + else + damageDone = tmpDamage; + + damageTaken = tmpDamage; + } + } // Signal to pets that their owner was attacked - except when DOT. if (attacker != victim && damagetype != DOT) @@ -776,7 +797,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons else victim->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Damage); - if (!damage && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage) + if (!damageTaken && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage) if (victim != attacker && victim->GetTypeId() == TYPEID_PLAYER) if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL]) if (spell->getState() == SPELL_STATE_PREPARING && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageAbsorb)) @@ -800,7 +821,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons continue; SpellInfo const* spell = (*i)->GetSpellInfo(); - uint32 share = CalculatePct(damage, (*i)->GetAmount()); + uint32 share = CalculatePct(damageDone, (*i)->GetAmount()); /// @todo check packets if damage is done by victim, or by attacker of victim Unit::DealDamageMods(attacker, shareDamageTarget, share, nullptr); @@ -817,7 +838,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons attacker->RewardRage(rage); } - if (!damage) + if (!damageDone) return 0; uint32 health = victim->GetHealth(); @@ -825,18 +846,18 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons // duel ends when player has 1 or less hp bool duel_hasEnded = false; bool duel_wasMounted = false; - if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->duel && damage >= (health-1)) + if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->duel && damageTaken >= (health-1)) { if (!attacker) return 0; // prevent kill only if killed in duel and killed by opponent or opponent controlled creature if (victim->ToPlayer()->duel->Opponent == attacker->GetControllingPlayer()) - damage = health - 1; + damageTaken = health - 1; duel_hasEnded = true; } - else if (victim->IsVehicle() && damage >= (health-1) && victim->GetCharmer() && victim->GetCharmer()->GetTypeId() == TYPEID_PLAYER) + else if (victim->IsVehicle() && damageTaken >= (health-1) && victim->GetCharmer() && victim->GetCharmer()->GetTypeId() == TYPEID_PLAYER) { Player* victimRider = victim->GetCharmer()->ToPlayer(); @@ -847,7 +868,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons // prevent kill only if killed in duel and killed by opponent or opponent controlled creature if (victimRider->duel->Opponent == attacker->GetControllingPlayer()) - damage = health - 1; + damageTaken = health - 1; duel_wasMounted = true; duel_hasEnded = true; @@ -861,31 +882,28 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons // in bg, count dmg if victim is also a player if (victim->GetTypeId() == TYPEID_PLAYER) if (Battleground* bg = killer->GetBattleground()) - bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage); + bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damageDone); - killer->UpdateCriteria(CriteriaType::DamageDealt, health > damage ? damage : health, 0, 0, victim); - killer->UpdateCriteria(CriteriaType::HighestDamageDone, damage); + killer->UpdateCriteria(CriteriaType::DamageDealt, health > damageDone ? damageDone : health, 0, 0, victim); + killer->UpdateCriteria(CriteriaType::HighestDamageDone, damageDone); } } if (victim->GetTypeId() == TYPEID_PLAYER) - victim->ToPlayer()->UpdateCriteria(CriteriaType::HighestDamageTaken, damage); - - if (attacker) - damage /= victim->GetHealthMultiplierForTarget(attacker); + victim->ToPlayer()->UpdateCriteria(CriteriaType::HighestDamageTaken, damageTaken); if (victim->GetTypeId() != TYPEID_PLAYER && (!victim->IsControlledByPlayer() || victim->IsVehicle())) { victim->ToCreature()->SetTappedBy(attacker); if (!attacker || attacker->IsControlledByPlayer()) - victim->ToCreature()->LowerPlayerDamageReq(health < damage ? health : damage); + victim->ToCreature()->LowerPlayerDamageReq(health < damageTaken ? health : damageTaken); } bool killed = false; bool skipSettingDeathState = false; - if (health <= damage) + if (health <= damageTaken) { killed = true; @@ -895,7 +913,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons if (damagetype != NODAMAGE && damagetype != SELF_DAMAGE && victim->HasAuraType(SPELL_AURA_SCHOOL_ABSORB_OVERKILL)) { AuraEffectList vAbsorbOverkill = victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB_OVERKILL); - DamageInfo damageInfo = DamageInfo(attacker, victim, damage, spellProto, damageSchoolMask, damagetype, + DamageInfo damageInfo = DamageInfo(attacker, victim, damageTaken, spellProto, damageSchoolMask, damagetype, cleanDamage ? cleanDamage->attackType : BASE_ATTACK); for (AuraEffect* absorbAurEff : vAbsorbOverkill) { @@ -908,7 +926,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons continue; // cannot absorb over limit - if (damage >= victim->CountPctFromMaxHealth(100 + absorbAurEff->GetMiscValueB())) + if (damageTaken >= victim->CountPctFromMaxHealth(100 + absorbAurEff->GetMiscValueB())) continue; // get amount which can be still absorbed by the aura @@ -950,7 +968,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons } } - damage = damageInfo.GetDamage(); + damageTaken = damageInfo.GetDamage(); } } @@ -962,9 +980,9 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons else { if (victim->GetTypeId() == TYPEID_PLAYER) - victim->ToPlayer()->UpdateCriteria(CriteriaType::TotalDamageTaken, damage); + victim->ToPlayer()->UpdateCriteria(CriteriaType::TotalDamageTaken, damageTaken); - victim->ModifyHealth(-(int32)damage); + victim->ModifyHealth(-(int32)damageTaken); if (damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE) victim->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::NonPeriodicDamage, spellProto); @@ -972,11 +990,11 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons if (victim->GetTypeId() != TYPEID_PLAYER) { // Part of Evade mechanics. DoT's and Thorns / Retribution Aura do not contribute to this - if (damagetype != DOT && damage > 0 && !victim->GetOwnerGUID().IsPlayer() && (!spellProto || !spellProto->HasAura(SPELL_AURA_DAMAGE_SHIELD))) + if (damagetype != DOT && damageTaken > 0 && !victim->GetOwnerGUID().IsPlayer() && (!spellProto || !spellProto->HasAura(SPELL_AURA_DAMAGE_SHIELD))) victim->ToCreature()->SetLastDamagedTime(GameTime::GetGameTime() + MAX_AGGRO_RESET_TIME); if (attacker && (!spellProto || !spellProto->HasAttribute(SPELL_ATTR4_NO_HARMFUL_THREAT))) - victim->GetThreatManager().AddThreat(attacker, float(damage), spellProto); + victim->GetThreatManager().AddThreat(attacker, float(damageTaken), spellProto); } else // victim is a player { @@ -1008,7 +1026,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons { auto isCastInterrupted = [&]() { - if (!damage) + if (!damageTaken) return spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::ZeroDamageCancels); if ((victim->IsPlayer() && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageCancelsPlayerOnly))) @@ -1022,7 +1040,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons auto isCastDelayed = [&]() { - if (!damage) + if (!damageTaken) return false; if ((victim->IsPlayer() && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamagePushbackPlayerOnly))) @@ -1041,7 +1059,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons } } - if (damage && victim->IsPlayer()) + if (damageTaken && victim->IsPlayer()) if (Spell* spell = victim->m_currentSpells[CURRENT_CHANNELED_SPELL]) if (spell->getState() == SPELL_STATE_CASTING && spell->m_spellInfo->HasChannelInterruptFlag(SpellAuraInterruptFlags::DamageChannelDuration)) spell->DelayedChannel(); @@ -1072,7 +1090,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons if (victim->GetStandState() && victim->IsPlayer()) victim->SetStandState(UNIT_STAND_STATE_STAND); - return damage; + return damageTaken; } void Unit::CastStop(uint32 except_spellid) |