diff options
65 files changed, 951 insertions, 885 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 75fb30efcaa..734c6673400 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -543,6 +543,8 @@ CREATE TABLE `character_aura` ( `maxDuration` int(11) NOT NULL DEFAULT '0', `remainTime` int(11) NOT NULL DEFAULT '0', `remainCharges` tinyint(3) unsigned NOT NULL DEFAULT '0', + `critChance` float NOT NULL DEFAULT '0', + `applyResilience` tinyint(3) NOT NULL DEFAULT '0', PRIMARY KEY (`guid`,`casterGuid`,`spell`,`effectMask`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Player System'; /*!40101 SET character_set_client = @saved_cs_client */; @@ -2317,6 +2319,8 @@ CREATE TABLE `pet_aura` ( `maxDuration` int(11) NOT NULL DEFAULT '0', `remainTime` int(11) NOT NULL DEFAULT '0', `remainCharges` tinyint(3) unsigned NOT NULL DEFAULT '0', + `critChance` float NOT NULL DEFAULT '0', + `applyResilience` tinyint(3) NOT NULL DEFAULT '0', PRIMARY KEY (`guid`,`casterGuid`,`spell`,`effectMask`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Pet System'; /*!40101 SET character_set_client = @saved_cs_client */; @@ -2616,7 +2620,8 @@ INSERT INTO `updates` VALUES ('2017_04_12_01_characters.sql','5A8A1215E3A2356722F52CD7A64BBE03D21FBEA3','ARCHIVED','2017-04-12 00:00:00',0), ('2017_04_19_00_characters.sql','CE06FA9005C8A8EE4BDD925520278A5D83E87485','RELEASED','2017-04-19 00:07:40',25), ('2017_10_29_00_characters.sql','6209D716E22C391F1FB464221D9F25AF','RELEASED','2017-04-19 00:07:40',25), -('2017_11_27_00_characters.sql','6FF1F84B8985ADFC7FF97F0BF8E53403CF13C320','RELEASED','2017-11-27 22:08:42',0); +('2017_11_27_00_characters.sql','6FF1F84B8985ADFC7FF97F0BF8E53403CF13C320','RELEASED','2017-11-27 22:08:42',0), +('2018_01_13_00_characters.sql','E3C0DA9995BA71ED5A267294470CD03DC51862DD','RELEASED','2018-01-13 00:00:00',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/characters/3.3.5/2018_01_13_00_characters.sql b/sql/updates/characters/3.3.5/2018_01_13_00_characters.sql new file mode 100644 index 00000000000..10000251269 --- /dev/null +++ b/sql/updates/characters/3.3.5/2018_01_13_00_characters.sql @@ -0,0 +1,7 @@ +ALTER TABLE `character_aura` +ADD COLUMN `critChance` FLOAT NOT NULL DEFAULT '0' AFTER `remainCharges`, +ADD COLUMN `applyResilience` TINYINT(3) NOT NULL DEFAULT '0' AFTER `critChance`; + +ALTER TABLE `pet_aura` +ADD COLUMN `critChance` FLOAT NOT NULL DEFAULT '0' AFTER `remainCharges`, +ADD COLUMN `applyResilience` TINYINT(3) NOT NULL DEFAULT '0' AFTER `critChance`; diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index a31fa944c47..50bc9baa428 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, remainCharges, critChance, applyResilience FROM character_aura WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_SPELL, "SELECT spell, active, disabled FROM character_spell WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS, "SELECT quest, status, explored, timer, mobcount1, mobcount2, mobcount3, mobcount4, " "itemcount1, itemcount2, itemcount3, itemcount4, playercount FROM character_queststatus WHERE guid = ? AND status <> 0", CONNECTION_ASYNC); @@ -243,8 +243,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); // Account data PrepareStatement(CHAR_SEL_ACCOUNT_DATA, "SELECT type, time, data FROM account_data WHERE accountId = ?", CONNECTION_ASYNC); @@ -573,7 +573,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); @@ -584,7 +584,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_SEL_CHAR_PET_BY_ENTRY, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, CreatedBySpell, PetType FROM character_pet WHERE owner = ? AND id = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_PET_BY_ENTRY_AND_SLOT_2, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, CreatedBySpell, PetType FROM character_pet WHERE owner = ? AND entry = ? AND (slot = ? OR slot > ?)", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_PET_BY_SLOT, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, CreatedBySpell, PetType FROM character_pet WHERE owner = ? AND (slot = ? OR slot > ?) ", CONNECTION_SYNCH); diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index abd82bf7f4a..29c275a0922 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -1177,6 +1177,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) @@ -1210,7 +1212,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); } @@ -1275,6 +1277,8 @@ void Pet::_SaveAuras(SQLTransaction& 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 862f36b8dfc..b98daee4fd3 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -771,7 +771,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(); @@ -781,7 +781,7 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) break; } - DealDamageMods(this, damage, &absorb); + Unit::DealDamageMods(this, damage, &absorb); WorldPacket data(SMSG_ENVIRONMENTALDAMAGELOG, (21)); data << uint64(GetGUID()); @@ -791,7 +791,7 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) data << uint32(resist); SendMessageToSet(&data, 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()) { @@ -17769,8 +17769,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) @@ -17794,6 +17794,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) @@ -17831,7 +17833,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()); @@ -19517,7 +19519,9 @@ void Player::_SaveAuras(SQLTransaction& 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 d74b36c1e84..271cd465709 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1594,6 +1594,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> 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 811be1e2076..5020baa928f 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -625,7 +625,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())) { @@ -635,20 +635,20 @@ 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) { uint32 rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0); if (victim->IsAIEnabled) - victim->GetAI()->DamageTaken(this, damage); + victim->GetAI()->DamageTaken(attacker, damage); - if (IsAIEnabled) - GetAI()->DamageDealt(victim, damage, damagetype); + if (attacker && attacker->IsAIEnabled) + attacker->GetAI()->DamageDealt(victim, damage, damagetype); // Hook for OnDamage Event - sScriptMgr->OnDamage(this, victim, damage); + sScriptMgr->OnDamage(attacker, victim, damage); - if (victim->GetTypeId() == TYPEID_PLAYER && this != victim) + if (victim->GetTypeId() == TYPEID_PLAYER && attacker != victim) { // Signal to pets that their owner was attacked - except when DOT. if (damagetype != DOT) @@ -656,7 +656,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam for (Unit* controlled : victim->m_Controlled) if (Creature* cControlled = controlled->ToCreature()) if (cControlled->IsAIEnabled) - cControlled->AI()->OwnerAttackedBy(this); + cControlled->AI()->OwnerAttackedBy(attacker); } if (victim->ToPlayer()->GetCommandStatus(CHEAT_GOD)) @@ -674,16 +674,20 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam else victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, 0); - // interrupt spells with SPELL_INTERRUPT_FLAG_ABORT_ON_DMG on absorbed damage (no dots) - if (!damage && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage) - if (victim != this && victim->GetTypeId() == TYPEID_PLAYER) - if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL]) - if (spell->getState() == SPELL_STATE_PREPARING) - { - uint32 interruptFlags = spell->m_spellInfo->InterruptFlags; - if ((interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG) != 0) - victim->InterruptNonMeleeSpells(false); - } + // interrupt spells with SPELL_INTERRUPT_FLAG_ABORT_ON_DMG on absorbed damage (no dots) + if (!damage && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage) + { + if (victim != attacker && victim->GetTypeId() == TYPEID_PLAYER) + { + if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL]) + if (spell->getState() == SPELL_STATE_PREPARING) + { + uint32 interruptFlags = spell->m_spellInfo->InterruptFlags; + if ((interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG) != 0) + victim->InterruptNonMeleeSpells(false); + } + } + } // 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 @@ -706,13 +710,13 @@ 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 weaponSpeedHitFactor; @@ -721,11 +725,11 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam case BASE_ATTACK: case OFF_ATTACK: { - weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * (cleanDamage->attackType == BASE_ATTACK ? 3.5f : 1.75f)); + weaponSpeedHitFactor = uint32(attacker->GetAttackTime(cleanDamage->attackType) / 1000.0f * (cleanDamage->attackType == BASE_ATTACK ? 3.5f : 1.75f)); if (cleanDamage->hitOutCome == MELEE_HIT_CRIT) weaponSpeedHitFactor *= 2; - RewardRage(rage_damage, weaponSpeedHitFactor, true); + attacker->RewardRage(rage_damage, weaponSpeedHitFactor, true); break; } case RANGED_ATTACK: @@ -744,18 +748,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 == this || victim->ToPlayer()->duel->opponent->GetGUID() == GetOwnerGUID()) + if (victim->ToPlayer()->duel->opponent == attacker || victim->ToPlayer()->duel->opponent->GetGUID() == attacker->GetOwnerGUID()) damage = health - 1; duel_hasEnded = true; @@ -766,8 +770,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 == this || victimRider->duel->opponent->GetGUID() == GetCharmerGUID()) + if (victimRider->duel->opponent == attacker || victimRider->duel->opponent->GetGUID() == attacker->GetCharmerGUID()) damage = health - 1; duel_wasMounted = true; @@ -775,17 +782,18 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam } } - if (GetTypeId() == TYPEID_PLAYER && this != victim) + if (attacker && attacker != victim) { - Player* killer = 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); + 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); - killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, health > damage ? damage : health, 0, victim); - killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage); + killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, health > damage ? damage : health, 0, victim); + killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage); + } } if (victim->GetTypeId() == TYPEID_PLAYER) @@ -793,25 +801,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); @@ -826,7 +830,8 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam 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); + if (attacker) + victim->GetThreatManager().AddThreat(attacker, float(damage), spellProto); } else // victim is a player { @@ -839,29 +844,31 @@ 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) { rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0); victim->RewardRage(rage_damage, 0, 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 && damage) { - if (victim != this && victim->GetTypeId() == TYPEID_PLAYER && // does not support creature push_back + if (victim != attacker && victim->GetTypeId() == TYPEID_PLAYER && // does not support creature push_back (!spellProto || !(spellProto->HasAttribute(SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE) || spellProto->HasAttribute(SPELL_ATTR3_TREAT_AS_PERIODIC)))) { if (damagetype != DOT) + { if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL]) + { if (spell->getState() == SPELL_STATE_PREPARING) { uint32 interruptFlags = spell->m_spellInfo->InterruptFlags; @@ -870,14 +877,18 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam else if (interruptFlags & SPELL_INTERRUPT_FLAG_PUSH_BACK) spell->Delayed(); } + } + } if (Spell* spell = victim->m_currentSpells[CURRENT_CHANNELED_SPELL]) + { if (spell->getState() == SPELL_STATE_CASTING) { uint32 channelInterruptFlags = spell->m_spellInfo->ChannelInterruptFlags; if (((channelInterruptFlags & CHANNEL_FLAG_DELAY) != 0) && (damagetype != DOT)) spell->DelayedChannel(); } + } } } @@ -901,8 +912,6 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam } } - TC_LOG_DEBUG("entities.unit", "DealDamageEnd returned %d damage", damage); - return damage; } @@ -970,8 +979,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 @@ -1035,10 +1044,8 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama damage -= damageInfo->blocked; } - if (attackType != RANGED_ATTACK) - ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_MELEE); - else - ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_RANGED); + if (CanApplyResilience()) + Unit::ApplyResilience(victim, nullptr, &damage, crit, (attackType == RANGED_ATTACK ? CR_CRIT_TAKEN_RANGED : CR_CRIT_TAKEN_MELEE)); break; } // Magical Attacks @@ -1049,10 +1056,11 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama if (crit) { damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT; - damage = SpellCriticalDamageBonus(spellInfo, damage, victim); + damage = Unit::SpellCriticalDamageBonus(this, spellInfo, damage, victim); } - ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_SPELL); + if (CanApplyResilience()) + Unit::ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_SPELL); break; } default: @@ -1069,7 +1077,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(); @@ -1103,7 +1111,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 @@ -1167,9 +1175,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 @@ -1278,7 +1286,8 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam int32 resilienceReduction = damageInfo->damage; // attackType is checked already for BASE_ATTACK or OFF_ATTACK so it can't be RANGED_ATTACK here - ApplyResilience(victim, nullptr, &resilienceReduction, (damageInfo->hitOutCome == MELEE_HIT_CRIT), CR_CRIT_TAKEN_MELEE); + if (CanApplyResilience()) + Unit::ApplyResilience(victim, nullptr, &resilienceReduction, (damageInfo->hitOutCome == MELEE_HIT_CRIT), CR_CRIT_TAKEN_MELEE); resilienceReduction = damageInfo->damage - resilienceReduction; damageInfo->damage -= resilienceReduction; damageInfo->cleanDamage += resilienceReduction; @@ -1289,7 +1298,7 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam damageInfo->procVictim |= PROC_FLAG_TAKEN_DAMAGE; // Calculate absorb & resists DamageInfo dmgInfo(*damageInfo); - CalcAbsorbResist(dmgInfo); + Unit::CalcAbsorbResist(dmgInfo); damageInfo->absorb = dmgInfo.GetAbsorb(); damageInfo->resist = dmgInfo.GetResist(); @@ -1353,7 +1362,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) && @@ -1412,12 +1421,12 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) uint32 damage = aurEff->GetAmount(); if (Unit* caster = aurEff->GetCaster()) { - damage = caster->SpellDamageBonusDone(this, spellInfo, damage, SPELL_DIRECT_DAMAGE); + damage = caster->SpellDamageBonusDone(this, spellInfo, damage, SPELL_DIRECT_DAMAGE, { }); damage = SpellDamageBonusTaken(caster, spellInfo, damage, SPELL_DIRECT_DAMAGE); } // 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); @@ -1430,7 +1439,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) data << uint32(spellInfo->SchoolMask); 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); } } } @@ -1443,7 +1452,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) @@ -1466,72 +1475,75 @@ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* s return true; } -uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType) const +/*static*/ uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, uint8 attackerLevel /*= 0*/, WeaponAttackType attackType /*= MAX_ATTACK*/) { float armor = float(victim->GetArmor()); // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura - armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL); - - if (spellInfo) - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor); - - AuraEffectList const& resIgnoreAurasAb = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST); - for (AuraEffectList::const_iterator j = resIgnoreAurasAb.begin(); j != resIgnoreAurasAb.end(); ++j) + if (attacker) { - if ((*j)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL && (*j)->IsAffectedOnSpell(spellInfo)) - armor = std::floor(AddPct(armor, -(*j)->GetAmount())); - } + armor += attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL); - AuraEffectList const& resIgnoreAuras = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST); - for (AuraEffectList::const_iterator j = resIgnoreAuras.begin(); j != resIgnoreAuras.end(); ++j) - { - if ((*j)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) - armor = std::floor(AddPct(armor, -(*j)->GetAmount())); - } + if (spellInfo) + if (Player* modOwner = attacker->GetSpellModOwner()) + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor); - // Apply Player CR_ARMOR_PENETRATION rating and buffs from stances\specializations etc. - if (GetTypeId() == TYPEID_PLAYER) - { - float arpPct = ToPlayer()->GetRatingBonusValue(CR_ARMOR_PENETRATION); + AuraEffectList const& resIgnoreAurasAb = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST); + for (AuraEffect const* aurEff : resIgnoreAurasAb) + { + if (aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL && aurEff->IsAffectedOnSpell(spellInfo)) + armor = std::floor(AddPct(armor, -aurEff->GetAmount())); + } - Item const* weapon = ToPlayer()->GetWeaponForAttack(attackType, true); - arpPct += GetTotalAuraModifier(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT, [weapon](AuraEffect const* aurEff) -> bool + AuraEffectList const& resIgnoreAuras = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST); + for (AuraEffect const* aurEff : resIgnoreAuras) { - return aurEff->GetSpellInfo()->IsItemFitToSpellRequirements(weapon); - }); + if (aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) + armor = std::floor(AddPct(armor, -aurEff->GetAmount())); + } - // no more than 100% - RoundToInterval(arpPct, 0.f, 100.f); + // Apply Player CR_ARMOR_PENETRATION rating and buffs from stances\specializations etc. + if (attacker->GetTypeId() == TYPEID_PLAYER) + { + float arpPct = attacker->ToPlayer()->GetRatingBonusValue(CR_ARMOR_PENETRATION); - float maxArmorPen = 0.f; - if (victim->getLevel() < 60) - maxArmorPen = float(400 + 85 * victim->getLevel()); - else - maxArmorPen = 400 + 85 * victim->getLevel() + 4.5f * 85 * (victim->getLevel() - 59); + Item const* weapon = attacker->ToPlayer()->GetWeaponForAttack(attackType, true); + arpPct += attacker->GetTotalAuraModifier(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT, [weapon](AuraEffect const* aurEff) -> bool + { + return aurEff->GetSpellInfo()->IsItemFitToSpellRequirements(weapon); + }); - // Cap armor penetration to this number - maxArmorPen = std::min((armor + maxArmorPen) / 3.f, armor); - // Figure out how much armor do we ignore - armor -= CalculatePct(maxArmorPen, arpPct); + // no more than 100% + RoundToInterval(arpPct, 0.f, 100.f); + + float maxArmorPen = 0.f; + if (victim->getLevel() < 60) + maxArmorPen = float(400 + 85 * victim->getLevel()); + else + maxArmorPen = 400 + 85 * victim->getLevel() + 4.5f * 85 * (victim->getLevel() - 59); + + // Cap armor penetration to this number + maxArmorPen = std::min((armor + maxArmorPen) / 3.f, armor); + // Figure out how much armor do we ignore + armor -= CalculatePct(maxArmorPen, arpPct); + } } if (armor < 0.0f) armor = 0.0f; - float levelModifier = getLevel(); - if (levelModifier > 59) - levelModifier = levelModifier + 4.5f * (levelModifier - 59); + float levelModifier = attacker ? attacker->getLevel() : attackerLevel; + if (levelModifier > 59.f) + levelModifier = levelModifier + 4.5f * (levelModifier - 59.f); - float damageReduction = 0.1f * armor / (8.5f * levelModifier + 40); + float damageReduction = 0.1f * armor / (8.5f * levelModifier + 40.f); damageReduction /= (1.0f + damageReduction); RoundToInterval(damageReduction, 0.f, 0.75f); return std::max<uint32>(damage * (1.0f - damageReduction), 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)) @@ -1552,8 +1564,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) { @@ -1579,14 +1590,17 @@ uint32 Unit::CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMas if (damageResisted > 0.0f) // if any damage was resisted { int32 ignoredResistance = 0; - ignoredResistance += GetTotalAuraModifier(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST, [schoolMask, spellInfo](AuraEffect const* aurEff) -> bool + if (attacker) { - if ((aurEff->GetMiscValue() & schoolMask) && aurEff->IsAffectedOnSpell(spellInfo)) - return true; - return false; - }); + ignoredResistance += attacker->GetTotalAuraModifier(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST, [schoolMask, spellInfo](AuraEffect const* aurEff) -> bool + { + if ((aurEff->GetMiscValue() & schoolMask) && aurEff->IsAffectedOnSpell(spellInfo)) + return true; + return false; + }); - ignoredResistance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask); + ignoredResistance += attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask); + } ignoredResistance = std::min<int32>(ignoredResistance, 100); ApplyPct(damageResisted, 100 - ignoredResistance); @@ -1594,7 +1608,7 @@ uint32 Unit::CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMas // 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 = CalcArmorReducedDamage(victim, damage, spellInfo, BASE_ATTACK); + uint32 damageAfterArmor = Unit::CalcArmorReducedDamage(attacker, victim, damage, spellInfo, BASE_ATTACK); float armorReduction = damage - damageAfterArmor; // pick the lower one, the weakest resistance counts @@ -1606,20 +1620,22 @@ 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) @@ -1632,8 +1648,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; @@ -1648,26 +1664,30 @@ 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())); - auraAbsorbMod = std::max(auraAbsorbMod, static_cast<float>(GetMaxPositiveAuraModifier(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL, [&damageInfo](AuraEffect const* aurEff) -> bool + float auraAbsorbMod = 0.f; + if (Unit* attacker = damageInfo.GetAttacker()) { - if (!(aurEff->GetMiscValue() & damageInfo.GetSchoolMask())) - return false; + auraAbsorbMod = attacker->GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL, damageInfo.GetSchoolMask()); + auraAbsorbMod = std::max(auraAbsorbMod, static_cast<float>(attacker->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL, [&damageInfo](AuraEffect const* aurEff) -> bool + { + if (!(aurEff->GetMiscValue() & damageInfo.GetSchoolMask())) + return false; - if (!aurEff->IsAffectedOnSpell(damageInfo.GetSpellInfo())) - return false; + if (!aurEff->IsAffectedOnSpell(damageInfo.GetSpellInfo())) + return false; - return true; - }))); + return true; + }))); + } RoundToInterval(auraAbsorbMod, 0.0f, 100.0f); @@ -1785,7 +1805,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 @@ -1820,12 +1840,13 @@ void Unit::CalcAbsorbResist(DamageInfo& damageInfo) uint32 splitted = splitDamage; uint32 splitted_absorb = 0; - DealDamageMods(caster, splitted, &splitted_absorb); + Unit::DealDamageMods(caster, splitted, &splitted_absorb); - SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitted, damageInfo.GetSchoolMask(), splitted_absorb, 0, false, 0, false); + if (Unit* attacker = damageInfo.GetAttacker()) + attacker->SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitted, damageInfo.GetSchoolMask(), splitted_absorb, 0, false, 0, false); CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false); + Unit::DealDamage(damageInfo.GetAttacker(), caster, splitted, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false); } // We're going to call functions which can modify content of the list during iteration over it's elements @@ -1864,20 +1885,21 @@ void Unit::CalcAbsorbResist(DamageInfo& damageInfo) } uint32 split_absorb = 0; - DealDamageMods(caster, splitDamage, &split_absorb); + Unit::DealDamageMods(caster, splitDamage, &split_absorb); - SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitDamage, damageInfo.GetSchoolMask(), split_absorb, 0, false, 0, false); + if (Unit* attacker = damageInfo.GetAttacker()) + 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_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, PROC_HIT_NONE, nullptr, &damageInfo, nullptr); + Unit::ProcSkillsAndAuras(damageInfo.GetAttacker(), caster, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, 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; @@ -1971,13 +1993,13 @@ 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); SendAttackStateUpdate(&damageInfo); 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.", @@ -2055,7 +2077,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackTy int32 miss_chance = int32(MeleeSpellMissChance(victim, attType, attackerWeaponSkill - victimMaxSkillValueForLevel, 0) * 100.0f); // Critical hit chance - int32 crit_chance = int32(GetUnitCriticalChance(attType, victim) * 100.0f); + int32 crit_chance = int32(GetUnitCriticalChanceAgainst(attType, victim) * 100.0f); int32 dodge_chance = int32(GetUnitDodgeChance(attType, victim) * 100.0f); int32 block_chance = int32(GetUnitBlockChance(attType, victim) * 100.0f); @@ -2534,7 +2556,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 @@ -2781,14 +2803,9 @@ float Unit::GetUnitBlockChance(WeaponAttackType attType, Unit const* victim) con return std::max(chance, 0.0f); } -float Unit::GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victim) const +float Unit::GetUnitCriticalChanceDone(WeaponAttackType attackType) const { - int32 const attackerWeaponSkill = GetWeaponSkillValue(attackType, victim); - int32 const victimDefenseSkill = victim->GetDefenseSkillValue(this); - int32 const skillDiff = victimDefenseSkill - attackerWeaponSkill; - - float chance = 0.0f; - float skillBonus = 0.0f; + float chance = 0.f; if (GetTypeId() == TYPEID_PLAYER) { switch (attackType) @@ -2818,29 +2835,40 @@ float Unit::GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victi } } + return chance; +} + +float Unit::GetUnitCriticalChanceTaken(Unit const* attacker, WeaponAttackType attackType, float critDone) const +{ + int32 const attackerWeaponSkill = attacker->GetWeaponSkillValue(attackType, this); + int32 const victimDefenseSkill = GetDefenseSkillValue(attacker); + int32 const skillDiff = victimDefenseSkill - attackerWeaponSkill; + + float skillBonus = 0.0f; + float chance = critDone; + // flat aura mods if (attackType == RANGED_ATTACK) - chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE); + chance += GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE); else - chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE); + chance += GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE); - chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [this](AuraEffect const* aurEff) -> bool + chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [attacker](AuraEffect const* aurEff) -> bool { - if (aurEff->GetCasterGUID() == GetGUID()) + if (aurEff->GetCasterGUID() == attacker->GetGUID()) return true; return false; }); - chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); - // reduce crit chance from Rating for players - if (attackType != RANGED_ATTACK) - ApplyResilience(victim, &chance, nullptr, false, CR_CRIT_TAKEN_MELEE); - else - ApplyResilience(victim, &chance, nullptr, false, CR_CRIT_TAKEN_RANGED); + if (attacker->CanApplyResilience()) + Unit::ApplyResilience(this, &chance, nullptr, false, (attackType == RANGED_ATTACK ? CR_CRIT_TAKEN_RANGED : CR_CRIT_TAKEN_MELEE)); + + // applied after resilience + chance += GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); // Apply crit chance from defense skill - if (victim->GetTypeId() == TYPEID_PLAYER) + if (GetTypeId() == TYPEID_PLAYER) skillBonus = -skillDiff * 0.04f; else { @@ -2850,7 +2878,13 @@ float Unit::GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victi } chance += skillBonus; - return std::max(chance, 0.0f); + return std::max(chance, 0.f); +} + +float Unit::GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const* victim) const +{ + float chance = GetUnitCriticalChanceDone(attackType); + return victim->GetUnitCriticalChanceTaken(this, attackType, chance); } uint32 Unit::GetWeaponSkillValue(WeaponAttackType attType, Unit const* target) const @@ -3442,7 +3476,6 @@ void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask) if (aurApp->GetRemoveMode()) return; - aura->HandleAuraSpecificPeriodics(aurApp, caster); aura->HandleAuraSpecificMods(aurApp, caster, true, false); // apply effects of the aura @@ -3953,7 +3986,7 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, U caster->GetSingleCastAuras().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(); } } @@ -5215,16 +5248,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) @@ -6340,39 +6374,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 (victim->IsAIEnabled) - victim->GetAI()->HealReceived(this, addhealth); + if (healer) + { + if (victim->IsAIEnabled) + victim->GetAI()->HealReceived(healer, addhealth); - if (IsAIEnabled) - GetAI()->HealDone(victim, addhealth); + if (healer->IsAIEnabled) + healer->GetAI()->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, 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, victim); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST, addhealth); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST, addhealth); + } } if (Player* player = victim->ToPlayer()) @@ -6615,9 +6655,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(); } @@ -6647,7 +6686,7 @@ void Unit::EnergizeBySpell(Unit* victim, SpellInfo const* spellInfo, int32 damag victim->GetThreatManager().ForwardThreatForAssistingMe(this, float(damage)/2, spellInfo, true); } -uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack) const +uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, Optional<float> const& donePctTotal, uint32 stack /*= 1*/) const { if (!spellProto || !victim || damagetype == DIRECT_DAMAGE) return pdamage; @@ -6659,20 +6698,20 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin // For totems get damage bonus from owner if (GetTypeId() == TYPEID_UNIT && IsTotem()) if (Unit* owner = GetOwner()) - return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype); + return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, donePctTotal, stack); float ApCoeffMod = 1.0f; int32 DoneTotal = 0; + float DoneTotalMod = donePctTotal ? *donePctTotal : SpellDamagePctDone(victim, spellProto, damagetype); // done scripted mod (take it from owner) Unit const* owner = GetOwner() ? GetOwner() : this; - AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) + DoneTotal += owner->GetTotalAuraModifier(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS, [spellProto](AuraEffect const* aurEff) -> bool { - if (!(*i)->IsAffectedOnSpell(spellProto)) - continue; + if (!aurEff->IsAffectedOnSpell(spellProto)) + return false; - switch ((*i)->GetMiscValue()) + switch (aurEff->GetMiscValue()) { case 4418: // Increased Shock Damage case 4554: // Increased Lightning Damage @@ -6682,12 +6721,17 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin case 5148: // Idol of the Shooting Star case 6008: // Increased Lightning Damage case 8627: // Totem of Hex - { - DoneTotal += (*i)->GetAmount(); + return true; + default: break; - } } - } + + return false; + }); + + // Some spells don't benefit from pct done mods + if (!spellProto->HasAttribute(SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS)) + DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, victim->GetCreatureTypeMask()); // Custom scripted damage switch (spellProto->SpellFamilyName) @@ -6711,7 +6755,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin case 49638: if (SpellInfo const* proto = sSpellMgr->GetSpellInfo(itr->first)) AddPct(ApCoeffMod, proto->Effects[EFFECT_0].CalcValue()); - break; + break; } } } @@ -6765,18 +6809,11 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod); } - float tmpDamage = (int32(pdamage) + DoneTotal); + float tmpDamage = float(int32(pdamage) + DoneTotal) * DoneTotalMod; - // DOTs calculated in AuraEffect::PeriodicDamageAurasTick - // Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods. - if (damagetype != DOT) - { - tmpDamage *= SpellDamagePctDone(victim, spellProto, damagetype); - - // apply spellmod to Done damage (flat and pct) - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage); - } + // apply spellmod to Done damage (flat and pct) + if (Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage); return uint32(std::max(tmpDamage, 0.0f)); } @@ -6786,13 +6823,18 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage if (!spellProto || !victim || damagetype == DIRECT_DAMAGE) return 1.0f; + // Some spells don't benefit from done mods + if (spellProto->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS)) + return 1.0f; + // Some spells don't benefit from pct done mods if (spellProto->HasAttribute(SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS)) return 1.0f; - // For totems pct done mods are calculated when its calculation is run on the player in SpellDamageBonusDone. + // For totems get damage bonus from owner if (GetTypeId() == TYPEID_UNIT && IsTotem()) - return 1.0f; + if (Unit* owner = GetOwner()) + return owner->SpellDamagePctDone(victim, spellProto, damagetype); // Done total percent damage auras float DoneTotalMod = 1.0f; @@ -7221,94 +7263,84 @@ int32 Unit::SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) const return GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_TAKEN, schoolMask); } -bool Unit::IsSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType /*= BASE_ATTACK*/) const +float Unit::SpellCritChanceDone(SpellInfo const* spellInfo, SpellSchoolMask schoolMask, WeaponAttackType attackType /*= BASE_ATTACK*/) const { - return roll_chance_f(GetUnitSpellCriticalChance(victim, spellProto, schoolMask, attackType)); -} - -float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType /*= BASE_ATTACK*/) const -{ - //! Mobs can't crit with spells. Player Totems can - //! Fire Elemental (from totem) can too - but this part is a hack and needs more research - if (GetGUID().IsCreatureOrVehicle() && !(IsTotem() && GetOwnerGUID().IsPlayer()) && GetEntry() != 15438) + //! Mobs can't crit with spells. (Except player controlled) + if (GetTypeId() == TYPEID_UNIT && !GetSpellModOwner()) return 0.0f; // not critting spell - if (spellProto->HasAttribute(SPELL_ATTR2_CANT_CRIT)) + if (spellInfo->HasAttribute(SPELL_ATTR2_CANT_CRIT)) return 0.0f; float crit_chance = 0.0f; - switch (spellProto->DmgClass) + switch (spellInfo->DmgClass) { - case SPELL_DAMAGE_CLASS_NONE: - // We need more spells to find a general way (if there is any) - switch (spellProto->Id) - { - case 379: // Earth Shield - case 33778: // Lifebloom Final Bloom - case 64844: // Divine Hymn - case 71607: // Item - Bauble of True Blood 10m - case 71646: // Item - Bauble of True Blood 25m - break; - default: - return 0.0f; - } - // Do not add a break here, case fallthrough is intentional! Adding a break will make above spells unable to crit. case SPELL_DAMAGE_CLASS_MAGIC: { if (schoolMask & SPELL_SCHOOL_MASK_NORMAL) crit_chance = 0.0f; // For other schools else if (GetTypeId() == TYPEID_PLAYER) - { crit_chance = GetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + GetFirstSchoolInMask(schoolMask)); - - // register aura mod, this is needed for Arcane Potency - if (Spell* spell = ToPlayer()->m_spellModTakingSpell) - { - std::vector<Aura*> affectingAuras; - (void)GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE, [&affectingAuras](AuraEffect const* aurEff) -> bool - { - affectingAuras.push_back(aurEff->GetBase()); - return true; - }); - - (void)GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, [&affectingAuras, schoolMask](AuraEffect const* aurEff) -> bool - { - if ((aurEff->GetMiscValue() & schoolMask) != 0) - { - affectingAuras.push_back(aurEff->GetBase()); - return true; - } - - return false; - }); - - for (Aura* aura : affectingAuras) - spell->m_appliedMods.insert(aura); - } - } else { crit_chance = (float)m_baseSpellCritChance; crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask); } + break; + } + case SPELL_DAMAGE_CLASS_MELEE: + case SPELL_DAMAGE_CLASS_RANGED: + { + crit_chance += GetUnitCriticalChanceDone(attackType); + crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask); + break; + } + case SPELL_DAMAGE_CLASS_NONE: + default: + return 0.0f; + } + // percent done + // only players use intelligence for critical chance computations + if (Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance); + + return std::max(crit_chance, 0.0f); +} + +float Unit::SpellCritChanceTaken(Unit const* caster, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType /*= BASE_ATTACK*/) const +{ + // not critting spell + if (spellInfo->HasAttribute(SPELL_ATTR2_CANT_CRIT)) + return 0.0f; + + float crit_chance = doneChance; + switch (spellInfo->DmgClass) + { + case SPELL_DAMAGE_CLASS_MAGIC: + { // taken - if (victim) + if (!spellInfo->IsPositive()) { - if (!spellProto->IsPositive()) - { - // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE - crit_chance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask); - // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE - crit_chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); - ApplyResilience(victim, &crit_chance, nullptr, false, CR_CRIT_TAKEN_SPELL); - } - // scripted (increase crit chance ... against ... target by x% - AuraEffectList const& mOverrideClassScript = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE + crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask); + + if (caster && caster->CanApplyResilience()) + Unit::ApplyResilience(this, &crit_chance, nullptr, false, CR_CRIT_TAKEN_SPELL); + + // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE + // applied after resilience + crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); + } + + // scripted (increase crit chance ... against ... target by x% + if (caster) + { + AuraEffectList const& mOverrideClassScript = caster->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); for (AuraEffect const* aurEff : mOverrideClassScript) { - if (!aurEff->IsAffectedOnSpell(spellProto)) + if (!aurEff->IsAffectedOnSpell(spellInfo)) continue; float modChance = 0.f; @@ -7320,18 +7352,18 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto modChance += 17.f; case 849: // Shatter (Rank 1) modChance += 17.f; - if (!victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) + if (!HasAuraState(AURA_STATE_FROZEN, spellInfo, caster)) break; crit_chance += modChance; break; case 7917: // Glyph of Shadowburn - if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this)) + if (HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellInfo, caster)) crit_chance += aurEff->GetAmount(); break; case 7997: // Renewed Hope case 7998: - if (victim->HasAura(6788)) + if (HasAura(6788)) crit_chance += aurEff->GetAmount(); break; default: @@ -7339,61 +7371,61 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto } } // Custom crit by class - switch (spellProto->SpellFamilyName) + switch (spellInfo->SpellFamilyName) { case SPELLFAMILY_MAGE: // Glyph of Fire Blast - if (spellProto->SpellFamilyFlags[0] == 0x2 && spellProto->SpellIconID == 12) - if (victim->HasAuraWithMechanic((1 << MECHANIC_STUN) | (1 << MECHANIC_KNOCKOUT))) - if (AuraEffect const* aurEff = GetAuraEffect(56369, EFFECT_0)) + if (spellInfo->SpellFamilyFlags[0] == 0x2 && spellInfo->SpellIconID == 12) + if (HasAuraWithMechanic((1 << MECHANIC_STUN) | (1 << MECHANIC_KNOCKOUT))) + if (AuraEffect const* aurEff = caster->GetAuraEffect(56369, EFFECT_0)) crit_chance += aurEff->GetAmount(); break; case SPELLFAMILY_DRUID: // Improved Faerie Fire - if (victim->HasAuraState(AURA_STATE_FAERIE_FIRE)) - if (AuraEffect const* aurEff = GetDummyAuraEffect(SPELLFAMILY_DRUID, 109, 0)) + if (HasAuraState(AURA_STATE_FAERIE_FIRE)) + if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 109, 0)) crit_chance += aurEff->GetAmount(); // cumulative effect - don't break // Starfire - if (spellProto->SpellFamilyFlags[0] & 0x4 && spellProto->SpellIconID == 1485) + if (spellInfo->SpellFamilyFlags[0] & 0x4 && spellInfo->SpellIconID == 1485) { // Improved Insect Swarm - if (AuraEffect const* aurEff = GetDummyAuraEffect(SPELLFAMILY_DRUID, 1771, 0)) - if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00000002, 0, 0)) + if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 1771, 0)) + if (GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00000002, 0, 0)) crit_chance += aurEff->GetAmount(); - break; + break; } break; case SPELLFAMILY_ROGUE: // Shiv-applied poisons can't crit - if (FindCurrentSpellBySpellId(5938)) + if (caster->FindCurrentSpellBySpellId(5938)) crit_chance = 0.0f; break; case SPELLFAMILY_PALADIN: // Flash of light - if (spellProto->SpellFamilyFlags[0] & 0x40000000) + if (spellInfo->SpellFamilyFlags[0] & 0x40000000) { // Sacred Shield - if (AuraEffect const* aura = victim->GetAuraEffect(58597, 1, GetGUID())) + if (AuraEffect const* aura = GetAuraEffect(58597, 1, GetGUID())) crit_chance += aura->GetAmount(); break; } // Exorcism - else if (spellProto->GetCategory() == 19) + else if (spellInfo->GetCategory() == 19) { - if (victim->GetCreatureTypeMask() & CREATURE_TYPEMASK_DEMON_OR_UNDEAD) + if (GetCreatureTypeMask() & CREATURE_TYPEMASK_DEMON_OR_UNDEAD) return 100.0f; break; } break; case SPELLFAMILY_SHAMAN: // Lava Burst - if (spellProto->SpellFamilyFlags[1] & 0x00001000) + if (spellInfo->SpellFamilyFlags[1] & 0x00001000) { - if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0, 0, GetGUID())) - if (victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE) > -100) + if (GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0, 0, GetGUID())) + if (GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE) > -100) return 100.0f; break; } @@ -7401,67 +7433,61 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto } // Spell crit suppression - if (victim->GetTypeId() == TYPEID_UNIT) + if (GetTypeId() == TYPEID_UNIT) { - int32 const levelDiff = static_cast<int32>(victim->getLevelForTarget(this)) - getLevel(); + int32 const levelDiff = static_cast<int32>(getLevelForTarget(caster)) - caster->getLevel(); crit_chance -= levelDiff * 0.7f; } } break; } case SPELL_DAMAGE_CLASS_MELEE: - if (victim) + { + // Custom crit by class + if (caster) { - // Custom crit by class - switch (spellProto->SpellFamilyName) + switch (spellInfo->SpellFamilyName) { case SPELLFAMILY_DRUID: // Rend and Tear - bonus crit chance for Ferocious Bite on bleeding targets - if (spellProto->SpellFamilyFlags[0] & 0x00800000 - && spellProto->SpellIconID == 1680 - && victim->HasAuraState(AURA_STATE_BLEEDING)) + if (spellInfo->SpellFamilyFlags[0] & 0x00800000 + && spellInfo->SpellIconID == 1680 + && HasAuraState(AURA_STATE_BLEEDING)) { - if (AuraEffect const* rendAndTear = GetDummyAuraEffect(SPELLFAMILY_DRUID, 2859, 1)) + if (AuraEffect const* rendAndTear = caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 2859, 1)) crit_chance += rendAndTear->GetAmount(); break; } break; case SPELLFAMILY_WARRIOR: // Victory Rush - if (spellProto->SpellFamilyFlags[1] & 0x100) + if (spellInfo->SpellFamilyFlags[1] & 0x100) { // Glyph of Victory Rush - if (AuraEffect const* aurEff = GetAuraEffect(58382, 0)) + if (AuraEffect const* aurEff = caster->GetAuraEffect(58382, 0)) crit_chance += aurEff->GetAmount(); break; } break; } } + } /// Intentional fallback. Calculate critical strike chance for both Ranged and Melee spells case SPELL_DAMAGE_CLASS_RANGED: - { - if (victim) - { - crit_chance += GetUnitCriticalChance(attackType, victim); - crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask); - } + if (caster) + crit_chance = GetUnitCriticalChanceTaken(caster, attackType, crit_chance); break; - } + case SPELL_DAMAGE_CLASS_NONE: default: - return 0.0f; + return 0.f; } - // percent done - // only players use intelligence for critical chance computations - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance); // for this types the bonus was already added in GetUnitCriticalChance, do not add twice - if (spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE && spellProto->DmgClass != SPELL_DAMAGE_CLASS_RANGED) + if (caster && spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && spellInfo->DmgClass != SPELL_DAMAGE_CLASS_RANGED) { - crit_chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [this, spellProto](AuraEffect const* aurEff) -> bool + crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [caster, spellInfo](AuraEffect const* aurEff) -> bool { - if (aurEff->GetCasterGUID() == GetGUID() && aurEff->IsAffectedOnSpell(spellProto)) + if (aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectedOnSpell(spellInfo)) return true; return false; }); @@ -7470,7 +7496,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto return std::max(crit_chance, 0.0f); } -uint32 Unit::SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim) +/*static*/ uint32 Unit::SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim) { // Calculate critical bonus int32 crit_bonus = damage; @@ -7488,29 +7514,32 @@ uint32 Unit::SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage break; } - crit_mod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellProto->GetSchoolMask()) - 1.0f) * 100; + if (caster) + { + crit_mod += (caster->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellProto->GetSchoolMask()) - 1.0f) * 100; - if (victim) - crit_mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, victim->GetCreatureTypeMask()); + if (victim) + crit_mod += caster->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, victim->GetCreatureTypeMask()); - if (crit_bonus != 0) - AddPct(crit_bonus, crit_mod); + if (crit_bonus != 0) + AddPct(crit_bonus, crit_mod); - crit_bonus -= damage; + crit_bonus -= damage; - if (damage > uint32(crit_bonus)) - { - // adds additional damage to critBonus (from talents) - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); - } + if (damage > uint32(crit_bonus)) + { + // adds additional damage to critBonus (from talents) + if (Player* modOwner = caster->GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); + } - crit_bonus += damage; + crit_bonus += damage; + } return crit_bonus; } -uint32 Unit::SpellCriticalHealingBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim) +/*static*/ uint32 Unit::SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim) { // Calculate critical bonus int32 crit_bonus; @@ -7526,26 +7555,30 @@ uint32 Unit::SpellCriticalHealingBonus(SpellInfo const* spellProto, uint32 damag break; } - if (victim) + if (caster) { - uint32 creatureTypeMask = victim->GetCreatureTypeMask(); - crit_bonus = int32(crit_bonus * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask)); + if (victim) + { + uint32 creatureTypeMask = victim->GetCreatureTypeMask(); + crit_bonus = int32(crit_bonus * caster->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask)); + } } if (crit_bonus > 0) damage += crit_bonus; - damage = int32(float(damage) * GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT)); + if (caster) + damage = int32(float(damage) * caster->GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT)); return damage; } -uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack) const +uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, Optional<float> const& donePctTotal, uint32 stack /*= 1*/) const { // For totems get healing bonus from owner (statue isn't totem in fact) if (GetTypeId() == TYPEID_UNIT && IsTotem()) if (Unit* owner = GetOwner()) - return owner->SpellHealingBonusDone(victim, spellProto, healamount, damagetype, stack); + return owner->SpellHealingBonusDone(victim, spellProto, healamount, damagetype, donePctTotal, stack); // No bonus healing for potion spells if (spellProto->SpellFamilyName == SPELLFAMILY_POTION) @@ -7553,20 +7586,22 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui float ApCoeffMod = 1.0f; int32 DoneTotal = 0; + float DoneTotalMod = donePctTotal ? *donePctTotal : SpellHealingPctDone(victim, spellProto); // done scripted mod (take it from owner) Unit const* owner = GetOwner() ? GetOwner() : this; AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) + for (AuraEffect const* aurEff : mOverrideClassScript) { - if (!(*i)->IsAffectedOnSpell(spellProto)) + if (!aurEff->IsAffectedOnSpell(spellProto)) continue; - switch ((*i)->GetMiscValue()) + + switch (aurEff->GetMiscValue()) { case 4415: // Increased Rejuvenation Healing case 4953: case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind - DoneTotal += (*i)->GetAmount(); + DoneTotal += aurEff->GetAmount(); break; default: break; @@ -7669,26 +7704,28 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui DoneTotal = 0; } - float heal = float(int32(healamount) + DoneTotal); + float heal = float(int32(healamount) + DoneTotal) * DoneTotalMod; - // DOTs calculated in AuraEffect::HandlePeriodicHealAurasTick - // Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods. - if (damagetype != DOT) - { - heal *= SpellHealingPctDone(victim, spellProto); - - // apply spellmod to Done amount - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, heal); - } + // apply spellmod to Done amount + if (Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal); return uint32(std::max(heal, 0.0f)); } float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const { - // For totems pct done mods are calculated when its calculation is run on the player in SpellHealingBonusDone. + // For totems get healing bonus from owner if (GetTypeId() == TYPEID_UNIT && IsTotem()) + if (Unit* owner = GetOwner()) + return owner->SpellHealingPctDone(victim, spellProto); + + // Some spells don't benefit from done mods + if (spellProto->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS)) + return 1.0f; + + // Some spells don't benefit from done mods + if (spellProto->HasAttribute(SPELL_ATTR6_LIMIT_PCT_HEALING_MODS)) return 1.0f; // No bonus healing for potion spells @@ -7703,27 +7740,28 @@ float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const // done scripted mod (take it from owner) Unit const* owner = GetOwner() ? GetOwner() : this; AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) + for (AuraEffect const* aurEff : mOverrideClassScript) { - if (!(*i)->IsAffectedOnSpell(spellProto)) + if (!aurEff->IsAffectedOnSpell(spellProto)) continue; - switch ((*i)->GetMiscValue()) + + switch (aurEff->GetMiscValue()) { case 21: // Test of Faith case 6935: case 6918: if (victim->HealthBelowPct(50)) - AddPct(DoneTotalMod, (*i)->GetAmount()); + AddPct(DoneTotalMod, aurEff->GetAmount()); break; case 7798: // Glyph of Regrowth { if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_DRUID, 0x40, 0, 0)) - AddPct(DoneTotalMod, (*i)->GetAmount()); + AddPct(DoneTotalMod, aurEff->GetAmount()); break; } case 8477: // Nourish Heal Boost { - int32 stepPercent = (*i)->GetAmount(); + int32 stepPercent = aurEff->GetAmount(); int32 modPercent = 0; AuraApplicationMap const& victimAuras = victim->GetAppliedAuras(); for (AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr) @@ -7731,6 +7769,7 @@ float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const Aura const* aura = itr->second->GetBase(); if (aura->GetCasterGUID() != GetGUID()) continue; + SpellInfo const* m_spell = aura->GetSpellInfo(); if (m_spell->SpellFamilyName != SPELLFAMILY_DRUID || !(m_spell->SpellFamilyFlags[1] & 0x00000010 || m_spell->SpellFamilyFlags[0] & 0x50)) @@ -7742,8 +7781,8 @@ float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const } case 7871: // Glyph of Lesser Healing Wave { - if (victim->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0, 0x00000400, 0, GetGUID())) - AddPct(DoneTotalMod, (*i)->GetAmount()); + if (victim->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0, 0x00000400, 0)) + AddPct(DoneTotalMod, aurEff->GetAmount()); break; } default: @@ -11591,14 +11630,20 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id) return 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; @@ -11689,48 +11734,44 @@ 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_KILLED, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); + Unit::ProcSkillsAndAuras(attacker, victim, PROC_FLAG_KILL, PROC_FLAG_KILLED, 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, victim); + if (attacker) + if (Player* killerPlayer = attacker->GetCharmerOrOwnerPlayerOrPlayerItself()) + killerPlayer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, victim); + // Spirit of Redemption // if talent known but not triggered (check priest class for speedup check) bool spiritOfRedemption = false; if (victim->GetTypeId() == TYPEID_PLAYER && victim->getClass() == CLASS_PRIEST) { - AuraEffectList const& dummyAuras = victim->GetAuraEffectsByType(SPELL_AURA_DUMMY); - for (AuraEffectList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr) + if (AuraEffect const* aurEff = victim->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 1654, EFFECT_0)) { - if ((*itr)->GetSpellInfo()->SpellIconID == 1654) - { - AuraEffect const* aurEff = *itr; - // save value before aura remove - uint32 ressSpellId = victim->GetUInt32Value(PLAYER_SELF_RES_SPELL); - if (!ressSpellId) - ressSpellId = victim->ToPlayer()->GetResurrectionSpellId(); - // Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers) - victim->RemoveAllAurasOnDeath(); - // restore for use at real death - victim->SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId); + // save value before aura remove + uint32 ressSpellId = victim->GetUInt32Value(PLAYER_SELF_RES_SPELL); + if (!ressSpellId) + ressSpellId = victim->ToPlayer()->GetResurrectionSpellId(); + // Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers) + victim->RemoveAllAurasOnDeath(); + // restore for use at real death + victim->SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId); - // FORM_SPIRITOFREDEMPTION and related auras - victim->CastSpell(victim, 27827, aurEff); - spiritOfRedemption = true; - break; - } + // FORM_SPIRITOFREDEMPTION and related auras + victim->CastSpell(victim, 27827, aurEff); + spiritOfRedemption = true; } } @@ -11767,8 +11808,8 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) plrVictim->SendDirectMessage(&data); } // Call KilledUnit for creatures - if (GetTypeId() == TYPEID_UNIT && IsAIEnabled) - ToCreature()->AI()->KilledUnit(victim); + if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled) + attacker->ToCreature()->AI()->KilledUnit(victim); // last damage from non duel opponent or opponent controlled creature if (plrVictim->duel) @@ -11794,31 +11835,30 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) } // Call KilledUnit for creatures, this needs to be called after the lootable flag is set - if (GetTypeId() == TYPEID_UNIT && IsAIEnabled) - ToCreature()->AI()->KilledUnit(victim); + if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled) + attacker->ToCreature()->AI()->KilledUnit(victim); // Call creature just died function if (creature->IsAIEnabled) - creature->AI()->JustDied(this); + creature->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)) + /// @todo do instance binding anyway if the charmer/owner is offline + 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 { @@ -11835,7 +11875,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); @@ -11861,26 +11901,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 (Player* killedPlr = victim->ToPlayer()) - sScriptMgr->OnPVPKill(killerPlr, killedPlr); - else if (Creature* killedCre = victim->ToCreature()) - sScriptMgr->OnCreatureKill(killerPlr, killedCre); - } - else if (Creature* killerCre = ToCreature()) + if (attacker) { - 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); + } } } @@ -12649,23 +12692,26 @@ void Unit::SendPlaySpellImpact(ObjectGuid guid, uint32 id) SendMessageToSet(&data, false); } -void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type) const +bool Unit::CanApplyResilience() const +{ + return !IsVehicle() && GetOwnerGUID().IsPlayer(); +} + +/*static*/ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type) { // player mounted on multi-passenger mount is also classified as vehicle - if (IsVehicle() || (victim->IsVehicle() && victim->GetTypeId() != TYPEID_PLAYER)) + if (victim->IsVehicle() && victim->GetTypeId() != TYPEID_PLAYER) return; - Unit const* source = nullptr; - if (GetTypeId() == TYPEID_PLAYER) - source = this; - else if (GetTypeId() == TYPEID_UNIT && GetOwner() && GetOwner()->GetTypeId() == TYPEID_PLAYER) - source = GetOwner(); - 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; @@ -12676,7 +12722,7 @@ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool // Crit chance reduction works against nonpets if (crit) *crit -= target->GetMeleeCritChanceReduction(); - if (source && damage) + if (damage) { if (isCrit) *damage -= target->GetMeleeCritDamageReduction(*damage); @@ -12687,7 +12733,7 @@ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool // Crit chance reduction works against nonpets if (crit) *crit -= target->GetRangedCritChanceReduction(); - if (source && damage) + if (damage) { if (isCrit) *damage -= target->GetRangedCritDamageReduction(*damage); @@ -12698,7 +12744,7 @@ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool // Crit chance reduction works against nonpets if (crit) *crit -= target->GetSpellCritChanceReduction(); - if (source && damage) + if (damage) { if (isCrit) *damage -= target->GetSpellCritDamageReduction(*damage); @@ -12710,6 +12756,15 @@ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool } } +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, int32 skillDiff, uint32 spellId) const diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 6adf01b367c..407168b4dab 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -846,7 +846,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); } @@ -921,13 +921,13 @@ class TC_GAME_API Unit : public WorldObject void Dismount(); 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); @@ -964,7 +964,10 @@ class TC_GAME_API Unit : public WorldObject uint32 GetRangedDamageReduction(uint32 damage) const { return GetCombatRatingDamageReduction(CR_CRIT_TAKEN_RANGED, 2.0f, 100.0f, damage); } uint32 GetSpellDamageReduction(uint32 damage) const { return GetCombatRatingDamageReduction(CR_CRIT_TAKEN_SPELL, 2.0f, 100.0f, damage); } - void ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type) const; + virtual bool CanApplyResilience() const; + static void ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type); + + int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, Unit* caster) const; float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const; SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const; @@ -975,7 +978,9 @@ class TC_GAME_API Unit : public WorldObject float GetUnitParryChance(WeaponAttackType attType, Unit const* victim) const; float GetUnitBlockChance(WeaponAttackType attType, Unit const* victim) const; float GetUnitMissChance(WeaponAttackType attType) const; - float GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victim) const; + float GetUnitCriticalChanceDone(WeaponAttackType attackType) const; + float GetUnitCriticalChanceTaken(Unit const* attacker, WeaponAttackType attackType, float critDone) const; + float GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const* victim) const; int32 GetMechanicResistChance(SpellInfo const* spellInfo) const; bool CanUseAttackType(uint8 attacktype) const; @@ -1500,12 +1505,12 @@ class TC_GAME_API Unit : public WorldObject int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const; int32 SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) const; - uint32 SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1) const; + uint32 SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, Optional<float> const& donePctTotal, uint32 stack = 1) const; float SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype) const; uint32 SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1) const; int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const; int32 SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) const; - uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1) const; + uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, Optional<float> const& donePctTotal, uint32 stack = 1) const; float SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const; uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1) const; @@ -1514,10 +1519,10 @@ class TC_GAME_API Unit : public WorldObject bool isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType = BASE_ATTACK); bool isBlockCritical(); - bool IsSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK) const; - float GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK) const; - uint32 SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim); - uint32 SpellCriticalHealingBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim); + float SpellCritChanceDone(SpellInfo const* spellInfo, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK) const; + float SpellCritChanceTaken(Unit const* caster, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType = BASE_ATTACK) const; + static uint32 SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim); + static uint32 SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim); void SetLastManaUse(uint32 spellCastTime) { m_lastManaUse = spellCastTime; } bool IsUnderLastManaUseEffect() const; @@ -1538,10 +1543,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, uint32 damage, SpellInfo const* spellInfo, uint8 attackerLevel = 0, WeaponAttackType attackType = MAX_ATTACK); + 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/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 58266fc3559..f093b2cc508 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -381,13 +381,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_critChance(0.0f), m_donePct(1.0f), -m_spellmod(nullptr), _periodicTimer(0), _amplitude(0), _ticksDone(0), m_effIndex(effIndex), +_amount(), m_spellmod(nullptr), _periodicTimer(0), _amplitude(0), _ticksDone(0), m_effIndex(effIndex), m_canBeRecalculated(true), m_isPeriodic(false) { CalculatePeriodic(caster, true, false); - m_amount = CalculateAmount(caster); + _amount = CalculateAmount(caster); CalculateSpellMod(); } @@ -493,6 +492,24 @@ int32 AuraEffect::CalculateAmount(Unit* caster) break; } + if (caster) + { + switch (GetAuraType()) + { + case SPELL_AURA_PERIODIC_DAMAGE: + case SPELL_AURA_PERIODIC_LEECH: + if (GetBase()->GetType() == UNIT_AURA_TYPE) + amount = caster->SpellDamageBonusDone(GetBase()->GetUnitOwner(), GetSpellInfo(), amount, DOT, GetBase()->GetDonePct()); + break; + case SPELL_AURA_PERIODIC_HEAL: + if (GetBase()->GetType() == UNIT_AURA_TYPE) + amount = caster->SpellHealingBonusDone(GetBase()->GetUnitOwner(), GetSpellInfo(), amount, DOT, GetBase()->GetDonePct()); + break; + default: + break; + } + } + GetBase()->CallScriptEffectCalcAmountHandlers(this, amount, m_canBeRecalculated); amount *= GetBase()->GetStackAmount(); return amount; @@ -643,7 +660,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(); @@ -799,17 +816,9 @@ void AuraEffect::Update(uint32 diff, Unit* caster) } } -bool AuraEffect::CanPeriodicTickCrit(Unit const* caster) const +float AuraEffect::GetCritChanceFor(Unit const* caster, Unit const* target) const { - ASSERT(caster); - if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_PERIODIC_CRIT, m_spellInfo)) - return true; - - // Rupture - since 3.3.3 can crit - if (m_spellInfo->SpellIconID == 500 && m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE) - return true; - - return false; + return target->SpellCritChanceTaken(caster, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), GetBase()->GetCritChance(), GetSpellInfo()->GetAttackType()); } bool AuraEffect::IsAffectedOnSpell(SpellInfo const* spell) const @@ -2942,7 +2951,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(), GetAmount() - 1, aurApp); } else { @@ -2951,7 +2960,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(); } @@ -3381,7 +3390,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 @@ -3930,7 +3939,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); @@ -4708,7 +4717,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); @@ -4756,7 +4765,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(); @@ -4836,7 +4845,7 @@ void AuraEffect::HandleAuraConvertRune(AuraApplication const* aurApp, uint8 mode if (player->getClass() != CLASS_DEATH_KNIGHT) return; - uint32 runes = m_amount; + uint32 runes = GetAmount(); // convert number of runes specified in aura amount of rune type in miscvalue to runetype in miscvalueb if (apply) { @@ -5060,7 +5069,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())) @@ -5076,104 +5088,100 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - // AOE spells are not affected by the new periodic system. - 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 HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); if (GetAuraType() == SPELL_AURA_PERIODIC_DAMAGE) { - if (isAreaAura) - damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellDamagePctDone(target, m_spellInfo, DOT); - else - damage = std::max(int32(damage * GetDonePct()), 0); - - if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage); - - damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); - - // Calculate armor mitigation - if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), GetEffIndex())) - { - uint32 damageReductedArmor = caster->CalcArmorReducedDamage(target, damage, GetSpellInfo()); - cleanDamage.mitigated_damage += damage - damageReductedArmor; - damage = damageReductedArmor; - } + // leave only target depending bonuses, rest is handled in calculate amount + if (GetBase()->GetType() == DYNOBJ_AURA_TYPE) + damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, { }, GetBase()->GetStackAmount()); - // Curse of Agony damage-per-tick calculation - if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellInfo()->SpellFamilyFlags[0] & 0x400) && GetSpellInfo()->SpellIconID == 544) - { - uint32 totalTicks = GetTotalTicks(); - // 1..4 ticks, 1/2 from normal tick damage - if (_ticksDone <= totalTicks / 3) - damage = damage / 2; - // 9..12 ticks, 3/2 from normal tick damage - else if (_ticksDone > totalTicks * 2 / 3) - damage += (damage + 1) / 2; // +1 prevent 0.5 damage possible lost at 1..4 ticks - // 5..8 ticks have normal tick damage - } - // There is a Chance to make a Soul Shard when Drain soul does damage - if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellInfo()->SpellFamilyFlags[0] & 0x00004000)) + switch (GetSpellInfo()->SpellFamilyName) { - if (caster->GetTypeId() == TYPEID_PLAYER && caster->ToPlayer()->isHonorOrXPTarget(target)) + case SPELLFAMILY_WARLOCK: { - if (roll_chance_i(20)) + // Curse of Agony damage-per-tick calculation + if ((GetSpellInfo()->SpellFamilyFlags[0] & 0x400) && GetSpellInfo()->SpellIconID == 544) + { + uint32 totalTicks = GetTotalTicks(); + // 1..4 ticks, 1/2 from normal tick damage + if (_ticksDone <= totalTicks / 3) + damage = damage / 2; + // 9..12 ticks, 3/2 from normal tick damage + else if (_ticksDone > totalTicks * 2 / 3) + damage += (damage + 1) / 2; // +1 prevent 0.5 damage possible lost at 1..4 ticks + // 5..8 ticks have normal tick damage + } + // There is a Chance to make a Soul Shard when Drain soul does damage + else if ((GetSpellInfo()->SpellFamilyFlags[0] & 0x00004000)) { - caster->CastSpell(caster, 43836, this); - // Glyph of Drain Soul - chance to create an additional Soul Shard - if (AuraEffect* aur = caster->GetAuraEffect(58070, 0)) - if (roll_chance_i(aur->GetMiscValue())) - caster->CastSpell(caster, 58068, aur); + if (caster && caster->GetTypeId() == TYPEID_PLAYER && caster->ToPlayer()->isHonorOrXPTarget(target)) + { + if (roll_chance_i(20)) + { + caster->CastSpell(caster, 43836, this); + // Glyph of Drain Soul - chance to create an additional Soul Shard + if (AuraEffect* aur = caster->GetAuraEffect(58070, 0)) + if (roll_chance_i(aur->GetMiscValue())) + caster->CastSpell(caster, 58068, aur); + } + } } + break; } - } - if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_GENERIC) - { - switch (GetId()) + case SPELLFAMILY_GENERIC: { - case 70911: // Unbound Plague - case 72854: // Unbound Plague - case 72855: // Unbound Plague - case 72856: // Unbound Plague - damage *= uint32(pow(1.25f, int32(_ticksDone))); - break; - default: - break; + switch (GetId()) + { + case 70911: // Unbound Plague + case 72854: // Unbound Plague + case 72855: // Unbound Plague + case 72856: // Unbound Plague + damage *= uint32(pow(1.25f, int32(_ticksDone))); + break; + default: + break; + } + break; } + default: + break; } } else // ceil obtained value, it may happen that 10 ticks for 10% damage may not kill owner damage = uint32(ceil(CalculatePct<float, float>(target->GetMaxHealth(), damage))); - if (!m_spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE)) - { - if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura) - { - damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); - if (caster->GetTypeId() != TYPEID_PLAYER) - damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); - } - } + damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); - bool crit = false; + bool crit = roll_chance_f(GetCritChanceFor(caster, target)); + if (crit) + damage = Unit::SpellCriticalDamageBonus(caster, m_spellInfo, damage, target); - if (CanPeriodicTickCrit(caster)) - crit = roll_chance_f(isAreaAura ? caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask()) : GetCritChance()); + // Calculate armor mitigation + if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), GetEffIndex())) + { + uint32 damageReductedArmor = Unit::CalcArmorReducedDamage(caster, target, damage, GetSpellInfo(), GetBase()->GetCasterLevel()); + cleanDamage.mitigated_damage += damage - damageReductedArmor; + damage = damageReductedArmor; + } - if (crit) - damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target); + 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 = target->CalculateAOEAvoidance(damage, m_spellInfo->SchoolMask, caster); + } int32 dmg = damage; - if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE)) - caster->ApplyResilience(target, nullptr, &dmg, crit, CR_CRIT_TAKEN_SPELL); + if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE) && GetBase()->CanApplyResilience()) + Unit::ApplyResilience(target, nullptr, &dmg, crit, CR_CRIT_TAKEN_SPELL); 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(); @@ -5181,7 +5189,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_DONE_PERIODIC; @@ -5200,14 +5208,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_NONE, hitMask, nullptr, &damageInfo, nullptr); + Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, 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())) @@ -5222,56 +5233,41 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - 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 HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); - if (isAreaAura) - damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellDamagePctDone(target, m_spellInfo, DOT); - else - damage = std::max(int32(damage * GetDonePct()), 0); - - if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage); - + if (GetBase()->GetType() == DYNOBJ_AURA_TYPE) + damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, { }, GetBase()->GetStackAmount()); damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); + bool crit = roll_chance_f(GetCritChanceFor(caster, target)); + if (crit) + damage = Unit::SpellCriticalDamageBonus(caster, m_spellInfo, damage, target); + // 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(), GetBase()->GetCasterLevel()); cleanDamage.mitigated_damage += damage - damageReductedArmor; damage = damageReductedArmor; } - if (!m_spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE)) + if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE)) { - if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura) - { - 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)); - } + 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); } - bool crit = false; - - if (CanPeriodicTickCrit(caster)) - crit = roll_chance_f(isAreaAura ? caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask()) : GetCritChance()); - - if (crit) - damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target); - int32 dmg = damage; - if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE)) - caster->ApplyResilience(target, nullptr, &dmg, crit, CR_CRIT_TAKEN_SPELL); + if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE) && GetBase()->CanApplyResilience()) + Unit::ApplyResilience(target, nullptr, &dmg, crit, CR_CRIT_TAKEN_SPELL); 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(); @@ -5292,22 +5288,22 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c procVictim |= PROC_FLAG_TAKEN_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_NONE, 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_NONE, hitMask, nullptr, &damageInfo, nullptr); - uint32 heal = uint32(caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, 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 = caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, { }, GetBase()->GetStackAmount()); + heal = caster->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT, GetBase()->GetStackAmount()); - caster->GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal()*0.5f, GetSpellInfo()); - caster->ProcSkillsAndAuras(caster, PROC_FLAG_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, 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_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo); } void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) const @@ -5337,12 +5333,15 @@ void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) HealInfo healInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); caster->HealBySpell(healInfo); - caster->ProcSkillsAndAuras(target, PROC_FLAG_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, PROC_HIT_NORMAL, nullptr, nullptr, &healInfo); + Unit::ProcSkillsAndAuras(caster, target, PROC_FLAG_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, 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)) @@ -5352,72 +5351,32 @@ 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); - - // Healing over time taken percent - float minval_hot = (float)target->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT); - if (minval_hot) - AddPct(TakenTotalMod, minval_hot); - - float maxval_hot = (float)target->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT); - if (maxval_hot) - AddPct(TakenTotalMod, maxval_hot); - - TakenTotalMod = std::max(TakenTotalMod, 0.0f); - damage = uint32(target->CountPctFromMaxHealth(damage)); - damage = uint32(damage * TakenTotalMod); - } else { - if (isAreaAura) - damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellHealingPctDone(target, m_spellInfo); - else - damage = std::max(int32(damage * GetDonePct()), 0); - - if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage); - - damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); + if (GetBase()->GetType() == DYNOBJ_AURA_TYPE) + damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, { }, GetBase()->GetStackAmount()); } - bool crit = false; - - if (CanPeriodicTickCrit(caster)) - crit = roll_chance_f(isAreaAura ? caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask()) : GetCritChance()); + damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); + bool crit = roll_chance_f(GetCritChanceFor(caster, target)); if (crit) - damage = caster->SpellCriticalHealingBonus(m_spellInfo, damage, target); + damage = Unit::SpellCriticalHealingBonus(caster, m_spellInfo, damage, target); TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s heal of %s for %u health inflicted by %u", GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId()); @@ -5425,13 +5384,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, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo()); bool haveCastItem = !GetBase()->GetCastItemGUID().IsEmpty(); @@ -5445,11 +5405,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 @@ -5461,7 +5421,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_NONE, hitMask, nullptr, nullptr, &healInfo); + Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo); } void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const @@ -5482,7 +5442,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 @@ -5559,7 +5519,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()); @@ -5593,7 +5553,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); @@ -5621,7 +5581,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); // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) if (powerType == POWER_MANA) @@ -5637,7 +5597,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); @@ -5655,7 +5615,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_NONE, hitMask, nullptr, &dotDamageInfo, nullptr); + Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dotDamageInfo, nullptr); } void AuraEffect::HandleModAttackPowerOfArmorAuraTick(Unit* target, Unit* caster) const @@ -5723,10 +5683,10 @@ void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEv } SpellNonMeleeDamage damageInfo(target, triggerTarget, GetId(), GetSpellInfo()->SchoolMask); - uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE); + uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE, { }); 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 befe0d7a2f6..1818dc359af 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -55,8 +55,8 @@ 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; } - void SetAmount(int32 amount) { m_amount = amount; m_canBeRecalculated = false;} + int32 GetAmount() const { return _amount; } + void SetAmount(int32 amount) { _amount = amount; m_canBeRecalculated = false; } int32 GetPeriodicTimer() const { return _periodicTimer; } void SetPeriodicTimer(int32 periodicTimer) { _periodicTimer = periodicTimer; } @@ -73,13 +73,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 SetCritChance(float val) { m_critChance = val; } - float GetCritChance() const { return m_critChance; } - void SetDonePct(float val) { m_donePct = val; } - float GetDonePct() const { return m_donePct; } - void Update(uint32 diff, Unit* caster); uint32 GetTickNumber() const { return _ticksDone; } @@ -109,10 +102,7 @@ class TC_GAME_API AuraEffect SpellInfo const* const m_spellInfo; int32 const m_baseAmount; - int32 m_amount; - int32 m_bonusAmount; - float m_critChance; - float m_donePct; + int32 _amount; SpellModifier* m_spellmod; @@ -124,8 +114,8 @@ class TC_GAME_API AuraEffect uint8 const m_effIndex; bool m_canBeRecalculated; bool m_isPeriodic; - private: - bool CanPeriodicTickCrit(Unit const* caster) const; + + float GetCritChanceFor(Unit const* caster, Unit const* target) const; public: // aura effect apply/remove handlers diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index d1285e5633c..5d34233fc00 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -344,7 +344,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_isSingleTarget(false), m_isUsingCharges(false), m_dropEvent(nullptr), m_procCooldown(std::chrono::steady_clock::time_point::min()) { @@ -356,7 +356,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 @@ -379,6 +387,58 @@ void Aura::_InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount) } } +bool Aura::CanPeriodicTickCrit(Unit const* caster) const +{ + if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_PERIODIC_CRIT, GetSpellInfo())) + return true; + + // Rupture - since 3.3.3 can crit + if (GetSpellInfo()->SpellIconID == 500 && GetSpellInfo()->SpellFamilyName == SPELLFAMILY_ROGUE) + return true; + + return false; +} + +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 @@ -870,13 +930,8 @@ void Aura::SetStackAmount(uint8 stackAmount) m_effects[i]->ChangeAmount(m_effects[i]->CalculateAmount(caster), false, true); for (std::list<AuraApplication*>::const_iterator apptItr = applications.begin(); apptItr != applications.end(); ++apptItr) - { if (!(*apptItr)->GetRemoveMode()) - { - HandleAuraSpecificPeriodics(*apptItr, caster); HandleAuraSpecificMods(*apptItr, caster, true, true); - } - } SetNeedClientUpdateForTargets(); } @@ -1067,13 +1122,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) { @@ -1307,10 +1364,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b // Improved Devouring Plague if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 3790, 1)) { - int32 damage = (devouringPlague->GetAmount() + devouringPlague->GetBonusAmount()) * devouringPlague->GetDonePct(); - if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage); - + int32 damage = devouringPlague->GetAmount(); damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT); CastSpellExtraArgs args(devouringPlague), args2(devouringPlague); @@ -1672,50 +1726,6 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b } } -void Aura::HandleAuraSpecificPeriodics(AuraApplication const* aurApp, Unit* caster) -{ - Unit* target = aurApp->GetTarget(); - - if (!caster || aurApp->GetRemoveMode()) - return; - - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (!HasEffect(i)) - continue; - - if (m_spellInfo->Effects[i].IsAreaAuraEffect() || m_spellInfo->Effects[i].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) - continue; - - switch (m_spellInfo->Effects[i].ApplyAuraName) - { - case SPELL_AURA_PERIODIC_DAMAGE: - case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: - case SPELL_AURA_PERIODIC_LEECH: - { - AuraEffect* aurEff = GetEffect(i); - - aurEff->SetDonePct(caster->SpellDamagePctDone(target, m_spellInfo, DOT)); - aurEff->SetBonusAmount(caster->SpellDamageBonusDone(target, m_spellInfo, 0, DOT, GetStackAmount())); - aurEff->SetCritChance(caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask())); - break; - } - case SPELL_AURA_PERIODIC_HEAL: - case SPELL_AURA_OBS_MOD_HEALTH: - { - AuraEffect* aurEff = GetEffect(i); - - aurEff->SetDonePct(caster->SpellHealingPctDone(target, m_spellInfo)); - aurEff->SetBonusAmount(caster->SpellHealingBonusDone(target, m_spellInfo, 0, DOT, GetStackAmount())); - aurEff->SetCritChance(caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask())); - break; - } - default: - break; - } - } -} - bool Aura::CanBeAppliedOn(Unit* target) { // unit not in world or during remove from world diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index c99f9f1a73a..82613cea9ea 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -82,6 +82,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, bool resetPeriodicTimer); @@ -94,6 +103,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; } @@ -148,7 +158,13 @@ class TC_GAME_API Aura void SetStackAmount(uint8 num); bool ModStackAmount(int32 num, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT, bool resetPeriodicTimer = true); - 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; @@ -173,9 +189,12 @@ class TC_GAME_API Aura void UnregisterSingleTarget(); 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; AuraEffect* GetEffect(uint8 effIndex) const { ASSERT (effIndex < MAX_SPELL_EFFECTS); return m_effects[effIndex]; } @@ -192,7 +211,6 @@ class TC_GAME_API Aura void SetNeedClientUpdateForTargets() const; void HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, bool apply, bool onReapply); - void HandleAuraSpecificPeriodics(AuraApplication const* aurApp, Unit* caster); bool CanBeAppliedOn(Unit* target); bool CheckAreaTarget(Unit* target); bool CanStackWith(Aura const* existingAura) const; @@ -258,7 +276,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 184a003cba0..8fd6715bf24 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2017,7 +2017,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; } @@ -2394,7 +2394,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (crit) { hitMask |= PROC_HIT_CRITICAL; - addhealth = caster->SpellCriticalHealingBonus(m_spellInfo, addhealth, nullptr); + addhealth = Unit::SpellCriticalHealingBonus(caster, m_spellInfo, addhealth, nullptr); } else hitMask |= PROC_HIT_NORMAL; @@ -2406,7 +2406,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // Do triggers for unit if (canEffectTrigger) - 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) @@ -2426,7 +2426,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); // Send log damage message to client caster->SendSpellNonMeleeDamageLog(&damageInfo); @@ -2442,7 +2442,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (canEffectTrigger) { 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); if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) && !m_spellInfo->HasAttribute(SPELL_ATTR4_CANT_TRIGGER_ITEM_SPELLS) && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) @@ -2459,7 +2459,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (canEffectTrigger) { 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_STOP_ATTACK_TARGET) && !m_spellInfo->HasAttribute(SPELL_ATTR4_CANT_TRIGGER_ITEM_SPELLS) && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) @@ -3379,7 +3379,7 @@ void Spell::_cast(bool skipCheck) if (!(hitMask & PROC_HIT_CRITICAL)) hitMask |= PROC_HIT_NORMAL; - 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); } void Spell::handle_immediate() @@ -3575,7 +3575,7 @@ void Spell::_handle_finish_phase() procAttacker = IsPositive() ? PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG; } - 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() @@ -7308,9 +7308,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) { @@ -7330,7 +7328,8 @@ void Spell::DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier) } } - targetInfo.crit = m_caster->IsSpellCrit(unit, m_spellInfo, m_spellSchoolMask, m_attackType); + 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 5baf98ebf10..2e43d43bd81 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -286,7 +286,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*/) @@ -303,7 +303,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(); @@ -430,10 +430,7 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) if (aura) { // Calculate damage of Immolate/Shadowflame tick - int32 pdamage = (aura->GetAmount() + aura->GetBonusAmount()) * aura->GetDonePct(); - if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, pdamage); - + int32 pdamage = aura->GetAmount(); pdamage = unitTarget->SpellDamageBonusTaken(m_caster, aura->GetSpellInfo(), pdamage, DOT); // And multiply by amount of ticks to get damage potential @@ -670,7 +667,7 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) if (m_originalCaster && damage > 0 && apply_direct_bonus) { - damage = m_originalCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE); + damage = m_originalCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE, { }); damage = unitTarget->SpellDamageBonusTaken(m_originalCaster, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE); } @@ -1210,7 +1207,7 @@ void Spell::EffectPowerDrain(SpellEffIndex effIndex) return; // add spell damage bonus - damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE); + damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE, { }); damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE); // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) @@ -1372,10 +1369,7 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/) return; } - int32 tickheal = (targetAura->GetAmount() + targetAura->GetBonusAmount()) * targetAura->GetDonePct(); - if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(targetAura->GetId(), SPELLMOD_DOT, tickheal); - + int32 tickheal = targetAura->GetAmount(); unitTarget->SpellHealingBonusTaken(m_caster, targetAura->GetSpellInfo(), tickheal, DOT); //int32 tickheal = targetAura->GetSpellInfo()->EffectBasePoints[idx] + 1; @@ -1401,24 +1395,27 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/) // Nourish else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[1] & 0x2000000) { - addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL); + addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL, { }); // Glyph of Nourish if (AuraEffect const* aurEff = m_caster->GetAuraEffect(62971, 0)) { - Unit::AuraEffectList const& Periodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL); - for (Unit::AuraEffectList::const_iterator i = Periodic.begin(); i != Periodic.end(); ++i) + uint32 auraCount = 0; + Unit::AuraEffectList const& periodicHeals = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL); + for (AuraEffect const* hot : periodicHeals) { - if (m_caster->GetGUID() == (*i)->GetCasterGUID()) - AddPct(addhealth, aurEff->GetAmount()); + if (m_caster->GetGUID() == hot->GetCasterGUID()) + ++auraCount; } + + AddPct(addhealth, aurEff->GetAmount() * auraCount); } } // Death Pact - return pct of max health to caster else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000) - addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, int32(caster->CountPctFromMaxHealth(damage)), HEAL); + addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, int32(caster->CountPctFromMaxHealth(damage)), HEAL, { }); else - addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL); + addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL, { }); addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL); @@ -1442,10 +1439,8 @@ void Spell::EffectHealPct(SpellEffIndex /*effIndex*/) if (!m_originalCaster) return; - uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, unitTarget->CountPctFromMaxHealth(damage), HEAL); - heal = unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL); - - m_healing += heal; + uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, unitTarget->CountPctFromMaxHealth(damage), HEAL, { }); + m_healing += unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL); } void Spell::EffectHealMechanical(SpellEffIndex /*effIndex*/) @@ -1460,8 +1455,7 @@ void Spell::EffectHealMechanical(SpellEffIndex /*effIndex*/) if (!m_originalCaster) return; - uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, uint32(damage), HEAL); - + uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, uint32(damage), HEAL, { }); m_healing += unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL); } @@ -1473,7 +1467,7 @@ void Spell::EffectHealthLeech(SpellEffIndex effIndex) if (!unitTarget || !unitTarget->IsAlive() || damage < 0) return; - damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE); + damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE, { }); damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE); TC_LOG_DEBUG("spells", "HealthLeech :%i", damage); @@ -1486,7 +1480,7 @@ void Spell::EffectHealthLeech(SpellEffIndex effIndex) if (m_caster->IsAlive()) { - healthGain = m_caster->SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, HEAL); + healthGain = m_caster->SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, HEAL, { }); healthGain = m_caster->SpellHealingBonusTaken(m_caster, m_spellInfo, healthGain, HEAL); HealInfo healInfo(m_caster, m_caster, healthGain, m_spellInfo, m_spellSchoolMask); @@ -3406,7 +3400,7 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex) { int32 duration = m_spellInfo->GetDuration(); unitTarget->GetSpellHistory()->LockSpellSchool(curSpellInfo->GetSchoolMask(), unitTarget->ModSpellDuration(m_spellInfo, unitTarget, duration, false, 1 << effIndex)); - m_originalCaster->ProcSkillsAndAuras(unitTarget, PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_HIT, PROC_HIT_INTERRUPT, nullptr, nullptr, nullptr); + Unit::ProcSkillsAndAuras(m_originalCaster, unitTarget, PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_HIT, PROC_HIT_INTERRUPT, nullptr, nullptr, nullptr); } ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo->Id); unitTarget->InterruptSpell(CurrentSpellTypes(i), false); diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 274d77c0134..731d4f4dfb7 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2977,6 +2977,21 @@ void SpellMgr::LoadSpellInfoCorrections() }); } + // Allows those to crit + ApplySpellFix({ + 379, // Earth Shield + 33778, // Lifebloom Final Bloom + 64844, // Divine Hymn + 71607, // Item - Bauble of True Blood 10m + 71646, // Item - Bauble of True Blood 25m + 71610, // Item - Althor's Abacus trigger 10m + 71641 // Item - Althor's Abacus trigger 25m + }, [](SpellInfo* spellInfo) + { + // We need more spells to find a general way (if there is any) + spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC; + }); + // Spell Reflection ApplySpellFix({ 57643 }, [](SpellInfo* spellInfo) { @@ -3172,6 +3187,14 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_20_YARDS); }); + // Arcane Potency + ApplySpellFix({ 57529, 57531 }, [](SpellInfo* spellInfo) + { + spellInfo->Effects[EFFECT_0].SpellClassMask = flag96(); + spellInfo->Effects[EFFECT_0].ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER; + spellInfo->Effects[EFFECT_0].MiscValue = SPELLMOD_CRITICAL_CHANCE; + }); + ApplySpellFix({ 44978, // Wild Magic 45001, // Wild Magic diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index f61400c6b4b..aa6f1c7b5f3 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -634,9 +634,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; @@ -2334,7 +2334,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; @@ -2347,7 +2347,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, " "); @@ -2356,7 +2356,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; @@ -2365,8 +2365,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; } @@ -2384,11 +2384,11 @@ public: Player* attacker = handler->GetSession()->GetPlayer(); SpellNonMeleeDamage dmgInfo(attacker, target, spellid, spellInfo->GetSchoolMask()); - damage = attacker->SpellDamageBonusDone(target, spellInfo, damage, SPELL_DIRECT_DAMAGE); + damage = attacker->SpellDamageBonusDone(target, spellInfo, damage, SPELL_DIRECT_DAMAGE, { }); damage = target->SpellDamageBonusTaken(attacker, spellInfo, damage, SPELL_DIRECT_DAMAGE); attacker->CalculateSpellDamageTaken(&dmgInfo, damage, spellInfo); - 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 e5fbd9fb0bb..c779ae9db33 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp @@ -158,7 +158,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 59f647b7cb3..1169772f369 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp @@ -584,7 +584,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/MagistersTerrace/boss_felblood_kaelthas.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp index 4ffaf1c5f42..a79ece86c6d 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp @@ -570,7 +570,7 @@ public: { //spell Burn should possible do this, but it doesn't, so do this for now. uint16 dmg = urand(1650, 2050); - me->DealDamage(me, dmg, 0, DOT, SPELL_SCHOOL_MASK_FIRE, nullptr, false); + Unit::DealDamage(me, me, dmg, 0, DOT, SPELL_SCHOOL_MASK_FIRE, nullptr, false); BurnTimer += 2000; } BurnTimer -= diff; diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp index 09f995994da..ee2c7d70bfe 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp @@ -142,7 +142,7 @@ public: case 6: Talk(SAY_PERSUADED6); - player->Kill(me); + Unit::Kill(player, me); speechCounter = 0; player->GroupEventHappens(QUEST_HOW_TO_WIN_FRIENDS, me); return; diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp index b9516df7b0a..1d221606877 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp @@ -234,7 +234,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 2a27aa8006a..1eaf4005e7b 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 46d8b24e6cd..f360a25a6be 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/ZulAman/boss_akilzon.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp index 47e54eece77..818fd205679 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp @@ -216,7 +216,7 @@ class boss_akilzon : public CreatureScript me->InterruptNonMeleeSpells(false); CloudGUID.Clear(); if (Cloud) - Cloud->DealDamage(Cloud, Cloud->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + Cloud->KillSelf(); SetWeather(WEATHER_STATE_FINE, 0.0f); isRaining = false; } diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp index 390381ea3fc..98272d1526d 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp @@ -331,7 +331,7 @@ class boss_hexlord_malacrass : public CreatureScript { Unit* Temp = ObjectAccessor::GetUnit(*me, AddGUID[i]); if (Temp && Temp->IsAlive()) - Temp->DealDamage(Temp, Temp->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + Temp->KillSelf(); } } diff --git a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp index a631dd417e7..a8e6857bd34 100644 --- a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp +++ b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp @@ -59,7 +59,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 a1701b52f92..1fe47520fee 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp @@ -392,7 +392,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 e442af3c594..323d027b2d0 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 @@ -297,7 +297,7 @@ class instance_culling_of_stratholme : public InstanceMapScript if (Creature* infinite = instance->GetCreature(_infiniteGUID)) { if (Creature* guardian = infinite->FindNearestCreature(NPC_GUARDIAN_OF_TIME, 100.0f)) - infinite->Kill(guardian); + Unit::Kill(infinite, guardian); if (Creature* rift = infinite->FindNearestCreature(NPC_TIME_RIFT, 100.0f)) { diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp index b785aa0fb50..25b30c130cf 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp @@ -80,7 +80,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 b6b98aa182f..59b89c2ed09 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 @@ -83,7 +83,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 c7e74ec1b36..c0d97f39c41 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 5bc21333b95..3048fbb5c15 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 @@ -182,7 +182,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/OnyxiasLair/boss_onyxia.cpp b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp index 0799b96a379..0bef0dabac1 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->SetDisableGravity(false); me->RemoveByteFlag(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); 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 c750a127163..de35c64119b 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp @@ -102,7 +102,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 @@ -261,7 +261,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 f042f707f67..daf33fb3c79 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp @@ -285,7 +285,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 0174e42f56d..38bda91bce7 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp @@ -816,7 +816,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 2f9c010e63b..941deb21c37 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 @@ -273,7 +273,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 94aed04c62d..fe78ac3266b 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -451,7 +451,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 4ac7f99e2c2..eb909ffa7bb 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 70f9c167cc2..c49b61b3014 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp @@ -331,7 +331,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 50ed4cc21b4..8550a5711ac 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -374,7 +374,7 @@ class boss_valithria_dreamwalker : public CreatureScript lichKing->CastSpell(lichKing, SPELL_SPAWN_CHEST, false); if (Creature* trigger = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VALITHRIA_TRIGGER))) - me->Kill(trigger); + Unit::Kill(me, trigger); } } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index 8b0e8f4baae..46890132586 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -881,7 +881,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 ed16b6728ac..c49af265572 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 a7526420fd4..e81104ac77f 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp @@ -130,7 +130,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 34bd11c3314..9a6401fa8cb 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp @@ -555,7 +555,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 a92f6b0e62a..3d247223c97 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 @@ -1196,7 +1196,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 369a9c2f4d2..161287ccce8 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 4e9b8a5780a..a4b5de9dd5b 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 15e6be5ade7..af81915f694 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))) @@ -3101,7 +3101,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 fa7952110ac..d7dcf7e3639 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 05b887f695e..d414a82bcd7 100644 --- a/src/server/scripts/Northrend/zone_grizzly_hills.cpp +++ b/src/server/scripts/Northrend/zone_grizzly_hills.cpp @@ -136,7 +136,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 c297cb14460..8fb3fa601e7 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp @@ -344,7 +344,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 666dc045b5a..b429eda5aee 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 @@ -158,7 +158,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 9ceef78a818..bf8040bd287 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()) @@ -316,7 +316,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 67a4b69375d..96001562d10 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 27f414783ed..07a7c3a910d 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp @@ -551,7 +551,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 0a009c2ae63..047ba40bd9f 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp @@ -109,7 +109,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 2868c89439d..b317bda4e0e 100644 --- a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp +++ b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp @@ -553,7 +553,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 de0d34c59c0..bda0a4257ce 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -781,7 +781,7 @@ class spell_dk_dancing_rune_weapon : public SpellScriptLoader int32 amount = static_cast<int32>(damageInfo->GetDamage()) / 2; drw->SendSpellNonMeleeDamageLog(drw->GetVictim(), spellInfo->Id, amount, spellInfo->GetSchoolMask(), 0, 0, false, 0, false); - drw->DealDamage(drw->GetVictim(), amount, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true); + Unit::DealDamage(drw, drw->GetVictim(), amount, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true); } void Register() override @@ -1278,7 +1278,7 @@ class spell_dk_hysteria : public AuraScript void PeriodicTick(AuraEffect const* aurEff) { uint32 const damage = GetTarget()->CountPctFromMaxHealth(GetTarget()->CalculateSpellDamage(nullptr, GetSpellInfo(), aurEff->GetEffIndex())); - GetTarget()->DealDamage(GetTarget(), damage, nullptr, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + Unit::DealDamage(GetTarget(), GetTarget(), damage, nullptr, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); } void Register() override @@ -1733,40 +1733,36 @@ class spell_dk_pestilence : public SpellScriptLoader { 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(); - float critChance = aurEffOld->GetCritChance(); - 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->SetCritChance(critChance); // Blood Plague can crit if caster has T9. - aurEffNew->SetDonePct(donePct); - aurEffNew->SetBonusAmount(caster->SpellDamageBonusDone(hitUnit, aurEffNew->GetSpellInfo(), 0, DOT)); - } + aurEffNew->ChangeAmount(aurEffNew->CalculateAmount(aurEffNew->GetCaster()), false); } } } if (Aura* aurOld = victim->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID())) // Check Frost Fever application on victim. { + float donePct = aurOld->GetDonePct(); + if (AuraEffect* aurEffOld = aurOld->GetEffect(EFFECT_0)) { - float donePct = aurEffOld->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. { + aurNew->SetDonePct(donePct); if (AuraEffect* aurEffNew = aurNew->GetEffect(EFFECT_0)) - { - aurEffNew->SetDonePct(donePct); - aurEffNew->SetBonusAmount(caster->SpellDamageBonusDone(hitUnit, aurEffNew->GetSpellInfo(), 0, DOT)); - } + aurEffNew->ChangeAmount(aurEffNew->CalculateAmount(aurEffNew->GetCaster()), false); } } } @@ -2569,7 +2565,7 @@ class spell_dk_wandering_plague : public SpellScriptLoader PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); Unit* target = eventInfo.GetProcTarget(); - if (!roll_chance_f(caster->GetUnitCriticalChance(BASE_ATTACK, target))) + if (!roll_chance_f(caster->GetUnitCriticalChanceAgainst(BASE_ATTACK, target))) return; DamageInfo* damageInfo = eventInfo.GetDamageInfo(); diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index fdedfa6124a..9f349f223f8 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -1012,7 +1012,7 @@ class spell_dru_lifebloom : public SpellScriptLoader int32 healAmount = aurEff->GetAmount(); if (Unit* caster = GetCaster()) { - healAmount = caster->SpellHealingBonusDone(target, GetSpellInfo(), healAmount, HEAL, stack); + healAmount = caster->SpellHealingBonusDone(target, GetSpellInfo(), healAmount, HEAL, { }, stack); healAmount = target->SpellHealingBonusTaken(caster, GetSpellInfo(), healAmount, HEAL, stack); // restore mana diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index 89b14f71ccb..bb741a94819 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -254,10 +254,7 @@ class spell_hun_chimera_shot : public SpellScriptLoader spellId = SPELL_HUNTER_CHIMERA_SHOT_SERPENT; // first, calculate damage of basic tick (C&P from AuraEffect::HandlePeriodicDamageAurasTick) - basePoint = (aurEff->GetAmount() + aurEff->GetBonusAmount()) * aurEff->GetDonePct(); - if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(aurEff->GetId(), SPELLMOD_DOT, basePoint); - + basePoint = aurEff->GetAmount(); basePoint = unitTarget->SpellDamageBonusTaken(caster, aurEff->GetSpellInfo(), basePoint, DOT, aura->GetStackAmount()); // then, multiply to get damage potential diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index bc7219a1e03..e3664c16f3f 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -880,7 +880,7 @@ class spell_pri_pain_and_suffering_proc : public SpellScriptLoader { if (AuraEffect* aur = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, caster->GetGUID())) { - aur->SetBonusAmount(caster->SpellDamageBonusDone(target, aur->GetSpellInfo(), 0, DOT)); + aur->ChangeAmount(aur->CalculateAmount(aur->GetCaster()), false); aur->CalculatePeriodic(caster, false, false); aur->GetBase()->RefreshDuration(); } @@ -1112,10 +1112,7 @@ class spell_pri_renew : public SpellScriptLoader // Empowered Renew if (AuraEffect const* empoweredRenewAurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, PRIEST_ICON_ID_EMPOWERED_RENEW_TALENT, EFFECT_1)) { - int32 heal = (aurEff->GetAmount() + aurEff->GetBonusAmount()) * aurEff->GetDonePct(); - if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetId(), SPELLMOD_DOT, heal); - + int32 heal = aurEff->GetAmount(); heal = GetTarget()->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT); heal *= GetSpellInfo()->GetMaxTicks(); diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index c8cb24336ae..be2e27ab540 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -435,7 +435,7 @@ class spell_sha_earth_shield : public SpellScriptLoader void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) { if (Unit* caster = GetCaster()) - amount = caster->SpellHealingBonusDone(GetUnitOwner(), GetSpellInfo(), amount, HEAL); + amount = caster->SpellHealingBonusDone(GetUnitOwner(), GetSpellInfo(), amount, HEAL, { }); // SpellHealingBonusTaken will be called on Heal } @@ -996,7 +996,7 @@ class spell_sha_healing_stream_totem : public SpellScriptLoader if (Unit* owner = caster->GetOwner()) { if (triggeringSpell) - damage = int32(owner->SpellHealingBonusDone(target, triggeringSpell, damage, HEAL)); + damage = int32(owner->SpellHealingBonusDone(target, triggeringSpell, damage, HEAL, { })); // Restorative Totems if (AuraEffect* dummy = owner->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, SHAMAN_ICON_ID_RESTORATIVE_TOTEMS, 1)) diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index 38772874e0e..bd82af3bd8b 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -524,7 +524,7 @@ class spell_warl_everlasting_affliction : public SpellScriptLoader // Refresh corruption on target if (AuraEffect* aur = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x2, 0, 0, caster->GetGUID())) { - aur->SetBonusAmount(caster->SpellDamageBonusDone(target, aur->GetSpellInfo(), 0, DOT)); + aur->ChangeAmount(aur->CalculateAmount(aur->GetCaster()), false); aur->CalculatePeriodic(caster, false, false); aur->GetBase()->RefreshDuration(true); } diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 929bdb8fac3..0a735e39fea 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -102,7 +102,7 @@ class spell_warr_bloodthirst : public SpellScriptLoader if (Unit* target = GetHitUnit()) { - damage = GetCaster()->SpellDamageBonusDone(target, GetSpellInfo(), uint32(damage), SPELL_DIRECT_DAMAGE); + damage = GetCaster()->SpellDamageBonusDone(target, GetSpellInfo(), uint32(damage), SPELL_DIRECT_DAMAGE, { }); damage = target->SpellDamageBonusTaken(GetCaster(), GetSpellInfo(), uint32(damage), SPELL_DIRECT_DAMAGE); } SetHitDamage(damage); |