From 1d3fbff3327629e46de3af506dc57880fffb52d5 Mon Sep 17 00:00:00 2001 From: ariel- Date: Mon, 2 May 2022 15:12:59 +0200 Subject: [PATCH] Core/Auras: removed caster dependency from core - Decoupled Unit logic: split of spell critical chance into done (caster bonuses) and taken (target bonuses), this allows to precalculate caster bonuses on aura apply and then check victim's auras on damage/healing calc - Made static a bunch of methods (they no longer have this pointer because they are now called from periodic handlers which may or may not have an active caster in world) - Simplified all AuraEffect bonuses into AuraEffect::_amount, no more duplicated code - Critical chance and whether or not caster is player owned unit (for resilience calcs) is now saved one level upper, on Aura itself (it's impossible as of 3.3.5 to have different effects with different critical chances) - Minor cleanup of SPELL_DAMAGE_CLASS_NONE and Arcane Potency (#18813) crit handling --- .../Implementation/CharacterDatabase.cpp | 10 +- src/server/game/Entities/Pet/Pet.cpp | 6 +- src/server/game/Entities/Player/Player.cpp | 18 +- src/server/game/Entities/Player/Player.h | 2 + src/server/game/Entities/Unit/Unit.cpp | 437 ++++++++++-------- src/server/game/Entities/Unit/Unit.h | 27 +- src/server/game/Handlers/MovementHandler.cpp | 2 +- .../game/Spells/Auras/SpellAuraEffects.cpp | 180 +++----- .../game/Spells/Auras/SpellAuraEffects.h | 11 +- src/server/game/Spells/Auras/SpellAuras.cpp | 63 ++- src/server/game/Spells/Auras/SpellAuras.h | 25 +- src/server/game/Spells/Spell.cpp | 31 +- src/server/game/Spells/SpellEffects.cpp | 10 +- src/server/scripts/Commands/cs_misc.cpp | 16 +- .../MoltenCore/boss_ragnaros.cpp | 2 +- .../EasternKingdoms/Karazhan/karazhan.cpp | 2 +- .../SunwellPlateau/boss_brutallus.cpp | 2 +- .../SunwellPlateau/boss_felmyst.cpp | 2 +- .../SunwellPlateau/boss_kalecgos.cpp | 2 +- .../zone_western_plaguelands.cpp | 2 +- .../BattleForMountHyjal/boss_archimonde.cpp | 2 +- .../instance_culling_of_stratholme.cpp | 2 +- .../CullingOfStratholme/npc_arthas.cpp | 2 +- .../TheBlackMorass/boss_aeonus.cpp | 2 +- .../TheBlackMorass/boss_chrono_lord_deja.cpp | 2 +- .../TheBlackMorass/boss_temporus.cpp | 2 +- .../instance_the_black_morass.cpp | 2 +- .../Kalimdor/Firelands/boss_lord_rhyolith.cpp | 2 +- .../Kalimdor/OnyxiasLair/boss_onyxia.cpp | 2 +- .../Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp | 4 +- .../TempleOfAhnQiraj/boss_viscidus.cpp | 2 +- .../ObsidianSanctum/obsidian_sanctum.cpp | 2 +- .../boss_baltharus_the_warborn.cpp | 2 +- .../RubySanctum/boss_halion.cpp | 2 +- .../Gundrak/boss_drakkari_colossus.cpp | 2 +- .../boss_blood_prince_council.cpp | 2 +- .../boss_valithria_dreamwalker.cpp | 2 +- .../IcecrownCitadel/icecrown_citadel.cpp | 2 +- .../boss_ioc_horde_alliance.cpp | 2 +- .../Northrend/Naxxramas/boss_faerlina.cpp | 2 +- .../Ulduar/HallsOfStone/halls_of_stone.cpp | 2 +- .../Ulduar/boss_algalon_the_observer.cpp | 2 +- .../Northrend/Ulduar/Ulduar/boss_mimiron.cpp | 6 +- .../Northrend/Ulduar/Ulduar/boss_xt002.cpp | 2 +- .../Ulduar/Ulduar/boss_yogg_saron.cpp | 4 +- .../scripts/Northrend/zone_borean_tundra.cpp | 2 +- .../scripts/Northrend/zone_grizzly_hills.cpp | 2 +- .../boss_fathomlord_karathress.cpp | 2 +- .../boss_leotheras_the_blind.cpp | 2 +- .../TheSlavePens/boss_ahune.cpp | 6 +- .../ShatteredHalls/shattered_halls.cpp | 2 +- .../Outland/TempestKeep/Eye/boss_alar.cpp | 2 +- .../botanica/boss_warp_splinter.cpp | 2 +- .../Outland/zone_shadowmoon_valley.cpp | 2 +- src/server/scripts/Spells/spell_dk.cpp | 32 +- src/server/scripts/Spells/spell_druid.cpp | 6 + 56 files changed, 531 insertions(+), 437 deletions(-) diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 562ef7b412..2f8883b430 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -71,7 +71,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_GROUP_MEMBER, "SELECT guid FROM group_member WHERE memberGuid = ?", CONNECTION_BOTH); PrepareStatement(CHAR_SEL_CHARACTER_INSTANCE, "SELECT id, permanent, map, difficulty, extendState, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_AURAS, "SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, " - "base_amount0, base_amount1, base_amount2, maxduration, remaintime, remaincharges FROM character_aura WHERE guid = ?", CONNECTION_ASYNC); + "base_amount0, base_amount1, base_amount2, maxduration, remaintime, remaincharge, critChance, applyResilience FROM character_aura WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_SPELL, "SELECT spell, active, disabled FROM character_spell WHERE guid = ?", CONNECTION_BOTH); PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS, "SELECT quest, status, explored, timer, mobcount1, mobcount2, mobcount3, mobcount4, " "itemcount1, itemcount2, itemcount3, itemcount4, itemcount5, itemcount6, playercount FROM character_queststatus WHERE guid = ? AND status <> 0", CONNECTION_ASYNC); @@ -273,8 +273,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_EQUIP_SET, "DELETE FROM character_equipmentsets WHERE setguid=?", CONNECTION_ASYNC); // Auras - PrepareStatement(CHAR_INS_AURA, "INSERT INTO character_aura (guid, casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, maxduration, remaintime, remaincharges) " - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_AURA, "INSERT INTO character_aura (guid, casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, maxduration, remaintime, remaincharges, critChance, applyResilience) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); // Currency PrepareStatement(CHAR_SEL_PLAYER_CURRENCY, "SELECT Currency, Quantity, WeeklyQuantity, TrackedQuantity, Flags FROM character_currency WHERE CharacterGuid = ?", CONNECTION_ASYNC); @@ -620,7 +620,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME_BY_OWNER, "DELETE FROM character_pet_declinedname WHERE owner = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME, "DELETE FROM character_pet_declinedname WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_PET_DECLINEDNAME, "INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_PET_AURA, "SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, maxDuration, remainTime, remainCharges FROM pet_aura WHERE guid = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_PET_AURA, "SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, maxDuration, remainTime, remainCharges, critChance, applyResilience FROM pet_aura WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_PET_SPELL, "SELECT spell, active FROM pet_spell WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_PET_SPELL_COOLDOWN, "SELECT spell, time, categoryId, categoryEnd FROM pet_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_PET_DECLINED_NAME, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_pet_declinedname WHERE owner = ? AND id = ?", CONNECTION_SYNCH); @@ -631,7 +631,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_PET_SPELL_BY_SPELL, "DELETE FROM pet_spell WHERE guid = ? and spell = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_PET_SPELL, "INSERT INTO pet_spell (guid, spell, active) VALUES (?, ?, ?)", CONNECTION_BOTH); PrepareStatement(CHAR_INS_PET_AURA, "INSERT INTO pet_aura (guid, casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, " - "base_amount0, base_amount1, base_amount2, maxDuration, remainTime, remainCharges) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_BOTH); + "base_amount0, base_amount1, base_amount2, maxDuration, remainTime, remainCharges, critChance, applyResilience) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_BOTH); PrepareStatement(CHAR_DEL_CHAR_PET_BY_OWNER, "DELETE FROM character_pet WHERE owner = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_PET_NAME, "UPDATE character_pet SET name = ?, renamed = 1 WHERE owner = ? AND id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_PET_SLOT_BY_SLOT, "UPDATE character_pet SET slot = ? WHERE owner = ? AND slot = ?", CONNECTION_ASYNC); diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 77b8cb24af..abc027510d 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -1151,6 +1151,8 @@ void Pet::_LoadAuras(uint32 timediff) int32 maxduration = fields[11].GetInt32(); int32 remaintime = fields[12].GetInt32(); uint8 remaincharges = fields[13].GetUInt8(); + float critChance = fields[14].GetFloat(); + bool applyResilience = fields[15].GetBool(); SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); if (!spellInfo) @@ -1184,7 +1186,7 @@ void Pet::_LoadAuras(uint32 timediff) aura->Remove(); continue; } - aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, &damage[0]); + aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, critChance, applyResilience, &damage[0]); aura->ApplyForTargets(); TC_LOG_DEBUG("entities.pet", "Added aura spellid %u, effectmask %u", spellInfo->Id, effmask); } @@ -1249,6 +1251,8 @@ void Pet::_SaveAuras(CharacterDatabaseTransaction& trans) stmt->setInt32(index++, itr->second->GetMaxDuration()); stmt->setInt32(index++, itr->second->GetDuration()); stmt->setUInt8(index++, itr->second->GetCharges()); + stmt->setFloat(index++, itr->second->GetCritChance()); + stmt->setBool(index++, itr->second->CanApplyResilience()); trans->Append(stmt); } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index c8684118a7..5c54aa5f24 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -716,7 +716,7 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) case DAMAGE_SLIME: { DamageInfo dmgInfo(this, this, damage, nullptr, type == DAMAGE_LAVA ? SPELL_SCHOOL_MASK_FIRE : SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, BASE_ATTACK); - CalcAbsorbResist(dmgInfo); + Unit::CalcAbsorbResist(dmgInfo); absorb = dmgInfo.GetAbsorb(); resist = dmgInfo.GetResist(); damage = dmgInfo.GetDamage(); @@ -726,7 +726,7 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) break; } - DealDamageMods(this, damage, &absorb); + Unit::DealDamageMods(this, damage, &absorb); WorldPackets::CombatLog::EnvironmentalDamageLog environmentalDamageLog; environmentalDamageLog.Victim = GetGUID(); @@ -736,7 +736,7 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) environmentalDamageLog.Resisted = resist; SendMessageToSet(environmentalDamageLog.Write(), true); - uint32 final_damage = DealDamage(this, damage, nullptr, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + uint32 final_damage = Unit::DealDamage(this, this, damage, nullptr, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); if (!IsAlive()) { @@ -17950,8 +17950,8 @@ void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff) /* 0 1 2 3 4 5 6 7 8 9 10 QueryResult* result = CharacterDatabase.PQuery("SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, - 11 12 13 - maxDuration, remainTime, remainCharges FROM character_aura WHERE guid = '%u'", GetGUID().GetCounter()); + 11 12 13 14 15 + maxDuration, remainTime, remainCharges, critChance, applyResilience FROM character_aura WHERE guid = '%u'", GetGUID().GetCounter()); */ if (result) @@ -17975,6 +17975,8 @@ void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff) int32 maxduration = fields[11].GetInt32(); int32 remaintime = fields[12].GetInt32(); uint8 remaincharges = fields[13].GetUInt8(); + float critChance = fields[14].GetFloat(); + bool applyResilience = fields[15].GetBool(); SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); if (!spellInfo) @@ -18012,7 +18014,7 @@ void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff) continue; } - aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, &damage[0]); + aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, critChance, applyResilience, &damage[0]); aura->ApplyForTargets(); TC_LOG_DEBUG("entities.player", "Player::_LoadAuras: Added aura (SpellID: %u, EffectMask: %u) to player '%s (%s)", spellInfo->Id, effmask, GetName().c_str(), GetGUID().ToString().c_str()); @@ -19932,7 +19934,9 @@ void Player::_SaveAuras(CharacterDatabaseTransaction& trans) stmt->setInt32(index++, baseDamage[2]); stmt->setInt32(index++, itr->second->GetMaxDuration()); stmt->setInt32(index++, itr->second->GetDuration()); - stmt->setUInt8(index, itr->second->GetCharges()); + stmt->setUInt8(index++, itr->second->GetCharges()); + stmt->setFloat(index++, itr->second->GetCritChance()); + stmt->setBool(index++, itr->second->CanApplyResilience()); trans->Append(stmt); } } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 262f73c837..f6b519914c 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1808,6 +1808,8 @@ class TC_GAME_API Player : public Unit, public GridObject uint32 GetBaseSpellPowerBonus() const { return m_baseSpellPower; } int32 GetSpellPenetrationItemMod() const { return m_spellPenetrationItemMod; } + bool CanApplyResilience() const override { return true; } + float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const; void UpdateBlockPercentage(); void UpdateCritPercentage(WeaponAttackType attType); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index bdc25c16ad..798d65349d 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -729,7 +729,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons || HasBreakableByDamageAuraType(SPELL_AURA_TRANSFORM, excludeAura)); } -void Unit::DealDamageMods(Unit const* victim, uint32 &damage, uint32* absorb) const +/*static*/ void Unit::DealDamageMods(Unit const* victim, uint32& damage, uint32* absorb) { if (!victim || !victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks())) { @@ -739,12 +739,12 @@ void Unit::DealDamageMods(Unit const* victim, uint32 &damage, uint32* absorb) co } } -uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss) +/*static*/ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss) { // Sparring Checks if (Creature* target = victim->ToCreature()) { - if (IsCreature() && !IsCharmedOwnedByPlayerOrPlayer()) + if (attacker->IsCreature() && !attacker->IsCharmedOwnedByPlayerOrPlayer()) { if (target->GetNoNpcDamageBelowPctHealthValue() != 0.0f) { @@ -757,23 +757,23 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam } if (UnitAI* victimAI = victim->GetAI()) - victimAI->DamageTaken(this, damage); + victimAI->DamageTaken(attacker, damage); - if (UnitAI* attackerAI = GetAI()) + if (UnitAI* attackerAI = attacker->GetAI()) attackerAI->DamageDealt(victim, damage, damagetype); // Hook for OnDamage Event - sScriptMgr->OnDamage(this, victim, damage); + sScriptMgr->OnDamage(attacker, victim, damage); if (victim->GetTypeId() == TYPEID_PLAYER) { // Signal to pets that their owner was attacked - except when DOT. - if (this != victim && damagetype != DOT) + if (attacker != victim && damagetype != DOT) { for (Unit* controlled : victim->m_Controlled) if (Creature* cControlled = controlled->ToCreature()) if (CreatureAI* controlledAI = cControlled->AI()) - controlledAI->OwnerAttackedBy(this); + controlledAI->OwnerAttackedBy(attacker); } if (victim->ToPlayer()->GetCommandStatus(CHEAT_GOD)) @@ -812,19 +812,19 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam uint32 share = CalculatePct(damage, (*i)->GetAmount()); /// @todo check packets if damage is done by victim, or by attacker of victim - DealDamageMods(shareDamageTarget, share, nullptr); - DealDamage(shareDamageTarget, share, nullptr, NODAMAGE, spell->GetSchoolMask(), spell, false); + Unit::DealDamageMods(shareDamageTarget, share, nullptr); + Unit::DealDamage(attacker, shareDamageTarget, share, nullptr, NODAMAGE, spell->GetSchoolMask(), spell, false); } } // Rage from Damage made (only from direct weapon damage) - if (cleanDamage && damagetype == DIRECT_DAMAGE && this != victim && GetPowerType() == POWER_RAGE) + if (attacker && cleanDamage && damagetype == DIRECT_DAMAGE && attacker != victim && attacker->GetPowerType() == POWER_RAGE) { - uint32 rage = uint32((float)GetAttackTime(cleanDamage->attackType) / 1000 * 6.5f); + uint32 rage = uint32((float)attacker->GetAttackTime(cleanDamage->attackType) / 1000 * 6.5f); // Sentinel - if (victim->GetVictim() && victim->GetVictim() != this) - if (AuraEffect* aurEff = GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_GENERIC, 1916, EFFECT_1)) + if (victim->GetVictim() && victim->GetVictim() != attacker) + if (AuraEffect* aurEff = attacker->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_GENERIC, 1916, EFFECT_1)) rage += CalculatePct(rage, aurEff->GetAmount()); switch (cleanDamage->attackType) @@ -833,7 +833,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam rage /= 2; [[fallthrough]]; case BASE_ATTACK: - RewardRage(rage, true); + attacker->RewardRage(rage, true); break; default: break; @@ -849,18 +849,18 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam return 0; } - TC_LOG_DEBUG("entities.unit", "DealDamageStart"); - uint32 health = victim->GetHealth(); - TC_LOG_DEBUG("entities.unit", "%s dealt %u damage to %s", GetGUID().ToString().c_str(), damage, victim->GetGUID().ToString().c_str()); // 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 (!attacker) + return 0; + // prevent kill only if killed in duel and killed by opponent or opponent controlled creature - if (victim->ToPlayer()->duel->opponent == GetControllingPlayer()) + if (victim->ToPlayer()->duel->opponent == attacker->GetControllingPlayer()) damage = health - 1; duel_hasEnded = true; @@ -871,8 +871,11 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam if (victimRider && victimRider->duel && victimRider->duel->isMounted) { + if (!attacker) + return 0; + // prevent kill only if killed in duel and killed by opponent or opponent controlled creature - if (victimRider->duel->opponent == GetControllingPlayer()) + if (victimRider->duel->opponent == attacker->GetControllingPlayer()) damage = health - 1; duel_wasMounted = true; @@ -880,17 +883,18 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam } } - if (GetTypeId() == TYPEID_PLAYER && this != victim) + if (attacker && attacker != victim) { - Player* killer = ToPlayer(); + if (Player* killer = attacker->ToPlayer()) + { + // 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); - // 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); - - killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, health > damage ? damage : health, 0, 0, victim); - killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage); + killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, health > damage ? damage : health, 0, 0, victim); + killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage); + } } if (victim->GetTypeId() == TYPEID_PLAYER) @@ -898,25 +902,21 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam else if (!victim->IsControlledByPlayer() || victim->IsVehicle()) { if (!victim->ToCreature()->hasLootRecipient()) - victim->ToCreature()->SetLootRecipient(this); + victim->ToCreature()->SetLootRecipient(attacker); - if (IsControlledByPlayer() || (ToTempSummon() && ToTempSummon()->GetSummoner() && ToTempSummon()->GetSummoner()->GetTypeId() == TYPEID_PLAYER)) + if (!attacker || attacker->IsControlledByPlayer() || (attacker->ToTempSummon() && attacker->ToTempSummon()->GetSummoner() && attacker->ToTempSummon()->GetSummoner()->GetTypeId() == TYPEID_PLAYER)) victim->ToCreature()->LowerPlayerDamageReq(health < damage ? health : damage); } if (health <= damage) { - TC_LOG_DEBUG("entities.unit", "DealDamage: victim just died"); - - if (victim->GetTypeId() == TYPEID_PLAYER && victim != this) + if (victim->GetTypeId() == TYPEID_PLAYER && victim != attacker) victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, health); - Kill(victim, durabilityLoss); + Unit::Kill(attacker, victim, durabilityLoss); } else { - TC_LOG_DEBUG("entities.unit", "DealDamageAlive"); - if (victim->GetTypeId() == TYPEID_PLAYER) victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, damage); @@ -930,7 +930,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam // 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))) victim->ToCreature()->SetLastDamagedTime(GameTime::GetGameTime() + MAX_AGGRO_RESET_TIME); - victim->GetThreatManager().AddThreat(this, float(damage), spellProto); + victim->GetThreatManager().AddThreat(attacker, float(damage), spellProto); } else // victim is a player { @@ -943,25 +943,25 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam } // Rage from damage received - if (this != victim && victim->GetPowerType() == POWER_RAGE) + if (attacker != victim && victim->GetPowerType() == POWER_RAGE) { uint32 rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0); victim->RewardRage(rage_damage, false); } - if (GetTypeId() == TYPEID_PLAYER) + if (attacker && attacker->GetTypeId() == TYPEID_PLAYER) { // random durability for items (HIT DONE) if (roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE))) { EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END-1)); - ToPlayer()->DurabilityPointLossForEquipSlot(slot); + attacker->ToPlayer()->DurabilityPointLossForEquipSlot(slot); } } if (damagetype != NODAMAGE) { - if (victim != this + if (victim != attacker && (!spellProto || !(spellProto->HasAttribute(SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE) || spellProto->HasAttribute(SPELL_ATTR3_TREAT_AS_PERIODIC)))) { if (damagetype != DOT) @@ -1024,8 +1024,6 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam } } - TC_LOG_DEBUG("entities.unit", "DealDamageEnd returned %d damage", damage); - return damage; } @@ -1093,8 +1091,8 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama // Spells with SPELL_ATTR4_FIXED_DAMAGE ignore resilience because their damage is based off another spell's damage. if (!spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE)) { - if (IsDamageReducedByArmor(damageSchoolMask, spellInfo)) - damage = CalcArmorReducedDamage(victim, damage, spellInfo, attackType); + if (Unit::IsDamageReducedByArmor(damageSchoolMask, spellInfo)) + damage = Unit::CalcArmorReducedDamage(this, victim, damage, spellInfo, attackType); bool blocked = false; // Per-school calc @@ -1159,7 +1157,8 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama damage -= damageInfo->blocked; } - ApplyResilience(victim, &damage); + if (CanApplyResilience()) + Unit::ApplyResilience(victim, &damage); break; } // Magical Attacks @@ -1173,7 +1172,8 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama damage = Unit::SpellCriticalDamageBonus(this, spellInfo, damage); } - ApplyResilience(victim, &damage); + if (CanApplyResilience()) + Unit::ApplyResilience(victim, &damage); break; } @@ -1191,7 +1191,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama damageInfo->damage = damage; DamageInfo dmgInfo(*damageInfo, SPELL_DIRECT_DAMAGE, BASE_ATTACK, PROC_HIT_NONE); - CalcAbsorbResist(dmgInfo); + Unit::CalcAbsorbResist(dmgInfo); damageInfo->absorb = dmgInfo.GetAbsorb(); damageInfo->resist = dmgInfo.GetResist(); @@ -1225,7 +1225,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss) // Call default DealDamage CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL); - DealDamage(victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss); + Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss); } /// @todo for melee need create structure as in @@ -1286,9 +1286,9 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam sScriptMgr->ModifyMeleeDamage(damageInfo->target, damageInfo->attacker, damage); // Calculate armor reduction - if (IsDamageReducedByArmor((SpellSchoolMask)(damageInfo->damageSchoolMask))) + if (Unit::IsDamageReducedByArmor((SpellSchoolMask)(damageInfo->damageSchoolMask))) { - damageInfo->damage = CalcArmorReducedDamage(damageInfo->target, damage, nullptr, damageInfo->attackType); + damageInfo->damage = Unit::CalcArmorReducedDamage(damageInfo->attacker, damageInfo->target, damage, nullptr, damageInfo->attackType); damageInfo->cleanDamage += damage - damageInfo->damage; } else @@ -1389,7 +1389,8 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam damageInfo->HitInfo |= HITINFO_AFFECTS_VICTIM; int32 resilienceReduction = damageInfo->damage; - ApplyResilience(victim, &resilienceReduction); + if (CanApplyResilience()) + Unit::ApplyResilience(victim, &resilienceReduction); resilienceReduction = damageInfo->damage - resilienceReduction; damageInfo->damage -= resilienceReduction; damageInfo->cleanDamage += resilienceReduction; @@ -1400,7 +1401,7 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam damageInfo->procVictim |= PROC_FLAG_TAKE_ANY_DAMAGE; // Calculate absorb & resists DamageInfo dmgInfo(*damageInfo); - CalcAbsorbResist(dmgInfo); + Unit::CalcAbsorbResist(dmgInfo); damageInfo->absorb = dmgInfo.GetAbsorb(); damageInfo->resist = dmgInfo.GetResist(); @@ -1458,7 +1459,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) // Call default DealDamage CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, damageInfo->attackType, damageInfo->hitOutCome); - DealDamage(victim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), nullptr, durabilityLoss); + Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), nullptr, durabilityLoss); // If this is a creature and it attacks from behind it has a probability to daze it's victim if ((damageInfo->hitOutCome == MELEE_HIT_CRIT || damageInfo->hitOutCome == MELEE_HIT_CRUSHING || damageInfo->hitOutCome == MELEE_HIT_NORMAL || damageInfo->hitOutCome == MELEE_HIT_GLANCING) && @@ -1522,7 +1523,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) } // No Unit::CalcAbsorbResist here - opcode doesn't send that data - this damage is probably not affected by that - victim->DealDamageMods(this, damage, nullptr); + Unit::DealDamageMods(this, damage, nullptr); /// @todo Move this to a packet handler WorldPacket data(SMSG_SPELLDAMAGESHIELD, 8 + 8 + 4 + 4 + 4 + 4 + 4); @@ -1536,7 +1537,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) data << uint32(0); // FIX ME: Send resisted damage, both fully resisted and partly resisted victim->SendMessageToSet(&data, true); - victim->DealDamage(this, damage, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true); + Unit::DealDamage(victim, this, damage, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true); } } } @@ -1549,7 +1550,7 @@ void Unit::HandleEmoteCommand(uint32 anim_id) SendMessageToSet(&data, true); } -bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* spellInfo /*= nullptr*/, int8 effIndex /*= -1*/) +/*static*/ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* spellInfo /*= nullptr*/, int8 effIndex /*= -1*/) { // only physical spells damage gets reduced by armor if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0) @@ -1593,40 +1594,43 @@ static float GetArmorReduction(float armor, uint8 attackerLevel) return temp * 100; } -uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType /*attackType*/) const +/*static*/ uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType /*attackType*/, uint8 attackerLevel /*= 0*/) { float armor = float(victim->GetArmor()); - // bypass enemy armor by SPELL_AURA_BYPASS_ARMOR_FOR_CASTER - int32 armorBypassPct = victim->GetTotalAuraModifier(SPELL_AURA_BYPASS_ARMOR_FOR_CASTER, [&](AuraEffect const* aurEff) + if (attacker) { - return aurEff->GetCasterGUID() == GetGUID(); - }); + // bypass enemy armor by SPELL_AURA_BYPASS_ARMOR_FOR_CASTER + int32 armorBypassPct = victim->GetTotalAuraModifier(SPELL_AURA_BYPASS_ARMOR_FOR_CASTER, [&](AuraEffect const* aurEff) + { + return aurEff->GetCasterGUID() == attacker->GetGUID(); + }); - armor = CalculatePct(armor, 100 - std::min(armorBypassPct, 100)); + armor = CalculatePct(armor, 100 - std::min(armorBypassPct, 100)); - // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura - armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL); + // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura + armor += attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL); - if (spellInfo) - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor); + if (spellInfo) + if (Player* modOwner = attacker->GetSpellModOwner()) + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor); - for (AuraEffect const* aurEff : GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST)) - { - if (aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) - armor = std::floor(AddPct(armor, -aurEff->GetAmount())); + for (AuraEffect const* aurEff : attacker->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST)) + { + if (aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) + armor = std::floor(AddPct(armor, -aurEff->GetAmount())); + } + + if (armor < 0.0f) + armor = 0.0f; } - if (armor < 0.0f) - armor = 0.0f; - - float armorReduction = 100.f - GetArmorReduction(armor, getLevel()); + float armorReduction = 100.f - GetArmorReduction(armor, attacker ? attacker->getLevel() : attackerLevel); return std::max(CalculatePct(damage, armorReduction), 1); } -uint32 Unit::CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) const +/*static*/ uint32 Unit::CalcSpellResistedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) { // Magic damage, check for resists if (!(schoolMask & SPELL_SCHOOL_MASK_MAGIC)) @@ -1651,7 +1655,7 @@ uint32 Unit::CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMas return 0; } - float const averageResist = CalculateAverageResistReduction(schoolMask, victim, spellInfo); + float const averageResist = Unit::CalculateAverageResistReduction(attacker, schoolMask, victim, spellInfo); float discreteResistProbability[11] = { }; if (averageResist <= 0.1f) @@ -1677,18 +1681,21 @@ uint32 Unit::CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMas float damageResisted = damage * resistance / 10.f; if (damageResisted > 0.0f) // if any damage was resisted { - int32 ignoredResistance = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask); - ignoredResistance = std::min(ignoredResistance, 100); - ApplyPct(damageResisted, 100 - ignoredResistance); - - // Spells with melee and magic school mask, decide whether resistance or armor absorb is higher - if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC)) + if (attacker) { - uint32 damageAfterArmor = CalcArmorReducedDamage(victim, damage, spellInfo, BASE_ATTACK); - float armorReduction = damage - damageAfterArmor; + int32 ignoredResistance = attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask); + ignoredResistance = std::min(ignoredResistance, 100); + ApplyPct(damageResisted, 100 - ignoredResistance); - // pick the lower one, the weakest resistance counts - damageResisted = std::min(damageResisted, armorReduction); + // Spells with melee and magic school mask, decide whether resistance or armor absorb is higher + if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC)) + { + uint32 damageAfterArmor = Unit::CalcArmorReducedDamage(attacker, victim, damage, spellInfo, BASE_ATTACK); + float armorReduction = damage - damageAfterArmor; + + // pick the lower one, the weakest resistance counts + damageResisted = std::min(damageResisted, armorReduction); + } } } @@ -1696,20 +1703,23 @@ uint32 Unit::CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMas return uint32(damageResisted); } -float Unit::CalculateAverageResistReduction(SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo) const +/*static*/ float Unit::CalculateAverageResistReduction(Unit const* attacker, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo) { float victimResistance = float(victim->GetResistance(schoolMask)); - // pets inherit 100% of masters penetration - // excluding traps - Player const* player = GetSpellModOwner(); - if (player && GetEntry() != WORLD_TRIGGER) + if (attacker) { - victimResistance += float(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask)); - victimResistance -= float(player->GetSpellPenetrationItemMod()); + // pets inherit 100% of masters penetration + // excluding traps + Player const* player = attacker->GetSpellModOwner(); + if (player && attacker->GetEntry() != WORLD_TRIGGER) + { + victimResistance += float(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask)); + victimResistance -= float(player->GetSpellPenetrationItemMod()); + } + else + victimResistance += float(attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask)); } - else - victimResistance += float(GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask)); // holy resistance exists in pve and comes from level difference, ignore template values if (schoolMask & SPELL_SCHOOL_MASK_HOLY) @@ -1722,8 +1732,8 @@ float Unit::CalculateAverageResistReduction(SpellSchoolMask schoolMask, Unit con victimResistance = std::max(victimResistance, 0.0f); // level-based resistance does not apply to binary spells, and cannot be overcome by spell penetration - if (!spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL)) - victimResistance += std::max((float(victim->getLevelForTarget(this)) - float(getLevelForTarget(victim))) * 5.0f, 0.0f); + if (attacker && (!spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))) + victimResistance += std::max((float(victim->getLevelForTarget(attacker)) - float(attacker->getLevelForTarget(victim))) * 5.0f, 0.0f); static uint32 const BOSS_LEVEL = 83; static float const BOSS_RESISTANCE_CONSTANT = 510.0f; @@ -1738,28 +1748,29 @@ float Unit::CalculateAverageResistReduction(SpellSchoolMask schoolMask, Unit con return victimResistance / (victimResistance + resistanceConstant); } -void Unit::CalcAbsorbResist(DamageInfo& damageInfo) +/*static*/ void Unit::CalcAbsorbResist(DamageInfo& damageInfo) { if (!damageInfo.GetVictim() || !damageInfo.GetVictim()->IsAlive() || !damageInfo.GetDamage()) return; - uint32 resistedDamage = CalcSpellResistedDamage(damageInfo.GetVictim(), damageInfo.GetDamage(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo()); + uint32 resistedDamage = Unit::CalcSpellResistedDamage(damageInfo.GetAttacker(), damageInfo.GetVictim(), damageInfo.GetDamage(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo()); damageInfo.ResistDamage(resistedDamage); // Ignore Absorption Auras - float auraAbsorbMod(GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL, damageInfo.GetSchoolMask())); - - AuraEffectList const& abilityAbsorbAuras = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL); - for (AuraEffect const* aurEff : abilityAbsorbAuras) + float auraAbsorbMod = 0.f; + if (Unit* attacker = damageInfo.GetAttacker()) { - if (!(aurEff->GetMiscValue() & damageInfo.GetSchoolMask())) - continue; + auraAbsorbMod = attacker->GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL, damageInfo.GetSchoolMask()); + auraAbsorbMod = std::max(auraAbsorbMod, static_cast(attacker->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL, [&damageInfo](AuraEffect const* aurEff) -> bool + { + if (!(aurEff->GetMiscValue() & damageInfo.GetSchoolMask())) + return false; - if (!aurEff->IsAffectingSpell(damageInfo.GetSpellInfo())) - continue; + if (!aurEff->IsAffectingSpell(damageInfo.GetSpellInfo())) + return false; - if ((aurEff->GetAmount() > auraAbsorbMod)) - auraAbsorbMod = float(aurEff->GetAmount()); + return true; + }))); } RoundToInterval(auraAbsorbMod, 0.0f, 100.0f); @@ -1878,7 +1889,7 @@ void Unit::CalcAbsorbResist(DamageInfo& damageInfo) damageInfo.ModifyDamage(absorbIgnoringDamage); // split damage auras - only when not damaging self - if (damageInfo.GetVictim() != this) + if (damageInfo.GetVictim() != damageInfo.GetAttacker()) { // We're going to call functions which can modify content of the list during iteration over it's elements // Let's copy the list so we can prevent iterator invalidation @@ -1916,27 +1927,30 @@ void Unit::CalcAbsorbResist(DamageInfo& damageInfo) } uint32 split_absorb = 0; - DealDamageMods(caster, splitDamage, &split_absorb); + Unit::DealDamageMods(caster, splitDamage, &split_absorb); - // Sparring Checks - if (Creature* target = damageInfo.GetVictim()->ToCreature()) - if (IsCreature() && !IsCharmedOwnedByPlayerOrPlayer()) - if (target->GetNoNpcDamageBelowPctHealthValue() != 0.0f) - if (target->GetHealthPct() <= target->GetNoNpcDamageBelowPctHealthValue()) - damageInfo.ModifyDamage(damageInfo.GetDamage() * -1); + if (Unit* attacker = damageInfo.GetAttacker()) + { + // Sparring Checks + if (Creature* target = damageInfo.GetVictim()->ToCreature()) + if (attacker->IsCreature() && !attacker->IsCharmedOwnedByPlayerOrPlayer()) + if (target->GetNoNpcDamageBelowPctHealthValue() != 0.0f) + if (target->GetHealthPct() <= target->GetNoNpcDamageBelowPctHealthValue()) + damageInfo.ModifyDamage(damageInfo.GetDamage() * -1); - SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitDamage, damageInfo.GetSchoolMask(), split_absorb, 0, false, 0, false); + attacker->SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitDamage, damageInfo.GetSchoolMask(), split_absorb, 0, false, 0, false); + } CleanDamage cleanDamage = CleanDamage(splitDamage, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - DealDamage(caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false); + Unit::DealDamage(damageInfo.GetAttacker(), caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false); // break 'Fear' and similar auras - ProcSkillsAndAuras(caster, PROC_FLAG_NONE, PROC_FLAG_TAKE_HARMFUL_SPELL, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, PROC_HIT_NONE, nullptr, &damageInfo, nullptr); + Unit::ProcSkillsAndAuras(damageInfo.GetAttacker(), caster, PROC_FLAG_NONE, PROC_FLAG_TAKE_HARMFUL_SPELL, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, PROC_HIT_NONE, nullptr, &damageInfo, nullptr); } } } -void Unit::CalcHealAbsorb(HealInfo& healInfo) const +/*static*/ void Unit::CalcHealAbsorb(HealInfo& healInfo) { if (!healInfo.GetHeal()) return; @@ -2057,7 +2071,7 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr CalcDamageInfo damageInfo; CalculateMeleeDamage(victim, 0, &damageInfo, attType); // Send log damage message to client - DealDamageMods(victim, damageInfo.damage, &damageInfo.absorb); + Unit::DealDamageMods(victim, damageInfo.damage, &damageInfo.absorb); // Sparring Checks if (Creature* target = victim->ToCreature()) @@ -2071,7 +2085,7 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr DealMeleeDamage(&damageInfo, true); DamageInfo dmgInfo(damageInfo); - ProcSkillsAndAuras(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr); + Unit::ProcSkillsAndAuras(damageInfo.attacker, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr); if (GetTypeId() == TYPEID_PLAYER) TC_LOG_DEBUG("entities.unit", "AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.", @@ -2562,7 +2576,7 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo { // resistance chance for binary spells, equals to average damage reduction of non-binary spell if (spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL) && (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_MAGIC)) - resist_chance += int32(CalculateAverageResistReduction(spellInfo->GetSchoolMask(), victim, spellInfo) * 10000.f); // 100 for spell calculations, and 100 for return value percentage + resist_chance += int32(Unit::CalculateAverageResistReduction(this, spellInfo->GetSchoolMask(), victim, spellInfo) * 10000.f); // 100 for spell calculations, and 100 for return value percentage } // Roll chance @@ -3890,7 +3904,7 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, U caster->GetLimitedCastAuras(aura->GetId()).push_back(aura); } // FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate - newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? 1 : aura->GetCharges(), 1, recalculateMask, &damage[0]); + newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? 1 : aura->GetCharges(), 1, recalculateMask, aura->GetCritChance(), aura->CanApplyResilience(), &damage[0]); newAura->ApplyForTargets(); } } @@ -5211,16 +5225,17 @@ void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 SpellID, uint32 Damag SendSpellNonMeleeDamageLog(&log); } -void Unit::ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo) +/*static*/ void Unit::ProcSkillsAndAuras(Unit* actor, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo) { WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK; - if (typeMaskActor) - ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType); + if (typeMaskActor && actor) + actor->ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType); if (typeMaskActionTarget && actionTarget) - actionTarget->ProcSkillsAndReactives(true, this, typeMaskActionTarget, hitMask, attType); + actionTarget->ProcSkillsAndReactives(true, actor, typeMaskActionTarget, hitMask, attType); - TriggerAurasProcOnEvent(actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); + if (actor) + actor->TriggerAurasProcOnEvent(actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); } void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo) @@ -6297,39 +6312,45 @@ void Unit::SetCharm(Unit* charm, bool apply) UpdatePetCombatState(); } -void Unit::DealHeal(HealInfo& healInfo) +/*static*/ void Unit::DealHeal(HealInfo& healInfo) { int32 gain = 0; + Unit* healer = healInfo.GetHealer(); Unit* victim = healInfo.GetTarget(); uint32 addhealth = healInfo.GetHeal(); - if (UnitAI* victimAI = victim->GetAI()) - victimAI->HealReceived(this, addhealth); + if (healer) + { + if (UnitAI* victimAI = victim->GetAI()) + victimAI->HealReceived(healer, addhealth); - if (UnitAI* healerAI = GetAI()) - healerAI->HealDone(victim, addhealth); + if (UnitAI* healerAI = healer->GetAI()) + healerAI->HealDone(victim, addhealth); + } if (addhealth) gain = victim->ModifyHealth(int32(addhealth)); // Hook for OnHeal Event - sScriptMgr->OnHeal(this, victim, (uint32&)gain); + sScriptMgr->OnHeal(healer, victim, (uint32&)gain); - Unit* unit = this; + Unit* unit = healer; + if (healer && healer->GetTypeId() == TYPEID_UNIT && healer->IsTotem()) + unit = healer->GetOwner(); - if (GetTypeId() == TYPEID_UNIT && IsTotem()) - unit = GetOwner(); - - if (Player* player = unit->ToPlayer()) + if (unit) { - if (Battleground* bg = player->GetBattleground()) - bg->UpdatePlayerScore(player, SCORE_HEALING_DONE, gain); + if (Player* player = unit->ToPlayer()) + { + if (Battleground* bg = player->GetBattleground()) + bg->UpdatePlayerScore(player, SCORE_HEALING_DONE, gain); - // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria) - if (gain) - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, 0, victim); + // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria) + if (gain) + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, 0, victim); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST, addhealth); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST, addhealth); + } } if (Player* player = victim->ToPlayer()) @@ -6579,9 +6600,8 @@ void Unit::SendHealSpellLog(HealInfo& healInfo, bool critical /*= false*/) int32 Unit::HealBySpell(HealInfo& healInfo, bool critical /*= false*/) { // calculate heal absorb and reduce healing - CalcHealAbsorb(healInfo); - - DealHeal(healInfo); + Unit::CalcHealAbsorb(healInfo); + Unit::DealHeal(healInfo); SendHealSpellLog(healInfo, critical); return healInfo.GetEffectiveHeal(); } @@ -9262,7 +9282,7 @@ void Unit::AtEnterCombat() InterruptNonMeleeSpells(false); RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::EnteringCombat); - ProcSkillsAndAuras(nullptr, PROC_FLAG_ENTER_COMBAT, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); + ProcSkillsAndAuras(this, nullptr, PROC_FLAG_ENTER_COMBAT, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); } void Unit::AtExitCombat() @@ -11723,14 +11743,20 @@ void Unit::PlayOneShotAnimKitId(uint16 animKitId) SendMessageToSet(packet.Write(), true); } -void Unit::Kill(Unit* victim, bool durabilityLoss) +/*static*/ void Unit::Kill(Unit* attacker, Unit* victim, bool durabilityLoss /*= true*/) { // Prevent killing unit twice (and giving reward from kill twice) if (!victim->GetHealth()) return; + if (attacker && !attacker->IsInMap(victim)) + attacker = nullptr; + // find player: owner of controlled `this` or `this` itself maybe - Player* player = GetCharmerOrOwnerPlayerOrPlayerItself(); + Player* player = nullptr; + if (attacker) + player = attacker->GetCharmerOrOwnerPlayerOrPlayerItself(); + Creature* creature = victim->ToCreature(); bool isRewardAllowed = true; @@ -11843,23 +11869,24 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) } // Do KILL and KILLED procs. KILL proc is called only for the unit who landed the killing blow (and its owner - for pets and totems) regardless of who tapped the victim - if (IsPet() || IsTotem()) + if (attacker && (attacker->IsPet() || attacker->IsTotem())) { // proc only once for victim - if (Unit* owner = GetOwner()) - owner->ProcSkillsAndAuras(victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); + if (Unit* owner = attacker->GetOwner()) + Unit::ProcSkillsAndAuras(owner, victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); } if (!victim->IsCritter()) - ProcSkillsAndAuras(victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); + Unit::ProcSkillsAndAuras(attacker, victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); // Proc auras on death - must be before aura/combat remove - victim->ProcSkillsAndAuras(victim, PROC_FLAG_NONE, PROC_FLAG_DEATH, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); + Unit::ProcSkillsAndAuras(victim, victim, PROC_FLAG_NONE, PROC_FLAG_DEATH, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); // update get killing blow achievements, must be done before setDeathState to be able to require auras on target // and before Spirit of Redemption as it also removes auras - if (Player* killerPlayer = GetCharmerOrOwnerPlayerOrPlayerItself()) - killerPlayer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, 0, victim); + if (attacker) + if (Player* killerPlayer = attacker->GetCharmerOrOwnerPlayerOrPlayerItself()) + killerPlayer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, 0, victim); TC_LOG_DEBUG("entities.unit", "SET JUST_DIED"); victim->setDeathState(JUST_DIED); @@ -11895,11 +11922,11 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) // Durability loss is calculated more accurately again for each item in Player::DurabilityLoss plrVictim->DurabilityLossAll(baseLoss, false); // durability lost message - SendDurabilityLoss(plrVictim, loss); + plrVictim->SendDurabilityLoss(plrVictim, loss); } // Call KilledUnit for creatures - if (IsCreature() && IsAIEnabled()) - ToCreature()->AI()->KilledUnit(victim); + if (attacker && attacker->IsCreature() && attacker->IsAIEnabled()) + attacker->ToCreature()->AI()->KilledUnit(victim); // last damage from non duel opponent or opponent controlled creature if (plrVictim->duel) @@ -11923,31 +11950,30 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) } // Call KilledUnit for creatures, this needs to be called after the lootable flag is set - if (IsCreature() && IsAIEnabled()) - ToCreature()->AI()->KilledUnit(victim); + if (attacker && attacker->IsCreature() && attacker->IsAIEnabled()) + attacker->ToCreature()->AI()->KilledUnit(victim); // Call creature just died function if (CreatureAI* ai = creature->AI()) - ai->JustDied(this); + ai->JustDied(attacker); if (TempSummon* summon = creature->ToTempSummon()) if (Unit* summoner = summon->GetSummoner()) if (summoner->ToCreature() && summoner->IsAIEnabled()) - summoner->ToCreature()->AI()->SummonedCreatureDies(creature, this); + summoner->ToCreature()->AI()->SummonedCreatureDies(creature, attacker); // Dungeon specific stuff, only applies to players killing creatures if (creature->GetInstanceId()) { Map* instanceMap = creature->GetMap(); - Player* creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself(); /// @todo do instance binding anyway if the charmer/owner is offline - if (instanceMap->IsDungeon() && (creditedPlayer || this == victim)) + if (instanceMap->IsDungeon() && ((attacker && attacker->GetCharmerOrOwnerPlayerOrPlayerItself()) || attacker == victim)) { if (instanceMap->IsRaidOrHeroicDungeon()) { if (creature->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND) - ((InstanceMap*)instanceMap)->PermBindAllPlayers(); + instanceMap->ToInstanceMap()->PermBindAllPlayers(); } else { @@ -11964,7 +11990,7 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) // outdoor pvp things, do these after setting the death state, else the player activity notify won't work... doh... // handle player kill only if not suicide (spirit of redemption for example) - if (player && this != victim) + if (player && attacker != victim) { if (OutdoorPvP* pvp = player->GetOutdoorPvP()) pvp->HandleKill(player, victim); @@ -11990,26 +12016,29 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) } // achievement stuff - if (victim->GetTypeId() == TYPEID_PLAYER) + if (attacker && victim->GetTypeId() == TYPEID_PLAYER) { - if (GetTypeId() == TYPEID_UNIT) - victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry()); - else if (GetTypeId() == TYPEID_PLAYER && victim != this) - victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, ToPlayer()->GetTeam()); + if (attacker->GetTypeId() == TYPEID_UNIT) + victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, attacker->GetEntry()); + else if (attacker->GetTypeId() == TYPEID_PLAYER && victim != attacker) + victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, attacker->ToPlayer()->GetTeam()); } // Hook for OnPVPKill Event - if (Player* killerPlr = ToPlayer()) + if (attacker) { - if (Player* killedPlr = victim->ToPlayer()) - sScriptMgr->OnPVPKill(killerPlr, killedPlr); - else if (Creature* killedCre = victim->ToCreature()) - sScriptMgr->OnCreatureKill(killerPlr, killedCre); - } - else if (Creature* killerCre = ToCreature()) - { - if (Player* killed = victim->ToPlayer()) - sScriptMgr->OnPlayerKilledByCreature(killerCre, killed); + if (Player* killerPlr = attacker->ToPlayer()) + { + if (Player* killedPlr = victim->ToPlayer()) + sScriptMgr->OnPVPKill(killerPlr, killedPlr); + else if (Creature* killedCre = victim->ToCreature()) + sScriptMgr->OnCreatureKill(killerPlr, killedCre); + } + else if (Creature* killerCre = attacker->ToCreature()) + { + if (Player* killed = victim->ToPlayer()) + sScriptMgr->OnPlayerKilledByCreature(killerCre, killed); + } } } @@ -12793,21 +12822,26 @@ void Unit::CancelSpellMissiles(uint32 spellId, bool reverseMissile /*= false*/) } } -void Unit::ApplyResilience(Unit const* victim, int32* damage) const +bool Unit::CanApplyResilience() const +{ + return !IsVehicle() && GetOwnerGUID().IsPlayer(); +} + +/*static*/ void Unit::ApplyResilience(Unit const* victim, int32* damage) { // player mounted on multi-passenger mount is also classified as vehicle - if (IsVehicle() || (victim->IsVehicle() && victim->GetTypeId() != TYPEID_PLAYER)) - return; - - // Don't consider resilience if not in PvP - player or pet - if (!GetCharmerOrOwnerPlayerOrPlayerItself()) + if (victim->IsVehicle() && victim->GetTypeId() != TYPEID_PLAYER) return; Unit const* target = nullptr; if (victim->GetTypeId() == TYPEID_PLAYER) target = victim; - else if (victim->GetTypeId() == TYPEID_UNIT && victim->GetOwner() && victim->GetOwner()->GetTypeId() == TYPEID_PLAYER) - target = victim->GetOwner(); + else // victim->GetTypeId() == TYPEID_UNIT + { + if (Unit* owner = victim->GetOwner()) + if (owner->GetTypeId() == TYPEID_PLAYER) + target = owner; + } if (!target) return; @@ -12815,6 +12849,15 @@ void Unit::ApplyResilience(Unit const* victim, int32* damage) const *damage -= target->GetDamageReduction(*damage); } +int32 Unit::CalculateAOEAvoidance(int32 damage, uint32 schoolMask, Unit* caster) const +{ + damage = int32(float(damage) * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, schoolMask)); + if (caster->GetTypeId() == TYPEID_UNIT) + damage = int32(float(damage) * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, schoolMask)); + + return damage; +} + // Melee based spells can be miss, parry or dodge on this step // Crit or block - determined on damage calculation phase! (and can be both in some time) float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, SpellInfo const* spellInfo /*= nullptr*/) const diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 6bf39a5521..8a162802c3 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -941,7 +941,7 @@ class TC_GAME_API Unit : public WorldObject uint32 GetResistance(SpellSchools school) const { return GetUInt32Value(UNIT_FIELD_RESISTANCES+school); } uint32 GetResistance(SpellSchoolMask mask) const; void SetResistance(SpellSchools school, int32 val) { SetStatInt32Value(UNIT_FIELD_RESISTANCES+school, val); } - float CalculateAverageResistReduction(SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo = nullptr) const; + static float CalculateAverageResistReduction(Unit const* attacker, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo = nullptr); uint32 GetHealth() const { return GetUInt32Value(UNIT_FIELD_HEALTH); } uint32 GetMaxHealth() const { return GetUInt32Value(UNIT_FIELD_MAXHEALTH); } @@ -1036,13 +1036,13 @@ class TC_GAME_API Unit : public WorldObject void PlayOneShotAnimKitId(uint16 animKitId); uint32 GetMaxSkillValueForLevel(Unit const* target = nullptr) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } - void DealDamageMods(Unit const* victim, uint32 &damage, uint32* absorb) const; - uint32 DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDamage = nullptr, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = nullptr, bool durabilityLoss = true); - void Kill(Unit* victim, bool durabilityLoss = true); - void KillSelf(bool durabilityLoss = true) { Kill(this, durabilityLoss); } - void DealHeal(HealInfo& healInfo); + static void DealDamageMods(Unit const* victim, uint32& damage, uint32* absorb); + static uint32 DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage = nullptr, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = nullptr, bool durabilityLoss = true); + static void Kill(Unit* attacker, Unit* victim, bool durabilityLoss = true); + void KillSelf(bool durabilityLoss = true) { Unit::Kill(this, this, durabilityLoss); } + static void DealHeal(HealInfo& healInfo); - void ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, + static void ProcSkillsAndAuras(Unit* actor, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo); @@ -1066,7 +1066,10 @@ class TC_GAME_API Unit : public WorldObject // player or player's pet resilience (-1%) uint32 GetDamageReduction(uint32 damage) const { return GetCombatRatingDamageReduction(CR_RESILIENCE_PLAYER_DAMAGE_TAKEN, 1.0f, 100.0f, damage); } - void ApplyResilience(Unit const* victim, int32* damage) const; + virtual bool CanApplyResilience() const; + static void ApplyResilience(Unit const* victim, int32* damage); + + int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, Unit* caster) const; float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, SpellInfo const* spellInfo = nullptr) const; SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo); @@ -1666,10 +1669,10 @@ class TC_GAME_API Unit : public WorldObject virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const; // redefined in Creature static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const* spellInfo = nullptr, int8 effIndex = -1); - uint32 CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = MAX_ATTACK) const; - uint32 CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) const; - void CalcAbsorbResist(DamageInfo& damageInfo); - void CalcHealAbsorb(HealInfo& healInfo) const; + static uint32 CalcArmorReducedDamage(Unit const* attacker, Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = MAX_ATTACK, uint8 attackerLevel = 0); + static uint32 CalcSpellResistedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo); + static void CalcAbsorbResist(DamageInfo& damageInfo); + static void CalcHealAbsorb(HealInfo& healInfo); void UpdateSpeed(UnitMoveType mtype); float GetSpeed(UnitMoveType mtype) const; diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 41d73f1f34..d9200ca060 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -453,7 +453,7 @@ void WorldSession::HandleMovementOpcode(uint16 opcode, MovementInfo& movementInf if (opcode == MSG_MOVE_JUMP) { plrMover->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2::Jump); - plrMover->ProcSkillsAndAuras(nullptr, PROC_FLAG_JUMP, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); + Unit::ProcSkillsAndAuras(plrMover, nullptr, PROC_FLAG_JUMP, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); } } } diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index cac4c41d67..9545d85861 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -441,12 +441,12 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= AuraEffect::AuraEffect(Aura* base, uint8 effIndex, int32 *baseAmount, Unit* caster): m_base(base), m_spellInfo(base->GetSpellInfo()), m_baseAmount(baseAmount ? *baseAmount : m_spellInfo->Effects[effIndex].BasePoints), -m_bonusAmount(0), m_donePct(1.0f), m_spellmod(nullptr), m_periodicTimer(0), m_tickNumber(0), +m_spellmod(nullptr), m_periodicTimer(0), m_tickNumber(0), m_effIndex(effIndex), m_canBeRecalculated(true), m_isPeriodic(false) { CalculatePeriodic(caster, true, false); - m_amount = CalculateAmount(caster); + _amount = CalculateAmount(caster); CalculateSpellMod(); } @@ -481,7 +481,7 @@ void AuraEffect::GetApplicationList(Container& applicationContainer) const void AuraEffect::SetAmount(int32 amount) { - m_amount = amount; + _amount = amount; m_canBeRecalculated = false; if (GetSpellInfo()->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT) || Aura::EffectTypeNeedsSendingAmount(GetAuraType())) @@ -726,7 +726,7 @@ void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply) if (handleMask & AURA_EFFECT_HANDLE_CHANGE_AMOUNT) { if (!mark) - m_amount = newAmount; + _amount = newAmount; else SetAmount(newAmount); CalculateSpellMod(); @@ -3083,7 +3083,7 @@ void AuraEffect::HandleAuraControlVehicle(AuraApplication const* aurApp, uint8 m // so this break such spells or most of them. // Current formula about m_amount: effect base points + dieside - 1 // TO DO: Reasearch more about 0/0 and fix it. - caster->_EnterVehicle(target->GetVehicleKit(), m_amount - 1, aurApp); + caster->_EnterVehicle(target->GetVehicleKit(), _amount - 1, aurApp); } else { @@ -3092,7 +3092,7 @@ void AuraEffect::HandleAuraControlVehicle(AuraApplication const* aurApp, uint8 m if (GetId() == 53111) // Devour Humanoid { - target->Kill(caster); + Unit::Kill(target, caster); if (caster->GetTypeId() == TYPEID_UNIT) caster->ToCreature()->DespawnOrUnsummon(); } @@ -3548,7 +3548,7 @@ void AuraEffect::HandleModPercentStat(AuraApplication const* aurApp, uint8 mode, if (GetMiscValue() == i || GetMiscValue() == -1) { if (apply) - target->ApplyStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(m_amount)); + target->ApplyStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(GetAmount())); else { float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [i](AuraEffect const* aurEff) -> bool @@ -4096,7 +4096,7 @@ void AuraEffect::HandleModCombatSpeedPct(AuraApplication const* aurApp, uint8 mo target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply); target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(spellGroupVal), !apply); } - target->ApplyCastTimePercentMod(float(m_amount), apply); + target->ApplyCastTimePercentMod(float(GetAmount()), apply); target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply); target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply); target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(GetAmount()), apply); @@ -4299,7 +4299,7 @@ void AuraEffect::HandleOverrideSpellPowerByAttackPower(AuraApplication const* au if (!target) return; - target->ApplyModSignedFloatValue(PLAYER_FIELD_OVERRIDE_SPELL_POWER_BY_AP_PCT, float(m_amount), apply); + target->ApplyModSignedFloatValue(PLAYER_FIELD_OVERRIDE_SPELL_POWER_BY_AP_PCT, float(GetAmount()), apply); target->UpdateSpellDamageAndHealingBonus(); } @@ -4894,7 +4894,7 @@ void AuraEffect::HandleChannelDeathItem(AuraApplication const* aurApp, uint8 mod //Adding items uint32 noSpaceForCount = 0; - uint32 count = m_amount; + uint32 count = GetAmount(); ItemPosCountVec dest; InventoryResult msg = plCaster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, GetSpellInfo()->Effects[m_effIndex].ItemType, count, &noSpaceForCount); @@ -4942,7 +4942,7 @@ void AuraEffect::HandleForceReaction(AuraApplication const* aurApp, uint8 mode, return; uint32 factionId = GetMiscValue(); - ReputationRank factionRank = ReputationRank(m_amount); + ReputationRank factionRank = ReputationRank(GetAmount()); player->GetReputationMgr().ApplyForceReaction(factionId, factionRank, apply); player->GetReputationMgr().SendForceReactions(); @@ -5033,7 +5033,7 @@ void AuraEffect::HandleAuraConvertRune(AuraApplication const* aurApp, uint8 mode * Amount is the number of runes that will be converted if available */ - uint32 runes = m_amount; + uint32 runes = GetAmount(); if (apply) { @@ -5296,7 +5296,7 @@ void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const if (caster) { CastSpellExtraArgs args; - args.SpellValueOverrides.AddMod(SpellValueMod(SPELLVALUE_BASE_POINT0), m_amount); + args.SpellValueOverrides.AddMod(SpellValueMod(SPELLVALUE_BASE_POINT0), GetAmount()); args.SetTriggeringAura(this); caster->CastSpell(target, 53352, args); } @@ -5333,7 +5333,7 @@ void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const { case 49016: // Hysteria uint32 damage = uint32(target->CountPctFromMaxHealth(1)); - target->DealDamage(target, damage, nullptr, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + Unit::DealDamage(target, target, damage, nullptr, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); break; } // Blood of the North @@ -5564,7 +5564,7 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) case 16191: { CastSpellExtraArgs args(this); - args.SpellValueOverrides.AddMod(SPELLVALUE_BASE_POINT0, m_amount); + args.SpellValueOverrides.AddMod(SPELLVALUE_BASE_POINT0, GetAmount()); args.SetTriggeringAura(this); target->CastSpell(target, triggerSpellId, args); return; @@ -5655,7 +5655,10 @@ void AuraEffect::HandlePeriodicTriggerSpellWithValueAuraTick(Unit* target, Unit* void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const { - if (!caster || !target->IsAlive()) + // dynobj auras must always have a caster + ASSERT(GetSpellInfo()->Effects[GetEffIndex()].Effect != SPELL_EFFECT_PERSISTENT_AREA_AURA || caster); + + if (!target->IsAlive()) return; if (target->HasUnitState(UNIT_STATE_ISOLATED) || target->IsImmunedToDamage(GetSpellInfo())) @@ -5763,18 +5766,24 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const // Calculate armor mitigation if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), GetEffIndex())) { - uint32 damageReductedArmor = caster->CalcArmorReducedDamage(target, damage, GetSpellInfo()); + uint32 damageReductedArmor = Unit::CalcArmorReducedDamage(caster, target, damage, GetSpellInfo()); cleanDamage.mitigated_damage += damage - damageReductedArmor; damage = damageReductedArmor; } - int32 dmg = damage; if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE)) - caster->ApplyResilience(target, &dmg); + { + if (GetSpellInfo()->Effects[GetEffIndex()].IsTargetingArea() || GetSpellInfo()->Effects[GetEffIndex()].IsAreaAuraEffect() || GetSpellInfo()->Effects[GetEffIndex()].Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA) + damage = target->CalculateAOEAvoidance(damage, m_spellInfo->SchoolMask, caster); + } + + int32 dmg = damage; + if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE) && GetBase()->CanApplyResilience()) + Unit::ApplyResilience(target, &dmg); damage = dmg; DamageInfo damageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK); - caster->CalcAbsorbResist(damageInfo); + Unit::CalcAbsorbResist(damageInfo); damage = damageInfo.GetDamage(); uint32 absorb = damageInfo.GetAbsorb(); @@ -5782,7 +5791,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s attacked %s for %u dmg inflicted by %u absorb is %u", GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId(), absorb); - caster->DealDamageMods(target, damage, &absorb); + Unit::DealDamageMods(target, damage, &absorb); // Set trigger flag uint32 procAttacker = PROC_FLAG_NONE, procVictim = PROC_FLAG_NONE; @@ -5806,14 +5815,17 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const SpellPeriodicAuraLogInfo pInfo(this, damage, overkill, absorb, resist, 0.0f, crit); target->SendPeriodicAuraLog(&pInfo); - caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true); + Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true); - caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, nullptr, &damageInfo, nullptr); + Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, nullptr, &damageInfo, nullptr); } void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const { - if (!caster || !target->IsAlive()) + // dynobj auras must always have a caster + ASSERT(GetSpellInfo()->Effects[GetEffIndex()].Effect != SPELL_EFFECT_PERSISTENT_AREA_AURA || caster); + + if (!target->IsAlive()) return; if (target->HasUnitState(UNIT_STATE_ISOLATED) || target->IsImmunedToDamage(GetSpellInfo())) @@ -5851,28 +5863,24 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c // Calculate armor mitigation if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), GetEffIndex())) { - uint32 damageReductedArmor = caster->CalcArmorReducedDamage(target, damage, GetSpellInfo()); + uint32 damageReductedArmor = Unit::CalcArmorReducedDamage(caster, target, damage, GetSpellInfo()); cleanDamage.mitigated_damage += damage - damageReductedArmor; damage = damageReductedArmor; } - if (!m_spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE)) + if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE)) { if (GetSpellInfo()->Effects[GetEffIndex()].IsTargetingArea() || GetSpellInfo()->Effects[GetEffIndex()].IsAreaAuraEffect() || GetSpellInfo()->Effects[GetEffIndex()].Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA) - { - damage = uint32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); - if (caster->GetTypeId() != TYPEID_PLAYER) - damage = uint32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); - } + damage = target->CalculateAOEAvoidance(damage, m_spellInfo->SchoolMask, caster); } int32 dmg = damage; - if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE)) - caster->ApplyResilience(target, &dmg); + if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE) && GetBase()->CanApplyResilience()) + Unit::ApplyResilience(target, &dmg); damage = dmg; DamageInfo damageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK); - caster->CalcAbsorbResist(damageInfo); + Unit::CalcAbsorbResist(damageInfo); uint32 absorb = damageInfo.GetAbsorb(); uint32 resist = damageInfo.GetResist(); @@ -5899,22 +5907,22 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c procVictim |= PROC_FLAG_TAKE_ANY_DAMAGE; } - int32 new_damage = caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false); - if (caster->IsAlive()) - { - caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, nullptr, &damageInfo, nullptr); + int32 new_damage = Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false); + if (!caster || !caster->IsAlive()) + return; - float gainMultiplier = GetSpellInfo()->Effects[GetEffIndex()].CalcValueMultiplier(caster); + Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, nullptr, &damageInfo, nullptr); - uint32 heal = uint32(caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, GetEffIndex(), GetBase()->GetStackAmount())); - heal = uint32(caster->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT, GetBase()->GetStackAmount())); + float gainMultiplier = GetSpellInfo()->Effects[GetEffIndex()].CalcValueMultiplier(caster); - HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); - caster->HealBySpell(healInfo); + uint32 heal = uint32(caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, GetEffIndex(), GetBase()->GetStackAmount())); + heal = uint32(caster->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT, GetBase()->GetStackAmount())); - caster->GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo()); - caster->ProcSkillsAndAuras(caster, PROC_FLAG_DEAL_PERIODIC, PROC_FLAG_TAKE_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, nullptr, nullptr, &healInfo); - } + HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); + caster->HealBySpell(healInfo); + + caster->GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo()); + Unit::ProcSkillsAndAuras(caster, caster, PROC_FLAG_DEAL_PERIODIC, PROC_FLAG_TAKE_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, nullptr, nullptr, &healInfo); } void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) const @@ -5944,12 +5952,15 @@ void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) HealInfo healInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); caster->HealBySpell(healInfo); - caster->ProcSkillsAndAuras(target, PROC_FLAG_DEAL_PERIODIC, PROC_FLAG_TAKE_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, PROC_HIT_NORMAL, nullptr, nullptr, &healInfo); + Unit::ProcSkillsAndAuras(caster, target, PROC_FLAG_DEAL_PERIODIC, PROC_FLAG_TAKE_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, PROC_HIT_NORMAL, nullptr, nullptr, &healInfo); } void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const { - if (!caster || !target->IsAlive()) + // dynobj auras must always have a caster + ASSERT(GetSpellInfo()->Effects[GetEffIndex()].Effect != SPELL_EFFECT_PERSISTENT_AREA_AURA || caster); + + if (!target->IsAlive()) return; if (target->HasUnitState(UNIT_STATE_ISOLATED)) @@ -5959,66 +5970,28 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const } // heal for caster damage (must be alive) - if (target != caster && GetSpellInfo()->HasAttribute(SPELL_ATTR2_HEALTH_FUNNEL) && !caster->IsAlive()) + if (target != caster && GetSpellInfo()->HasAttribute(SPELL_ATTR2_HEALTH_FUNNEL) && (!caster || !caster->IsAlive())) return; // don't regen when permanent aura target has full power if (GetBase()->IsPermanent() && target->IsFullHealth()) return; - bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); // ignore negative values (can be result apply spellmods to aura damage - uint32 damage = std::max(GetAmount() + GetBonusAmount(), 0); // if isAreaAura == true, GetBonusAmount == 0. + uint32 damage = std::max(GetAmount(), 0); // Script Hook For HandlePeriodicHealAurasTick -- Allow scripts to change the Damage pre class mitigation calculations sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); if (GetAuraType() == SPELL_AURA_OBS_MOD_HEALTH) - { - // Taken mods - float TakenTotalMod = 1.0f; - - // Tenacity increase healing % taken - if (AuraEffect const* Tenacity = target->GetAuraEffect(58549, 0)) - AddPct(TakenTotalMod, Tenacity->GetAmount()); - - // Healing taken percent - float minval = (float)target->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT); - if (minval) - AddPct(TakenTotalMod, minval); - - float maxval = (float)target->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT); - if (maxval) - AddPct(TakenTotalMod, maxval); - - TakenTotalMod = std::max(TakenTotalMod, 0.0f); - damage = uint32(target->CountPctFromMaxHealth(damage)); - damage = uint32(damage * TakenTotalMod); - } else { - // Wild Growth = amount + (6 - 2*doneTicks) * ticks* amount / 100 - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellIconID == 2864) - { - int32 addition = int32(float(damage * GetTotalTicks()) * ((6-float(2*(GetTickNumber()-1)))/100)); - - // Item - Druid T10 Restoration 2P Bonus - if (AuraEffect* aurEff = caster->GetAuraEffect(70658, 0)) - // divided by 50 instead of 100 because calculated as for every 2 tick - addition += abs(int32((addition * aurEff->GetAmount()) / 50)); - - damage += addition; - } - - if (isAreaAura) + if (GetBase()->GetType() == DYNOBJ_AURA_TYPE) damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, GetEffIndex(), GetBase()->GetStackAmount()) * caster->SpellHealingPctDone(target, m_spellInfo); - else - damage = std::max(int32(damage * GetDonePct()), 0); - - damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); } + damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); bool crit = false; @@ -6034,13 +6007,14 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const uint32 heal = damage; HealInfo healInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); - caster->CalcHealAbsorb(healInfo); - caster->DealHeal(healInfo); + Unit::CalcHealAbsorb(healInfo); + Unit::DealHeal(healInfo); SpellPeriodicAuraLogInfo pInfo(this, heal, heal - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit); target->SendPeriodicAuraLog(&pInfo); - target->GetThreatManager().ForwardThreatForAssistingMe(caster, float(healInfo.GetEffectiveHeal()) * 0.5f, GetSpellInfo()); + if (caster) + target->GetThreatManager().ForwardThreatForAssistingMe(caster, float(healInfo.GetEffectiveHeal()) * 0.5f, GetSpellInfo()); bool haveCastItem = !GetBase()->GetCastItemGUID().IsEmpty(); @@ -6054,11 +6028,11 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const funnelDamage = healInfo.GetEffectiveHeal(); uint32 funnelAbsorb = 0; - caster->DealDamageMods(caster, funnelDamage, &funnelAbsorb); + Unit::DealDamageMods(caster, funnelDamage, &funnelAbsorb); caster->SendSpellNonMeleeDamageLog(caster, GetId(), funnelDamage, GetSpellInfo()->GetSchoolMask(), funnelAbsorb, 0, false, 0, false); CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - caster->DealDamage(caster, funnelDamage, &cleanDamage, NODAMAGE, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true); + Unit::DealDamage(caster, caster, funnelDamage, &cleanDamage, SELF_DAMAGE, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true); } // %-based heal - does not proc auras @@ -6074,7 +6048,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const uint32 hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL; // ignore item heals if (!haveCastItem) - caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, nullptr, nullptr, &healInfo); + Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, nullptr, nullptr, &healInfo); } void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const @@ -6095,7 +6069,7 @@ void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) con return; // ignore negative values (can be result apply spellmods to aura damage - int32 drainAmount = std::max(m_amount, 0); + int32 drainAmount = std::max(GetAmount(), 0); // Special case: draining x% of mana (up to a maximum of 2*x% of the caster's maximum mana) // It's mana percent cost spells, m_amount is percent drain from target @@ -6166,7 +6140,7 @@ void AuraEffect::HandleObsModPowerAuraTick(Unit* target, Unit* caster) const return; // ignore negative values (can be result apply spellmods to aura damage - uint32 amount = std::max(m_amount, 0) * target->GetMaxPower(powerType) /100; + uint32 amount = std::max(GetAmount(), 0) * target->GetMaxPower(powerType) / 100; TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s energize %s for %u dmg inflicted by %u", GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), amount, GetId()); @@ -6196,7 +6170,7 @@ void AuraEffect::HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) cons return; // ignore negative values (can be result apply spellmods to aura damage - int32 amount = std::max(m_amount, 0); + int32 amount = std::max(GetAmount(), 0); SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f, false); target->SendPeriodicAuraLog(&pInfo); @@ -6224,7 +6198,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con } // ignore negative values (can be result apply spellmods to aura damage - int32 damage = std::max(m_amount, 0); + int32 damage = std::max(GetAmount(), 0); uint32 gain = uint32(-target->ModifyPower(powerType, -damage)); @@ -6236,7 +6210,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con // no SpellDamageBonus for burn mana caster->CalculateSpellDamageTaken(&damageInfo, int32(gain * dmgMultiplier), spellProto); - caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); + Unit::DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); caster->SendSpellNonMeleeDamageLog(&damageInfo); @@ -6260,7 +6234,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con caster->DealSpellDamage(&damageInfo, true); DamageInfo dotDamageInfo(damageInfo, DOT, BASE_ATTACK, hitMask); - caster->ProcSkillsAndAuras(target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_HIT, hitMask, nullptr, &dotDamageInfo, nullptr); + Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_HIT, hitMask, nullptr, &dotDamageInfo, nullptr); } void AuraEffect::HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) @@ -6334,7 +6308,7 @@ void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEv uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE, GetEffIndex()); damage = triggerTarget->SpellDamageBonusTaken(target, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE); target->CalculateSpellDamageTaken(&damageInfo, damage, GetSpellInfo()); - target->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); + Unit:: DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); target->SendSpellNonMeleeDamageLog(&damageInfo); TC_LOG_DEBUG("spells", "AuraEffect::HandleProcTriggerDamageAuraProc: Triggering %u spell damage from aura %u proc", damage, GetId()); target->DealSpellDamage(&damageInfo, true); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index eb5d3479fa..a9579f18b7 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -54,7 +54,7 @@ class TC_GAME_API AuraEffect int32 GetMiscValueB() const { return m_spellInfo->Effects[m_effIndex].MiscValueB; } int32 GetMiscValue() const { return m_spellInfo->Effects[m_effIndex].MiscValue; } AuraType GetAuraType() const { return (AuraType)m_spellInfo->Effects[m_effIndex].ApplyAuraName; } - int32 GetAmount() const { return m_amount; } + int32 GetAmount() const { return _amount; } void SetAmount(int32 amount); int32 GetPeriodicTimer() const { return m_periodicTimer; } @@ -72,11 +72,6 @@ class TC_GAME_API AuraEffect void HandleEffect(Unit* target, uint8 mode, bool apply); void ApplySpellMod(Unit* target, bool apply); - void SetBonusAmount(int32 val) { m_bonusAmount = val; } - int32 GetBonusAmount() const { return m_bonusAmount; } - void SetDonePct(float val) { m_donePct = val; } - float GetDonePct() const { return m_donePct; } - void Update(uint32 diff, Unit* caster); void UpdatePeriodic(Unit* caster); @@ -105,9 +100,7 @@ class TC_GAME_API AuraEffect SpellInfo const* const m_spellInfo; int32 const m_baseAmount; - int32 m_amount; - int32 m_bonusAmount; - float m_donePct; + int32 _amount; SpellModifier* m_spellmod; diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 091f5c1805..1ee5831152 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -357,7 +357,7 @@ Aura::Aura(SpellInfo const* spellproto, WorldObject* owner, Unit* caster, Item* m_spellInfo(spellproto), m_casterGuid(casterGUID ? casterGUID : caster->GetGUID()), m_castItemGuid(castItem ? castItem->GetGUID() : ObjectGuid::Empty), m_applyTime(GameTime::GetGameTime()), m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0), -m_casterLevel(caster ? caster->getLevel() : m_spellInfo->SpellLevel), m_procCharges(0), m_stackAmount(1), +_casterInfo(), m_procCharges(0), m_stackAmount(1), m_isRemoved(false), m_isLimitedTarget(false), m_isUsingCharges(false), m_dropEvent(nullptr), m_procCooldown(std::chrono::steady_clock::time_point::min()) { @@ -371,7 +371,15 @@ m_procCooldown(std::chrono::steady_clock::time_point::min()) m_procCharges = CalcMaxCharges(caster); m_isUsingCharges = m_procCharges != 0; memset(m_effects, 0, sizeof(m_effects)); + // m_casterLevel = cast item level/caster level, caster level should be saved to db, confirmed with sniffs + _casterInfo.Level = m_spellInfo->SpellLevel; + if (caster) + { + _casterInfo.Level = caster->getLevel(); + _casterInfo.ApplyResilience = caster->CanApplyResilience(); + SaveCasterInfo(caster); + } } AuraScript* Aura::GetScriptByName(std::string const& scriptName) const @@ -394,6 +402,55 @@ void Aura::_InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount) } } +bool Aura::CanPeriodicTickCrit(Unit const* caster) const +{ + if (m_spellInfo->HasAttribute(SPELL_ATTR8_PERIODIC_CAN_CRIT)) + return true; + + return caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_PERIODIC_CRIT, GetSpellInfo()); + +} + +float Aura::CalcPeriodicCritChance(Unit const* caster) const +{ + Player* modOwner = caster->GetSpellModOwner(); + if (!modOwner || !CanPeriodicTickCrit(modOwner)) + return 0.f; + + float critChance = modOwner->SpellCritChanceDone(GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), GetSpellInfo()->GetAttackType()); + return std::max(0.f, critChance); +} + +void Aura::SaveCasterInfo(Unit* caster) +{ + _casterInfo.CritChance = CalcPeriodicCritChance(caster); + + if (GetType() == UNIT_AURA_TYPE) + { + /* + * Get critical chance from last effect type (damage or healing) + * this could potentialy be wrong if any spell has both damage and heal periodics + * The only two spells in 3.3.5 with those conditions are 17484 and 50344 + * which shouldn't be allowed to crit, so we're fine + */ + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + switch (GetSpellInfo()->Effects[i].ApplyAuraName) + { + case SPELL_AURA_PERIODIC_HEAL: + _casterInfo.BonusDonePct = caster->SpellHealingPctDone(GetUnitOwner(), GetSpellInfo()); + break; + case SPELL_AURA_PERIODIC_DAMAGE: + case SPELL_AURA_PERIODIC_LEECH: + _casterInfo.BonusDonePct = caster->SpellDamagePctDone(GetUnitOwner(), GetSpellInfo(), DOT); + break; + default: + break; + } + } + } +} + Aura::~Aura() { // unload scripts @@ -1098,13 +1155,15 @@ int32 Aura::CalcDispelChance(Unit const* auraTarget, bool offensive) const return 100 - resistChance; } -void Aura::SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, int32 * amount) +void Aura::SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, float critChance, bool applyResilience, int32* amount) { m_maxDuration = maxduration; m_duration = duration; m_procCharges = charges; m_isUsingCharges = m_procCharges != 0; m_stackAmount = stackamount; + SetCritChance(critChance); + SetCanApplyResilience(applyResilience); Unit* caster = GetCaster(); for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 55bb49028b..7901c8dad5 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -90,6 +90,15 @@ class TC_GAME_API AuraApplication void ClientUpdate(bool remove = false); }; +// Caches some information about caster (because it may no longer exist) +struct CasterInfo +{ + float CritChance = 0.f; + float BonusDonePct = 0.f; + uint8 Level = 0; + bool ApplyResilience = false; +}; + class TC_GAME_API Aura { friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); @@ -102,6 +111,7 @@ class TC_GAME_API Aura static Aura* Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID); explicit Aura(SpellInfo const* spellproto, WorldObject* owner, Unit* caster, Item* castItem, ObjectGuid casterGUID); void _InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount); + void SaveCasterInfo(Unit* caster); virtual ~Aura(); SpellInfo const* GetSpellInfo() const { return m_spellInfo; } @@ -157,7 +167,13 @@ class TC_GAME_API Aura void SetStackAmount(uint8 num); bool ModStackAmount(int32 num, AuraRemoveFlags removeMode = AuraRemoveFlags::ByDefault); - uint8 GetCasterLevel() const { return m_casterLevel; } + bool CanApplyResilience() const { return _casterInfo.ApplyResilience; } + void SetCanApplyResilience(bool val) { _casterInfo.ApplyResilience = val; } + uint8 GetCasterLevel() const { return _casterInfo.Level; } + float GetCritChance() const { return _casterInfo.CritChance; } + void SetCritChance(float val) { _casterInfo.CritChance = val; } + float GetDonePct() const { return _casterInfo.BonusDonePct; } + void SetDonePct(float val) { _casterInfo.BonusDonePct = val; } bool HasMoreThanOneEffectForType(AuraType auraType) const; bool IsArea() const; @@ -182,9 +198,12 @@ class TC_GAME_API Aura void UnregisterLimitedTarget(); int32 CalcDispelChance(Unit const* auraTarget, bool offensive) const; - void SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, int32 * amount); + void SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, float critChance, bool applyResilience, int32* amount); // helpers for aura effects + bool CanPeriodicTickCrit(Unit const* caster) const; + float CalcPeriodicCritChance(Unit const* caster) const; + bool HasEffect(uint8 effIndex) const { return GetEffect(effIndex) != nullptr; } bool HasEffectType(AuraType type) const; static bool EffectTypeNeedsSendingAmount(AuraType type); @@ -270,7 +289,7 @@ class TC_GAME_API Aura int32 m_timeCla; // Timer for power per sec calcultion int32 m_updateTargetMapInterval; // Timer for UpdateTargetMapOfEffect - uint8 const m_casterLevel; // Aura level (store caster level for correct show level dep amount) + CasterInfo _casterInfo; uint8 m_procCharges; // Aura charges (0 for infinite) uint8 m_stackAmount; // Aura stack amount diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index e043b0d7ef..42679c45d8 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2141,7 +2141,7 @@ class ProcReflectDelayed : public BasicEvent uint32 const spellPhaseMask = PROC_SPELL_PHASE_NONE; uint32 const hitMask = PROC_HIT_REFLECT; - caster->ProcSkillsAndAuras(_victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr); + Unit::ProcSkillsAndAuras(caster, _victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr); return true; } @@ -2657,7 +2657,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // Do triggers for unit if (canTriggerCasterProcs || canTriggerTargetProcs) - caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, nullptr, &healInfo); + Unit::ProcSkillsAndAuras(caster, unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, nullptr, &healInfo); } // Do damage and triggers else if (m_damage > 0) @@ -2677,7 +2677,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) { // Add bonuses and fill damageInfo struct caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo, m_attackType, target->crit); - caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); + Unit::DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); if (Creature* target = damageInfo.target->ToCreature()) if (caster->IsCreature() && !caster->IsCharmedOwnedByPlayerOrPlayer()) @@ -2699,12 +2699,12 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (canTriggerCasterProcs || canTriggerTargetProcs) { DamageInfo spellDamageInfo(damageInfo, SPELL_DIRECT_DAMAGE, m_attackType, hitMask); - caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, this, &spellDamageInfo, nullptr); + Unit::ProcSkillsAndAuras(caster, unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, this, &spellDamageInfo, nullptr); // Pets and Guardians units should trigger procs for their owner as well if (caster->IsSummon() && (caster->IsGuardian() || caster->IsPet())) if (Unit* summoner = caster->ToTempSummon()->GetSummoner()) - summoner->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, this, &spellDamageInfo, nullptr); + Unit::ProcSkillsAndAuras(summoner, unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, this, &spellDamageInfo, nullptr); if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) && !m_spellInfo->HasAttribute(SPELL_ATTR4_CANT_TRIGGER_ITEM_SPELLS) && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) @@ -2721,7 +2721,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (canTriggerCasterProcs || canTriggerTargetProcs) { DamageInfo spellNoDamageInfo(damageInfo, NODAMAGE, m_attackType, hitMask); - caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_NO_DMG_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, &spellNoDamageInfo, nullptr); + Unit::ProcSkillsAndAuras(caster, unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_NO_DMG_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, &spellNoDamageInfo, nullptr); if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) && !m_spellInfo->HasAttribute(SPELL_ATTR4_CANT_TRIGGER_ITEM_SPELLS) && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) @@ -3698,7 +3698,7 @@ void Spell::_cast(bool skipCheck) m_originalCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::ActionDelayed); m_originalCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::ActionDelayed); - m_originalCaster->ProcSkillsAndAuras(nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr); + Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr); // Call CreatureAI hook OnSuccessfulSpellCast if (Creature* caster = m_originalCaster->ToCreature()) @@ -3913,7 +3913,7 @@ void Spell::_handle_finish_phase() } } - m_originalCaster->ProcSkillsAndAuras(nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_FINISH, m_hitMask, this, nullptr, nullptr); + Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_FINISH, m_hitMask, this, nullptr, nullptr); } void Spell::SendSpellCooldown() @@ -7864,9 +7864,7 @@ void Spell::DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier) { if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->Effects[i].IsAreaAuraEffect() || m_spellInfo->Effects[i].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) { - m_damage = int32(float(m_damage) * unit->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); - if (m_caster->GetTypeId() != TYPEID_PLAYER) - m_damage = int32(float(m_damage) * unit->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); + m_damage = unit->CalculateAOEAvoidance(m_damage, m_spellInfo->SchoolMask, m_caster); if (m_caster->GetTypeId() == TYPEID_PLAYER) { @@ -7886,15 +7884,8 @@ void Spell::DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier) } } - float critChance = m_spellValue->CriticalChance; - if (m_originalCaster) - { - if (!critChance) - critChance = m_originalCaster->SpellCritChanceDone(m_spellInfo, m_spellSchoolMask, m_attackType); - critChance = unit->SpellCritChanceTaken(m_originalCaster, m_spellInfo, m_spellSchoolMask, critChance, m_attackType); - } - - targetInfo.crit = roll_chance_f(critChance); + float critChance = m_caster->SpellCritChanceDone(m_spellInfo, m_spellSchoolMask, m_attackType); + targetInfo.crit = roll_chance_f(unit->SpellCritChanceTaken(m_caster, m_spellInfo, m_spellSchoolMask, critChance, m_attackType)); } SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 6476a9b14f..75f3448bdb 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -322,7 +322,7 @@ void Spell::EffectInstaKill(SpellEffIndex /*effIndex*/) data << uint32(m_spellInfo->Id); m_caster->SendMessageToSet(&data, true); - m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), nullptr, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + Unit::DealDamage(m_caster, unitTarget, unitTarget->GetHealth(), nullptr, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); } void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/) @@ -339,7 +339,7 @@ void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/) else { DamageInfo damageInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK); - m_caster->CalcAbsorbResist(damageInfo); + Unit::CalcAbsorbResist(damageInfo); uint32 absorb = damageInfo.GetAbsorb(); uint32 resist = damageInfo.GetResist(); @@ -1166,9 +1166,7 @@ void Spell::EffectHealPct(SpellEffIndex effIndex) return; uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, unitTarget->CountPctFromMaxHealth(damage), HEAL, effIndex); - heal = unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL); - - m_healing += heal; + m_healing += unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL); } void Spell::EffectHealMechanical(SpellEffIndex effIndex) @@ -3658,7 +3656,7 @@ void Spell::EffectStuck(SpellEffIndex /*effIndex*/) // the player dies if hearthstone is in cooldown, else the player is teleported to home if (player->GetSpellHistory()->HasCooldown(8690)) { - player->Kill(player); + Unit::Kill(player, player); return; } diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 1fa443ebd4..63ec4fd448 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -638,9 +638,9 @@ public: if (target->IsAlive()) { if (sWorld->getBoolConfig(CONFIG_DIE_COMMAND_MODE)) - handler->GetSession()->GetPlayer()->Kill(target); + Unit::Kill(handler->GetSession()->GetPlayer(), target); else - handler->GetSession()->GetPlayer()->DealDamage(target, target->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + Unit::DealDamage(handler->GetSession()->GetPlayer(), target, target->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); } return true; @@ -2301,7 +2301,7 @@ public: // flat melee damage without resistence/etc reduction if (!schoolStr) { - handler->GetSession()->GetPlayer()->DealDamage(target, damage, nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + Unit::DealDamage(handler->GetSession()->GetPlayer(), target, damage, nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); if (target != handler->GetSession()->GetPlayer()) handler->GetSession()->GetPlayer()->SendAttackStateUpdate (HITINFO_AFFECTS_VICTIM, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_HIT, 0); return true; @@ -2314,7 +2314,7 @@ public: SpellSchoolMask schoolmask = SpellSchoolMask(1 << school); if (Unit::IsDamageReducedByArmor(schoolmask)) - damage = handler->GetSession()->GetPlayer()->CalcArmorReducedDamage(target, damage, nullptr, BASE_ATTACK); + damage = Unit::CalcArmorReducedDamage(handler->GetSession()->GetPlayer(), target, damage, nullptr, BASE_ATTACK); char* spellStr = strtok((char*)nullptr, " "); @@ -2323,7 +2323,7 @@ public: { Player* attacker = handler->GetSession()->GetPlayer(); DamageInfo dmgInfo(attacker, target, damage, nullptr, schoolmask, SPELL_DIRECT_DAMAGE, BASE_ATTACK); - attacker->CalcAbsorbResist(dmgInfo); + Unit::CalcAbsorbResist(dmgInfo); if (!dmgInfo.GetDamage()) return true; @@ -2332,8 +2332,8 @@ public: uint32 absorb = dmgInfo.GetAbsorb(); uint32 resist = dmgInfo.GetResist(); - attacker->DealDamageMods(target, damage, &absorb); - attacker->DealDamage(target, damage, nullptr, DIRECT_DAMAGE, schoolmask, nullptr, false); + Unit::DealDamageMods(target, damage, &absorb); + Unit::DealDamage(attacker, target, damage, nullptr, DIRECT_DAMAGE, schoolmask, nullptr, false); attacker->SendAttackStateUpdate(HITINFO_AFFECTS_VICTIM, target, 0, schoolmask, damage, absorb, resist, VICTIMSTATE_HIT, 0); return true; } @@ -2351,7 +2351,7 @@ public: Player* attacker = handler->GetSession()->GetPlayer(); SpellNonMeleeDamage dmgInfo(attacker, target, spellid, spellInfo->GetSchoolMask()); - attacker->DealDamageMods(dmgInfo.target, dmgInfo.damage, &dmgInfo.absorb); + Unit::DealDamageMods(dmgInfo.target, dmgInfo.damage, &dmgInfo.absorb); attacker->SendSpellNonMeleeDamageLog(&dmgInfo); attacker->DealSpellDamage(&dmgInfo, true); return true; diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp index 57205dcf06..c409231c85 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp @@ -157,7 +157,7 @@ class boss_ragnaros : public CreatureScript case EVENT_INTRO_4: Talk(SAY_ARRIVAL5_RAG); if (Creature* executus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_MAJORDOMO_EXECUTUS))) - me->Kill(executus); + Unit::Kill(me, executus); break; case EVENT_INTRO_5: me->SetReactState(REACT_AGGRESSIVE); diff --git a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp index 6ee2bcf648..079fd0e665 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp @@ -583,7 +583,7 @@ public: } case 15: if (Creature* arca = ObjectAccessor::GetCreature(*me, ArcanagosGUID)) - arca->DealDamage(arca, arca->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + arca->KillSelf(); return 5000; default: return 9999999; diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp index 6823394db6..f4bd1769e3 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp @@ -235,7 +235,7 @@ public: ++IntroPhase; break; case 7: - me->Kill(Madrigosa); + Unit::Kill(me, Madrigosa); Madrigosa->AI()->Talk(YELL_MADR_DEATH); me->SetFullHealth(); me->AttackStop(); diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp index 1c318d114d..e14d9dc229 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp @@ -217,7 +217,7 @@ public: summon->CastSpell(summon, SPELL_FOG_CHARM, true); summon->CastSpell(summon, SPELL_FOG_CHARM2, true); } - me->DealDamage(caster, caster->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + Unit::DealDamage(me, caster, caster->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); } } diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp index 939cb3c08a..65d781334f 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp @@ -478,7 +478,7 @@ struct boss_sathrovarr : public BossAI if (spell->Id == SPELL_TAP_CHECK_DAMAGE) { DoCastSelf(SPELL_TELEPORT_BACK, true); - caster->Kill(me); + Unit::Kill(caster, me); } } diff --git a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp index 7ab8081310..6a2c7f188d 100644 --- a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp +++ b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp @@ -58,7 +58,7 @@ public: void DoDie() { //summoner dies here - me->DealDamage(me, me->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + me->KillSelf(); //override any database `spawntimesecs` to prevent duplicated summons uint32 rTime = me->GetRespawnDelay(); if (rTime < 600) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp index 3ac7fd2663..265d9db561 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp @@ -391,7 +391,7 @@ public: DoSpawnCreature(NPC_ANCIENT_WISP, float(rand32() % 40), float(rand32() % 40), 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); ++WispCount; if (WispCount >= 30) - me->DealDamage(me, me->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + me->KillSelf(); events.ScheduleEvent(EVENT_SUMMON_WHISP, 1500); break; default: diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp index e24f282801..4a7058f4db 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp @@ -494,7 +494,7 @@ class instance_culling_of_stratholme : public InstanceMapScript { corruptor->AI()->DoAction(-ACTION_CORRUPTOR_LEAVE); if (Creature* guardian = instance->GetCreature(_guardianGUID)) - corruptor->Kill(guardian); // @todo is there some spell for this? + Unit::Kill(corruptor, guardian); // @todo is there some spell for this? } SetBossState(DATA_INFINITE_CORRUPTOR, FAIL); } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/npc_arthas.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/npc_arthas.cpp index be174b9ebb..8b77efcf84 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/npc_arthas.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/npc_arthas.cpp @@ -1672,7 +1672,7 @@ class spell_stratholme_crusader_strike : public SpellScript { if (Unit* target = GetHitUnit()) if (target->GetEntry() == NPC_CITIZEN || target->GetEntry() == NPC_RESIDENT) - GetCaster()->Kill(target); + Unit::Kill(GetCaster(), target); } void Register() override diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp index c9fb3b273d..e62b3ad237 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp @@ -79,7 +79,7 @@ public: if (me->IsWithinDistInMap(who, 20.0f)) { Talk(SAY_BANISH); - me->DealDamage(who, who->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + Unit::DealDamage(me, who, who->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); } } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_chrono_lord_deja.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_chrono_lord_deja.cpp index 943d62d157..a5995b5986 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_chrono_lord_deja.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_chrono_lord_deja.cpp @@ -82,7 +82,7 @@ public: if (me->IsWithinDistInMap(who, 20.0f)) { Talk(SAY_BANISH); - me->DealDamage(who, who->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + Unit::DealDamage(me, who, who->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); } } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_temporus.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_temporus.cpp index db2060b85a..670cb962e7 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_temporus.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_temporus.cpp @@ -94,7 +94,7 @@ public: { Talk(SAY_BANISH); - me->DealDamage(who, who->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + Unit::DealDamage(me, who, who->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); } } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp index 2c5642b8bb..183c4f7d00 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp @@ -176,7 +176,7 @@ public: { if (medivh->IsAlive()) { - medivh->DealDamage(medivh, medivh->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + medivh->KillSelf(); m_auiEncounter[0] = FAIL; m_auiEncounter[1] = NOT_STARTED; } diff --git a/src/server/scripts/Kalimdor/Firelands/boss_lord_rhyolith.cpp b/src/server/scripts/Kalimdor/Firelands/boss_lord_rhyolith.cpp index b085f6f975..4245ac8a6d 100644 --- a/src/server/scripts/Kalimdor/Firelands/boss_lord_rhyolith.cpp +++ b/src/server/scripts/Kalimdor/Firelands/boss_lord_rhyolith.cpp @@ -570,7 +570,7 @@ struct boss_lord_rhyolith : public BossAI // Deal damage to trigger the damage taken hook, which manages the model changes and phase switch if (targetHealthPct < me->GetHealthPct()) - me->DealDamage(me, CalculatePct(me->GetMaxHealth(), me->GetHealthPct() - targetHealthPct)); + Unit::DealDamage(me, me, CalculatePct(me->GetMaxHealth(), me->GetHealthPct() - targetHealthPct)); events.Repeat(5s); break; } diff --git a/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp index f63e187a33..398843deea 100644 --- a/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp +++ b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp @@ -231,7 +231,7 @@ public: me->SetCanFly(false); me->SetDisableGravity(false); if (Creature* trigger = ObjectAccessor::GetCreature(*me, triggerGUID)) - me->Kill(trigger); + Unit::Kill(me, trigger); me->SetReactState(REACT_AGGRESSIVE); // tank selection based on phase one. If tank is not there i take nearest one if (Unit* tank = ObjectAccessor::GetUnit(*me, tankGUID)) diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp index 0bcb3368c0..54cbc34fc4 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp @@ -101,7 +101,7 @@ class boss_buru : public CreatureScript { if (action == ACTION_EXPLODE) if (_phase == PHASE_EGG) - me->DealDamage(me, 45000); + Unit::DealDamage(me, me, 45000); } void KilledUnit(Unit* victim) override @@ -258,7 +258,7 @@ class spell_egg_explosion : public SpellScriptLoader void HandleDummyHitTarget(SpellEffIndex /*effIndex*/) { if (Unit* target = GetHitUnit()) - GetCaster()->DealDamage(target, -16 * GetCaster()->GetDistance(target) + 500); + Unit::DealDamage(GetCaster(), target, -16 * GetCaster()->GetDistance(target) + 500); } void Register() override diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp index 8ac2420a47..783ae00ea4 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp @@ -286,7 +286,7 @@ class npc_glob_of_viscidus : public CreatureScript { Viscidus->SetVisible(true); if (Viscidus->GetVictim()) - Viscidus->EnsureVictim()->Kill(Viscidus); + Unit::Kill(Viscidus->EnsureVictim(), Viscidus); } else { diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp index 71a0fa64fe..1802593a81 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp @@ -815,7 +815,7 @@ public: me->SummonCreature(NPC_TWILIGHT_WHELP, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); else me->SummonCreature(NPC_SARTHARION_TWILIGHT_WHELP, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); - me->DealDamage(me, me->GetHealth()); + me->KillSelf(); } void JustSummoned(Creature* who) override diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp index c8e0b09a59..9b06d5c3da 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp @@ -274,7 +274,7 @@ class npc_baltharus_the_warborn_clone : public CreatureScript { // This is here because DamageTaken wont trigger if the damage is deadly. if (Creature* baltharus = instance->GetCreature(DATA_BALTHARUS_THE_WARBORN)) - killer->Kill(baltharus); + Unit::Kill(killer, baltharus); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp index e99226a317..b9d7d96048 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -455,7 +455,7 @@ class boss_twilight_halion : public CreatureScript halion->LowerPlayerDamageReq(halion->GetMaxHealth()); if (halion->IsAlive()) - killer->Kill(halion); + Unit::Kill(killer, halion); } if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) diff --git a/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp b/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp index 29918277c5..9f0c772e75 100644 --- a/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp +++ b/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp @@ -265,7 +265,7 @@ class boss_drakkari_elemental : public CreatureScript Talk(EMOTE_ACTIVATE_ALTAR); if (Creature* colossus = instance->GetCreature(DATA_DRAKKARI_COLOSSUS)) - killer->Kill(colossus); + Unit::Kill(killer, colossus); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp index 5624a37d3e..83fac20f75 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp @@ -330,7 +330,7 @@ class boss_blood_council_controller : public CreatureScript // Make sure looting is allowed if (me->IsDamageEnoughForLootingAndReward()) prince->LowerPlayerDamageReq(prince->GetMaxHealth()); - killer->Kill(prince); + Unit::Kill(killer, prince); } } } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp index 4343d2c753..3342e5083c 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -389,7 +389,7 @@ class boss_valithria_dreamwalker : public CreatureScript me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->DespawnOrUnsummon(4000); if (Creature* trigger = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VALITHRIA_TRIGGER))) - me->Kill(trigger); + Unit::Kill(me, trigger); if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VALITHRIA_LICH_KING))) lichKing->CastSpell(lichKing, SPELL_SPAWN_CHEST); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index da8b0665a0..da79a77af2 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -771,7 +771,7 @@ class boss_sister_svalna : public CreatureScript switch (spell->Id) { case SPELL_IMPALING_SPEAR_KILL: - me->Kill(target); + Unit::Kill(me, target); break; case SPELL_IMPALING_SPEAR: if (TempSummon* summon = target->SummonCreature(NPC_IMPALING_SPEAR, *target)) diff --git a/src/server/scripts/Northrend/IsleOfConquest/boss_ioc_horde_alliance.cpp b/src/server/scripts/Northrend/IsleOfConquest/boss_ioc_horde_alliance.cpp index 3b4890e920..27e9b9c611 100644 --- a/src/server/scripts/Northrend/IsleOfConquest/boss_ioc_horde_alliance.cpp +++ b/src/server/scripts/Northrend/IsleOfConquest/boss_ioc_horde_alliance.cpp @@ -71,7 +71,7 @@ public: void SpellHit(Unit* caster, SpellInfo const* /*spell*/) override { if (caster->IsVehicle()) - me->Kill(caster); + Unit::Kill(me, caster); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp index 3745fa0275..618ea02ea4 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp @@ -131,7 +131,7 @@ class boss_faerlina : public CreatureScript { ++_frenzyDispels; Talk(EMOTE_WIDOW_EMBRACE, caster); - me->Kill(caster); + Unit::Kill(me, caster); } } diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp index 75567ce077..fee32932cb 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp @@ -579,7 +579,7 @@ public: me->SetStandState(UNIT_STAND_STATE_STAND); instance->HandleGameObject(instance->GetGuidData(DATA_GO_SKY_FLOOR), true); if (Creature* temp = ObjectAccessor::GetCreature(*me, uiControllerGUID)) - temp->DealDamage(temp, temp->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + temp->KillSelf(); bIsBattle = true; SetEscortPaused(false); JumpToNextStep(6500); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 0c36c18585..f0715a4d02 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -1189,7 +1189,7 @@ class spell_algalon_collapse : public SpellScriptLoader void HandlePeriodic(AuraEffect const* /*aurEff*/) { PreventDefaultAction(); - GetTarget()->DealDamage(GetTarget(), GetTarget()->CountPctFromMaxHealth(1), nullptr, NODAMAGE); + Unit::DealDamage(GetTarget(), GetTarget(), GetTarget()->CountPctFromMaxHealth(1), nullptr, NODAMAGE); } void Register() override diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index 813be0aae3..84b127cced 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -366,9 +366,9 @@ static bool IsEncounterFinished(Unit* who) vx001->GetStandState() == UNIT_STAND_STATE_DEAD && aerial->GetStandState() == UNIT_STAND_STATE_DEAD) { - who->Kill(mkii); - who->Kill(vx001); - who->Kill(aerial); + Unit::Kill(who, mkii); + Unit::Kill(who, vx001); + Unit::Kill(who, aerial); mkii->DespawnOrUnsummon(120000); vx001->DespawnOrUnsummon(120000); aerial->DespawnOrUnsummon(120000); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp index 3aadbc4fe4..eb5e652ac7 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp @@ -699,7 +699,7 @@ class npc_boombot : public CreatureScript data << uint32(SPELL_BOOM); me->SendMessageToSet(&data, false); - me->DealDamage(me, me->GetHealth(), nullptr, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + me->KillSelf(); damage = 0; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp index 54a05637e7..306e6c2e92 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp @@ -949,7 +949,7 @@ class boss_yogg_saron : public CreatureScript Talk(SAY_YOGG_SARON_DEATH); if (Creature* creature = _instance->GetCreature(DATA_VOICE_OF_YOGG_SARON)) - me->Kill(creature); + Unit::Kill(me, creature); for (uint8 i = DATA_SARA; i <= DATA_BRAIN_OF_YOGG_SARON; ++i) if (Creature* creature = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(i))) @@ -3023,7 +3023,7 @@ class spell_yogg_saron_titanic_storm : public SpellScriptLoader // 64172 void HandleScript(SpellEffIndex /*effIndex*/) { if (Unit* target = GetHitUnit()) - GetCaster()->Kill(target); + Unit::Kill(GetCaster(), target); } void Register() override diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp index 052768048d..d3538e0517 100644 --- a/src/server/scripts/Northrend/zone_borean_tundra.cpp +++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp @@ -149,7 +149,7 @@ public: DoCast(me, SPELL_EXPLODE_CART, true); if (Unit* worm = me->FindNearestCreature(NPC_SCOURGED_BURROWER, 3.0f)) { - me->Kill(worm); + Unit::Kill(me, worm); worm->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); } phaseTimer = 2000; diff --git a/src/server/scripts/Northrend/zone_grizzly_hills.cpp b/src/server/scripts/Northrend/zone_grizzly_hills.cpp index 98f7e4fcb9..c9f925e16c 100644 --- a/src/server/scripts/Northrend/zone_grizzly_hills.cpp +++ b/src/server/scripts/Northrend/zone_grizzly_hills.cpp @@ -134,7 +134,7 @@ public: { if (Creature* RWORG = ObjectAccessor::GetCreature(*me, _RavenousworgGUID)) { - RWORG->Kill(Mrfloppy); + Unit::Kill(RWORG, Mrfloppy); Mrfloppy->ExitVehicle(); RWORG->SetFaction(FACTION_MONSTER); RWORG->GetMotionMaster()->MovePoint(0, RWORG->GetPositionX()+10, RWORG->GetPositionY()+80, RWORG->GetPositionZ()); diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp index 7b6837a9ba..e5d69c2699 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp @@ -343,7 +343,7 @@ public: Creature* Pet = ObjectAccessor::GetCreature(*me, SummonedPet); if (Pet && Pet->IsAlive()) - Pet->DealDamage(Pet, Pet->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + Pet->KillSelf(); SummonedPet.Clear(); diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp index 63b72a78db..e82a407e50 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp @@ -157,7 +157,7 @@ public: AttackStart(owner); } else if (owner && owner->isDead()) { - me->DealDamage(me, me->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + me->KillSelf(); return; } } diff --git a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_ahune.cpp b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_ahune.cpp index 50d6365ed0..1dcafee317 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_ahune.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/TheSlavePens/boss_ahune.cpp @@ -201,9 +201,9 @@ public: instance->DoCastSpellOnPlayers(SPELL_AHUNE_ACHIEVEMENT); if (Creature* ahuneBunny = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AHUNE_BUNNY))) - me->Kill(ahuneBunny); + Unit::Kill(me, ahuneBunny); if (Creature* frozenCore = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FROZEN_CORE))) - me->Kill(frozenCore); + Unit::Kill(me, frozenCore); Map::PlayerList const& players = me->GetMap()->GetPlayers(); if (!players.isEmpty()) @@ -315,7 +315,7 @@ public: void JustDied(Unit* /*killer*/) override { if (Creature* ahune = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AHUNE))) - me->Kill(ahune); + Unit::Kill(me, ahune); DoCast(SPELL_SUMMON_LOOT_MISSILE); DoCast(SPELL_MINION_DESPAWNER); diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp index 7ce96782f0..0d2c99b9c8 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp @@ -125,7 +125,7 @@ class boss_shattered_executioner : public CreatureScript if (type == DATA_PRISONERS_EXECUTED && data <= 3) { if (Creature* victim = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FIRST_PRISONER + data - 1))) - me->Kill(victim); + Unit::Kill(me, victim); if (data == 1) { diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp index 4af439b6a5..a64d530cd0 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp @@ -521,7 +521,7 @@ class npc_ember_of_alar : public CreatureScript if (toDie) { - me->DealDamage(me, me->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + me->KillSelf(); //me->SetVisibility(VISIBILITY_OFF); } diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp index 38f15439a5..7fdd21c84a 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp @@ -108,7 +108,7 @@ class npc_warp_splinter_treant : public CreatureScript { int32 CurrentHP_Treant = (int32)me->GetHealth(); Warp->CastSpell(Warp, SPELL_HEAL_FATHER, CastSpellExtraArgs(me->GetGUID()).AddSpellBP0(CurrentHP_Treant)); - me->DealDamage(me, me->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + me->KillSelf(); return; } me->GetMotionMaster()->MoveFollow(Warp, 0, 0); diff --git a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp index 01ed56980f..6fddfb5bee 100644 --- a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp +++ b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp @@ -551,7 +551,7 @@ public: player->KilledMonsterCredit(23209); } PoisonTimer = 0; - me->DealDamage(me, me->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + me->KillSelf(); } else PoisonTimer -= diff; } if (!UpdateVictim()) diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index b02b8e7431..e13af415a3 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -678,37 +678,35 @@ class spell_dk_pestilence : public SpellScript { if (Aura* aurOld = victim->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID())) // Check Blood Plague application on victim. { + float donePct = aurOld->GetDonePct(); + float critChance = aurOld->GetCritChance(); + if (AuraEffect* aurEffOld = aurOld->GetEffect(EFFECT_0)) { - float donePct = aurEffOld->GetDonePct(); - caster->CastSpell(hitUnit, SPELL_DK_BLOOD_PLAGUE, true); // Spread the disease to hitUnit. if (Aura* aurNew = hitUnit->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID())) // Check Blood Plague application on hitUnit. { + aurNew->SetCritChance(critChance); // Blood Plague can crit if caster has T9. + aurNew->SetDonePct(donePct); if (AuraEffect* aurEffNew = aurNew->GetEffect(EFFECT_0)) - { - aurEffNew->SetDonePct(donePct); - aurEffNew->SetBonusAmount(caster->SpellDamageBonusDone(hitUnit, aurEffNew->GetSpellInfo(), 0, DOT, aurEffNew->GetEffIndex())); - } + aurEffNew->ChangeAmount(aurEffNew->CalculateAmount(aurEffNew->GetCaster()), false); } } - } - if (Aura* aurOld = victim->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID())) // Check Frost Fever application on victim. - { - if (AuraEffect* aurEffOld = aurOld->GetEffect(EFFECT_0)) + if (Aura* aurOld = victim->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID())) // Check Frost Fever application on victim. { - float donePct = aurEffOld->GetDonePct(); + float donePct = aurOld->GetDonePct(); - caster->CastSpell(hitUnit, SPELL_DK_FROST_FEVER, true); // Spread the disease to hitUnit. - - if (Aura* aurNew = hitUnit->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID())) // Check Frost Fever application on hitUnit. + if (AuraEffect* aurEffOld = aurOld->GetEffect(EFFECT_0)) { - if (AuraEffect* aurEffNew = aurNew->GetEffect(EFFECT_0)) + caster->CastSpell(hitUnit, SPELL_DK_FROST_FEVER, true); // Spread the disease to hitUnit. + + if (Aura* aurNew = hitUnit->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID())) // Check Frost Fever application on hitUnit. { - aurEffNew->SetDonePct(donePct); - aurEffNew->SetBonusAmount(caster->SpellDamageBonusDone(hitUnit, aurEffNew->GetSpellInfo(), 0, DOT, aurEffNew->GetEffIndex())); + aurNew->SetDonePct(donePct); + if (AuraEffect* aurEffNew = aurNew->GetEffect(EFFECT_0)) + aurEffNew->ChangeAmount(aurEffNew->CalculateAmount(aurEffNew->GetCaster()), false); } } } diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index f8c5a4ff1b..f22d70371d 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -1265,6 +1265,8 @@ class spell_dru_rejuvenation : public AuraScript { if (AuraEffect* naturesBountyAurEff = caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_DRUID, SPELL_ICON_ID_NATURES_BOUNTY, EFFECT_0)) { + /* + * @todo: rework // a bit cheaty here but as long as we don't have a unit internal aura count... naturesBountyAurEff->SetBonusAmount(naturesBountyAurEff->GetBonusAmount() + 1); if (naturesBountyAurEff->GetBonusAmount() >= 3) @@ -1272,6 +1274,7 @@ class spell_dru_rejuvenation : public AuraScript int32 bp0 = -naturesBountyAurEff->GetSpellInfo()->Effects[EFFECT_1].BasePoints; caster->CastSpell(caster, SPELL_DRUID_NATURES_BOUNTY, CastSpellExtraArgs(true).AddSpellBP0(bp0)); } + */ } } } @@ -1294,9 +1297,12 @@ class spell_dru_rejuvenation : public AuraScript { if (AuraEffect* naturesBountyAurEff = caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_DRUID, SPELL_ICON_ID_NATURES_BOUNTY, EFFECT_0)) { + /* + * @todo: rework naturesBountyAurEff->SetBonusAmount(naturesBountyAurEff->GetBonusAmount() > 0 ? naturesBountyAurEff->GetBonusAmount() - 1 : 0); if (naturesBountyAurEff->GetBonusAmount() < 3 && caster->HasAura(SPELL_DRUID_NATURES_BOUNTY)) caster->RemoveAurasDueToSpell(SPELL_DRUID_NATURES_BOUNTY); + */ } } }