aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Spells/Spell.cpp
diff options
context:
space:
mode:
authorariel- <ariel-@users.noreply.github.com>2018-02-10 16:43:01 -0300
committerShauren <shauren.trinity@gmail.com>2021-08-28 15:59:11 +0200
commit962f6d7988b9003e550f6745be7cff812e9d8efa (patch)
treeee6ab5872b947afb00f4ca99e87c7dddea35bdb3 /src/server/game/Spells/Spell.cpp
parent65dca120d34febdaa84a63e17f638ab0fa59b3df (diff)
Core/Spells: rework part 5: GameObject casting
Closes #21330 Closes #18885 Ref #18752 (cherry picked from commit 45c5e1b9d63796d168339a44f63418f220cf2403)
Diffstat (limited to 'src/server/game/Spells/Spell.cpp')
-rw-r--r--src/server/game/Spells/Spell.cpp1196
1 files changed, 679 insertions, 517 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index de06b241220..968c0e0ca1e 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -57,7 +57,7 @@
#include "WorldSession.h"
#include <numeric>
-extern NonDefaultConstructible<pEffect> SpellEffects[TOTAL_SPELL_EFFECTS];
+extern NonDefaultConstructible<SpellEffectHandlerFn> SpellEffectHandlers[TOTAL_SPELL_EFFECTS];
SpellDestination::SpellDestination()
{
@@ -429,9 +429,9 @@ bool SpellCastTargets::HasDst() const
return (GetTargetMask() & TARGET_FLAG_DEST_LOCATION) != 0;
}
-void SpellCastTargets::Update(Unit* caster)
+void SpellCastTargets::Update(WorldObject* caster)
{
- m_objectTarget = !m_objectTargetGUID.IsEmpty() ? ((m_objectTargetGUID == caster->GetGUID()) ? caster : ObjectAccessor::GetWorldObject(*caster, m_objectTargetGUID)) : nullptr;
+ m_objectTarget = (m_objectTargetGUID == caster->GetGUID()) ? caster : ObjectAccessor::GetWorldObject(*caster, m_objectTargetGUID);
m_itemTarget = nullptr;
if (caster->GetTypeId() == TYPEID_PLAYER)
@@ -470,29 +470,7 @@ void SpellCastTargets::Update(Unit* caster)
}
}
-void SpellCastTargets::OutDebug() const
-{
- if (!m_targetMask)
- TC_LOG_DEBUG("spells", "No targets");
-
- TC_LOG_DEBUG("spells", "target mask: %u", m_targetMask);
- if (m_targetMask & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_GAMEOBJECT_MASK))
- TC_LOG_DEBUG("spells", "Object target: %s", m_objectTargetGUID.ToString().c_str());
- if (m_targetMask & TARGET_FLAG_ITEM)
- TC_LOG_DEBUG("spells", "Item target: %s", m_itemTargetGUID.ToString().c_str());
- if (m_targetMask & TARGET_FLAG_TRADE_ITEM)
- TC_LOG_DEBUG("spells", "Trade item target: %s", m_itemTargetGUID.ToString().c_str());
- if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
- TC_LOG_DEBUG("spells", "Source location: transport guid:%s trans offset: %s position: %s", m_src._transportGUID.ToString().c_str(), m_src._transportOffset.ToString().c_str(), m_src._position.ToString().c_str());
- if (m_targetMask & TARGET_FLAG_DEST_LOCATION)
- TC_LOG_DEBUG("spells", "Destination location: transport guid:%s trans offset: %s position: %s", m_dst._transportGUID.ToString().c_str(), m_dst._transportOffset.ToString().c_str(), m_dst._position.ToString().c_str());
- if (m_targetMask & TARGET_FLAG_STRING)
- TC_LOG_DEBUG("spells", "String: %s", m_strTarget.c_str());
- TC_LOG_DEBUG("spells", "speed: %f", m_speed);
- TC_LOG_DEBUG("spells", "pitch: %f", m_pitch);
-}
-
-SpellValue::SpellValue(SpellInfo const* proto, Unit const* caster)
+SpellValue::SpellValue(SpellInfo const* proto, WorldObject const* caster)
{
memset(EffectBasePoints, 0, sizeof(EffectBasePoints));
for (SpellEffectInfo const* effect : proto->GetEffects())
@@ -511,7 +489,7 @@ class TC_GAME_API SpellEvent : public BasicEvent
{
public:
SpellEvent(Spell* spell);
- virtual ~SpellEvent();
+ ~SpellEvent();
bool Execute(uint64 e_time, uint32 p_time) override;
void Abort(uint64 e_time) override;
@@ -522,7 +500,7 @@ protected:
Spell* m_Spell;
};
-Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID) :
+Spell::Spell(WorldObject* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID) :
m_spellInfo(info), m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster),
m_spellValue(new SpellValue(m_spellInfo, caster)), _spellEvent(nullptr)
{
@@ -544,11 +522,14 @@ m_spellValue(new SpellValue(m_spellInfo, caster)), _spellEvent(nullptr)
m_spellSchoolMask = info->GetSchoolMask(); // Can be override for some spell (wand shoot for example)
- if (m_attackType == RANGED_ATTACK)
+ if (Player const* playerCaster = m_caster->ToPlayer())
+ {
// wand case
- if ((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0 && m_caster->GetTypeId() == TYPEID_PLAYER)
- if (Item* pItem = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK))
- m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetTemplate()->GetDamageType());
+ if (m_attackType == RANGED_ATTACK)
+ if ((playerCaster->getClassMask() & CLASSMASK_WAND_USERS) != 0)
+ if (Item* pItem = playerCaster->GetWeaponForAttack(RANGED_ATTACK))
+ m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetTemplate()->GetDamageType());
+ }
if (Player const* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(info, SpellModOp::Doses, m_spellValue->AuraStackAmount, this);
@@ -559,7 +540,7 @@ m_spellValue(new SpellValue(m_spellInfo, caster)), _spellEvent(nullptr)
m_originalCasterGUID = m_caster->GetGUID();
if (m_originalCasterGUID == m_caster->GetGUID())
- m_originalCaster = m_caster;
+ m_originalCaster = m_caster->ToUnit();
else
{
m_originalCaster = ObjectAccessor::GetUnit(*m_caster, m_originalCasterGUID);
@@ -597,6 +578,7 @@ m_spellValue(new SpellValue(m_spellInfo, caster)), _spellEvent(nullptr)
memset(m_misc.Raw.Data, 0, sizeof(m_misc.Raw.Data));
m_SpellVisual.SpellXSpellVisualID = caster->GetCastSpellXSpellVisualId(m_spellInfo);
m_triggeredByAuraSpell = nullptr;
+ unitCaster = nullptr;
_spellAura = nullptr;
_dynObjAura = nullptr;
@@ -614,7 +596,7 @@ m_spellValue(new SpellValue(m_spellInfo, caster)), _spellEvent(nullptr)
// Determine if spell can be reflected back to the caster
// Patch 1.2 notes: Spell Reflection no longer reflects abilities
- m_canReflect = m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !m_spellInfo->HasAttribute(SPELL_ATTR0_ABILITY)
+ m_canReflect = caster->IsUnit() && m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !m_spellInfo->HasAttribute(SPELL_ATTR0_ABILITY)
&& !m_spellInfo->HasAttribute(SPELL_ATTR1_CANT_BE_REFLECTED) && !m_spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
&& !m_spellInfo->IsPassive();
@@ -681,11 +663,11 @@ void Spell::InitExplicitTargets(SpellCastTargets const& targets)
}
// try to use attacked unit as a target
else if ((m_caster->GetTypeId() == TYPEID_UNIT) && neededTargets & (TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT))
- unit = m_caster->GetVictim();
+ unit = m_caster->ToUnit()->GetVictim();
// didn't find anything - let's use self as target
if (!unit && neededTargets & (TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY | TARGET_FLAG_UNIT_ALLY))
- unit = m_caster;
+ unit = m_caster->ToUnit();
m_targets.SetUnitTarget(unit);
}
@@ -723,10 +705,10 @@ void Spell::SelectExplicitTargets()
if (Unit* target = m_targets.GetUnitTarget())
{
// check for explicit target redirection, for Grounding Totem for example
- if (m_spellInfo->GetExplicitTargetMask() & TARGET_FLAG_UNIT_ENEMY
- || (m_spellInfo->GetExplicitTargetMask() & TARGET_FLAG_UNIT && !m_caster->IsFriendlyTo(target)))
+ if ((m_spellInfo->GetExplicitTargetMask() & TARGET_FLAG_UNIT_ENEMY) ||
+ ((m_spellInfo->GetExplicitTargetMask() & TARGET_FLAG_UNIT) && !m_caster->IsFriendlyTo(target)))
{
- Unit* redirect;
+ Unit* redirect = nullptr;
switch (m_spellInfo->DmgClass)
{
case SPELL_DAMAGE_CLASS_MAGIC:
@@ -734,10 +716,10 @@ void Spell::SelectExplicitTargets()
break;
case SPELL_DAMAGE_CLASS_MELEE:
case SPELL_DAMAGE_CLASS_RANGED:
- redirect = m_caster->GetMeleeHitRedirectTarget(target, m_spellInfo);
+ // should gameobjects cast damagetype melee/ranged spells this needs to be changed
+ redirect = ASSERT_NOTNULL(m_caster->ToUnit())->GetMeleeHitRedirectTarget(target, m_spellInfo);
break;
default:
- redirect = nullptr;
break;
}
if (redirect && (redirect != target))
@@ -1203,7 +1185,7 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge
void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask)
{
- Unit* referer = nullptr;
+ WorldObject* referer = nullptr;
switch (targetType.GetReferenceType())
{
case TARGET_REFERENCE_TYPE_SRC:
@@ -1264,7 +1246,7 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge
case TARGET_UNIT_TARGET_ALLY_OR_RAID:
if (Unit* targetedUnit = m_targets.GetUnitTarget())
{
- if (!m_caster->IsInRaidWith(targetedUnit))
+ if (!m_caster->IsUnit() || !m_caster->ToUnit()->IsInRaidWith(targetedUnit))
{
targets.push_back(m_targets.GetUnitTarget());
@@ -1384,15 +1366,19 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
}
case TARGET_DEST_CASTER_FRONT_LEAP:
{
- float dist = m_spellInfo->GetEffect(effIndex)->CalcRadius(m_caster);
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ break;
+
+ float dist = m_spellInfo->GetEffect(effIndex)->CalcRadius(unitCaster);
float angle = targetType.CalcDirectionAngle();
Position pos = dest._position;
- m_caster->MovePositionToFirstCollision(pos, dist, angle);
+ unitCaster->MovePositionToFirstCollision(pos, dist, angle);
// Generate path to that point.
if (!m_preGeneratedPath)
- m_preGeneratedPath = std::make_unique<PathGenerator>(m_caster);
+ m_preGeneratedPath = std::make_unique<PathGenerator>(unitCaster);
m_preGeneratedPath->SetPathLengthLimit(dist);
@@ -1412,9 +1398,10 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
m_caster->UpdateAllowedPositionZ(dest._position.GetPositionX(), dest._position.GetPositionY(), dest._position.m_positionZ);
break;
case TARGET_DEST_SUMMONER:
- if (TempSummon const* casterSummon = m_caster->ToTempSummon())
- if (Unit const* summoner = casterSummon->GetSummoner())
- dest = SpellDestination(*summoner);
+ if (Unit const* unitCaster = m_caster->ToUnit())
+ if (TempSummon const* casterSummon = unitCaster->ToTempSummon())
+ if (Unit const* summoner = casterSummon->GetSummoner())
+ dest = SpellDestination(*summoner);
break;
default:
{
@@ -1552,14 +1539,17 @@ void Spell::SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImpli
target = m_caster->GetCharmerOrOwner();
break;
case TARGET_UNIT_PET:
- target = m_caster->GetGuardianPet();
+ if (Unit* unitCaster = m_caster->ToUnit())
+ target = unitCaster->GetGuardianPet();
break;
case TARGET_UNIT_SUMMONER:
- if (m_caster->IsSummon())
- target = m_caster->ToTempSummon()->GetSummoner();
+ if (Unit* unitCaster = m_caster->ToUnit())
+ if (unitCaster->IsSummon())
+ target = unitCaster->ToTempSummon()->GetSummoner();
break;
case TARGET_UNIT_VEHICLE:
- target = m_caster->GetVehicleBase();
+ if (Unit* unitCaster = m_caster->ToUnit())
+ target = unitCaster->GetVehicleBase();
break;
case TARGET_UNIT_PASSENGER_0:
case TARGET_UNIT_PASSENGER_1:
@@ -1569,11 +1559,13 @@ void Spell::SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImpli
case TARGET_UNIT_PASSENGER_5:
case TARGET_UNIT_PASSENGER_6:
case TARGET_UNIT_PASSENGER_7:
- if (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsVehicle())
- target = m_caster->GetVehicleKit()->GetPassenger(targetType.GetTarget() - TARGET_UNIT_PASSENGER_0);
+ if (Creature* vehicleBase = m_caster->ToCreature())
+ if (vehicleBase->IsVehicle())
+ target = vehicleBase->GetVehicleKit()->GetPassenger(targetType.GetTarget() - TARGET_UNIT_PASSENGER_0);
break;
case TARGET_UNIT_OWN_CRITTER:
- target = ObjectAccessor::GetCreatureOrPetOrVehicle(*m_caster, m_caster->GetCritterGUID());
+ if (Unit const* unitCaster = m_caster->ToUnit())
+ target = ObjectAccessor::GetCreatureOrPetOrVehicle(*m_caster, unitCaster->GetCritterGUID());
break;
default:
break;
@@ -1581,8 +1573,13 @@ void Spell::SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImpli
CallScriptObjectTargetSelectHandlers(target, effIndex, targetType);
- if (target && target->ToUnit())
- AddUnitTarget(target->ToUnit(), 1 << effIndex, checkIfValid);
+ if (target)
+ {
+ if (Unit* unit = target->ToUnit())
+ AddUnitTarget(unit, 1 << effIndex, checkIfValid);
+ else if (GameObject* go = target->ToGameObject())
+ AddGOTarget(go, 1 << effIndex);
+ }
}
void Spell::SelectImplicitTargetObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
@@ -1676,7 +1673,7 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTarge
float b = tangent(m_targets.GetPitch());
float a = (srcToDestDelta - dist2d * b) / (dist2d * dist2d);
if (a > -0.0001f)
- a = 0;
+ a = 0.f;
// We should check if triggered spell has greater range (which is true in many cases, and initial spell has too short max range)
// limit max range to 300 yards, sometimes triggered spells can have 50000yds
@@ -1684,15 +1681,16 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTarge
if (SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(effect->TriggerSpell, GetCastDifficulty()))
bestDist = std::min(std::max(bestDist, triggerSpellInfo->GetMaxRange(false)), std::min(dist2d, 300.0f));
- std::list<WorldObject*>::const_iterator itr = targets.begin();
- for (; itr != targets.end(); ++itr)
+ // GameObjects don't cast traj
+ Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
+ for (auto itr = targets.begin(); itr != targets.end(); ++itr)
{
- if (m_spellInfo->CheckTarget(m_caster, *itr, true) != SPELL_CAST_OK)
+ if (m_spellInfo->CheckTarget(unitCaster, *itr, true) != SPELL_CAST_OK)
continue;
if (Unit* unit = (*itr)->ToUnit())
{
- if (m_caster == *itr || m_caster->IsOnVehicle(unit) || unit->GetVehicle())
+ if (unitCaster == *itr || unitCaster->IsOnVehicle(unit) || unit->GetVehicle())
continue;
if (Creature* creatureTarget = unit->ToCreature())
@@ -1702,14 +1700,14 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTarge
}
}
- const float size = std::max((*itr)->GetCombatReach(), 1.0f);
- const float objDist2d = srcPos.GetExactDist2d(*itr);
- const float dz = (*itr)->GetPositionZ() - srcPos.m_positionZ;
+ float const size = std::max((*itr)->GetCombatReach(), 1.0f);
+ float const objDist2d = srcPos.GetExactDist2d(*itr);
+ float const dz = (*itr)->GetPositionZ() - srcPos.m_positionZ;
- const float horizontalDistToTraj = std::fabs(objDist2d * std::sin(srcPos.GetRelativeAngle(*itr)));
- const float sizeFactor = std::cos((horizontalDistToTraj / size) * (M_PI / 2.0f));
- const float distToHitPoint = std::max(objDist2d * std::cos(srcPos.GetRelativeAngle(*itr)) - size * sizeFactor, 0.0f);
- const float height = distToHitPoint * (a * distToHitPoint + b);
+ float const horizontalDistToTraj = std::fabs(objDist2d * std::sin(srcPos.GetRelativeAngle(*itr)));
+ float const sizeFactor = std::cos((horizontalDistToTraj / size) * (M_PI / 2.0f));
+ float const distToHitPoint = std::max(objDist2d * std::cos(srcPos.GetRelativeAngle(*itr)) - size * sizeFactor, 0.0f);
+ float const height = distToHitPoint * (a * distToHitPoint + b);
if (fabs(dz - height) > size + b / 2.0f + TRAJECTORY_MISSILE_SIZE)
continue;
@@ -1723,17 +1721,14 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTarge
if (dist2d > bestDist)
{
- float x = m_targets.GetSrcPos()->m_positionX + std::cos(m_caster->GetOrientation()) * bestDist;
- float y = m_targets.GetSrcPos()->m_positionY + std::sin(m_caster->GetOrientation()) * bestDist;
+ float x = m_targets.GetSrcPos()->m_positionX + std::cos(unitCaster->GetOrientation()) * bestDist;
+ float y = m_targets.GetSrcPos()->m_positionY + std::sin(unitCaster->GetOrientation()) * bestDist;
float z = m_targets.GetSrcPos()->m_positionZ + bestDist * (a * bestDist + b);
- SpellDestination dest(x, y, z, m_caster->GetOrientation());
+ SpellDestination dest(x, y, z, unitCaster->GetOrientation());
CallScriptDestinationTargetSelectHandlers(dest, effIndex, targetType);
m_targets.ModDst(dest);
}
-
- if (Vehicle* veh = m_caster->GetVehicleKit())
- veh->SetLastShootPos(*m_targets.GetDstPos());
}
void Spell::SelectImplicitLineTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask)
@@ -1809,9 +1804,9 @@ void Spell::SelectEffectTypeImplicitTargets(uint32 effIndex)
{
case SPELL_EFFECT_SUMMON_RAF_FRIEND:
case SPELL_EFFECT_SUMMON_PLAYER:
- if (m_caster->GetTypeId() == TYPEID_PLAYER && !m_caster->GetTarget().IsEmpty())
+ if (m_caster->GetTypeId() == TYPEID_PLAYER && !m_caster->ToPlayer()->GetTarget().IsEmpty())
{
- WorldObject* target = ObjectAccessor::FindPlayer(m_caster->GetTarget());
+ WorldObject* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetTarget());
CallScriptObjectTargetSelectHandlers(target, SpellEffIndex(effIndex), SpellImplicitTargetInfo());
// scripts may modify the target - recheck
@@ -1939,7 +1934,7 @@ uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionConta
}
template<class SEARCHER>
-void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, Unit* referer, Position const* pos, float radius)
+void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius)
{
if (!containerMask)
return;
@@ -1979,7 +1974,7 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargetObjectTypes objec
return target;
}
-void Spell::SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, Unit* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer* condList)
+void Spell::SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, WorldObject* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer* condList)
{
uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList);
if (!containerTypeMask)
@@ -2093,7 +2088,7 @@ GameObject* Spell::SearchSpellFocus()
GameObject* focus = nullptr;
Trinity::GameObjectFocusCheck check(m_caster, m_spellInfo->RequiresSpellFocus);
Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck> searcher(m_caster, focus, check);
- SearchTargets<Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck> > (searcher, GRID_MAP_TYPE_MASK_GAMEOBJECT, m_caster, m_caster, m_caster->GetVisibilityRange());
+ SearchTargets(searcher, GRID_MAP_TYPE_MASK_GAMEOBJECT, m_caster, m_caster, m_caster->GetVisibilityRange());
return focus;
}
@@ -2210,7 +2205,7 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
return;
if (checkIfValid)
- if (m_spellInfo->CheckTarget(m_caster, target, implicit || m_caster->GetEntry() == WORLD_TRIGGER) != SPELL_CAST_OK) // skip stealth checks for GO casts
+ if (m_spellInfo->CheckTarget(m_caster, target, implicit) != SPELL_CAST_OK) // skip stealth checks for AOE
return;
// Check for effect immune skip if immuned
@@ -2241,10 +2236,8 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
targetInfo.IsCrit = false;
// Calculate hit result
- if (m_originalCaster)
- targetInfo.MissCondition = m_originalCaster->SpellHitResult(target, m_spellInfo, m_canReflect && !(IsPositive() && m_caster->IsFriendlyTo(target)));
- else
- targetInfo.MissCondition = SPELL_MISS_EVADE; //SPELL_MISS_NONE;
+ WorldObject* caster = m_originalCaster ? m_originalCaster : m_caster;
+ targetInfo.MissCondition = caster->SpellHitResult(target, m_spellInfo, m_canReflect && !(IsPositive() && m_caster->IsFriendlyTo(target)));
// Spell have speed - need calculate incoming time
// Incoming time is zero for self casts. At least I think so.
@@ -2269,8 +2262,9 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
// If target reflect spell back to caster
if (targetInfo.MissCondition == SPELL_MISS_REFLECT)
{
- // Calculate reflected spell result on caster
- targetInfo.ReflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, false); // can't reflect twice
+ // Calculate reflected spell result on caster (shouldn't be able to reflect gameobject spells)
+ Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
+ targetInfo.ReflectResult = unitCaster->SpellHitResult(unitCaster, m_spellInfo, false); // can't reflect twice
// Proc spell reflect aura when missile hits the original target
target->m_Events.AddEvent(new ProcReflectDelayed(target, m_originalCasterGUID), target->m_Events.CalculateTime(targetInfo.TimeDelay));
@@ -2385,7 +2379,7 @@ int64 Spell::GetUnitTargetCountForEffect(SpellEffIndex effect) const
{
return std::count_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [effect](TargetInfo const& targetInfo)
{
- return targetInfo.EffectMask & (1 << effect);
+ return targetInfo.MissCondition == SPELL_MISS_MISS && targetInfo.EffectMask & (1 << effect);
});
}
@@ -2407,7 +2401,7 @@ int64 Spell::GetItemTargetCountForEffect(SpellEffIndex effect) const
void Spell::TargetInfo::PreprocessTarget(Spell* spell)
{
- Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
+ Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
if (!unit)
return;
@@ -2422,7 +2416,7 @@ void Spell::TargetInfo::PreprocessTarget(Spell* spell)
if (MissCondition == SPELL_MISS_NONE)
_spellHitTarget = unit;
else if (MissCondition == SPELL_MISS_REFLECT && ReflectResult == SPELL_MISS_NONE)
- _spellHitTarget = spell->m_caster;
+ _spellHitTarget = spell->m_caster->ToUnit();
_enablePVP = false; // need to check PvP state before spell effects, but act on it afterwards
if (_spellHitTarget)
@@ -2435,7 +2429,7 @@ void Spell::TargetInfo::PreprocessTarget(Spell* spell)
if (missInfo != SPELL_MISS_NONE)
{
if (missInfo != SPELL_MISS_MISS)
- spell->m_caster->SendSpellMiss(unit, spell->m_spellInfo->Id, missInfo);
+ spell->m_caster->ToUnit()->SendSpellMiss(unit, spell->m_spellInfo->Id, missInfo);
spell->m_damage = 0;
_spellHitTarget = nullptr;
}
@@ -2450,7 +2444,7 @@ void Spell::TargetInfo::PreprocessTarget(Spell* spell)
void Spell::TargetInfo::DoTargetSpellHit(Spell* spell, uint8 effIndex)
{
- Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
+ Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
if (!unit)
return;
@@ -2479,7 +2473,7 @@ void Spell::TargetInfo::DoTargetSpellHit(Spell* spell, uint8 effIndex)
void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell)
{
- Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
+ Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
if (!unit)
return;
@@ -2494,7 +2488,7 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell)
// Get original caster (if exist) and calculate damage/healing from him data
// Skip if m_originalCaster not available
- Unit* caster = spell->m_originalCaster ? spell->m_originalCaster : spell->m_caster;
+ Unit* caster = spell->m_originalCaster ? spell->m_originalCaster : spell->m_caster->ToUnit();
if (!caster)
return;
@@ -2640,8 +2634,9 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell)
// Failed Pickpocket, reveal rogue
if (MissCondition == SPELL_MISS_RESIST && spell->m_spellInfo->HasAttribute(SPELL_ATTR0_CU_PICKPOCKET) && spell->unitTarget->GetTypeId() == TYPEID_UNIT)
{
- spell->m_caster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Interacting);
- spell->unitTarget->ToCreature()->EngageWithTarget(spell->m_caster);
+ Unit* unitCaster = ASSERT_NOTNULL(spell->m_caster->ToUnit());
+ unitCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Interacting);
+ spell->unitTarget->ToCreature()->EngageWithTarget(unitCaster);
}
}
@@ -2669,7 +2664,8 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell)
// _spellHitTarget can be null if spell is missed in DoSpellHitOnUnit
if (MissCondition != SPELL_MISS_EVADE && _spellHitTarget && !spell->m_caster->IsFriendlyTo(unit) && (!spell->IsPositive() || spell->m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)))
{
- spell->m_caster->AttackedTarget(unit, spell->m_spellInfo->HasInitialAggro());
+ if (Unit* unitCaster = spell->m_caster->ToUnit())
+ unitCaster->AttackedTarget(unit, spell->m_spellInfo->HasInitialAggro());
if (!unit->IsStandState())
unit->SetStandState(UNIT_STAND_STATE_STAND);
@@ -2683,11 +2679,20 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell)
{
//AI functions
if (_spellHitTarget->GetTypeId() == TYPEID_UNIT)
+ {
if (_spellHitTarget->ToCreature()->IsAIEnabled)
- _spellHitTarget->ToCreature()->AI()->SpellHit(spell->m_caster, spell->m_spellInfo);
+ {
+ if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT)
+ _spellHitTarget->ToCreature()->AI()->SpellHit(spell->m_caster->ToGameObject(), spell->m_spellInfo);
+ else
+ _spellHitTarget->ToCreature()->AI()->SpellHit(spell->m_caster->ToUnit(), spell->m_spellInfo);
+ }
+ }
if (spell->m_caster->GetTypeId() == TYPEID_UNIT && spell->m_caster->ToCreature()->IsAIEnabled)
spell->m_caster->ToCreature()->AI()->SpellHitTarget(_spellHitTarget, spell->m_spellInfo);
+ else if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT && spell->m_caster->ToGameObject()->AI())
+ spell->m_caster->ToGameObject()->AI()->SpellHitTarget(_spellHitTarget, spell->m_spellInfo);
// Needs to be called after dealing damage/healing to not remove breaking on damage auras
spell->DoTriggersOnSpellHit(_spellHitTarget, EffectMask);
@@ -2701,7 +2706,7 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell)
void Spell::GOTargetInfo::DoTargetSpellHit(Spell* spell, uint8 effIndex)
{
- GameObject* go = ObjectAccessor::GetGameObject(*spell->m_caster, TargetGUID);
+ GameObject* go = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToGameObject() : ObjectAccessor::GetGameObject(*spell->m_caster, TargetGUID);
if (!go)
return;
@@ -2709,8 +2714,19 @@ void Spell::GOTargetInfo::DoTargetSpellHit(Spell* spell, uint8 effIndex)
spell->HandleEffects(nullptr, nullptr, go, effIndex, SPELL_EFFECT_HANDLE_HIT_TARGET);
+ //AI functions
if (go->AI())
- go->AI()->SpellHit(spell->m_caster, spell->m_spellInfo);
+ {
+ if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT)
+ go->AI()->SpellHit(spell->m_caster->ToGameObject(), spell->m_spellInfo);
+ else
+ go->AI()->SpellHit(spell->m_caster->ToUnit(), spell->m_spellInfo);
+ }
+
+ if (spell->m_caster->GetTypeId() == TYPEID_UNIT && spell->m_caster->ToCreature()->IsAIEnabled)
+ spell->m_caster->ToCreature()->AI()->SpellHitTarget(go, spell->m_spellInfo);
+ else if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT && spell->m_caster->ToGameObject()->AI())
+ spell->m_caster->ToGameObject()->AI()->SpellHitTarget(go, spell->m_spellInfo);
spell->CallScriptOnHitHandlers();
spell->CallScriptAfterHitHandlers();
@@ -2778,17 +2794,23 @@ SpellMissInfo Spell::PreprocessSpellHit(Unit* unit, TargetInfo& hitInfo)
playerOwner->UpdatePvP(true);
}
}
- if (unit->IsInCombat() && m_spellInfo->HasInitialAggro())
+
+ if (m_originalCaster && unit->IsInCombat() && m_spellInfo->HasInitialAggro())
{
- if (m_caster->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE)) // only do explicit combat forwarding for PvP enabled units
- m_caster->GetCombatManager().InheritCombatStatesFrom(unit); // for creature v creature combat, the threat forward does it for us
- unit->GetThreatManager().ForwardThreatForAssistingMe(m_caster, 0.0f, nullptr, true);
+ if (m_originalCaster->HasUnitFlag(UNIT_FLAG_PVP_ATTACKABLE)) // only do explicit combat forwarding for PvP enabled units
+ m_originalCaster->GetCombatManager().InheritCombatStatesFrom(unit); // for creature v creature combat, the threat forward does it for us
+ unit->GetThreatManager().ForwardThreatForAssistingMe(m_originalCaster, 0.0f, nullptr, true);
}
}
}
+ // original caster for auras
+ WorldObject* origCaster = m_caster;
+ if (m_originalCaster)
+ origCaster = m_originalCaster;
+
// check immunity due to diminishing returns
- if (m_originalCaster && Aura::BuildEffectMaskForOwner(m_spellInfo, MAX_EFFECT_MASK, unit))
+ if (Aura::BuildEffectMaskForOwner(m_spellInfo, MAX_EFFECT_MASK, unit))
{
for (SpellEffectInfo const* auraSpellEffect : m_spellInfo->GetEffects())
if (auraSpellEffect)
@@ -2812,7 +2834,7 @@ SpellMissInfo Spell::PreprocessSpellHit(Unit* unit, TargetInfo& hitInfo)
// Now Reduce spell duration using data received at spell hit
// check whatever effects we're going to apply, diminishing returns only apply to negative aura effects
hitInfo.Positive = true;
- if (m_originalCaster == unit || !m_originalCaster->IsFriendlyTo(unit))
+ if (origCaster == unit || !origCaster->IsFriendlyTo(unit))
{
for (SpellEffectInfo const* effect : m_spellInfo->GetEffects())
{
@@ -2831,7 +2853,7 @@ SpellMissInfo Spell::PreprocessSpellHit(Unit* unit, TargetInfo& hitInfo)
hitInfo.AuraDuration = m_spellInfo->GetMaxDuration();
// unit is immune to aura if it was diminished to 0 duration
- if (!hitInfo.Positive && !unit->ApplyDiminishingToDuration(m_spellInfo, hitInfo.AuraDuration, m_originalCaster, diminishLevel))
+ if (!hitInfo.Positive && !unit->ApplyDiminishingToDuration(m_spellInfo, hitInfo.AuraDuration, origCaster, diminishLevel))
if (std::all_of(std::begin(m_spellInfo->GetEffects()), std::end(m_spellInfo->GetEffects()), [](SpellEffectInfo const* effInfo) { return !effInfo || !effInfo->IsEffect() || effInfo->IsEffect(SPELL_EFFECT_APPLY_AURA); }))
return SPELL_MISS_IMMUNE;
}
@@ -2841,10 +2863,13 @@ SpellMissInfo Spell::PreprocessSpellHit(Unit* unit, TargetInfo& hitInfo)
void Spell::DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& hitInfo)
{
- uint8 aura_effmask = Aura::BuildEffectMaskForOwner(m_spellInfo, 1 << effIndex, unit);
- if (aura_effmask)
+ if (uint32 aura_effmask = Aura::BuildEffectMaskForOwner(m_spellInfo, 1 << effIndex, unit))
{
+ WorldObject* caster = m_caster;
if (m_originalCaster)
+ caster = m_originalCaster;
+
+ if (caster)
{
bool refresh = false;
@@ -2855,7 +2880,7 @@ void Spell::DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& hitInfo)
AuraCreateInfo createInfo(m_castId, m_spellInfo, GetCastDifficulty(), allAuraEffectMask, unit);
createInfo
- .SetCaster(m_originalCaster)
+ .SetCasterGUID(caster->GetGUID())
.SetBaseAmount(&hitInfo.AuraBasePoints[0])
.SetCastItem(m_castItemGUID, m_castItemEntry, m_castItemLevel)
.SetPeriodicReset(resetPeriodicTimer)
@@ -2881,7 +2906,7 @@ void Spell::DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& hitInfo)
_spellAura->SetDiminishGroup(hitInfo.DRGroup);
- hitInfo.AuraDuration = m_originalCaster->ModSpellDuration(m_spellInfo, unit, hitInfo.AuraDuration, hitInfo.Positive, _spellAura->GetEffectMask());
+ hitInfo.AuraDuration = caster->ModSpellDuration(m_spellInfo, unit, hitInfo.AuraDuration, hitInfo.Positive, _spellAura->GetEffectMask());
if (hitInfo.AuraDuration > 0)
{
@@ -2889,7 +2914,7 @@ void Spell::DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& hitInfo)
// Haste modifies duration of channeled spells
if (m_spellInfo->IsChanneled())
- m_originalCaster->ModSpellDurationTime(m_spellInfo, hitInfo.AuraDuration, this);
+ caster->ModSpellDurationTime(m_spellInfo, hitInfo.AuraDuration, this);
else if (m_spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION))
{
int32 origDuration = hitInfo.AuraDuration;
@@ -2996,10 +3021,11 @@ bool Spell::UpdateChanneledTargetList()
{
if (targetInfo.MissCondition == SPELL_MISS_NONE && (channelTargetEffectMask & targetInfo.EffectMask))
{
- Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
+ Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
if (!unit)
{
- m_caster->RemoveChannelObject(targetInfo.TargetGUID);
+ if (Unit* unitCaster =m_caster->ToUnit())
+ unitCaster->RemoveChannelObject(targetInfo.TargetGUID);
continue;
}
@@ -3013,13 +3039,15 @@ bool Spell::UpdateChanneledTargetList()
{
targetInfo.EffectMask &= ~aurApp->GetEffectMask();
unit->RemoveAura(aurApp);
- m_caster->RemoveChannelObject(targetInfo.TargetGUID);
+ if (Unit* unitCaster = m_caster->ToUnit())
+ unitCaster->RemoveChannelObject(targetInfo.TargetGUID);
continue;
}
}
else // aura is dispelled
{
- m_caster->RemoveChannelObject(targetInfo.TargetGUID);
+ if (Unit* unitCaster = m_caster->ToUnit())
+ unitCaster->RemoveChannelObject(targetInfo.TargetGUID);
continue;
}
}
@@ -3066,20 +3094,22 @@ void Spell::prepare(SpellCastTargets const& targets, AuraEffect const* triggered
_spellEvent = new SpellEvent(this);
m_caster->m_Events.AddEvent(_spellEvent, m_caster->m_Events.CalculateTime(1));
- //Prevent casting at cast another spell (ServerSide check)
- if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS) && m_caster->IsNonMeleeSpellCast(false, true, true, m_spellInfo->Id == 75) && !m_castId.IsEmpty())
+ // check disables
+ if (DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, m_caster))
{
- SendCastResult(SPELL_FAILED_SPELL_IN_PROGRESS);
+ SendCastResult(SPELL_FAILED_SPELL_UNAVAILABLE);
finish(false);
return;
}
- if (DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, m_caster))
+ // Prevent casting at cast another spell (ServerSide check)
+ if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS) && m_caster->ToUnit() && m_caster->ToUnit()->IsNonMeleeSpellCast(false, true, true, m_spellInfo->Id == 75) && !m_castId.IsEmpty())
{
- SendCastResult(SPELL_FAILED_SPELL_UNAVAILABLE);
+ SendCastResult(SPELL_FAILED_SPELL_IN_PROGRESS);
finish(false);
return;
}
+
LoadScripts();
// Fill cost data (do not use power for item casts)
@@ -3087,7 +3117,7 @@ void Spell::prepare(SpellCastTargets const& targets, AuraEffect const* triggered
m_powerCost = m_spellInfo->CalcPowerCost(m_caster, m_spellSchoolMask, this);
// Set combo point requirement
- if ((_triggeredCastFlags & TRIGGERED_IGNORE_COMBO_POINTS) || m_CastItem || !m_caster->m_playerMovingMe)
+ if ((_triggeredCastFlags & TRIGGERED_IGNORE_COMBO_POINTS) || m_CastItem)
m_needComboPoints = false;
uint32 param1 = 0, param2 = 0;
@@ -3137,8 +3167,8 @@ void Spell::prepare(SpellCastTargets const& targets, AuraEffect const* triggered
// exception are only channeled spells that have no casttime and SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING
// (even if they are interrupted on moving, spells with almost immediate effect get to have their effect processed before movement interrupter kicks in)
// don't cancel spells which are affected by a SPELL_AURA_CAST_WHILE_WALKING effect
- if (((m_spellInfo->IsChanneled() || m_casttime) && m_caster->GetTypeId() == TYPEID_PLAYER && !(m_caster->IsCharmed() && m_caster->GetCharmerGUID().IsCreature()) && m_caster->isMoving() &&
- m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Movement)) && !m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo))
+ if (((m_spellInfo->IsChanneled() || m_casttime) && m_caster->GetTypeId() == TYPEID_PLAYER && !(m_caster->ToPlayer()->IsCharmed() && m_caster->ToPlayer()->GetCharmerGUID().IsCreature()) && m_caster->ToPlayer()->isMoving() &&
+ m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Movement)) && !m_caster->ToPlayer()->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo))
{
// 1. Has casttime, 2. Or doesn't have flag to allow movement during channel
if (m_casttime || !m_spellInfo->IsMoveAllowedChannel())
@@ -3150,7 +3180,7 @@ void Spell::prepare(SpellCastTargets const& targets, AuraEffect const* triggered
}
// focus if not controlled creature
- if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
+ if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->ToUnit()->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
{
if (!(m_spellInfo->IsNextMeleeSwingSpell() || IsAutoRepeat()))
{
@@ -3176,12 +3206,15 @@ void Spell::prepare(SpellCastTargets const& targets, AuraEffect const* triggered
cast(true);
else
{
- // stealth must be removed at cast starting (at show channel bar)
- // skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
- if (!(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS) && m_spellInfo->IsBreakingStealth() && !m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_ACTION_AURA_INTERRUPT_FLAGS))
- m_caster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Action);
+ if (Unit* unitCaster = m_caster->ToUnit())
+ {
+ // stealth must be removed at cast starting (at show channel bar)
+ // skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
+ if (!(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS) && m_spellInfo->IsBreakingStealth() && !m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_ACTION_AURA_INTERRUPT_FLAGS))
+ unitCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Action);
- m_caster->SetCurrentCastSpell(this);
+ unitCaster->SetCurrentCastSpell(this);
+ }
SendSpellStart();
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_GCD))
@@ -3218,7 +3251,7 @@ void Spell::cancel()
case SPELL_STATE_CASTING:
for (TargetInfo const& targetInfo : m_UniqueTargetInfo)
if (targetInfo.MissCondition == SPELL_MISS_NONE)
- if (Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID))
+ if (Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID))
unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL);
SendChannelUpdate(0);
@@ -3236,9 +3269,13 @@ void Spell::cancel()
if (m_selfContainer && *m_selfContainer == this)
*m_selfContainer = nullptr;
- m_caster->RemoveDynObject(m_spellInfo->Id);
- if (m_spellInfo->IsChanneled()) // if not channeled then the object for the current cast wasn't summoned yet
- m_caster->RemoveGameObject(m_spellInfo->Id, true);
+ // originalcaster handles gameobjects/dynobjects for gob caster
+ if (m_originalCaster)
+ {
+ m_originalCaster->RemoveDynObject(m_spellInfo->Id);
+ if (m_spellInfo->IsChanneled()) // if not channeled then the object for the current cast wasn't summoned yet
+ m_originalCaster->RemoveGameObject(m_spellInfo->Id, true);
+ }
//set state back so finish will be processed
m_spellState = oldState;
@@ -3301,7 +3338,7 @@ void Spell::_cast(bool skipCheck)
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING))
if (m_caster->GetTypeId() == TYPEID_UNIT && m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
- m_caster->SetInFront(m_targets.GetObjectTarget());
+ m_caster->ToCreature()->SetInFront(m_targets.GetObjectTarget());
// Should this be done for original caster?
Player* modOwner = m_caster->GetSpellModOwner();
@@ -3371,11 +3408,13 @@ void Spell::_cast(bool skipCheck)
DiminishingReturnsType type = m_spellInfo->GetDiminishingReturnsGroupType();
if (type == DRTYPE_ALL || (type == DRTYPE_PLAYER && target->IsAffectedByDiminishingReturns()))
{
- Unit* caster = m_originalCaster ? m_originalCaster : m_caster;
- if (target->HasStrongerAuraWithDR(m_spellInfo, caster))
+ if (Unit* caster = m_originalCaster ? m_originalCaster : m_caster->ToUnit())
{
- cleanupSpell(SPELL_FAILED_AURA_BOUNCED);
- return;
+ if (target->HasStrongerAuraWithDR(m_spellInfo, caster))
+ {
+ cleanupSpell(SPELL_FAILED_AURA_BOUNCED);
+ return;
+ }
}
}
}
@@ -3385,10 +3424,10 @@ void Spell::_cast(bool skipCheck)
// if the spell allows the creature to turn while casting, then adjust server-side orientation to face the target now
// client-side orientation is handled by the client itself, as the cast target is targeted due to Creature::FocusTarget
- if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
+ if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->ToUnit()->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
if (!m_spellInfo->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST))
if (WorldObject* objTarget = m_targets.GetObjectTarget())
- m_caster->SetInFront(objTarget);
+ m_caster->ToCreature()->SetInFront(objTarget);
SelectSpellTargets();
@@ -3407,9 +3446,10 @@ void Spell::_cast(bool skipCheck)
return;
}
- if (m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET))
- if (Creature* pet = ObjectAccessor::GetCreature(*m_caster, m_caster->GetPetGUID()))
- pet->DespawnOrUnsummon();
+ if (Unit* unitCaster = m_caster->ToUnit())
+ if (m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET))
+ if (Creature* pet = ObjectAccessor::GetCreature(*m_caster, unitCaster->GetPetGUID()))
+ pet->DespawnOrUnsummon();
PrepareTriggersExecutedOnHit();
@@ -3472,8 +3512,9 @@ void Spell::_cast(bool skipCheck)
m_spellState = SPELL_STATE_DELAYED;
SetDelayStart(0);
- if (m_caster->HasUnitState(UNIT_STATE_CASTING) && !m_caster->IsNonMeleeSpellCast(false, false, true))
- m_caster->ClearUnitState(UNIT_STATE_CASTING);
+ if (Unit* unitCaster = m_caster->ToUnit())
+ if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true))
+ unitCaster->ClearUnitState(UNIT_STATE_CASTING);
}
else
{
@@ -3488,7 +3529,10 @@ void Spell::_cast(bool skipCheck)
for (int32 id : *spell_triggered)
{
if (id < 0)
- m_caster->RemoveAurasDueToSpell(-id);
+ {
+ if (Unit* unitCaster = m_caster->ToUnit())
+ unitCaster->RemoveAurasDueToSpell(-id);
+ }
else
m_caster->CastSpell(m_targets.GetUnitTarget() ? m_targets.GetUnitTarget() : m_caster, id, true);
}
@@ -3499,10 +3543,10 @@ void Spell::_cast(bool skipCheck)
modOwner->SetSpellModTakingSpell(this, false);
//Clear spell cooldowns after every spell is cast if .cheat cooldown is enabled.
- if (modOwner->GetCommandStatus(CHEAT_COOLDOWN))
+ if (m_originalCaster && modOwner->GetCommandStatus(CHEAT_COOLDOWN))
{
- m_caster->GetSpellHistory()->ResetCooldown(m_spellInfo->Id, true);
- m_caster->GetSpellHistory()->RestoreCharge(m_spellInfo->ChargeCategoryId);
+ m_originalCaster->GetSpellHistory()->ResetCooldown(m_spellInfo->Id, true);
+ m_originalCaster->GetSpellHistory()->RestoreCharge(m_spellInfo->ChargeCategoryId);
}
}
@@ -3569,17 +3613,16 @@ void Spell::handle_immediate()
// Apply haste mods
m_caster->ModSpellDurationTime(m_spellInfo, duration, this);
- m_spellState = SPELL_STATE_CASTING;
- m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags, m_spellInfo->ChannelInterruptFlags2);
m_channeledDuration = duration;
SendChannelStart(duration);
}
else if (duration == -1)
- {
- m_spellState = SPELL_STATE_CASTING;
- m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags, m_spellInfo->ChannelInterruptFlags2);
SendChannelStart(duration);
- }
+
+ m_spellState = SPELL_STATE_CASTING;
+
+ // GameObjects shouldn't cast channeled spells
+ ASSERT_NOTNULL(m_caster->ToUnit())->AddInterruptMask(m_spellInfo->ChannelInterruptFlags, m_spellInfo->ChannelInterruptFlags2);
}
PrepareTargetProcessing();
@@ -3744,23 +3787,23 @@ void Spell::_handle_immediate_phase()
void Spell::_handle_finish_phase()
{
- if (m_caster->m_playerMovingMe)
+ if (Unit* unitCaster = m_caster->ToUnit())
{
// Take for real after all targets are processed
if (m_needComboPoints)
- m_caster->m_playerMovingMe->ClearComboPoints();
+ unitCaster->ClearComboPoints();
// Real add combo points from effects
if (m_comboPointGain)
- m_caster->m_playerMovingMe->GainSpellComboPoints(m_comboPointGain);
- }
+ unitCaster->AddComboPoints(m_comboPointGain);
- if (m_caster->m_extraAttacks && m_spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
- {
- if (Unit* victim = ObjectAccessor::GetUnit(*m_caster, m_targets.GetOrigUnitTargetGUID()))
- m_caster->HandleProcExtraAttackFor(victim);
- else
- m_caster->m_extraAttacks = 0;
+ if (unitCaster->m_extraAttacks && m_spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
+ {
+ if (Unit* victim = ObjectAccessor::GetUnit(*unitCaster, m_targets.GetOrigUnitTargetGUID()))
+ unitCaster->HandleProcExtraAttackFor(victim);
+ else
+ unitCaster->m_extraAttacks = 0;
+ }
}
// Handle procs on finish
@@ -3781,10 +3824,13 @@ void Spell::_handle_finish_phase()
void Spell::SendSpellCooldown()
{
+ if (!m_caster->IsUnit())
+ return;
+
if (m_CastItem)
- m_caster->GetSpellHistory()->HandleCooldowns(m_spellInfo, m_CastItem, this);
+ m_caster->ToUnit()->GetSpellHistory()->HandleCooldowns(m_spellInfo, m_CastItem, this);
else
- m_caster->GetSpellHistory()->HandleCooldowns(m_spellInfo, m_castItemEntry, this);
+ m_caster->ToUnit()->GetSpellHistory()->HandleCooldowns(m_spellInfo, m_castItemEntry, this);
}
void Spell::update(uint32 difftime)
@@ -3808,9 +3854,9 @@ void Spell::update(uint32 difftime)
// with the exception of spells affected with SPELL_AURA_CAST_WHILE_WALKING effect
SpellEffectInfo const* effect = m_spellInfo->GetEffect(EFFECT_0);
if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) &&
- m_caster->isMoving() && (m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Movement)) &&
- ((effect && effect->Effect != SPELL_EFFECT_STUCK) || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR)) &&
- !m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo))
+ m_caster->ToPlayer()->isMoving() && (m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Movement)) &&
+ ((effect && effect->Effect != SPELL_EFFECT_STUCK) || !m_caster->ToPlayer()->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR)) &&
+ !m_caster->ToPlayer()->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo))
{
// don't cancel for melee, autorepeat, triggered and instant spells
if (!m_spellInfo->IsNextMeleeSwingSpell() && !IsAutoRepeat() && !IsTriggered() && !(IsChannelActive() && m_spellInfo->IsMoveAllowedChannel()))
@@ -3818,7 +3864,7 @@ void Spell::update(uint32 difftime)
// if charmed by creature, trust the AI not to cheat and allow the cast to proceed
// @todo this is a hack, "creature" movesplines don't differentiate turning/moving right now
// however, checking what type of movement the spline is for every single spline would be really expensive
- if (!m_caster->GetCharmerGUID().IsCreature())
+ if (!m_caster->ToPlayer()->GetCharmerGUID().IsCreature())
cancel();
}
}
@@ -3852,7 +3898,7 @@ void Spell::update(uint32 difftime)
// Also remove applied auras
for (TargetInfo const& target : m_UniqueTargetInfo)
- if (Unit* unit = m_caster->GetGUID() == target.TargetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, target.TargetGUID))
+ if (Unit* unit = m_caster->GetGUID() == target.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, target.TargetGUID))
unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL);
}
@@ -3879,44 +3925,48 @@ void Spell::update(uint32 difftime)
void Spell::finish(bool ok)
{
+ if (m_spellState == SPELL_STATE_FINISHED)
+ return;
+ m_spellState = SPELL_STATE_FINISHED;
+
if (!m_caster)
return;
- if (m_spellState == SPELL_STATE_FINISHED)
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
return;
- m_spellState = SPELL_STATE_FINISHED;
if (m_spellInfo->IsChanneled())
- m_caster->UpdateInterruptMask();
+ unitCaster->UpdateInterruptMask();
- if (m_caster->HasUnitState(UNIT_STATE_CASTING) && !m_caster->IsNonMeleeSpellCast(false, false, true))
- m_caster->ClearUnitState(UNIT_STATE_CASTING);
+ if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true))
+ unitCaster->ClearUnitState(UNIT_STATE_CASTING);
// Unsummon summon as possessed creatures on spell cancel
- if (m_spellInfo->IsChanneled() && m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (m_spellInfo->IsChanneled() && unitCaster->GetTypeId() == TYPEID_PLAYER)
{
- if (Unit* charm = m_caster->GetCharm())
+ if (Unit* charm = unitCaster->GetCharm())
if (charm->GetTypeId() == TYPEID_UNIT
&& charm->ToCreature()->HasUnitTypeMask(UNIT_MASK_PUPPET)
&& charm->m_unitData->CreatedBySpell == int32(m_spellInfo->Id))
((Puppet*)charm)->UnSummon();
}
- if (Creature* creatureCaster = m_caster->ToCreature())
+ if (Creature* creatureCaster = unitCaster->ToCreature())
creatureCaster->ReleaseFocus(this);
if (!ok)
return;
- if (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsSummon())
+ if (unitCaster->GetTypeId() == TYPEID_UNIT && unitCaster->IsSummon())
{
// Unsummon statue
- uint32 spell = m_caster->m_unitData->CreatedBySpell;
+ uint32 spell = unitCaster->m_unitData->CreatedBySpell;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell, GetCastDifficulty());
if (spellInfo && spellInfo->IconFileDataId == 134230)
{
- TC_LOG_DEBUG("spells", "Statue %s is unsummoned in spell %d finish", m_caster->GetGUID().ToString().c_str(), m_spellInfo->Id);
- m_caster->setDeathState(JUST_DIED);
+ TC_LOG_DEBUG("spells", "Statue %s is unsummoned in spell %d finish", unitCaster->GetGUID().ToString().c_str(), m_spellInfo->Id);
+ unitCaster->setDeathState(JUST_DIED);
return;
}
}
@@ -3925,23 +3975,23 @@ void Spell::finish(bool ok)
{
if (!m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
{
- m_caster->resetAttackTimer(BASE_ATTACK);
- if (m_caster->haveOffhandWeapon())
- m_caster->resetAttackTimer(OFF_ATTACK);
- m_caster->resetAttackTimer(RANGED_ATTACK);
+ unitCaster->resetAttackTimer(BASE_ATTACK);
+ if (unitCaster->haveOffhandWeapon())
+ unitCaster->resetAttackTimer(OFF_ATTACK);
+ unitCaster->resetAttackTimer(RANGED_ATTACK);
}
}
// potions disabled by client, send event "not in combat" if need
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (unitCaster->GetTypeId() == TYPEID_PLAYER)
{
if (!m_triggeredByAuraSpell)
- m_caster->ToPlayer()->UpdatePotionCooldown(this);
+ unitCaster->ToPlayer()->UpdatePotionCooldown(this);
}
// Stop Attack for some spells
if (m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET))
- m_caster->AttackStop();
+ unitCaster->AttackStop();
}
template<class T>
@@ -4211,8 +4261,14 @@ void Spell::SendSpellStart()
TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_START id=%u", m_spellInfo->Id);
uint32 castFlags = CAST_FLAG_HAS_TRAJECTORY;
- uint32 schoolImmunityMask = m_caster->GetSchoolImmunityMask();
- uint32 mechanicImmunityMask = m_caster->GetMechanicImmunityMask();
+ uint32 schoolImmunityMask = 0;
+ uint32 mechanicImmunityMask = 0;
+ if (Unit* unitCaster = m_caster->ToUnit())
+ {
+ schoolImmunityMask = unitCaster->GetSchoolImmunityMask();
+ mechanicImmunityMask = unitCaster->GetMechanicImmunityMask();
+ }
+
if (schoolImmunityMask || mechanicImmunityMask)
castFlags |= CAST_FLAG_IMMUNITY;
@@ -4223,7 +4279,7 @@ void Spell::SendSpellStart()
castFlags |= CAST_FLAG_PROJECTILE;
if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
- (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsPet()))
+ (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsPet()))
&& std::find_if(m_powerCost.begin(), m_powerCost.end(), [](SpellPowerCost const& cost) { return cost.Power != POWER_HEALTH; }) != m_powerCost.end())
castFlags |= CAST_FLAG_POWER_LEFT_SELF;
@@ -4255,7 +4311,7 @@ void Spell::SendSpellStart()
{
WorldPackets::Spells::SpellPowerData powerData;
powerData.Type = cost.Power;
- powerData.Cost = m_caster->GetPower(cost.Power);
+ powerData.Cost = ASSERT_NOTNULL(m_caster->ToUnit())->GetPower(cost.Power);
castData.RemainingPower.push_back(powerData);
}
}
@@ -4324,12 +4380,12 @@ void Spell::SendSpellGo()
castFlags |= CAST_FLAG_PROJECTILE; // arrows/bullets visual
if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
- (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsPet()))
+ (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsPet()))
&& std::find_if(m_powerCost.begin(), m_powerCost.end(), [](SpellPowerCost const& cost) { return cost.Power != POWER_HEALTH; }) != m_powerCost.end())
- castFlags |= CAST_FLAG_POWER_LEFT_SELF; // should only be sent to self, but the current messaging doesn't make that possible
+ castFlags |= CAST_FLAG_POWER_LEFT_SELF;
if ((m_caster->GetTypeId() == TYPEID_PLAYER)
- && (m_caster->getClass() == CLASS_DEATH_KNIGHT)
+ && (m_caster->ToPlayer()->getClass() == CLASS_DEATH_KNIGHT)
&& HasPowerTypeCost(POWER_RUNES)
&& !(_triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST))
{
@@ -4345,7 +4401,6 @@ void Spell::SendSpellGo()
WorldPackets::Spells::SpellGo packet;
WorldPackets::Spells::SpellCastData& castData = packet.Cast;
-
if (m_CastItem)
castData.CasterGUID = m_CastItem->GetGUID();
else
@@ -4370,7 +4425,7 @@ void Spell::SendSpellGo()
{
WorldPackets::Spells::SpellPowerData powerData;
powerData.Type = cost.Power;
- powerData.Cost = m_caster->GetPower(cost.Power);
+ powerData.Cost = ASSERT_NOTNULL(m_caster->ToUnit())->GetPower(cost.Power);
castData.RemainingPower.push_back(powerData);
}
}
@@ -4450,26 +4505,26 @@ void Spell::UpdateSpellCastDataAmmo(WorldPackets::Spells::SpellAmmo& ammo)
uint32 ammoInventoryType = 0;
uint32 ammoDisplayID = 0;
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (Player const* playerCaster = m_caster->ToPlayer())
{
- Item* pItem = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK);
+ Item* pItem = playerCaster->GetWeaponForAttack(RANGED_ATTACK);
if (pItem)
{
ammoInventoryType = pItem->GetTemplate()->GetInventoryType();
if (ammoInventoryType == INVTYPE_THROWN)
- ammoDisplayID = pItem->GetDisplayId(m_caster->ToPlayer());
- else if (m_caster->HasAura(46699)) // Requires No Ammo
+ ammoDisplayID = pItem->GetDisplayId(playerCaster);
+ else if (playerCaster->HasAura(46699)) // Requires No Ammo
{
ammoDisplayID = 5996; // normal arrow
ammoInventoryType = INVTYPE_AMMO;
}
}
}
- else
+ else if (Unit const* unitCaster = m_caster->ToUnit())
{
- for (uint8 i = 0; i < 3; ++i)
+ for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
{
- if (uint32 item_id = m_caster->GetVirtualItemId(i))
+ if (uint32 item_id = unitCaster->GetVirtualItemId(i))
{
if (ItemEntry const* itemEntry = sItemStore.LookupEntry(item_id))
{
@@ -4478,7 +4533,7 @@ void Spell::UpdateSpellCastDataAmmo(WorldPackets::Spells::SpellAmmo& ammo)
switch (itemEntry->SubclassID)
{
case ITEM_SUBCLASS_WEAPON_THROWN:
- ammoDisplayID = sDB2Manager.GetItemDisplayId(item_id, m_caster->GetVirtualItemAppearanceMod(i));
+ ammoDisplayID = sDB2Manager.GetItemDisplayId(item_id, unitCaster->GetVirtualItemAppearanceMod(i));
ammoInventoryType = itemEntry->InventoryType;
break;
case ITEM_SUBCLASS_WEAPON_BOW:
@@ -4532,6 +4587,8 @@ void Spell::SendSpellExecuteLog()
spellLogEffect.FeedPetTargets = std::move(_feedPetTargets[effect->EffectIndex]);
}
+ spellExecuteLog.LogData.Initialize(this);
+
if (!spellExecuteLog.Effects.empty())
m_caster->SendCombatLogMessage(&spellExecuteLog);
}
@@ -4647,30 +4704,40 @@ void Spell::SendInterrupted(uint8 result)
void Spell::SendChannelUpdate(uint32 time)
{
+ // GameObjects don't channel
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return;
+
if (time == 0)
{
- m_caster->ClearChannelObjects();
- m_caster->SetChannelSpellId(0);
- m_caster->SetChannelVisual({});
+ unitCaster->ClearChannelObjects();
+ unitCaster->SetChannelSpellId(0);
+ unitCaster->SetChannelVisual({});
}
WorldPackets::Spells::SpellChannelUpdate spellChannelUpdate;
- spellChannelUpdate.CasterGUID = m_caster->GetGUID();
+ spellChannelUpdate.CasterGUID = unitCaster->GetGUID();
spellChannelUpdate.TimeRemaining = time;
- m_caster->SendMessageToSet(spellChannelUpdate.Write(), true);
+ unitCaster->SendMessageToSet(spellChannelUpdate.Write(), true);
}
void Spell::SendChannelStart(uint32 duration)
{
+ // GameObjects don't channel
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return;
+
WorldPackets::Spells::SpellChannelStart spellChannelStart;
- spellChannelStart.CasterGUID = m_caster->GetGUID();
+ spellChannelStart.CasterGUID = unitCaster->GetGUID();
spellChannelStart.SpellID = m_spellInfo->Id;
spellChannelStart.Visual = m_SpellVisual;
spellChannelStart.ChannelDuration = duration;
- m_caster->SendMessageToSet(spellChannelStart.Write(), true);
+ unitCaster->SendMessageToSet(spellChannelStart.Write(), true);
- uint32 schoolImmunityMask = m_caster->GetSchoolImmunityMask();
- uint32 mechanicImmunityMask = m_caster->GetMechanicImmunityMask();
+ uint32 schoolImmunityMask = unitCaster->GetSchoolImmunityMask();
+ uint32 mechanicImmunityMask = unitCaster->GetMechanicImmunityMask();
if (schoolImmunityMask || mechanicImmunityMask)
{
@@ -4701,35 +4768,36 @@ void Spell::SendChannelStart(uint32 duration)
for (TargetInfo const& target : m_UniqueTargetInfo)
{
if (target.EffectMask & channelAuraMask)
- m_caster->AddChannelObject(target.TargetGUID);
+ unitCaster->AddChannelObject(target.TargetGUID);
if (m_UniqueTargetInfo.size() == 1 && m_UniqueGOTargetInfo.empty())
- if(target.TargetGUID != m_caster->GetGUID())
- if (Creature* creatureCaster = m_caster->ToCreature())
+ if(target.TargetGUID != unitCaster->GetGUID())
+ if (Creature* creatureCaster = unitCaster->ToCreature())
if (!creatureCaster->IsFocusing(this))
creatureCaster->FocusTarget(this, ObjectAccessor::GetWorldObject(*creatureCaster, target.TargetGUID));
}
for (GOTargetInfo const& target : m_UniqueGOTargetInfo)
if (target.EffectMask & channelAuraMask)
- m_caster->AddChannelObject(target.TargetGUID);
+ unitCaster->AddChannelObject(target.TargetGUID);
- m_caster->SetChannelSpellId(m_spellInfo->Id);
- m_caster->SetChannelVisual(m_SpellVisual);
+ unitCaster->SetChannelSpellId(m_spellInfo->Id);
+ unitCaster->SetChannelVisual(m_SpellVisual);
}
void Spell::SendResurrectRequest(Player* target)
{
// get resurrector name for creature resurrections, otherwise packet will be not accepted
// for player resurrections the name is looked up by guid
- std::string const sentName(m_caster->GetTypeId() == TYPEID_PLAYER
- ? "" : m_caster->GetNameForLocaleIdx(target->GetSession()->GetSessionDbLocaleIndex()));
+ std::string sentName;
+ if (m_caster->GetTypeId() != TYPEID_PLAYER)
+ sentName = m_caster->GetNameForLocaleIdx(target->GetSession()->GetSessionDbLocaleIndex());
WorldPackets::Spells::ResurrectRequest resurrectRequest;
resurrectRequest.ResurrectOffererGUID = m_caster->GetGUID();
resurrectRequest.ResurrectOffererVirtualRealmAddress = GetVirtualRealmAddress();
resurrectRequest.Name = sentName;
- resurrectRequest.Sickness = m_caster->GetTypeId() != TYPEID_PLAYER && m_caster->IsSpiritHealer(); // "you'll be afflicted with resurrection sickness"
+ resurrectRequest.Sickness = m_caster->IsUnit() && m_caster->ToUnit()->IsSpiritHealer(); // "you'll be afflicted with resurrection sickness"
resurrectRequest.UseTimer = !m_spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_RESURRECTION_TIMER);
if (Pet* pet = target->GetPet())
if (CharmInfo* charmInfo = pet->GetCharmInfo())
@@ -4809,13 +4877,18 @@ void Spell::TakeCastItem()
void Spell::TakePower()
{
+ // GameObjects don't use power
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return;
+
if (m_CastItem || m_triggeredByAuraSpell)
return;
//Don't take power if the spell is cast while .cheat power is enabled.
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (unitCaster->GetTypeId() == TYPEID_PLAYER)
{
- if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_POWER))
+ if (unitCaster->ToPlayer()->GetCommandStatus(CHEAT_POWER))
return;
}
@@ -4823,7 +4896,7 @@ void Spell::TakePower()
{
Powers powerType = Powers(cost.Power);
bool hit = true;
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (unitCaster->GetTypeId() == TYPEID_PLAYER)
{
if (powerType == POWER_RAGE || powerType == POWER_ENERGY || powerType == POWER_RUNES)
{
@@ -4835,7 +4908,7 @@ void Spell::TakePower()
{
hit = false;
//lower spell cost on fail (by talent aura)
- if (Player* modOwner = m_caster->ToPlayer()->GetSpellModOwner())
+ if (Player* modOwner = unitCaster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo, SpellModOp::PowerCostOnMiss, cost.Amount);
}
}
@@ -4854,7 +4927,7 @@ void Spell::TakePower()
// health as power used
if (powerType == POWER_HEALTH)
{
- m_caster->ModifyHealth(-cost.Amount);
+ unitCaster->ModifyHealth(-cost.Amount);
continue;
}
@@ -4864,7 +4937,7 @@ void Spell::TakePower()
continue;
}
- m_caster->ModifyPower(powerType, -cost.Amount);
+ unitCaster->ModifyPower(powerType, -cost.Amount);
}
}
@@ -4898,7 +4971,7 @@ SpellCastResult Spell::CheckRuneCost() const
void Spell::TakeRunePower(bool didHit)
{
- if (m_caster->GetTypeId() != TYPEID_PLAYER || m_caster->getClass() != CLASS_DEATH_KNIGHT)
+ if (m_caster->GetTypeId() != TYPEID_PLAYER || m_caster->ToPlayer()->getClass() != CLASS_DEATH_KNIGHT)
return;
Player* player = m_caster->ToPlayer();
@@ -4972,6 +5045,11 @@ void Spell::TakeReagents()
void Spell::HandleThreatSpells()
{
+ // wild GameObject spells don't cause threat
+ Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
+ if (!unitCaster)
+ return;
+
if (m_UniqueTargetInfo.empty())
return;
@@ -4982,7 +5060,7 @@ void Spell::HandleThreatSpells()
if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(m_spellInfo->Id))
{
if (threatEntry->apPctMod != 0.0f)
- threat += threatEntry->apPctMod * m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
+ threat += threatEntry->apPctMod * unitCaster->GetTotalAttackPowerValue(BASE_ATTACK);
threat += threatEntry->flatMod;
}
@@ -5002,20 +5080,20 @@ void Spell::HandleThreatSpells()
if (ihit->MissCondition != SPELL_MISS_NONE)
threatToAdd = 0.0f;
- Unit* target = ObjectAccessor::GetUnit(*m_caster, ihit->TargetGUID);
+ Unit* target = ObjectAccessor::GetUnit(*unitCaster, ihit->TargetGUID);
if (!target)
continue;
// positive spells distribute threat among all units that are in combat with target, like healing
if (IsPositive())
- target->GetThreatManager().ForwardThreatForAssistingMe(m_caster, threatToAdd, m_spellInfo);
+ target->GetThreatManager().ForwardThreatForAssistingMe(unitCaster, threatToAdd, m_spellInfo);
// for negative spells threat gets distributed among affected targets
else
{
if (!target->CanHaveThreatList())
continue;
- target->GetThreatManager().AddThreat(m_caster, threatToAdd, m_spellInfo, true);
+ target->GetThreatManager().AddThreat(unitCaster, threatToAdd, m_spellInfo, true);
}
}
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()));
@@ -5028,6 +5106,7 @@ void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOT
itemTarget = pItemTarget;
gameObjTarget = pGOTarget;
destTarget = &m_destTargets[i]._position;
+ unitCaster = m_originalCaster ? m_originalCaster : m_caster->ToUnit();
effectInfo = m_spellInfo->GetEffect(i);
if (!effectInfo)
@@ -5035,18 +5114,15 @@ void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOT
TC_LOG_ERROR("spells", "Spell: %u HandleEffects at EffectIndex: %u missing effect", m_spellInfo->Id, i);
return;
}
- uint32 eff = effectInfo->Effect;
-
- TC_LOG_DEBUG("spells", "Spell: %u Effect: %u", m_spellInfo->Id, eff);
+ uint32 effect = effectInfo->Effect;
damage = CalculateDamage(i, unitTarget, &variance);
- bool preventDefault = CallScriptEffectHandlers((SpellEffIndex)i, mode);
+ SpellEffIndex effIndex = static_cast<SpellEffIndex>(i);
+ bool preventDefault = CallScriptEffectHandlers(effIndex, mode);
- if (!preventDefault && eff < TOTAL_SPELL_EFFECTS)
- {
- (this->*SpellEffects[eff].Value)((SpellEffIndex)i);
- }
+ if (!preventDefault)
+ (this->*SpellEffectHandlers[effect].Value)(effIndex);
}
/*static*/ Spell const* Spell::ExtractSpellFromEvent(BasicEvent* event)
@@ -5060,28 +5136,28 @@ void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOT
SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
{
// check death state
- if (!m_caster->IsAlive() && !m_spellInfo->IsPassive() && !(m_spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD) || (IsTriggered() && !m_triggeredByAuraSpell)))
+ if (m_caster->ToUnit() && !m_caster->ToUnit()->IsAlive() && !m_spellInfo->IsPassive() && !(m_spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD) || (IsTriggered() && !m_triggeredByAuraSpell)))
return SPELL_FAILED_CASTER_DEAD;
// check cooldowns to prevent cheating
if (!m_spellInfo->IsPassive())
{
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (Player const* playerCaster = m_caster->ToPlayer())
{
//can cast triggered (by aura only?) spells while have this flag
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE))
{
// These two auras check SpellFamilyName defined by db2 class data instead of current spell SpellFamilyName
- if (m_caster->HasAuraType(SPELL_AURA_DISABLE_CASTING_EXCEPT_ABILITIES)
+ if (playerCaster->HasAuraType(SPELL_AURA_DISABLE_CASTING_EXCEPT_ABILITIES)
&& !m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO)
&& !m_spellInfo->HasEffect(SPELL_EFFECT_ATTACK)
&& !m_spellInfo->HasAttribute(SPELL_ATTR12_IGNORE_CASTING_DISABLED)
- && !m_caster->HasAuraTypeWithFamilyFlags(SPELL_AURA_DISABLE_CASTING_EXCEPT_ABILITIES, sChrClassesStore.AssertEntry(m_caster->getClass())->SpellClassSet, m_spellInfo->SpellFamilyFlags))
+ && !playerCaster->HasAuraTypeWithFamilyFlags(SPELL_AURA_DISABLE_CASTING_EXCEPT_ABILITIES, sChrClassesStore.AssertEntry(playerCaster->getClass())->SpellClassSet, m_spellInfo->SpellFamilyFlags))
return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW;
- if (m_caster->HasAuraType(SPELL_AURA_DISABLE_ATTACKING_EXCEPT_ABILITIES))
+ if (playerCaster->HasAuraType(SPELL_AURA_DISABLE_ATTACKING_EXCEPT_ABILITIES))
{
- if (!m_caster->HasAuraTypeWithFamilyFlags(SPELL_AURA_DISABLE_ATTACKING_EXCEPT_ABILITIES, sChrClassesStore.AssertEntry(m_caster->getClass())->SpellClassSet, m_spellInfo->SpellFamilyFlags))
+ if (!playerCaster->HasAuraTypeWithFamilyFlags(SPELL_AURA_DISABLE_ATTACKING_EXCEPT_ABILITIES, sChrClassesStore.AssertEntry(playerCaster->getClass())->SpellClassSet, m_spellInfo->SpellFamilyFlags))
{
if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO)
|| m_spellInfo->IsNextMeleeSwingSpell()
@@ -5098,11 +5174,11 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
}
// check if we are using a potion in combat for the 2nd+ time. Cooldown is added only after caster gets out of combat
- if (!IsIgnoringCooldowns() && m_caster->ToPlayer()->GetLastPotionId() && m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent()))
+ if (!IsIgnoringCooldowns() && playerCaster->GetLastPotionId() && m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent()))
return SPELL_FAILED_NOT_READY;
}
- if (!m_caster->GetSpellHistory()->IsReady(m_spellInfo, m_castItemEntry, IsIgnoringCooldowns()))
+ if (m_caster->ToUnit() && !m_caster->ToUnit()->GetSpellHistory()->IsReady(m_spellInfo, m_castItemEntry, IsIgnoringCooldowns()))
{
if (m_triggeredByAuraSpell)
return SPELL_FAILED_DONT_REPORT;
@@ -5111,7 +5187,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
}
}
- if (m_spellInfo->HasAttribute(SPELL_ATTR7_IS_CHEAT_SPELL) && !m_caster->HasUnitFlag2(UNIT_FLAG2_ALLOW_CHEAT_SPELLS))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR7_IS_CHEAT_SPELL) && m_caster->IsUnit() && !m_caster->ToUnit()->HasUnitFlag2(UNIT_FLAG2_ALLOW_CHEAT_SPELLS))
{
m_customError = SPELL_CUSTOM_ERROR_GM_ONLY;
return SPELL_FAILED_CUSTOM_ERROR;
@@ -5130,94 +5206,97 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
if (m_caster->GetTypeId() == TYPEID_PLAYER && VMAP::VMapFactory::createOrGetVMapManager()->isLineOfSightCalcEnabled())
{
if (m_spellInfo->HasAttribute(SPELL_ATTR0_OUTDOORS_ONLY) &&
- !m_caster->IsOutdoors())
+ !m_caster->IsOutdoors())
return SPELL_FAILED_ONLY_OUTDOORS;
if (m_spellInfo->HasAttribute(SPELL_ATTR0_INDOORS_ONLY) &&
- m_caster->IsOutdoors())
+ m_caster->IsOutdoors())
return SPELL_FAILED_ONLY_INDOORS;
}
- // only check at first call, Stealth auras are already removed at second call
- // for now, ignore triggered spells
- if (strict && !(_triggeredCastFlags & TRIGGERED_IGNORE_SHAPESHIFT))
+ if (Unit* unitCaster = m_caster->ToUnit())
{
- bool checkForm = true;
- // Ignore form req aura
- Unit::AuraEffectList const& ignore = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT);
- for (AuraEffect const* aurEff : ignore)
+ // only check at first call, Stealth auras are already removed at second call
+ // for now, ignore triggered spells
+ if (strict && !(_triggeredCastFlags & TRIGGERED_IGNORE_SHAPESHIFT))
{
- if (!aurEff->IsAffectingSpell(m_spellInfo))
- continue;
+ bool checkForm = true;
+ // Ignore form req aura
+ Unit::AuraEffectList const& ignore = unitCaster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT);
+ for (AuraEffect const* aurEff : ignore)
+ {
+ if (!aurEff->IsAffectingSpell(m_spellInfo))
+ continue;
- checkForm = false;
- break;
- }
+ checkForm = false;
+ break;
+ }
- if (checkForm)
- {
- // Cannot be used in this stance/form
- SpellCastResult shapeError = m_spellInfo->CheckShapeshift(m_caster->GetShapeshiftForm());
- if (shapeError != SPELL_CAST_OK)
- return shapeError;
+ if (checkForm)
+ {
+ // Cannot be used in this stance/form
+ SpellCastResult shapeError = m_spellInfo->CheckShapeshift(unitCaster->GetShapeshiftForm());
+ if (shapeError != SPELL_CAST_OK)
+ return shapeError;
- if ((m_spellInfo->HasAttribute(SPELL_ATTR0_ONLY_STEALTHED)) && !(m_caster->HasStealthAura()))
- return SPELL_FAILED_ONLY_STEALTHED;
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_ONLY_STEALTHED) && !(unitCaster->HasStealthAura()))
+ return SPELL_FAILED_ONLY_STEALTHED;
+ }
}
- }
- bool reqCombat = true;
- Unit::AuraEffectList const& stateAuras = m_caster->GetAuraEffectsByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
- for (Unit::AuraEffectList::const_iterator j = stateAuras.begin(); j != stateAuras.end(); ++j)
- {
- if ((*j)->IsAffectingSpell(m_spellInfo))
+ bool reqCombat = true;
+ Unit::AuraEffectList const& stateAuras = unitCaster->GetAuraEffectsByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
+ for (Unit::AuraEffectList::const_iterator j = stateAuras.begin(); j != stateAuras.end(); ++j)
{
- m_needComboPoints = false;
- if ((*j)->GetMiscValue() == 1)
+ if ((*j)->IsAffectingSpell(m_spellInfo))
{
- reqCombat = false;
- break;
+ m_needComboPoints = false;
+ if ((*j)->GetMiscValue() == 1)
+ {
+ reqCombat = false;
+ break;
+ }
}
}
- }
- // caster state requirements
- // not for triggered spells (needed by execute)
- if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE))
- {
- if (m_spellInfo->CasterAuraState && !m_caster->HasAuraState(AuraStateType(m_spellInfo->CasterAuraState), m_spellInfo, m_caster))
- return SPELL_FAILED_CASTER_AURASTATE;
- if (m_spellInfo->ExcludeCasterAuraState && m_caster->HasAuraState(AuraStateType(m_spellInfo->ExcludeCasterAuraState), m_spellInfo, m_caster))
- return SPELL_FAILED_CASTER_AURASTATE;
+ // caster state requirements
+ // not for triggered spells (needed by execute)
+ if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE))
+ {
+ if (m_spellInfo->CasterAuraState && !unitCaster->HasAuraState(AuraStateType(m_spellInfo->CasterAuraState), m_spellInfo, unitCaster))
+ return SPELL_FAILED_CASTER_AURASTATE;
+ if (m_spellInfo->ExcludeCasterAuraState && unitCaster->HasAuraState(AuraStateType(m_spellInfo->ExcludeCasterAuraState), m_spellInfo, unitCaster))
+ return SPELL_FAILED_CASTER_AURASTATE;
- // Note: spell 62473 requres casterAuraSpell = triggering spell
- if (m_spellInfo->CasterAuraSpell && !m_caster->HasAura(m_spellInfo->CasterAuraSpell))
- return SPELL_FAILED_CASTER_AURASTATE;
- if (m_spellInfo->ExcludeCasterAuraSpell && m_caster->HasAura(m_spellInfo->ExcludeCasterAuraSpell))
- return SPELL_FAILED_CASTER_AURASTATE;
+ // Note: spell 62473 requres casterAuraSpell = triggering spell
+ if (m_spellInfo->CasterAuraSpell && !unitCaster->HasAura(m_spellInfo->CasterAuraSpell))
+ return SPELL_FAILED_CASTER_AURASTATE;
+ if (m_spellInfo->ExcludeCasterAuraSpell && unitCaster->HasAura(m_spellInfo->ExcludeCasterAuraSpell))
+ return SPELL_FAILED_CASTER_AURASTATE;
- if (reqCombat && m_caster->IsInCombat() && !m_spellInfo->CanBeUsedInCombat())
- return SPELL_FAILED_AFFECTING_COMBAT;
- }
+ if (reqCombat && unitCaster->IsInCombat() && !m_spellInfo->CanBeUsedInCombat())
+ return SPELL_FAILED_AFFECTING_COMBAT;
+ }
- // cancel autorepeat spells if cast start when moving
- // (not wand currently autorepeat cast delayed to moving stop anyway in spell update code)
- // Do not cancel spells which are affected by a SPELL_AURA_CAST_WHILE_WALKING effect
- if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->isMoving() && (!m_caster->IsCharmed() || !m_caster->GetCharmerGUID().IsCreature()) && !m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo))
- {
- // skip stuck spell to allow use it in falling case and apply spell limitations at movement
- SpellEffectInfo const* effect = m_spellInfo->GetEffect(EFFECT_0);
- if ((!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR) || (effect && effect->Effect != SPELL_EFFECT_STUCK)) &&
- (IsAutoRepeat() || m_spellInfo->HasAuraInterruptFlag(SpellAuraInterruptFlags::Standing)))
- return SPELL_FAILED_MOVING;
- }
+ // cancel autorepeat spells if cast start when moving
+ // (not wand currently autorepeat cast delayed to moving stop anyway in spell update code)
+ // Do not cancel spells which are affected by a SPELL_AURA_CAST_WHILE_WALKING effect
+ if (unitCaster->GetTypeId() == TYPEID_PLAYER && unitCaster->ToPlayer()->isMoving() && (!unitCaster->IsCharmed() || !unitCaster->GetCharmerGUID().IsCreature()) && !unitCaster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo))
+ {
+ // skip stuck spell to allow use it in falling case and apply spell limitations at movement
+ SpellEffectInfo const* effect = m_spellInfo->GetEffect(EFFECT_0);
+ if ((!unitCaster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR) || (effect && effect->Effect != SPELL_EFFECT_STUCK)) &&
+ (IsAutoRepeat() || m_spellInfo->HasAuraInterruptFlag(SpellAuraInterruptFlags::Standing)))
+ return SPELL_FAILED_MOVING;
+ }
- // Check vehicle flags
- if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE))
- {
- SpellCastResult vehicleCheck = m_spellInfo->CheckVehicle(m_caster);
- if (vehicleCheck != SPELL_CAST_OK)
- return vehicleCheck;
+ // Check vehicle flags
+ if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE))
+ {
+ SpellCastResult vehicleCheck = m_spellInfo->CheckVehicle(unitCaster);
+ if (vehicleCheck != SPELL_CAST_OK)
+ return vehicleCheck;
+ }
}
// check spell cast conditions from database
@@ -5246,8 +5325,8 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
if (!(m_spellInfo->IsPassive() && (!m_targets.GetUnitTarget() || m_targets.GetUnitTarget() == m_caster)))
{
// Check explicit target for m_originalCaster - todo: get rid of such workarounds
- Unit* caster = m_caster;
- if (m_originalCaster && m_caster->GetEntry() != WORLD_TRIGGER) // Do a simplified check for gameobject casts
+ WorldObject* caster = m_caster;
+ if (m_originalCaster)
caster = m_originalCaster;
SpellCastResult castResult = m_spellInfo->CheckExplicitTarget(caster, m_targets.GetObjectTarget(), m_targets.GetItemTarget());
@@ -5257,20 +5336,23 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
if (Unit* target = m_targets.GetUnitTarget())
{
- SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, m_caster->GetEntry() == WORLD_TRIGGER); // skip stealth checks for GO casts
+ SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, m_caster->GetTypeId() == TYPEID_GAMEOBJECT); // skip stealth checks for GO casts
if (castResult != SPELL_CAST_OK)
return castResult;
// If it's not a melee spell, check if vision is obscured by SPELL_AURA_INTERFERE_TARGETTING
if (m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE)
{
- for (auto const& itr : m_caster->GetAuraEffectsByType(SPELL_AURA_INTERFERE_TARGETTING))
- if (!m_caster->IsFriendlyTo(itr->GetCaster()) && !target->HasAura(itr->GetId(), itr->GetCasterGUID()))
- return SPELL_FAILED_VISION_OBSCURED;
+ if (Unit const* unitCaster = m_caster->ToUnit())
+ {
+ for (AuraEffect const* auraEff : unitCaster->GetAuraEffectsByType(SPELL_AURA_INTERFERE_TARGETTING))
+ if (!unitCaster->IsFriendlyTo(auraEff->GetCaster()) && !target->HasAura(auraEff->GetId(), auraEff->GetCasterGUID()))
+ return SPELL_FAILED_VISION_OBSCURED;
- for (auto const& itr : target->GetAuraEffectsByType(SPELL_AURA_INTERFERE_TARGETTING))
- if (!m_caster->IsFriendlyTo(itr->GetCaster()) && (!target->HasAura(itr->GetId(), itr->GetCasterGUID()) || !m_caster->HasAura(itr->GetId(), itr->GetCasterGUID())))
- return SPELL_FAILED_VISION_OBSCURED;
+ for (AuraEffect const* auraEff : target->GetAuraEffectsByType(SPELL_AURA_INTERFERE_TARGETTING))
+ if (!unitCaster->IsFriendlyTo(auraEff->GetCaster()) && (!target->HasAura(auraEff->GetId(), auraEff->GetCasterGUID()) || !unitCaster->HasAura(auraEff->GetId(), auraEff->GetCasterGUID())))
+ return SPELL_FAILED_VISION_OBSCURED;
+ }
}
if (target != m_caster)
@@ -5283,11 +5365,12 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
if ((m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER)) && !target->HasInArc(static_cast<float>(M_PI), m_caster))
return SPELL_FAILED_NOT_INFRONT;
- if (m_caster->GetEntry() != WORLD_TRIGGER) // Ignore LOS for gameobjects casts (wrongly cast by a trigger)
+ // Ignore LOS for gameobjects casts
+ if (m_caster->GetTypeId() != TYPEID_GAMEOBJECT)
{
WorldObject* losTarget = m_caster;
if (IsTriggered() && m_triggeredByAuraSpell)
- if (DynamicObject* dynObj = m_caster->GetDynObject(m_triggeredByAuraSpell->Id))
+ if (DynamicObject* dynObj = m_caster->ToUnit()->GetDynObject(m_triggeredByAuraSpell->Id))
losTarget = dynObj;
if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !m_spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, nullptr, SPELL_DISABLE_LOS) && !target->IsWithinLOSInMap(losTarget, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
@@ -5307,23 +5390,26 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
}
// check pet presence
- for (SpellEffectInfo const* effect : m_spellInfo->GetEffects())
+ if (Unit* unitCaster = m_caster->ToUnit())
{
- if (effect && effect->TargetA.GetTarget() == TARGET_UNIT_PET)
+ for (SpellEffectInfo const* effect : m_spellInfo->GetEffects())
{
- if (!m_caster->GetGuardianPet())
+ if (effect && effect->TargetA.GetTarget() == TARGET_UNIT_PET)
{
- if (m_triggeredByAuraSpell) // not report pet not existence for triggered spells
- return SPELL_FAILED_DONT_REPORT;
- else
- return SPELL_FAILED_NO_PET;
+ if (!unitCaster->GetGuardianPet())
+ {
+ if (m_triggeredByAuraSpell) // not report pet not existence for triggered spells
+ return SPELL_FAILED_DONT_REPORT;
+ else
+ return SPELL_FAILED_NO_PET;
+ }
+ break;
}
- break;
}
}
// Spell cast only in battleground
- if ((m_spellInfo->HasAttribute(SPELL_ATTR3_BATTLEGROUND)) && m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_BATTLEGROUND) && m_caster->GetTypeId() == TYPEID_PLAYER)
if (!m_caster->ToPlayer()->InBattleground())
return SPELL_FAILED_ONLY_BATTLEGROUNDS;
@@ -5337,7 +5423,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
}
// zone check
- if (m_caster->GetTypeId() == TYPEID_UNIT || !m_caster->ToPlayer()->IsGameMaster())
+ if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_caster->ToPlayer()->IsGameMaster())
{
uint32 zone, area;
m_caster->GetZoneAndAreaId(zone, area);
@@ -5348,19 +5434,21 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
}
// not let players cast spells at mount (and let do it to creatures)
- if (m_caster->IsMounted() && m_caster->GetTypeId() == TYPEID_PLAYER && !(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE) &&
- !m_spellInfo->IsPassive() && !m_spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_MOUNTED))
+ if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE))
{
- if (m_caster->IsInFlight())
- return SPELL_FAILED_NOT_ON_TAXI;
- else
- return SPELL_FAILED_NOT_MOUNTED;
+ if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->IsMounted() && !m_spellInfo->IsPassive() && !m_spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_MOUNTED))
+ {
+ if (m_caster->ToPlayer()->IsInFlight())
+ return SPELL_FAILED_NOT_ON_TAXI;
+ else
+ return SPELL_FAILED_NOT_MOUNTED;
+ }
}
// check spell focus object
if (m_spellInfo->RequiresSpellFocus)
{
- if (!m_caster->HasAuraTypeWithMiscvalue(SPELL_AURA_PROVIDE_SPELL_FOCUS, m_spellInfo->RequiresSpellFocus))
+ if (!m_caster->IsUnit() || !m_caster->ToUnit()->HasAuraTypeWithMiscvalue(SPELL_AURA_PROVIDE_SPELL_FOCUS, m_spellInfo->RequiresSpellFocus))
{
focusObject = SearchSpellFocus();
if (!focusObject)
@@ -5436,12 +5524,10 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
break;
Pet* pet = m_caster->ToPlayer()->GetPet();
-
if (!pet)
return SPELL_FAILED_NO_PET;
SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(effect->TriggerSpell, DIFFICULTY_NONE);
-
if (!learn_spellproto)
return SPELL_FAILED_NOT_KNOWN;
@@ -5549,7 +5635,6 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
return SPELL_FAILED_BAD_TARGETS;
Pet* pet = m_caster->ToPlayer()->GetPet();
-
if (!pet)
return SPELL_FAILED_NO_PET;
@@ -5559,14 +5644,18 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
if (foodItem->GetTemplate()->GetBaseItemLevel() + 30 <= pet->getLevel())
return SPELL_FAILED_FOOD_LOWLEVEL;
- if (m_caster->IsInCombat() || pet->IsInCombat())
+ if (m_caster->ToPlayer()->IsInCombat() || pet->IsInCombat())
return SPELL_FAILED_AFFECTING_COMBAT;
break;
}
case SPELL_EFFECT_CHARGE:
{
- if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURAS) && m_caster->HasUnitState(UNIT_STATE_ROOT))
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return SPELL_FAILED_BAD_TARGETS;
+
+ if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURAS) && unitCaster->HasUnitState(UNIT_STATE_ROOT))
return SPELL_FAILED_ROOTED;
if (GetSpellInfo()->NeedsExplicitUnitTarget())
@@ -5576,13 +5665,13 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
return SPELL_FAILED_DONT_REPORT;
// first we must check to see if the target is in LoS. A path can usually be built but LoS matters for charge spells
- if (!target->IsWithinLOSInMap(m_caster)) //Do full LoS/Path check. Don't exclude m2
+ if (!target->IsWithinLOSInMap(unitCaster)) //Do full LoS/Path check. Don't exclude m2
return SPELL_FAILED_LINE_OF_SIGHT;
float objSize = target->GetCombatReach();
- float range = m_spellInfo->GetMaxRange(true, m_caster, this) * 1.5f + objSize; // can't be overly strict
+ float range = m_spellInfo->GetMaxRange(true, unitCaster, this) * 1.5f + objSize; // can't be overly strict
- m_preGeneratedPath = std::make_unique<PathGenerator>(m_caster);
+ m_preGeneratedPath = std::make_unique<PathGenerator>(unitCaster);
m_preGeneratedPath->SetPathLengthLimit(range);
// first try with raycast, if it fails fall back to normal path
float targetObjectSize = std::min(target->GetCombatReach(), 4.0f);
@@ -5683,28 +5772,35 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
}
case SPELL_EFFECT_RESURRECT_PET:
{
- Creature* pet = m_caster->GetGuardianPet();
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return SPELL_FAILED_BAD_TARGETS;
+ Creature* pet = unitCaster->GetGuardianPet();
if (pet && pet->IsAlive())
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
-
break;
}
// This is generic summon effect
case SPELL_EFFECT_SUMMON:
{
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ break;
+
SummonPropertiesEntry const* SummonProperties = sSummonPropertiesStore.LookupEntry(effect->MiscValueB);
if (!SummonProperties)
break;
+
switch (SummonProperties->Control)
{
case SUMMON_CATEGORY_PET:
- if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET) && !m_caster->GetPetGUID().IsEmpty())
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET) && !unitCaster->GetPetGUID().IsEmpty())
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
/* fallthrough */
// intentional, check both GetPetGUID() and GetCharmGUID for SUMMON_CATEGORY_PET
case SUMMON_CATEGORY_PUPPET:
- if (!m_caster->GetCharmGUID().IsEmpty())
+ if (!unitCaster->GetCharmGUID().IsEmpty())
return SPELL_FAILED_ALREADY_HAVE_CHARM;
break;
}
@@ -5723,19 +5819,23 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
}
case SPELL_EFFECT_SUMMON_PET:
{
- if (!m_caster->GetPetGUID().IsEmpty()) //let warlock do a replacement summon
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return SPELL_FAILED_BAD_TARGETS;
+
+ if (!unitCaster->GetPetGUID().IsEmpty()) //let warlock do a replacement summon
{
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (unitCaster->GetTypeId() == TYPEID_PLAYER)
{
if (strict) //starting cast, trigger pet stun (cast by pet so it doesn't attack player)
- if (Pet* pet = m_caster->ToPlayer()->GetPet())
+ if (Pet* pet = unitCaster->ToPlayer()->GetPet())
pet->CastSpell(pet, 32752, pet->GetGUID());
}
else if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET))
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
}
- if (!m_caster->GetCharmGUID().IsEmpty())
+ if (!unitCaster->GetCharmGUID().IsEmpty())
return SPELL_FAILED_ALREADY_HAVE_CHARM;
break;
}
@@ -5743,7 +5843,8 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return SPELL_FAILED_BAD_TARGETS;
- if (!m_caster->GetTarget())
+
+ if (!m_caster->ToPlayer()->GetTarget())
return SPELL_FAILED_BAD_TARGETS;
Player* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetTarget());
@@ -5780,22 +5881,19 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
return SPELL_FAILED_BAD_TARGETS;
Player* playerCaster = m_caster->ToPlayer();
- //
- if (!(playerCaster->GetTarget()))
+ if (!playerCaster->GetTarget())
return SPELL_FAILED_BAD_TARGETS;
Player* target = playerCaster->GetSelectedPlayer();
-
if (!target ||
!(target->GetSession()->GetRecruiterId() == playerCaster->GetSession()->GetAccountId() || target->GetSession()->GetAccountId() == playerCaster->GetSession()->GetRecruiterId()))
return SPELL_FAILED_BAD_TARGETS;
-
break;
}
case SPELL_EFFECT_LEAP:
case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER:
{
- //Do not allow to cast it before BG starts.
+ //Do not allow to cast it before BG starts.
if (m_caster->GetTypeId() == TYPEID_PLAYER)
if (Battleground const* bg = m_caster->ToPlayer()->GetBattleground())
if (bg->GetStatus() != STATUS_IN_PROGRESS)
@@ -5810,9 +5908,13 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
}
case SPELL_EFFECT_LEAP_BACK:
{
- if (m_caster->HasUnitState(UNIT_STATE_ROOT))
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return SPELL_FAILED_BAD_TARGETS;
+
+ if (unitCaster->HasUnitState(UNIT_STATE_ROOT))
{
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (unitCaster->GetTypeId() == TYPEID_PLAYER)
return SPELL_FAILED_ROOTED;
else
return SPELL_FAILED_DONT_REPORT;
@@ -5822,7 +5924,11 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
case SPELL_EFFECT_JUMP:
case SPELL_EFFECT_JUMP_DEST:
{
- if (m_caster->HasUnitState(UNIT_STATE_ROOT))
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return SPELL_FAILED_BAD_TARGETS;
+
+ if (unitCaster->HasUnitState(UNIT_STATE_ROOT))
return SPELL_FAILED_ROOTED;
break;
}
@@ -5833,7 +5939,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
if (!player)
return SPELL_FAILED_TARGET_NOT_PLAYER;
- if (!spec || (spec->ClassID != m_caster->getClass() && !spec->IsPetSpecialization()))
+ if (!spec || (spec->ClassID != player->getClass() && !spec->IsPetSpecialization()))
return SPELL_FAILED_NO_SPEC;
if (spec->IsPetSpecialization())
@@ -5851,12 +5957,15 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
}
case SPELL_EFFECT_REMOVE_TALENT:
{
- if (m_caster->GetTypeId() != TYPEID_PLAYER)
+ Player* playerCaster = m_caster->ToPlayer();
+ if (!playerCaster)
return SPELL_FAILED_BAD_TARGETS;
+
TalentEntry const* talent = sTalentStore.LookupEntry(m_misc.TalentId);
if (!talent)
return SPELL_FAILED_DONT_REPORT;
- if (m_caster->GetSpellHistory()->HasCooldown(talent->SpellID))
+
+ if (playerCaster->GetSpellHistory()->HasCooldown(talent->SpellID))
{
if (param1)
*param1 = talent->SpellID;
@@ -5867,14 +5976,18 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
case SPELL_EFFECT_GIVE_ARTIFACT_POWER:
case SPELL_EFFECT_GIVE_ARTIFACT_POWER_NO_BONUS:
{
- if (m_caster->GetTypeId() != TYPEID_PLAYER)
+ Player* playerCaster = m_caster->ToPlayer();
+ if (!playerCaster)
return SPELL_FAILED_BAD_TARGETS;
- Aura* artifactAura = m_caster->GetAura(ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE);
+
+ Aura* artifactAura = playerCaster->GetAura(ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE);
if (!artifactAura)
return SPELL_FAILED_NO_ARTIFACT_EQUIPPED;
- Item* artifact = m_caster->ToPlayer()->GetItemByGuid(artifactAura->GetCastItemGUID());
+
+ Item* artifact = playerCaster->GetItemByGuid(artifactAura->GetCastItemGUID());
if (!artifact)
return SPELL_FAILED_NO_ARTIFACT_EQUIPPED;
+
if (effect->Effect == SPELL_EFFECT_GIVE_ARTIFACT_POWER)
{
ArtifactEntry const* artifactEntry = sArtifactStore.LookupEntry(artifact->GetTemplate()->GetArtifactID());
@@ -5911,16 +6024,20 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
case SPELL_AURA_MOD_CHARM:
case SPELL_AURA_AOE_CHARM:
{
- if (!m_caster->GetCharmerGUID().IsEmpty())
+ Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
+ if (!unitCaster)
+ return SPELL_FAILED_BAD_TARGETS;
+
+ if (!unitCaster->GetCharmerGUID().IsEmpty())
return SPELL_FAILED_CHARMED;
if (effect->ApplyAuraName == SPELL_AURA_MOD_CHARM
|| effect->ApplyAuraName == SPELL_AURA_MOD_POSSESS)
{
- if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET) && !m_caster->GetPetGUID().IsEmpty())
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET) && !unitCaster->GetPetGUID().IsEmpty())
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
- if (!m_caster->GetCharmGUID().IsEmpty())
+ if (!unitCaster->GetCharmGUID().IsEmpty())
return SPELL_FAILED_ALREADY_HAVE_CHARM;
}
@@ -5947,23 +6064,26 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
}
case SPELL_AURA_MOUNTED:
{
- if (m_caster->IsInWater() && m_spellInfo->HasAura(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED))
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return SPELL_FAILED_BAD_TARGETS;
+
+ if (unitCaster->IsInWater() && m_spellInfo->HasAura(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED))
return SPELL_FAILED_ONLY_ABOVEWATER;
// Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells
- bool allowMount = !m_caster->GetMap()->IsDungeon() || m_caster->GetMap()->IsBattlegroundOrArena();
- InstanceTemplate const* it = sObjectMgr->GetInstanceTemplate(m_caster->GetMapId());
+ bool allowMount = !unitCaster->GetMap()->IsDungeon() || unitCaster->GetMap()->IsBattlegroundOrArena();
+ InstanceTemplate const* it = sObjectMgr->GetInstanceTemplate(unitCaster->GetMapId());
if (it)
allowMount = it->AllowMount;
- if (m_caster->GetTypeId() == TYPEID_PLAYER && !allowMount && !m_spellInfo->RequiredAreasID)
+ if (unitCaster->GetTypeId() == TYPEID_PLAYER && !allowMount && !m_spellInfo->RequiredAreasID)
return SPELL_FAILED_NO_MOUNTS_ALLOWED;
- if (m_caster->IsInDisallowedMountForm())
+ if (unitCaster->IsInDisallowedMountForm())
{
SendMountResult(MountResult::Shapeshifted); // mount result gets sent before the cast result
return SPELL_FAILED_DONT_REPORT;
}
-
break;
}
case SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS:
@@ -5974,7 +6094,6 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
// can be cast at non-friendly unit or own pet/charm
if (m_caster->IsFriendlyTo(m_targets.GetUnitTarget()))
return SPELL_FAILED_TARGET_FRIENDLY;
-
break;
}
case SPELL_AURA_FLY:
@@ -6004,7 +6123,6 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
if (m_targets.GetUnitTarget()->GetPowerType() != POWER_MANA)
return SPELL_FAILED_BAD_TARGETS;
-
break;
}
default:
@@ -6022,7 +6140,6 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
return SPELL_FAILED_NOT_TRADING;
TradeData* my_trade = m_caster->ToPlayer()->GetTradeData();
-
if (!my_trade)
return SPELL_FAILED_NOT_TRADING;
@@ -6046,7 +6163,8 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
SpellCastResult Spell::CheckPetCast(Unit* target)
{
- if (m_caster->HasUnitState(UNIT_STATE_CASTING) && !(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS)) //prevent spellcast interruption by another spellcast
+ Unit* unitCaster = m_caster->ToUnit();
+ if (unitCaster && unitCaster->HasUnitState(UNIT_STATE_CASTING) && !(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS)) //prevent spellcast interruption by another spellcast
return SPELL_FAILED_SPELL_IN_PROGRESS;
// dead owner (pets still alive when owners ressed?)
@@ -6071,7 +6189,7 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
// Check if spell is affected by GCD
if (m_spellInfo->StartRecoveryCategory > 0)
- if (m_caster->GetCharmInfo() && m_caster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo))
+ if (unitCaster && unitCaster->GetCharmInfo() && unitCaster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo))
return SPELL_FAILED_NOT_READY;
return CheckCast(true);
@@ -6079,6 +6197,10 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
SpellCastResult Spell::CheckCasterAuras(uint32* param1) const
{
+ Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
+ if (!unitCaster)
+ return SPELL_CAST_OK;
+
// spells totally immuned to caster auras (wsg flag drop, give marks etc)
if (m_spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CASTER_AURAS))
return SPELL_CAST_OK;
@@ -6099,15 +6221,15 @@ SpellCastResult Spell::CheckCasterAuras(uint32* param1) const
SpellCastResult result = SPELL_CAST_OK;
// Get unit state
- uint32 const unitflag = m_caster->m_unitData->Flags;
+ uint32 const unitflag = unitCaster->m_unitData->Flags;
// this check should only be done when player does cast directly
// (ie not when it's called from a script) Breaks for example PlayerAI when charmed
/*
- if (!m_caster->GetCharmerGUID().IsEmpty())
+ if (!unitCaster->GetCharmerGUID().IsEmpty())
{
- if (Unit* charmer = m_caster->GetCharmer())
- if (charmer->GetUnitBeingMoved() != m_caster && !CheckSpellCancelsCharm(param1))
+ if (Unit* charmer = unitCaster->GetCharmer())
+ if (charmer->GetUnitBeingMoved() != unitCaster && !CheckSpellCancelsCharm(param1))
result = SPELL_FAILED_CHARMED;
}
*/
@@ -6116,7 +6238,7 @@ SpellCastResult Spell::CheckCasterAuras(uint32* param1) const
auto mechanicCheck = [&](AuraType type) -> SpellCastResult
{
bool foundNotMechanic = false;
- Unit::AuraEffectList const& auras = m_caster->GetAuraEffectsByType(type);
+ Unit::AuraEffectList const& auras = unitCaster->GetAuraEffectsByType(type);
for (AuraEffect const* aurEff : auras)
{
uint32 const mechanicMask = aurEff->GetSpellInfo()->GetAllEffectsMechanicMask();
@@ -6192,7 +6314,7 @@ SpellCastResult Spell::CheckCasterAuras(uint32* param1) const
else if (!CheckSpellCancelsConfuse(param1))
result = SPELL_FAILED_CONFUSED;
}
- else if (m_caster->HasUnitFlag2(UNIT_FLAG2_NO_ACTIONS) && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_NO_ACTIONS && !CheckSpellCancelsNoActions(param1))
+ else if (unitCaster->HasUnitFlag2(UNIT_FLAG2_NO_ACTIONS) && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_NO_ACTIONS && !CheckSpellCancelsNoActions(param1))
result = SPELL_FAILED_NO_ACTIONS;
// Attr must make flag drop spell totally immune from all effects
@@ -6204,8 +6326,12 @@ SpellCastResult Spell::CheckCasterAuras(uint32* param1) const
bool Spell::CheckSpellCancelsAuraEffect(AuraType auraType, uint32* param1) const
{
+ Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
+ if (!unitCaster)
+ return false;
+
// Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
- Unit::AuraEffectList const& auraEffects = m_caster->GetAuraEffectsByType(auraType);
+ Unit::AuraEffectList const& auraEffects = unitCaster->GetAuraEffectsByType(auraType);
if (auraEffects.empty())
return true;
@@ -6298,10 +6424,10 @@ SpellCastResult Spell::CheckArenaAndRatedBattlegroundCastRules()
return SPELL_CAST_OK;
}
-int32 Spell::CalculateDamage(uint8 i, Unit const* target, float* var /*= nullptr*/) const
+int32 Spell::CalculateDamage(uint8 effIndex, Unit const* target, float* var /*= nullptr*/) const
{
- bool needRecalculateBasePoints = !(m_spellValue->CustomBasePointsMask & (1 << i));
- return m_caster->CalculateSpellDamage(target, m_spellInfo, i, needRecalculateBasePoints ? nullptr : &m_spellValue->EffectBasePoints[i], var, m_castItemEntry, m_castItemLevel);
+ bool needRecalculateBasePoints = !(m_spellValue->CustomBasePointsMask & (1 << effIndex));
+ return m_caster->CalculateSpellDamage(target, m_spellInfo, effIndex, needRecalculateBasePoints ? nullptr : &m_spellValue->EffectBasePoints[effIndex], var, m_castItemEntry, m_castItemLevel);
}
bool Spell::CanAutoCast(Unit* target)
@@ -6403,7 +6529,7 @@ SpellCastResult Spell::CheckRange(bool strict) const
if (m_caster->GetTypeId() == TYPEID_PLAYER &&
(((m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc(static_cast<float>(M_PI), target))
- && !m_caster->IsWithinBoundaryRadius(target)))
+ && !m_caster->ToPlayer()->IsWithinBoundaryRadius(target)))
return SPELL_FAILED_UNIT_NOT_INFRONT;
}
@@ -6423,24 +6549,29 @@ std::pair<float, float> Spell::GetMinMaxRange(bool strict) const
float rangeMod = 0.0f;
float minRange = 0.0f;
float maxRange = 0.0f;
+
if (strict && m_spellInfo->IsNextMeleeSwingSpell())
- {
- maxRange = 100.0f;
- return std::pair<float, float>(minRange, maxRange);
- }
+ return { 0.0f, 100.0f };
+ Unit* unitCaster = m_caster->ToUnit();
if (m_spellInfo->RangeEntry)
{
Unit* target = m_targets.GetUnitTarget();
if (m_spellInfo->RangeEntry->Flags & SPELL_RANGE_MELEE)
{
- rangeMod = m_caster->GetMeleeRange(target ? target : m_caster); // when the target is not a unit, take the caster's combat reach as the target's combat reach.
+ // when the target is not a unit, take the caster's combat reach as the target's combat reach.
+ if (unitCaster)
+ rangeMod = unitCaster->GetMeleeRange(target ? target : unitCaster);
}
else
{
float meleeRange = 0.0f;
if (m_spellInfo->RangeEntry->Flags & SPELL_RANGE_RANGED)
- meleeRange = m_caster->GetMeleeRange(target ? target : m_caster); // when the target is not a unit, take the caster's combat reach as the target's combat reach.
+ {
+ // when the target is not a unit, take the caster's combat reach as the target's combat reach.
+ if (unitCaster)
+ meleeRange = unitCaster->GetMeleeRange(target ? target : unitCaster);
+ }
minRange = m_caster->GetSpellMinRangeForTarget(target, m_spellInfo) + meleeRange;
maxRange = m_caster->GetSpellMaxRangeForTarget(target, m_spellInfo);
@@ -6454,8 +6585,8 @@ std::pair<float, float> Spell::GetMinMaxRange(bool strict) const
}
}
- if (target && m_caster->isMoving() && target->isMoving() && !m_caster->IsWalking() && !target->IsWalking() &&
- (m_spellInfo->RangeEntry->Flags & SPELL_RANGE_MELEE || target->GetTypeId() == TYPEID_PLAYER))
+ if (target && unitCaster && unitCaster->isMoving() && target->isMoving() && !unitCaster->IsWalking() && !target->IsWalking() &&
+ ((m_spellInfo->RangeEntry->Flags & SPELL_RANGE_MELEE) || target->GetTypeId() == TYPEID_PLAYER))
rangeMod += 8.0f / 3.0f;
}
@@ -6468,11 +6599,15 @@ std::pair<float, float> Spell::GetMinMaxRange(bool strict) const
maxRange += rangeMod;
- return std::pair<float, float>(minRange, maxRange);
+ return { minRange, maxRange };
}
SpellCastResult Spell::CheckPower() const
{
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return SPELL_CAST_OK;
+
// item cast not used power
if (m_CastItem)
return SPELL_CAST_OK;
@@ -6482,7 +6617,7 @@ SpellCastResult Spell::CheckPower() const
// health as power used - need check health amount
if (cost.Power == POWER_HEALTH)
{
- if (int32(m_caster->GetHealth()) <= cost.Amount)
+ if (int64(unitCaster->GetHealth()) <= cost.Amount)
return SPELL_FAILED_CASTER_AURASTATE;
continue;
}
@@ -6502,7 +6637,7 @@ SpellCastResult Spell::CheckPower() const
}
// Check power amount
- if (int32(m_caster->GetPower(cost.Power)) < cost.Amount)
+ if (int32(unitCaster->GetPower(cost.Power)) < cost.Amount)
return SPELL_FAILED_NO_POWER;
}
@@ -6612,7 +6747,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
// Not own traded item (in trader trade slot) requires reagents even if triggered spell
if (!checkReagents)
if (Item* targetItem = m_targets.GetItemTarget())
- if (targetItem->GetOwnerGUID() != m_caster->GetGUID())
+ if (targetItem->GetOwnerGUID() != player->GetGUID())
checkReagents = true;
// check reagents (ignore triggered spells with reagents processed by original spell) and special reagent ignore case.
@@ -6707,24 +6842,24 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
case SPELL_EFFECT_CREATE_LOOT:
{
// m_targets.GetUnitTarget() means explicit cast, otherwise we dont check for possible equip error
- Unit* target = m_targets.GetUnitTarget() ? m_targets.GetUnitTarget() : m_caster;
- if (target && target->GetTypeId() == TYPEID_PLAYER && !IsTriggered() && effect->ItemType)
+ Unit* target = m_targets.GetUnitTarget() ? m_targets.GetUnitTarget() : player;
+ if (target->GetTypeId() == TYPEID_PLAYER && !IsTriggered() && effect->ItemType)
{
ItemPosCountVec dest;
-
InventoryResult msg = target->ToPlayer()->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, effect->ItemType, 1);
if (msg != EQUIP_ERR_OK)
{
- ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(effect->ItemType);
+ ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(effect->ItemType);
/// @todo Needs review
- if (pProto && !(pProto->GetItemLimitCategory()))
+ if (itemTemplate && !(itemTemplate->GetItemLimitCategory()))
{
player->SendEquipError(msg, nullptr, nullptr, effect->ItemType);
return SPELL_FAILED_DONT_REPORT;
}
else
{
- if (!(m_spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (m_spellInfo->SpellFamilyFlags[0] & 0x40000000)))
+ // Conjure Food/Water/Refreshment spells
+ if (m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE || (!(m_spellInfo->SpellFamilyFlags[0] & 0x40000000)))
return SPELL_FAILED_TOO_MANY_OF_ITEM;
else if (!(target->ToPlayer()->HasItemCount(effect->ItemType)))
{
@@ -6732,7 +6867,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
return SPELL_FAILED_DONT_REPORT;
}
else if (SpellEffectInfo const* efi = m_spellInfo->GetEffect(EFFECT_1))
- player->CastSpell(m_caster, efi->CalcValue(), false); // move this to anywhere
+ player->CastSpell(player, efi->CalcValue(), false); // move this to anywhere
return SPELL_FAILED_DONT_REPORT;
}
}
@@ -6744,7 +6879,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
&& (m_targets.GetItemTarget()->IsVellum()))
{
// cannot enchant vellum for other player
- if (m_targets.GetItemTarget()->GetOwner() != m_caster)
+ if (m_targets.GetItemTarget()->GetOwner() != player)
return SPELL_FAILED_NOT_TRADEABLE;
// do not allow to enchant vellum from scroll made by vellum-prevent exploit
if (m_CastItem && m_CastItem->GetTemplate()->GetFlags() & ITEM_FLAG_NO_REAGENT_COST)
@@ -6806,7 +6941,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
}
// Not allow enchant in trade slot for some enchant type
- if (targetItem->GetOwner() != m_caster)
+ if (targetItem->GetOwner() != player)
{
if (!enchantEntry)
return SPELL_FAILED_ERROR;
@@ -6821,7 +6956,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
if (!item)
return SPELL_FAILED_ITEM_NOT_FOUND;
// Not allow enchant in trade slot for some enchant type
- if (item->GetOwner() != m_caster)
+ if (item->GetOwner() != player)
{
uint32 enchant_id = effect->MiscValue;
SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
@@ -6851,7 +6986,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
return SPELL_FAILED_CANT_BE_DISENCHANTED;
// prevent disenchanting in trade slot
- if (item->GetOwnerGUID() != m_caster->GetGUID())
+ if (item->GetOwnerGUID() != player->GetGUID())
return SPELL_FAILED_CANT_BE_DISENCHANTED;
ItemTemplate const* itemProto = item->GetTemplate();
@@ -6874,7 +7009,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
if (!(item->GetTemplate()->GetFlags() & ITEM_FLAG_IS_PROSPECTABLE))
return SPELL_FAILED_CANT_BE_PROSPECTED;
//prevent prospecting in trade slot
- if (item->GetOwnerGUID() != m_caster->GetGUID())
+ if (item->GetOwnerGUID() != player->GetGUID())
return SPELL_FAILED_CANT_BE_PROSPECTED;
//Check for enough skill in jewelcrafting
uint32 item_prospectingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
@@ -6905,7 +7040,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
if (!(item->GetTemplate()->GetFlags() & ITEM_FLAG_IS_MILLABLE))
return SPELL_FAILED_CANT_BE_MILLED;
//prevent milling in trade slot
- if (item->GetOwnerGUID() != m_caster->GetGUID())
+ if (item->GetOwnerGUID() != player->GetGUID())
return SPELL_FAILED_CANT_BE_MILLED;
//Check for enough skill in inscription
uint32 item_millingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
@@ -6933,15 +7068,15 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
if (m_attackType != RANGED_ATTACK)
break;
- Item* pItem = player->GetWeaponForAttack(m_attackType);
- if (!pItem || pItem->IsBroken())
+ Item* item = player->GetWeaponForAttack(m_attackType);
+ if (!item || item->IsBroken())
return SPELL_FAILED_EQUIPPED_ITEM;
- switch (pItem->GetTemplate()->GetSubClass())
+ switch (item->GetTemplate()->GetSubClass())
{
case ITEM_SUBCLASS_WEAPON_THROWN:
{
- uint32 ammo = pItem->GetEntry();
+ uint32 const ammo = item->GetEntry();
if (!player->HasItemCount(ammo))
return SPELL_FAILED_NO_AMMO;
break;
@@ -7011,9 +7146,9 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
// check weapon presence in slots for main/offhand weapons
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT) && m_spellInfo->EquippedItemClass >= 0)
{
- auto weaponCheck = [this](WeaponAttackType attackType) -> SpellCastResult
+ auto weaponCheck = [&](WeaponAttackType attackType) -> SpellCastResult
{
- Item const* item = m_caster->ToPlayer()->GetWeaponForAttack(attackType);
+ Item const* item = player->GetWeaponForAttack(attackType);
// skip spell if no weapon in slot or broken
if (!item || item->IsBroken())
@@ -7046,20 +7181,20 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
void Spell::Delayed() // only called in DealDamage()
{
- if (!m_caster)// || m_caster->GetTypeId() != TYPEID_PLAYER)
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
return;
- //if (m_spellState == SPELL_STATE_DELAYED)
- // return; // spell is active and can't be time-backed
-
- if (isDelayableNoMore()) // Spells may only be delayed twice
+ if (IsDelayableNoMore()) // Spells may only be delayed twice
return;
//check pushback reduce
int32 delaytime = 500; // spellcasting delay is normally 500ms
+
int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
- m_caster->ToPlayer()->ApplySpellMod(m_spellInfo, SpellModOp::ResistPushback, delayReduce, this);
- delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
+ if (Player* player = unitCaster->GetSpellModOwner())
+ player->ApplySpellMod(m_spellInfo, SpellModOp::ResistPushback, delayReduce, this);
+ delayReduce += unitCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
if (delayReduce >= 100)
return;
@@ -7073,21 +7208,23 @@ void Spell::Delayed() // only called in DealDamage()
else
m_timer += delaytime;
- TC_LOG_DEBUG("spells", "Spell %u partially interrupted for (%d) ms at damage", m_spellInfo->Id, delaytime);
-
WorldPackets::Spells::SpellDelayed spellDelayed;
- spellDelayed.Caster = m_caster->GetGUID();
+ spellDelayed.Caster = unitCaster->GetGUID();
spellDelayed.ActualDelay = delaytime;
- m_caster->SendMessageToSet(spellDelayed.Write(), true);
+ unitCaster->SendMessageToSet(spellDelayed.Write(), true);
}
void Spell::DelayedChannel()
{
- if (!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER || getState() != SPELL_STATE_CASTING)
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
return;
- if (isDelayableNoMore()) // Spells may only be delayed twice
+ if (m_spellState != SPELL_STATE_CASTING)
+ return;
+
+ if (IsDelayableNoMore()) // Spells may only be delayed twice
return;
//check pushback reduce
@@ -7095,9 +7232,11 @@ void Spell::DelayedChannel()
int32 duration = ((m_channeledDuration > 0) ? m_channeledDuration : m_spellInfo->GetDuration());
int32 delaytime = CalculatePct(duration, 25); // channeling delay is normally 25% of its time per hit
+
int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
- m_caster->ToPlayer()->ApplySpellMod(m_spellInfo, SpellModOp::ResistPushback, delayReduce, this);
- delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
+ if (Player* player = unitCaster->GetSpellModOwner())
+ player->ApplySpellMod(m_spellInfo, SpellModOp::ResistPushback, delayReduce, this);
+ delayReduce += unitCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
if (delayReduce >= 100)
return;
@@ -7111,15 +7250,13 @@ void Spell::DelayedChannel()
else
m_timer -= delaytime;
- TC_LOG_DEBUG("spells", "Spell %u partially interrupted for %i ms, new duration: %u ms", m_spellInfo->Id, delaytime, m_timer);
-
for (TargetInfo const& targetInfo : m_UniqueTargetInfo)
if (targetInfo.MissCondition == SPELL_MISS_NONE)
- if (Unit* unit = (m_caster->GetGUID() == targetInfo.TargetGUID) ? m_caster : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID))
+ if (Unit* unit = (unitCaster->GetGUID() == targetInfo.TargetGUID) ? unitCaster : ObjectAccessor::GetUnit(*unitCaster, targetInfo.TargetGUID))
unit->DelayOwnedAuras(m_spellInfo->Id, m_originalCasterGUID, delaytime);
// partially interrupt persistent area auras
- if (DynamicObject* dynObj = m_caster->GetDynObject(m_spellInfo->Id))
+ if (DynamicObject* dynObj = unitCaster->GetDynObject(m_spellInfo->Id))
dynObj->Delay(delaytime);
SendChannelUpdate(m_timer);
@@ -7136,7 +7273,7 @@ bool Spell::HasPowerTypeCost(Powers power) const
bool Spell::UpdatePointers()
{
if (m_originalCasterGUID == m_caster->GetGUID())
- m_originalCaster = m_caster;
+ m_originalCaster = m_caster->ToUnit();
else
{
m_originalCaster = ObjectAccessor::GetUnit(*m_caster, m_originalCasterGUID);
@@ -7341,7 +7478,7 @@ bool Spell::IsProcDisabled() const
bool Spell::IsChannelActive() const
{
- return m_caster->GetChannelSpellId() != 0;
+ return m_caster->IsUnit() && m_caster->ToUnit()->GetChannelSpellId() != 0;
}
bool Spell::IsAutoActionResetSpell() const
@@ -7544,29 +7681,30 @@ void Spell::DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, Spe
Unit* unit = nullptr;
// In case spell hit target, do all effect on that target
if (targetInfo.MissCondition == SPELL_MISS_NONE)
- unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
+ unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
// In case spell reflect from target, do all effect on caster (if hit)
else if (targetInfo.MissCondition == SPELL_MISS_REFLECT && targetInfo.ReflectResult == SPELL_MISS_NONE)
- unit = m_caster;
+ unit = m_caster->ToUnit();
+
if (!unit)
return;
// This will only cause combat - the target will engage once the projectile hits (in DoAllEffectOnTarget)
- if (targetInfo.MissCondition != SPELL_MISS_EVADE && !m_caster->IsFriendlyTo(unit) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)) && (m_spellInfo->HasInitialAggro() || unit->IsEngaged()))
- m_caster->SetInCombatWith(unit);
+ if (m_originalCaster && targetInfo.MissCondition != SPELL_MISS_EVADE && !m_originalCaster->IsFriendlyTo(unit) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)) && (m_spellInfo->HasInitialAggro() || unit->IsEngaged()))
+ m_originalCaster->SetInCombatWith(unit);
m_damage = 0;
m_healing = 0;
HandleEffects(unit, nullptr, nullptr, effect->EffectIndex, SPELL_EFFECT_HANDLE_LAUNCH_TARGET);
- if (m_damage > 0)
+ if (m_originalCaster && m_damage > 0)
{
if (effect->IsTargetingArea() || effect->IsAreaAuraEffect() || effect->IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA))
{
- m_damage = unit->CalculateAOEAvoidance(m_damage, m_spellInfo->SchoolMask, m_caster->GetGUID());
+ m_damage = unit->CalculateAOEAvoidance(m_damage, m_spellInfo->SchoolMask, m_originalCaster->GetGUID());
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (m_originalCaster->GetTypeId() == TYPEID_PLAYER)
{
// cap damage of player AOE
int64 targetAmount = GetUnitTargetCountForEffect(SpellEffIndex(effect->EffectIndex));
@@ -7588,9 +7726,14 @@ void Spell::DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, Spe
targetInfo.Healing += m_healing;
float critChance = m_spellValue->CriticalChance;
- if (!critChance)
- critChance = m_caster->SpellCritChanceDone(this, nullptr, m_spellSchoolMask, m_attackType);
- targetInfo.IsCrit = roll_chance_f(unit->SpellCritChanceTaken(m_caster, this, nullptr, m_spellSchoolMask, critChance, m_attackType));
+ if (m_originalCaster)
+ {
+ if (!critChance)
+ critChance = m_originalCaster->SpellCritChanceDone(this, nullptr, m_spellSchoolMask, m_attackType);
+ critChance = unit->SpellCritChanceTaken(m_originalCaster, this, nullptr, m_spellSchoolMask, critChance, m_attackType);
+ }
+
+ targetInfo.IsCrit = roll_chance_f(critChance);
}
SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue)
@@ -7598,6 +7741,10 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk
if (!lockId) // possible case for GO and maybe for items.
return SPELL_CAST_OK;
+ Unit const* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return SPELL_FAILED_BAD_TARGETS;
+
// Get LockInfo
LockEntry const* lockInfo = sLockStore.LookupEntry(lockId);
@@ -7637,10 +7784,10 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk
// castitem check: rogue using skeleton keys. the skill values should not be added in this case.
skillValue = 0;
- if (!m_CastItem && m_caster->GetTypeId() == TYPEID_PLAYER)
- skillValue = m_caster->ToPlayer()->GetSkillValue(skillId);
+ if (!m_CastItem && unitCaster->GetTypeId() == TYPEID_PLAYER)
+ skillValue = unitCaster->ToPlayer()->GetSkillValue(skillId);
else if (lockInfo->Index[j] == LOCKTYPE_LOCKPICKING)
- skillValue = m_caster->getLevel() * 5;
+ skillValue = unitCaster->getLevel() * 5;
// skill bonus provided by casting spell (mostly item spells)
// add the effect base points modifier from the spell cast (cheat lock / skeleton key etc.)
@@ -7964,10 +8111,14 @@ bool Spell::CanExecuteTriggersOnHit(uint32 effMask, SpellInfo const* triggeredBy
void Spell::PrepareTriggersExecutedOnHit()
{
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return;
+
// handle SPELL_AURA_ADD_TARGET_TRIGGER auras:
// save auras which were present on spell caster on cast, to prevent triggered auras from affecting caster
// and to correctly calculate proc chance when combopoints are present
- Unit::AuraEffectList const& targetTriggers = m_caster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER);
+ Unit::AuraEffectList const& targetTriggers = unitCaster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER);
for (AuraEffect const* aurEff : targetTriggers)
{
if (!aurEff->IsAffectingSpell(m_spellInfo))
@@ -7979,7 +8130,7 @@ void Spell::PrepareTriggersExecutedOnHit()
// this possibly needs fixing
int32 auraBaseAmount = aurEff->GetBaseAmount();
// proc chance is stored in effect amount
- int32 chance = m_caster->CalculateSpellDamage(nullptr, aurEff->GetSpellInfo(), aurEff->GetEffIndex(), &auraBaseAmount);
+ int32 chance = unitCaster->CalculateSpellDamage(nullptr, aurEff->GetSpellInfo(), aurEff->GetEffIndex(), &auraBaseAmount);
chance *= aurEff->GetBase()->GetStackAmount();
// build trigger and add to the list
@@ -7995,23 +8146,30 @@ enum GCDLimits
MAX_GCD = 1500
};
-bool Spell::HasGlobalCooldown() const
+bool CanHaveGlobalCooldown(WorldObject const* caster)
{
// Only players or controlled units have global cooldown
- if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo())
+ if (caster->GetTypeId() != TYPEID_PLAYER && (caster->GetTypeId() != TYPEID_UNIT || !const_cast<WorldObject*>(caster)->ToCreature()->GetCharmInfo()))
return false;
- return m_caster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo);
+ return true;
+}
+
+bool Spell::HasGlobalCooldown() const
+{
+ if (!CanHaveGlobalCooldown(m_caster))
+ return false;
+
+ return m_caster->ToUnit()->GetSpellHistory()->HasGlobalCooldown(m_spellInfo);
}
void Spell::TriggerGlobalCooldown()
{
- int32 gcd = m_spellInfo->StartRecoveryTime;
- if (!gcd || !m_spellInfo->StartRecoveryCategory)
+ if (!CanHaveGlobalCooldown(m_caster))
return;
- // Only players or controlled units have global cooldown
- if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo())
+ int32 gcd = m_spellInfo->StartRecoveryTime;
+ if (!gcd || !m_spellInfo->StartRecoveryCategory)
return;
if (m_caster->GetTypeId() == TYPEID_PLAYER)
@@ -8035,58 +8193,55 @@ void Spell::TriggerGlobalCooldown()
// Apply haste rating
if (gcd > MIN_GCD && ((m_spellInfo->StartRecoveryCategory == 133 && !isMeleeOrRangedSpell)))
{
- gcd = int32(float(gcd) * m_caster->m_unitData->ModSpellHaste);
+ gcd = int32(float(gcd) * m_caster->ToUnit()->m_unitData->ModSpellHaste);
RoundToInterval<int32>(gcd, MIN_GCD, MAX_GCD);
}
- if (gcd > MIN_GCD && m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE_REGEN, m_spellInfo))
+ if (gcd > MIN_GCD && m_caster->ToUnit()->HasAuraTypeWithAffectMask(SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE_REGEN, m_spellInfo))
{
- gcd = int32(float(gcd) * m_caster->m_unitData->ModHasteRegen);
+ gcd = int32(float(gcd) * m_caster->ToUnit()->m_unitData->ModHasteRegen);
RoundToInterval<int32>(gcd, MIN_GCD, MAX_GCD);
}
}
- m_caster->GetSpellHistory()->AddGlobalCooldown(m_spellInfo, gcd);
+ m_caster->ToUnit()->GetSpellHistory()->AddGlobalCooldown(m_spellInfo, gcd);
}
void Spell::CancelGlobalCooldown()
{
- if (!m_spellInfo->StartRecoveryTime)
+ if (!CanHaveGlobalCooldown(m_caster))
return;
- // Cancel global cooldown when interrupting current cast
- if (m_caster->GetCurrentSpell(CURRENT_GENERIC_SPELL) != this)
+ if (!m_spellInfo->StartRecoveryTime)
return;
- // Only players or controlled units have global cooldown
- if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo())
+ // Cancel global cooldown when interrupting current cast
+ if (m_caster->ToUnit()->GetCurrentSpell(CURRENT_GENERIC_SPELL) != this)
return;
- m_caster->GetSpellHistory()->CancelGlobalCooldown(m_spellInfo);
+ m_caster->ToUnit()->GetSpellHistory()->CancelGlobalCooldown(m_spellInfo);
}
namespace Trinity
{
-WorldObjectSpellTargetCheck::WorldObjectSpellTargetCheck(Unit* caster, Unit* referer, SpellInfo const* spellInfo,
- SpellTargetCheckTypes selectionType, ConditionContainer* condList, SpellTargetObjectTypes objectType) :
- _caster(caster), _referer(referer), _spellInfo(spellInfo), _targetSelectionType(selectionType), _condList(condList), _objectType(objectType)
+WorldObjectSpellTargetCheck::WorldObjectSpellTargetCheck(WorldObject* caster, WorldObject* referer, SpellInfo const* spellInfo,
+ SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType) : _caster(caster), _referer(referer), _spellInfo(spellInfo),
+ _targetSelectionType(selectionType), _condSrcInfo(nullptr), _condList(condList), _objectType(objectType)
{
if (condList)
- _condSrcInfo = new ConditionSourceInfo(nullptr, caster);
- else
- _condSrcInfo = nullptr;
+ _condSrcInfo = std::make_unique<ConditionSourceInfo>(nullptr, caster);
}
WorldObjectSpellTargetCheck::~WorldObjectSpellTargetCheck()
{
- delete _condSrcInfo;
}
-bool WorldObjectSpellTargetCheck::operator()(WorldObject* target)
+bool WorldObjectSpellTargetCheck::operator()(WorldObject* target) const
{
if (_spellInfo->CheckTarget(_caster, target, true) != SPELL_CAST_OK)
return false;
+
Unit* unitTarget = target->ToUnit();
if (Corpse* corpseTarget = target->ToCorpse())
{
@@ -8097,6 +8252,7 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target)
return false;
}
+ Unit* refUnit = _referer->ToUnit();
if (unitTarget)
{
// do only faction checks here
@@ -8105,7 +8261,7 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target)
case TARGET_CHECK_ENEMY:
if (unitTarget->IsTotem())
return false;
- if (!_caster->IsValidAttackTarget(unitTarget, _spellInfo, nullptr, false))
+ if (!_caster->IsValidAttackTarget(unitTarget, _spellInfo, false))
return false;
break;
case TARGET_CHECK_ALLY:
@@ -8115,23 +8271,29 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target)
return false;
break;
case TARGET_CHECK_PARTY:
+ if (!refUnit)
+ return false;
if (unitTarget->IsTotem())
return false;
if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo, false))
return false;
- if (!_referer->IsInPartyWith(unitTarget))
+ if (!refUnit->IsInPartyWith(unitTarget))
return false;
break;
case TARGET_CHECK_RAID_CLASS:
- if (_referer->getClass() != unitTarget->getClass())
+ if (!refUnit)
+ return false;
+ if (refUnit->getClass() != unitTarget->getClass())
return false;
/* fallthrough */
case TARGET_CHECK_RAID:
+ if (!refUnit)
+ return false;
if (unitTarget->IsTotem())
return false;
if (!_caster->IsValidAssistTarget(unitTarget, _spellInfo, false))
return false;
- if (!_referer->IsInRaidWith(unitTarget))
+ if (!refUnit->IsInRaidWith(unitTarget))
return false;
break;
case TARGET_CHECK_SUMMONED:
@@ -8141,7 +8303,7 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target)
return false;
break;
case TARGET_CHECK_THREAT:
- if (_referer->GetThreatManager().GetThreat(unitTarget, true) <= 0.0f)
+ if (!_referer->IsUnit() || _referer->ToUnit()->GetThreatManager().GetThreat(unitTarget, true) <= 0.0f)
return false;
break;
case TARGET_CHECK_TAP:
@@ -8185,8 +8347,8 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target)
return sConditionMgr->IsObjectMeetToConditions(*_condSrcInfo, *_condList);
}
-WorldObjectSpellNearbyTargetCheck::WorldObjectSpellNearbyTargetCheck(float range, Unit* caster, SpellInfo const* spellInfo,
- SpellTargetCheckTypes selectionType, ConditionContainer* condList, SpellTargetObjectTypes objectType)
+WorldObjectSpellNearbyTargetCheck::WorldObjectSpellNearbyTargetCheck(float range, WorldObject* caster, SpellInfo const* spellInfo,
+ SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
: WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList, objectType), _range(range), _position(caster) { }
bool WorldObjectSpellNearbyTargetCheck::operator()(WorldObject* target)
@@ -8200,11 +8362,11 @@ bool WorldObjectSpellNearbyTargetCheck::operator()(WorldObject* target)
return false;
}
-WorldObjectSpellAreaTargetCheck::WorldObjectSpellAreaTargetCheck(float range, Position const* position, Unit* caster,
- Unit* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer* condList, SpellTargetObjectTypes objectType)
+WorldObjectSpellAreaTargetCheck::WorldObjectSpellAreaTargetCheck(float range, Position const* position, WorldObject* caster,
+ WorldObject* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
: WorldObjectSpellTargetCheck(caster, referer, spellInfo, selectionType, condList, objectType), _range(range), _position(position) { }
-bool WorldObjectSpellAreaTargetCheck::operator()(WorldObject* target)
+bool WorldObjectSpellAreaTargetCheck::operator()(WorldObject* target) const
{
if (target->ToGameObject())
{
@@ -8223,11 +8385,11 @@ bool WorldObjectSpellAreaTargetCheck::operator()(WorldObject* target)
return WorldObjectSpellTargetCheck::operator ()(target);
}
-WorldObjectSpellConeTargetCheck::WorldObjectSpellConeTargetCheck(float coneAngle, float lineWidth, float range, Unit* caster,
- SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer* condList, SpellTargetObjectTypes objectType)
+WorldObjectSpellConeTargetCheck::WorldObjectSpellConeTargetCheck(float coneAngle, float lineWidth, float range, WorldObject* caster,
+ SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
: WorldObjectSpellAreaTargetCheck(range, caster, caster, caster, spellInfo, selectionType, condList, objectType), _coneAngle(coneAngle), _lineWidth(lineWidth) { }
-bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target)
+bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target) const
{
if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_BACK))
{
@@ -8241,7 +8403,7 @@ bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target)
}
else
{
- if (!_caster->IsWithinBoundaryRadius(target->ToUnit()))
+ if (!_caster->IsUnit() || !_caster->ToUnit()->IsWithinBoundaryRadius(target->ToUnit()))
// ConeAngle > 0 -> select targets in front
// ConeAngle < 0 -> select targets in back
if (_caster->HasInArc(_coneAngle, target) != G3D::fuzzyGe(_coneAngle, 0.f))
@@ -8250,10 +8412,10 @@ bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target)
return WorldObjectSpellAreaTargetCheck::operator ()(target);
}
-WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Position const* position, Unit* caster, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer* condList, SpellTargetObjectTypes objectType)
+WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Position const* position, WorldObject* caster, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
: WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList, objectType), _range(range), _position(position) { }
-bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target)
+bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target) const
{
// return all targets on missile trajectory (0 - size of a missile)
if (!_caster->HasInLine(target, target->GetCombatReach(), TRAJECTORY_MISSILE_SIZE))
@@ -8265,11 +8427,11 @@ bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target)
return WorldObjectSpellTargetCheck::operator ()(target);
}
-WorldObjectSpellLineTargetCheck::WorldObjectSpellLineTargetCheck(Position const* srcPosition, Position const* dstPosition, float lineWidth, float range, Unit* caster,
- SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer* condList, SpellTargetObjectTypes objectType)
+WorldObjectSpellLineTargetCheck::WorldObjectSpellLineTargetCheck(Position const* srcPosition, Position const* dstPosition, float lineWidth, float range, WorldObject* caster,
+ SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
: WorldObjectSpellAreaTargetCheck(range, caster, caster, caster, spellInfo, selectionType, condList, objectType), _srcPosition(srcPosition), _dstPosition(dstPosition), _lineWidth(lineWidth) { }
-bool WorldObjectSpellLineTargetCheck::operator()(WorldObject* target)
+bool WorldObjectSpellLineTargetCheck::operator()(WorldObject* target) const
{
float angle = _caster->GetOrientation();
if (*_srcPosition != *_dstPosition)