aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Spells/Spell.cpp
diff options
context:
space:
mode:
authorGiacomo Pozzoni <giacomopoz@gmail.com>2020-06-29 21:03:03 +0000
committerShauren <shauren.trinity@gmail.com>2022-01-20 00:13:02 +0100
commit8f4db9aa6919e2b3b22ec21ffea4eacb605e9bc2 (patch)
tree9863a03c733072d6c7f8ab4125e8e683f72c3d6b /src/server/game/Spells/Spell.cpp
parentb9666481bbf943000c6c925c3287c1e1c9a94e7f (diff)
Core/Spells: implement corpse target type support and properly fix resurrections (#24921)
* Core/Spells: implement corpse target type support and properly fix resurrections (cherry picked from commit df193945d9aff8596985a20e2c654105354b0af7) * Core/Spells: implement TARGET_CORPSE_SRC_AREA_RAID and updated remaining resurrection effect handlers for updated corpse targeting (cherry picked from commit 98b075cb4b0da126d409ab42daa63a1f531a70ea) * Fix no-pch Co-authored-by: Ovahlord <dreadkiller@gmx.de> (cherry picked from commit cc71da35b5dc74abf71f8691161525a23d870bb5)
Diffstat (limited to 'src/server/game/Spells/Spell.cpp')
-rw-r--r--src/server/game/Spells/Spell.cpp161
1 files changed, 135 insertions, 26 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 9e1158407f0..e6e5e552767 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -572,6 +572,7 @@ m_spellValue(new SpellValue(m_spellInfo, caster)), _spellEvent(nullptr)
unitTarget = nullptr;
itemTarget = nullptr;
gameObjTarget = nullptr;
+ corpseTarget = nullptr;
destTarget = nullptr;
damage = 0;
targetMissInfo = SPELL_MISS_NONE;
@@ -1127,6 +1128,17 @@ void Spell::SelectImplicitNearbyTargets(SpellEffectInfo const& spellEffectInfo,
return;
}
break;
+ case TARGET_OBJECT_TYPE_CORPSE:
+ if (Corpse* corpseTarget = target->ToCorpse())
+ AddCorpseTarget(corpseTarget, effMask);
+ else
+ {
+ TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: OnObjectTargetSelect script hook for spell Id %u set object of wrong type, expected corpse, got %s, effect %u", m_spellInfo->Id, target->GetGUID().GetTypeName(), effMask);
+ SendCastResult(SPELL_FAILED_BAD_IMPLICIT_TARGETS);
+ finish(false);
+ return;
+ }
+ break;
case TARGET_OBJECT_TYPE_DEST:
{
SpellDestination dest(*target);
@@ -1188,12 +1200,14 @@ void Spell::SelectImplicitConeTargets(SpellEffectInfo const& spellEffectInfo, Sp
if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
Trinity::Containers::RandomResize(targets, maxTargets);
- for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
+ for (WorldObject* itr : targets)
{
- if (Unit* unit = (*itr)->ToUnit())
+ if (Unit* unit = itr->ToUnit())
AddUnitTarget(unit, effMask, false);
- else if (GameObject* gObjTarget = (*itr)->ToGameObject())
+ else if (GameObject* gObjTarget = itr->ToGameObject())
AddGOTarget(gObjTarget, effMask);
+ else if (Corpse* corpse = itr->ToCorpse())
+ AddCorpseTarget(corpse, effMask);
}
}
}
@@ -1309,12 +1323,14 @@ void Spell::SelectImplicitAreaTargets(SpellEffectInfo const& spellEffectInfo, Sp
targets.resize(maxTargets);
}
- for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
+ for (WorldObject* itr : targets)
{
- if (Unit* unit = (*itr)->ToUnit())
+ if (Unit* unit = itr->ToUnit())
AddUnitTarget(unit, effMask, false, true, center);
- else if (GameObject* gObjTarget = (*itr)->ToGameObject())
+ else if (GameObject* gObjTarget = itr->ToGameObject())
AddGOTarget(gObjTarget, effMask);
+ else if (Corpse* corpse = itr->ToCorpse())
+ AddCorpseTarget(corpse, effMask);
}
}
}
@@ -1616,6 +1632,8 @@ void Spell::SelectImplicitCasterObjectTargets(SpellEffectInfo const& spellEffect
AddUnitTarget(unit, 1 << spellEffectInfo.EffectIndex, checkIfValid);
else if (GameObject* go = target->ToGameObject())
AddGOTarget(go, 1 << spellEffectInfo.EffectIndex);
+ else if (Corpse* corpse = target->ToCorpse())
+ AddCorpseTarget(corpse, 1 << spellEffectInfo.EffectIndex);
}
}
@@ -1633,6 +1651,8 @@ void Spell::SelectImplicitTargetObjectTargets(SpellEffectInfo const& spellEffect
AddUnitTarget(unit, 1 << spellEffectInfo.EffectIndex, true, false);
else if (GameObject* gobj = target->ToGameObject())
AddGOTarget(gobj, 1 << spellEffectInfo.EffectIndex);
+ else if (Corpse* corpse = target->ToCorpse())
+ AddCorpseTarget(corpse, 1 << spellEffectInfo.EffectIndex);
SelectImplicitChainTargets(spellEffectInfo, targetType, target, 1 << spellEffectInfo.EffectIndex);
}
@@ -1817,6 +1837,8 @@ void Spell::SelectImplicitLineTargets(SpellEffectInfo const& spellEffectInfo, Sp
AddUnitTarget(unit, effMask, false);
else if (GameObject* gObjTarget = (*itr)->ToGameObject())
AddGOTarget(gObjTarget, effMask);
+ else if (Corpse* corpse = (*itr)->ToCorpse())
+ AddCorpseTarget(corpse, 1 << spellEffectInfo.EffectIndex);
}
}
}
@@ -1854,7 +1876,7 @@ void Spell::SelectEffectTypeImplicitTargets(SpellEffectInfo const& spellEffectIn
if (player->IsImmunedToSpellEffect(spell->GetSpellInfo(), spellEffectInfo, nullptr))
return;
- spell->HandleEffects(player, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
+ spell->HandleEffects(player, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
});
}
}
@@ -1886,11 +1908,7 @@ void Spell::SelectEffectTypeImplicitTargets(SpellEffectInfo const& spellEffectIn
else if (targetMask & TARGET_FLAG_CORPSE_MASK)
{
if (Corpse* corpseTarget = m_targets.GetCorpseTarget())
- {
- /// @todo this is a workaround - corpses should be added to spell target map too, but we can't do that so we add owner instead
- if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID()))
- target = owner;
- }
+ target = corpseTarget;
}
else //if (targetMask & TARGET_FLAG_UNIT_MASK)
target = m_caster;
@@ -1921,6 +1939,8 @@ void Spell::SelectEffectTypeImplicitTargets(SpellEffectInfo const& spellEffectIn
AddUnitTarget(target->ToUnit(), 1 << spellEffectInfo.EffectIndex, false);
else if (target->ToGameObject())
AddGOTarget(target->ToGameObject(), 1 << spellEffectInfo.EffectIndex);
+ else if (target->ToCorpse())
+ AddCorpseTarget(target->ToCorpse(), 1 << spellEffectInfo.EffectIndex);
}
}
@@ -1934,6 +1954,12 @@ uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionConta
{
case TARGET_OBJECT_TYPE_UNIT:
case TARGET_OBJECT_TYPE_UNIT_AND_DEST:
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_DEAD))
+ {
+ retMask &= GRID_MAP_TYPE_MASK_PLAYER | GRID_MAP_TYPE_MASK_CREATURE;
+ break;
+ }
+ [[fallthrough]];
case TARGET_OBJECT_TYPE_CORPSE:
case TARGET_OBJECT_TYPE_CORPSE_ENEMY:
case TARGET_OBJECT_TYPE_CORPSE_ALLY:
@@ -1946,8 +1972,7 @@ uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionConta
default:
break;
}
- if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_DEAD))
- retMask &= ~GRID_MAP_TYPE_MASK_CORPSE;
+
if (m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS))
retMask &= GRID_MAP_TYPE_MASK_CORPSE | GRID_MAP_TYPE_MASK_PLAYER;
if (m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_GHOSTS))
@@ -2386,6 +2411,58 @@ void Spell::AddItemTarget(Item* item, uint32 effectMask)
m_UniqueItemInfo.emplace_back(std::move(target));
}
+void Spell::AddCorpseTarget(Corpse* corpse, uint32 effectMask)
+{
+ for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
+ if (!spellEffectInfo.IsEffect())
+ effectMask &= ~(1 << spellEffectInfo.EffectIndex);
+
+ // no effects left
+ if (!effectMask)
+ return;
+
+ ObjectGuid targetGUID = corpse->GetGUID();
+
+ // Lookup target in already in list
+ auto ihit = std::find_if(std::begin(m_UniqueCorpseTargetInfo), std::end(m_UniqueCorpseTargetInfo), [targetGUID](CorpseTargetInfo const& target) { return target.TargetGUID == targetGUID; });
+ if (ihit != std::end(m_UniqueCorpseTargetInfo)) // Found in list
+ {
+ // Add only effect mask
+ ihit->EffectMask |= effectMask;
+ return;
+ }
+
+ // This is new target calculate data for him
+ CorpseTargetInfo target;
+ target.TargetGUID = targetGUID;
+ target.EffectMask = effectMask;
+
+ // Spell have speed - need calculate incoming time
+ if (m_caster != corpse)
+ {
+ float hitDelay = m_spellInfo->LaunchDelay;
+ if (m_spellInfo->HasAttribute(SPELL_ATTR9_SPECIAL_DELAY_CALCULATION))
+ hitDelay += m_spellInfo->Speed;
+ else if (m_spellInfo->Speed > 0.0f)
+ {
+ // calculate spell incoming interval
+ float dist = std::max(m_caster->GetDistance(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ()), 5.0f);
+ hitDelay += dist / m_spellInfo->Speed;
+ }
+
+ target.TimeDelay = uint64(std::floor(hitDelay * 1000.0f));
+ }
+ else
+ target.TimeDelay = 0LL;
+
+ // Calculate minimum incoming time
+ if (target.TimeDelay && (!m_delayMoment || m_delayMoment > target.TimeDelay))
+ m_delayMoment = target.TimeDelay;
+
+ // Add target to list
+ m_UniqueCorpseTargetInfo.emplace_back(std::move(target));
+}
+
void Spell::AddDestTarget(SpellDestination const& dest, uint32 effIndex)
{
m_destTargets[effIndex] = dest;
@@ -2415,6 +2492,14 @@ int64 Spell::GetItemTargetCountForEffect(SpellEffIndex effect) const
});
}
+int64 Spell::GetCorpseTargetCountForEffect(SpellEffIndex effect) const
+{
+ return std::count_if(m_UniqueCorpseTargetInfo.begin(), m_UniqueCorpseTargetInfo.end(), [effect](CorpseTargetInfo const& targetInfo)
+ {
+ return targetInfo.EffectMask & (1 << effect);
+ });
+}
+
void Spell::TargetInfo::PreprocessTarget(Spell* spell)
{
Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
@@ -2744,7 +2829,7 @@ void Spell::GOTargetInfo::DoTargetSpellHit(Spell* spell, SpellEffectInfo const&
spell->CallScriptBeforeHitHandlers(SPELL_MISS_NONE);
- spell->HandleEffects(nullptr, nullptr, go, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
+ spell->HandleEffects(nullptr, nullptr, go, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
// AI functions
if (go->AI())
@@ -2763,7 +2848,21 @@ void Spell::ItemTargetInfo::DoTargetSpellHit(Spell* spell, SpellEffectInfo const
{
spell->CallScriptBeforeHitHandlers(SPELL_MISS_NONE);
- spell->HandleEffects(nullptr, TargetItem, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
+ spell->HandleEffects(nullptr, TargetItem, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
+
+ spell->CallScriptOnHitHandlers();
+ spell->CallScriptAfterHitHandlers();
+}
+
+void Spell::CorpseTargetInfo::DoTargetSpellHit(Spell* spell, SpellEffectInfo const& spellEffectInfo)
+{
+ Corpse* corpse = ObjectAccessor::GetCorpse(*spell->m_caster, TargetGUID);
+ if (!corpse)
+ return;
+
+ spell->CallScriptBeforeHitHandlers(SPELL_MISS_NONE);
+
+ spell->HandleEffects(nullptr, nullptr, nullptr, corpse, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
spell->CallScriptOnHitHandlers();
spell->CallScriptAfterHitHandlers();
@@ -2969,7 +3068,7 @@ void Spell::DoSpellEffectHit(Unit* unit, SpellEffectInfo const& spellEffectInfo,
}
_spellAura = hitInfo.HitAura;
- HandleEffects(unit, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
+ HandleEffects(unit, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
_spellAura = nullptr;
}
@@ -3684,6 +3783,8 @@ void Spell::handle_immediate()
DoProcessTargetContainer(m_UniqueGOTargetInfo);
+ DoProcessTargetContainer(m_UniqueCorpseTargetInfo);
+
FinishTargetProcessing();
// spell is finished, perform some last features of the spell here
@@ -3820,7 +3921,7 @@ void Spell::_handle_immediate_phase()
continue;
// call effect handlers to handle destination hit
- HandleEffects(nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT);
+ HandleEffects(nullptr, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT);
}
// process items
@@ -4548,6 +4649,9 @@ void Spell::UpdateSpellCastDataTargets(WorldPackets::Spells::SpellCastData& data
for (GOTargetInfo const& targetInfo : m_UniqueGOTargetInfo)
data.HitTargets.push_back(targetInfo.TargetGUID); // Always hits
+ for (CorpseTargetInfo const& targetInfo : m_UniqueCorpseTargetInfo)
+ data.HitTargets.push_back(targetInfo.TargetGUID); // Always hits
+
// Reset m_needAliveTargetMask for non channeled spell
if (!m_spellInfo->IsChanneled())
m_channelTargetEffectMask = 0;
@@ -5160,12 +5264,13 @@ void Spell::HandleThreatSpells()
TC_LOG_DEBUG("spells", "Spell %u, added an additional %f threat for %s %u target(s)", m_spellInfo->Id, threat, IsPositive() ? "assisting" : "harming", uint32(m_UniqueTargetInfo.size()));
}
-void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOTarget, SpellEffectInfo const& spellEffectInfo, SpellEffectHandleMode mode)
+void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGoTarget, Corpse* pCorpseTarget, SpellEffectInfo const& spellEffectInfo, SpellEffectHandleMode mode)
{
effectHandleMode = mode;
unitTarget = pUnitTarget;
itemTarget = pItemTarget;
- gameObjTarget = pGOTarget;
+ gameObjTarget = pGoTarget;
+ corpseTarget = pCorpseTarget;
destTarget = &m_destTargets[spellEffectInfo.EffectIndex]._position;
effectInfo = &spellEffectInfo;
unitCaster = m_originalCaster ? m_originalCaster : m_caster->ToUnit();
@@ -7803,7 +7908,7 @@ void Spell::HandleLaunchPhase()
if (!spellEffectInfo.IsEffect())
continue;
- HandleEffects(nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_LAUNCH);
+ HandleEffects(nullptr, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_LAUNCH);
}
PrepareTargetProcessing();
@@ -7847,7 +7952,7 @@ void Spell::DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, Spe
m_damage = 0;
m_healing = 0;
- HandleEffects(unit, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_LAUNCH_TARGET);
+ HandleEffects(unit, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_LAUNCH_TARGET);
if (m_originalCaster && m_damage > 0)
{
@@ -8449,13 +8554,15 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) const
case TARGET_CHECK_ENEMY:
if (unitTarget->IsTotem())
return false;
- if (!_caster->IsValidAttackTarget(unitTarget, _spellInfo))
+ // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
+ if (!target->IsCorpse() && !_caster->IsValidAttackTarget(unitTarget, _spellInfo))
return false;
break;
case TARGET_CHECK_ALLY:
if (unitTarget->IsTotem())
return false;
- if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo))
+ // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
+ if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
return false;
break;
case TARGET_CHECK_PARTY:
@@ -8463,7 +8570,8 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) const
return false;
if (unitTarget->IsTotem())
return false;
- if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo))
+ // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
+ if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
return false;
if (!refUnit->IsInPartyWith(unitTarget))
return false;
@@ -8479,7 +8587,8 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) const
return false;
if (unitTarget->IsTotem())
return false;
- if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo))
+ // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
+ if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
return false;
if (!refUnit->IsInRaidWith(unitTarget))
return false;