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
committerAriel Silva <ariel-@users.noreply.github.com>2018-03-09 14:41:28 -0300
commit45c5e1b9d63796d168339a44f63418f220cf2403 (patch)
treec5c2ef9917147e38779d1f94e6ffc38386b9b251 /src/server/game/Spells/Spell.cpp
parent080d2c6cd439acb2059adc4e24a279de98aa0db6 (diff)
Core/Spells: rework part 5: GameObject casting
Closes #21330 Closes #18885 Ref #18752
Diffstat (limited to 'src/server/game/Spells/Spell.cpp')
-rw-r--r--src/server/game/Spells/Spell.cpp1262
1 files changed, 724 insertions, 538 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 145c385dcd0..8604a7f67ca 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -60,7 +60,7 @@
#include "WorldPacket.h"
#include "WorldSession.h"
-extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS];
+extern SpellEffectHandlerFn SpellEffectHandlers[TOTAL_SPELL_EFFECTS];
SpellDestination::SpellDestination()
{
@@ -454,9 +454,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 ? ((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)
@@ -493,28 +493,6 @@ 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", "elevation: %f", m_elevation);
-}
-
SpellValue::SpellValue(SpellInfo const* proto)
{
for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
@@ -529,7 +507,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;
@@ -539,7 +517,7 @@ class TC_GAME_API SpellEvent : public BasicEvent
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(sSpellMgr->GetSpellForDifficultyFromSpell(info, caster)),
m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster)
, m_spellValue(new SpellValue(m_spellInfo)), _spellEvent(nullptr)
@@ -563,11 +541,14 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO
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()->Damage[0].DamageType);
+ 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()->Damage[0].DamageType);
+ }
if (originalCasterGUID)
m_originalCasterGUID = originalCasterGUID;
@@ -575,7 +556,7 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO
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);
@@ -609,6 +590,7 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO
m_glyphIndex = 0;
m_preCastSpell = 0;
m_triggeredByAuraSpell = nullptr;
+ unitCaster = nullptr;
_spellAura = nullptr;
_dynObjAura = nullptr;
@@ -626,7 +608,7 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO
// 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->isType(TYPEMASK_UNIT) && 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();
@@ -697,11 +679,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->ToCreature()->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);
}
@@ -739,10 +721,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:
@@ -750,10 +732,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))
@@ -1200,7 +1182,8 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge
// Other special target selection goes here
if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
{
- maxTargets += m_caster->GetTotalAuraModifierByAffectMask(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS, m_spellInfo);
+ if (Unit* unitCaster = m_caster->ToUnit())
+ maxTargets += unitCaster->GetTotalAuraModifierByAffectMask(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS, m_spellInfo);
Trinity::Containers::RandomResize(targets, maxTargets);
}
@@ -1217,7 +1200,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:
@@ -1283,7 +1266,8 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge
// Other special target selection goes here
if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
{
- maxTargets += m_caster->GetTotalAuraModifierByAffectMask(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS, m_spellInfo);
+ if (Unit* unitCaster = m_caster->ToUnit())
+ maxTargets += unitCaster->GetTotalAuraModifierByAffectMask(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS, m_spellInfo);
Trinity::Containers::RandomResize(targets, maxTargets);
}
@@ -1361,15 +1345,19 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
}
case TARGET_DEST_CASTER_FRONT_LEAP:
{
- float dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster);
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ break;
+
+ float dist = m_spellInfo->Effects[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);
@@ -1511,14 +1499,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:
@@ -1528,8 +1519,9 @@ 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;
default:
break;
@@ -1537,8 +1529,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)
@@ -1627,7 +1624,7 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTarge
float b = tangent(m_targets.GetElevation());
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
@@ -1635,15 +1632,16 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTarge
if (SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(m_spellInfo->Effects[effIndex].TriggerSpell))
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())
@@ -1653,14 +1651,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;
@@ -1674,11 +1672,11 @@ 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);
}
@@ -1691,9 +1689,9 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex)
{
case SPELL_EFFECT_SUMMON_RAF_FRIEND:
case SPELL_EFFECT_SUMMON_PLAYER:
- if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->GetTarget())
+ if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->GetTarget())
{
- 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
@@ -1821,7 +1819,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;
@@ -1857,7 +1855,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)
@@ -1968,7 +1966,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;
}
@@ -2082,7 +2080,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
@@ -2127,10 +2125,8 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
}
// 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.
@@ -2154,8 +2150,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));
@@ -2265,7 +2262,7 @@ void Spell::AddDestTarget(SpellDestination const& dest, uint32 effIndex)
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;
@@ -2280,7 +2277,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)
@@ -2293,7 +2290,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;
}
@@ -2308,7 +2305,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;
@@ -2337,7 +2334,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;
@@ -2352,7 +2349,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;
@@ -2497,8 +2494,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(AURA_INTERRUPT_FLAG_TALK);
- spell->unitTarget->ToCreature()->EngageWithTarget(spell->m_caster);
+ Unit* unitCaster = ASSERT_NOTNULL(spell->m_caster->ToUnit());
+ unitCaster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK);
+ spell->unitTarget->ToCreature()->EngageWithTarget(unitCaster);
}
}
@@ -2526,7 +2524,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);
@@ -2540,11 +2539,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);
@@ -2558,7 +2566,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;
@@ -2566,8 +2574,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();
@@ -2635,17 +2654,23 @@ SpellMissInfo Spell::PreprocessSpellHit(Unit* unit, bool scaleAura, TargetInfo&
playerOwner->UpdatePvP(true);
}
}
- if (unit->IsInCombat() && m_spellInfo->HasInitialAggro())
+
+ if (m_originalCaster && unit->IsInCombat() && m_spellInfo->HasInitialAggro())
{
- if (m_caster->HasFlag(UNIT_FIELD_FLAGS, 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->HasFlag(UNIT_FIELD_FLAGS, 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))
{
// Select rank for aura with level requirements only in specific cases
// Unit has to be target only of aura effect, both caster and target have to be players, target has to be other than unit target
@@ -2683,7 +2708,7 @@ SpellMissInfo Spell::PreprocessSpellHit(Unit* unit, bool scaleAura, TargetInfo&
// 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 (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
@@ -2701,7 +2726,7 @@ SpellMissInfo Spell::PreprocessSpellHit(Unit* unit, bool scaleAura, TargetInfo&
hitInfo.AuraDuration = hitInfo.AuraSpellInfo->GetMaxDuration();
// unit is immune to aura if it was diminished to 0 duration
- if (!hitInfo.Positive && !unit->ApplyDiminishingToDuration(hitInfo.AuraSpellInfo, triggered, hitInfo.AuraDuration, m_originalCaster, diminishLevel))
+ if (!hitInfo.Positive && !unit->ApplyDiminishingToDuration(hitInfo.AuraSpellInfo, triggered, hitInfo.AuraDuration, origCaster, diminishLevel))
if (std::all_of(std::begin(hitInfo.AuraSpellInfo->Effects), std::end(hitInfo.AuraSpellInfo->Effects), [](SpellEffectInfo const& effInfo) { return !effInfo.IsEffect() || effInfo.Effect == SPELL_EFFECT_APPLY_AURA; }))
return SPELL_MISS_IMMUNE;
}
@@ -2711,10 +2736,13 @@ SpellMissInfo Spell::PreprocessSpellHit(Unit* unit, bool scaleAura, TargetInfo&
void Spell::DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& hitInfo)
{
- uint8 aura_effmask = Aura::BuildEffectMaskForOwner(m_spellInfo, 1 << effIndex, unit);
- if (aura_effmask)
+ if (uint8 aura_effmask = Aura::BuildEffectMaskForOwner(m_spellInfo, 1 << effIndex, unit))
{
+ WorldObject* caster = m_caster;
if (m_originalCaster)
+ caster = m_originalCaster;
+
+ if (caster)
{
bool refresh = false;
@@ -2728,7 +2756,7 @@ void Spell::DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& hitInfo)
AuraCreateInfo createInfo(hitInfo.AuraSpellInfo, allAuraEffectMask, unit);
createInfo
- .SetCaster(m_originalCaster)
+ .SetCasterGUID(caster->GetGUID())
.SetBaseAmount(bp)
.SetCastItem(m_CastItem)
.SetPeriodicReset(resetPeriodicTimer)
@@ -2754,13 +2782,13 @@ void Spell::DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& hitInfo)
_spellAura->SetDiminishGroup(hitInfo.DRGroup);
- hitInfo.AuraDuration = m_originalCaster->ModSpellDuration(hitInfo.AuraSpellInfo, unit, hitInfo.AuraDuration, hitInfo.Positive, _spellAura->GetEffectMask());
+ hitInfo.AuraDuration = caster->ModSpellDuration(hitInfo.AuraSpellInfo, unit, hitInfo.AuraDuration, hitInfo.Positive, _spellAura->GetEffectMask());
// Haste modifies duration of channeled spells
if (m_spellInfo->IsChanneled())
- m_originalCaster->ModSpellDurationTime(hitInfo.AuraSpellInfo, hitInfo.AuraDuration, this);
+ caster->ModSpellDurationTime(hitInfo.AuraSpellInfo, hitInfo.AuraDuration, this);
// and duration of auras affected by SPELL_AURA_PERIODIC_HASTE
- else if (m_originalCaster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, hitInfo.AuraSpellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION))
+ else if (m_originalCaster && (m_originalCaster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, hitInfo.AuraSpellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION)))
hitInfo.AuraDuration = int32(hitInfo.AuraDuration * m_originalCaster->GetFloatValue(UNIT_MOD_CAST_SPEED));
if (hitInfo.AuraDuration != _spellAura->GetMaxDuration())
@@ -2795,9 +2823,10 @@ void Spell::DoTriggersOnSpellHit(Unit* unit, uint8 effMask)
// Cast the serverside immunity shield marker
m_caster->CastSpell(unit, 61988, true);
- if (sSpellMgr->GetSpellInfo(m_preCastSpell))
- // Blizz seems to just apply aura without bothering to cast
- m_caster->AddAura(m_preCastSpell, unit);
+ // Blizz seems to just apply aura without bothering to cast
+ if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(m_preCastSpell))
+ if (Unit* unitCaster = m_caster->ToUnit())
+ unitCaster->AddAura(spellInfo, MAX_EFFECT_MASK, unit);
}
// handle SPELL_AURA_ADD_TARGET_TRIGGER auras
@@ -2876,7 +2905,7 @@ 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)
continue;
@@ -2922,20 +2951,23 @@ void Spell::prepare(SpellCastTargets const& targets, AuraEffect const* triggered
InitExplicitTargets(targets);
// Fill aura scaling information
- if (m_caster->IsControlledByPlayer() && !m_spellInfo->IsPassive() && m_spellInfo->SpellLevel && !m_spellInfo->IsChanneled() && !(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_SCALING))
+ if (Unit* unitCaster = m_caster->ToUnit())
{
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (unitCaster->IsControlledByPlayer() && !m_spellInfo->IsPassive() && m_spellInfo->SpellLevel && !m_spellInfo->IsChanneled() && !(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_SCALING))
{
- if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_APPLY_AURA)
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- // Change aura with ranks only if basepoints are taken from spellInfo and aura is positive
- if (m_spellInfo->IsPositiveEffect(i))
+ if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_APPLY_AURA)
{
- m_auraScaleMask |= (1 << i);
- if (m_spellValue->EffectBasePoints[i] != m_spellInfo->Effects[i].BasePoints)
+ // Change aura with ranks only if basepoints are taken from spellInfo and aura is positive
+ if (m_spellInfo->IsPositiveEffect(i))
{
- m_auraScaleMask = 0;
- break;
+ m_auraScaleMask |= (1 << i);
+ if (m_spellValue->EffectBasePoints[i] != m_spellInfo->Effects[i].BasePoints)
+ {
+ m_auraScaleMask = 0;
+ break;
+ }
}
}
}
@@ -2951,20 +2983,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_cast_count)
+ // 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_cast_count)
{
- 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)
@@ -3016,7 +3050,7 @@ void Spell::prepare(SpellCastTargets const& targets, AuraEffect const* triggered
// don't allow channeled spells / spells with cast time to be cast while moving
// 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)
- if ((m_spellInfo->IsChanneled() || m_casttime) && m_caster->GetTypeId() == TYPEID_PLAYER && !(m_caster->IsCharmed() && m_caster->GetCharmerGUID().IsCreature()) && m_caster->isMoving() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT))
+ 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 & SPELL_INTERRUPT_FLAG_MOVEMENT))
{
// 1. Has casttime, 2. Or doesn't have flag to allow movement during channel
if (m_casttime || !m_spellInfo->IsMoveAllowedChannel())
@@ -3051,20 +3085,25 @@ 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())
+ if (Unit* unitCaster = m_caster->ToUnit())
{
- m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CAST);
- for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- if (m_spellInfo->Effects[i].GetUsedTargetObjectType() == TARGET_OBJECT_TYPE_UNIT)
+ // 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())
+ {
+ unitCaster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CAST);
+ for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_SPELL_ATTACK);
- break;
+ if (m_spellInfo->Effects[i].GetUsedTargetObjectType() == TARGET_OBJECT_TYPE_UNIT)
+ {
+ unitCaster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_SPELL_ATTACK);
+ break;
+ }
}
- }
+ }
- m_caster->SetCurrentCastSpell(this);
+ unitCaster->SetCurrentCastSpell(this);
+ }
SendSpellStart();
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_GCD))
@@ -3101,7 +3140,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);
@@ -3119,9 +3158,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;
@@ -3184,7 +3227,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();
@@ -3255,11 +3298,13 @@ void Spell::_cast(bool skipCheck)
DiminishingReturnsType type = m_spellInfo->GetDiminishingReturnsGroupType(triggered);
if (type == DRTYPE_ALL || (type == DRTYPE_PLAYER && target->IsAffectedByDiminishingReturns()))
{
- Unit* caster = m_originalCaster ? m_originalCaster : m_caster;
- if (target->HasStrongerAuraWithDR(m_spellInfo, caster, triggered))
+ if (Unit* caster = m_originalCaster ? m_originalCaster : m_caster->ToUnit())
{
- cleanupSpell(SPELL_FAILED_AURA_BOUNCED);
- return;
+ if (target->HasStrongerAuraWithDR(m_spellInfo, caster, triggered))
+ {
+ cleanupSpell(SPELL_FAILED_AURA_BOUNCED);
+ return;
+ }
}
}
}
@@ -3272,7 +3317,7 @@ void Spell::_cast(bool skipCheck)
if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->HasFlag(UNIT_FIELD_FLAGS, 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();
@@ -3289,9 +3334,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();
@@ -3349,8 +3395,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
{
@@ -3365,7 +3412,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);
}
@@ -3376,8 +3426,8 @@ 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))
- m_caster->GetSpellHistory()->ResetCooldown(m_spellInfo->Id, true);
+ if (m_originalCaster && modOwner->GetCommandStatus(CHEAT_COOLDOWN))
+ m_originalCaster->GetSpellHistory()->ResetCooldown(m_spellInfo->Id, true);
}
SetExecutedCurrently(false);
@@ -3433,17 +3483,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_channeledDuration = duration;
SendChannelStart(duration);
}
else if (duration == -1)
- {
- m_spellState = SPELL_STATE_CASTING;
- m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags);
SendChannelStart(duration);
- }
+
+ m_spellState = SPELL_STATE_CASTING;
+
+ // GameObjects shouldn't cast channeled spells
+ ASSERT_NOTNULL(m_caster->ToUnit())->AddInterruptMask(m_spellInfo->ChannelInterruptFlags);
}
PrepareTargetProcessing();
@@ -3589,20 +3638,23 @@ void Spell::_handle_immediate_phase()
void Spell::_handle_finish_phase()
{
- // Take for real after all targets are processed
- if (m_needComboPoints)
- m_caster->ClearComboPoints();
+ if (Unit* unitCaster = m_caster->ToUnit())
+ {
+ // Take for real after all targets are processed
+ if (m_needComboPoints)
+ unitCaster->ClearComboPoints();
- // Real add combo points from effects
- if (m_comboTarget && m_comboPointGain)
- m_caster->AddComboPoints(m_comboTarget, m_comboPointGain);
+ // Real add combo points from effects
+ if (m_comboTarget && m_comboPointGain)
+ unitCaster->AddComboPoints(m_comboTarget, 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
@@ -3623,7 +3675,10 @@ void Spell::_handle_finish_phase()
void Spell::SendSpellCooldown()
{
- m_caster->GetSpellHistory()->HandleCooldowns(m_spellInfo, m_CastItem, this);
+ if (m_caster->GetTypeId() == TYPEID_GAMEOBJECT)
+ return;
+
+ m_caster->ToUnit()->GetSpellHistory()->HandleCooldowns(m_spellInfo, m_CastItem, this);
}
void Spell::update(uint32 difftime)
@@ -3644,9 +3699,9 @@ void Spell::update(uint32 difftime)
}
// check if the player caster has moved before the spell finished
- if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) &&
- m_caster->isMoving() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT &&
- (m_spellInfo->Effects[0].Effect != SPELL_EFFECT_STUCK || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR))))
+ if (m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0 &&
+ m_caster->ToPlayer()->isMoving() && m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT &&
+ (m_spellInfo->Effects[EFFECT_0].Effect != SPELL_EFFECT_STUCK || !m_caster->ToPlayer()->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR)))
{
// don't cancel for melee, autorepeat, triggered and instant spells
if (!m_spellInfo->IsNextMeleeSwingSpell() && !IsAutoRepeat() && !IsTriggered() && !(IsChannelActive() && m_spellInfo->IsMoveAllowedChannel()))
@@ -3654,7 +3709,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();
}
}
@@ -3688,7 +3743,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);
}
@@ -3715,44 +3770,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->GetUInt32Value(UNIT_CREATED_BY_SPELL) == 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->GetUInt32Value(UNIT_CREATED_BY_SPELL);
+ uint32 spell = unitCaster->GetUInt32Value(UNIT_CREATED_BY_SPELL);
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell);
if (spellInfo && spellInfo->SpellIconID == 2056)
{
- TC_LOG_DEBUG("spells", "Statue %d is unsummoned in spell %d finish", m_caster->GetGUID().GetCounter(), m_spellInfo->Id);
- m_caster->setDeathState(JUST_DIED);
+ TC_LOG_DEBUG("spells", "Statue %d is unsummoned in spell %d finish", unitCaster->GetGUID().GetCounter(), m_spellInfo->Id);
+ unitCaster->setDeathState(JUST_DIED);
return;
}
}
@@ -3760,7 +3819,7 @@ void Spell::finish(bool ok)
if (IsAutoActionResetSpell())
{
bool found = false;
- Unit::AuraEffectList const& vIgnoreReset = m_caster->GetAuraEffectsByType(SPELL_AURA_IGNORE_MELEE_RESET);
+ Unit::AuraEffectList const& vIgnoreReset = unitCaster->GetAuraEffectsByType(SPELL_AURA_IGNORE_MELEE_RESET);
for (Unit::AuraEffectList::const_iterator i = vIgnoreReset.begin(); i != vIgnoreReset.end(); ++i)
{
if ((*i)->IsAffectedOnSpell(m_spellInfo))
@@ -3772,23 +3831,23 @@ void Spell::finish(bool ok)
if (!found && !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();
}
void Spell::WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
@@ -4024,8 +4083,14 @@ void Spell::SendSpellStart()
//TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_START id=%u", m_spellInfo->Id);
uint32 castFlags = CAST_FLAG_UNKNOWN_2;
- 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;
@@ -4035,7 +4100,7 @@ void Spell::SendSpellStart()
if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) || m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NEEDS_AMMO_DATA))
castFlags |= CAST_FLAG_AMMO;
if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
- (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsPet()))
+ (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsPet()))
&& m_spellInfo->PowerType != POWER_HEALTH)
castFlags |= CAST_FLAG_POWER_LEFT_SELF;
@@ -4057,7 +4122,7 @@ void Spell::SendSpellStart()
m_targets.Write(data);
if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
- data << uint32(m_caster->GetPower((Powers)m_spellInfo->PowerType));
+ data << uint32(ASSERT_NOTNULL(m_caster->ToUnit())->GetPower((Powers)m_spellInfo->PowerType));
if (castFlags & CAST_FLAG_AMMO)
WriteAmmoToPacket(&data);
@@ -4089,12 +4154,12 @@ void Spell::SendSpellGo()
castFlags |= CAST_FLAG_AMMO; // 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()))
&& m_spellInfo->PowerType != POWER_HEALTH)
- 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)
&& m_spellInfo->RuneCostID
&& m_spellInfo->PowerType == POWER_RUNE
&& !(_triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST))
@@ -4113,7 +4178,6 @@ void Spell::SendSpellGo()
castFlags |= CAST_FLAG_NO_GCD;
WorldPacket data(SMSG_SPELL_GO, 50); // guess size
-
if (m_CastItem)
data << m_CastItem->GetPackGUID();
else
@@ -4130,7 +4194,7 @@ void Spell::SendSpellGo()
m_targets.Write(data);
if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
- data << uint32(m_caster->GetPower((Powers)m_spellInfo->PowerType));
+ data << uint32(ASSERT_NOTNULL(m_caster->ToUnit())->GetPower((Powers)m_spellInfo->PowerType));
if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list
{
@@ -4174,7 +4238,14 @@ void Spell::SendSpellGo()
data << uint8(0);
}
- m_caster->SendMessageToSet(&data, true);
+ // should be sent to self only
+ if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
+ {
+ if (Player* player = m_caster->GetAffectingPlayer())
+ player->SendDirectMessage(&data);
+ }
+ else
+ m_caster->SendMessageToSet(&data, true);
}
void Spell::WriteAmmoToPacket(WorldPacket* data)
@@ -4202,7 +4273,7 @@ void Spell::WriteAmmoToPacket(WorldPacket* data)
ammoInventoryType = pProto->InventoryType;
}
}
- else if (m_caster->HasAura(46699)) // Requires No Ammo
+ else if (m_caster->ToPlayer()->HasAura(46699)) // Requires No Ammo
{
ammoDisplayID = 5996; // normal arrow
ammoInventoryType = INVTYPE_AMMO;
@@ -4210,9 +4281,9 @@ void Spell::WriteAmmoToPacket(WorldPacket* data)
}
}
}
- else
+ else if (m_caster->GetTypeId() == TYPEID_UNIT)
{
- for (uint8 i = 0; i < 3; ++i)
+ for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
{
if (uint32 item_id = m_caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i))
{
@@ -4428,59 +4499,70 @@ 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->SetChannelObjectGuid(ObjectGuid::Empty);
- m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL, 0);
+ unitCaster->SetChannelObjectGuid(ObjectGuid::Empty);
+ unitCaster->SetUInt32Value(UNIT_CHANNEL_SPELL, 0);
}
WorldPacket data(MSG_CHANNEL_UPDATE, 8+4);
- data << m_caster->GetPackGUID();
+ data << unitCaster->GetPackGUID();
data << uint32(time);
- m_caster->SendMessageToSet(&data, true);
+ unitCaster->SendMessageToSet(&data, true);
}
void Spell::SendChannelStart(uint32 duration)
{
+ // GameObjects don't channel
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return;
+
ObjectGuid channelTarget = m_targets.GetObjectTargetGUID();
if (!channelTarget && !m_spellInfo->NeedsExplicitUnitTarget())
if (m_UniqueTargetInfo.size() + m_UniqueGOTargetInfo.size() == 1) // this is for TARGET_SELECT_CATEGORY_NEARBY
channelTarget = !m_UniqueTargetInfo.empty() ? m_UniqueTargetInfo.front().TargetGUID : m_UniqueGOTargetInfo.front().TargetGUID;
WorldPacket data(MSG_CHANNEL_START, (8+4+4));
- data << m_caster->GetPackGUID();
+ data << unitCaster->GetPackGUID();
data << uint32(m_spellInfo->Id);
data << uint32(duration);
- m_caster->SendMessageToSet(&data, true);
+ unitCaster->SendMessageToSet(&data, true);
m_timer = duration;
if (channelTarget)
{
- m_caster->SetChannelObjectGuid(channelTarget);
+ unitCaster->SetChannelObjectGuid(channelTarget);
- if (channelTarget != m_caster->GetGUID())
- if (Creature* creatureCaster = m_caster->ToCreature())
+ if (channelTarget != unitCaster->GetGUID())
+ if (Creature* creatureCaster = unitCaster->ToCreature())
if (!creatureCaster->IsFocusing(this))
creatureCaster->FocusTarget(this, ObjectAccessor::GetWorldObject(*creatureCaster, channelTarget));
}
- m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL, m_spellInfo->Id);
+ unitCaster->SetUInt32Value(UNIT_CHANNEL_SPELL, m_spellInfo->Id);
}
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());
WorldPacket data(SMSG_RESURRECT_REQUEST, 8 + 4 + sentName.size() + 1 + 1 + 1);
data << uint64(m_caster->GetGUID());
data << uint32(sentName.size() + 1);
data << sentName;
- data << uint8(m_caster->IsSpiritHealer()); // "you'll be afflicted with resurrection sickness"
+ data << uint8(m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsSpiritHealer()); // "you'll be afflicted with resurrection sickness"
// override delay sent with SMSG_CORPSE_RECLAIM_DELAY, set instant resurrection for spells with this attribute
data << uint8(!m_spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_RESURRECTION_TIMER));
target->SendDirectMessage(&data);
@@ -4556,19 +4638,24 @@ 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;
}
Powers powerType = Powers(m_spellInfo->PowerType);
bool hit = true;
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (unitCaster->GetTypeId() == TYPEID_PLAYER)
{
if (powerType == POWER_RAGE || powerType == POWER_ENERGY || powerType == POWER_RUNE)
{
@@ -4579,7 +4666,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->ToPlayer()->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_SPELL_COST_REFUND_ON_FAIL, m_powerCost);
}
}
@@ -4598,7 +4685,7 @@ void Spell::TakePower()
// health as power used
if (powerType == POWER_HEALTH)
{
- m_caster->ModifyHealth(-(int32)m_powerCost);
+ unitCaster->ModifyHealth(-(int32)m_powerCost);
return;
}
@@ -4608,40 +4695,45 @@ void Spell::TakePower()
return;
}
- m_caster->ModifyPower(powerType, -m_powerCost);
+ unitCaster->ModifyPower(powerType, -m_powerCost);
// Set the five second timer
if (powerType == POWER_MANA && m_powerCost > 0)
- m_caster->SetLastManaUse(GameTime::GetGameTimeMS());
+ unitCaster->SetLastManaUse(GameTime::GetGameTimeMS());
}
void Spell::TakeAmmo()
{
- if (m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
- {
- Item* pItem = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK);
+ // Only players use ammo
+ Player* player = m_caster->ToPlayer();
+ if (!player)
+ return;
- // wands don't have ammo
- if (!pItem || pItem->IsBroken() || pItem->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_WAND)
- return;
+ // only ranged
+ if (m_attackType != RANGED_ATTACK)
+ return;
+
+ // wands don't have ammo
+ Item* item = player->GetWeaponForAttack(RANGED_ATTACK);
+ if (!item || item->IsBroken() || item->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_WAND)
+ return;
- if (pItem->GetTemplate()->InventoryType == INVTYPE_THROWN)
+ if (item->GetTemplate()->InventoryType == INVTYPE_THROWN)
+ {
+ if (item->GetMaxStackCount() == 1)
{
- if (pItem->GetMaxStackCount() == 1)
- {
- // decrease durability for non-stackable throw weapon
- m_caster->ToPlayer()->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
- }
- else
- {
- // decrease items amount for stackable throw weapon
- uint32 count = 1;
- m_caster->ToPlayer()->DestroyItemCount(pItem, count, true);
- }
+ // decrease durability for non-stackable throw weapon
+ player->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
+ }
+ else
+ {
+ // decrease items amount for stackable throw weapon
+ uint32 count = 1;
+ player->DestroyItemCount(item, count, true);
}
- else if (uint32 ammo = m_caster->ToPlayer()->GetUInt32Value(PLAYER_AMMO_ID))
- m_caster->ToPlayer()->DestroyItemCount(ammo, 1, true);
}
+ else if (uint32 ammo = player->GetUInt32Value(PLAYER_AMMO_ID))
+ player->DestroyItemCount(ammo, 1, true);
}
SpellCastResult Spell::CheckRuneCost(uint32 runeCostID) const
@@ -4693,7 +4785,7 @@ SpellCastResult Spell::CheckRuneCost(uint32 runeCostID) 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;
SpellRuneCostEntry const* runeCostData = sSpellRuneCostStore.LookupEntry(m_spellInfo->RuneCostID);
@@ -4833,6 +4925,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;
@@ -4843,7 +4940,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;
}
@@ -4863,20 +4960,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()));
@@ -4889,26 +4986,25 @@ 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();
- uint8 eff = m_spellInfo->Effects[i].Effect;
-
- TC_LOG_DEBUG("spells", "Spell: %u Effect : %u", m_spellInfo->Id, eff);
+ uint8 effect = m_spellInfo->Effects[i].Effect;
+ ASSERT(effect < TOTAL_SPELL_EFFECTS); // checked at startup
// we do not need DamageMultiplier here.
- damage = CalculateDamage(i, nullptr);
+ damage = CalculateDamage(i);
- 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])((SpellEffIndex)i);
- }
+ if (!preventDefault)
+ (this->*SpellEffectHandlers[effect])(effIndex);
}
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
@@ -4925,7 +5021,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
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;
@@ -4953,95 +5049,98 @@ 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->IsAffectedOnSpell(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->IsAffectedOnSpell(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;
+ }
}
- }
- if (m_caster->HasAuraTypeWithMiscvalue(SPELL_AURA_BLOCK_SPELL_FAMILY, m_spellInfo->SpellFamilyName))
- return SPELL_FAILED_SPELL_UNAVAILABLE;
+ if (unitCaster->HasAuraTypeWithMiscvalue(SPELL_AURA_BLOCK_SPELL_FAMILY, m_spellInfo->SpellFamilyName))
+ return SPELL_FAILED_SPELL_UNAVAILABLE;
- 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)->IsAffectedOnSpell(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)->IsAffectedOnSpell(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->CasterAuraStateNot && m_caster->HasAuraState(AuraStateType(m_spellInfo->CasterAuraStateNot), 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->CasterAuraStateNot && unitCaster->HasAuraState(AuraStateType(m_spellInfo->CasterAuraStateNot), m_spellInfo, unitCaster))
+ return SPELL_FAILED_CASTER_AURASTATE;
- // Note: spell 62473 requres casterAuraSpell = triggering spell
- if (m_spellInfo->CasterAuraSpell && !m_caster->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->CasterAuraSpell, m_caster)))
- return SPELL_FAILED_CASTER_AURASTATE;
- if (m_spellInfo->ExcludeCasterAuraSpell && m_caster->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->ExcludeCasterAuraSpell, m_caster)))
- return SPELL_FAILED_CASTER_AURASTATE;
+ // Note: spell 62473 requres casterAuraSpell = triggering spell
+ if (m_spellInfo->CasterAuraSpell && !unitCaster->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->CasterAuraSpell, unitCaster)))
+ return SPELL_FAILED_CASTER_AURASTATE;
+ if (m_spellInfo->ExcludeCasterAuraSpell && unitCaster->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->ExcludeCasterAuraSpell, unitCaster)))
+ 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)
- if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->isMoving() && (!m_caster->IsCharmed() || !m_caster->GetCharmerGUID().IsCreature()))
- {
- // skip stuck spell to allow use it in falling case and apply spell limitations at movement
- if ((!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR) || m_spellInfo->Effects[0].Effect != SPELL_EFFECT_STUCK) &&
- (IsAutoRepeat() || (m_spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED) != 0))
- 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)
+ if (unitCaster->GetTypeId() == TYPEID_PLAYER && unitCaster->ToPlayer()->isMoving() && (!unitCaster->IsCharmed() || !unitCaster->GetCharmerGUID().IsCreature()))
+ {
+ // skip stuck spell to allow use it in falling case and apply spell limitations at movement
+ if ((!unitCaster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR) || m_spellInfo->Effects[EFFECT_0].Effect != SPELL_EFFECT_STUCK) &&
+ (IsAutoRepeat() || (m_spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED) != 0))
+ 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
@@ -5070,8 +5169,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());
@@ -5081,7 +5180,7 @@ 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;
@@ -5095,11 +5194,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_SKIP_CHECKCAST_LOS_CHECK) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, nullptr, SPELL_DISABLE_LOS) && !target->IsWithinLOSInMap(losTarget, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
@@ -5119,23 +5219,26 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
}
// check pet presence
- for (int j = 0; j < MAX_SPELL_EFFECTS; ++j)
+ if (Unit* unitCaster = m_caster->ToUnit())
{
- if (m_spellInfo->Effects[j].TargetA.GetTarget() == TARGET_UNIT_PET)
+ for (uint8 j = EFFECT_0; j < MAX_SPELL_EFFECTS; ++j)
{
- if (!m_caster->GetGuardianPet())
+ if (m_spellInfo->Effects[j].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;
@@ -5149,7 +5252,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
return SPELL_FAILED_NOT_IN_ARENA;
// 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);
@@ -5160,13 +5263,15 @@ 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
@@ -5238,22 +5343,25 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
{
if (Unit* target = m_targets.GetUnitTarget())
{
- // do not allow to cast on hostile targets in sanctuary
- if (!m_caster->IsFriendlyTo(target))
+ if (Unit* unitCaster = m_caster->ToUnit())
{
- if (m_caster->IsInSanctuary() || target->IsInSanctuary())
+ // do not allow to cast on hostile targets in sanctuary
+ if (!unitCaster->IsFriendlyTo(target))
{
- // fix for duels
- Player* player = m_caster->ToPlayer();
- if (!player || !player->duel || target != player->duel->opponent)
- return SPELL_FAILED_NOTHING_TO_DISPEL;
+ if (unitCaster->IsInSanctuary() || target->IsInSanctuary())
+ {
+ // fix for duels
+ Player* player = unitCaster->ToPlayer();
+ if (!player || !player->duel || target != player->duel->opponent)
+ return SPELL_FAILED_NOTHING_TO_DISPEL;
+ }
}
- }
- DispelChargesList dispelList;
- target->GetDispellableAuraList(m_caster, dispelMask, dispelList);
- if (dispelList.empty())
- return SPELL_FAILED_NOTHING_TO_DISPEL;
+ DispelChargesList dispelList;
+ target->GetDispellableAuraList(unitCaster, dispelMask, dispelList);
+ if (dispelList.empty())
+ return SPELL_FAILED_NOTHING_TO_DISPEL;
+ }
}
}
@@ -5271,12 +5379,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(m_spellInfo->Effects[i].TriggerSpell);
-
if (!learn_spellproto)
return SPELL_FAILED_NOT_KNOWN;
@@ -5309,9 +5415,12 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
}
case SPELL_EFFECT_APPLY_GLYPH:
{
+ if (m_caster->GetTypeId() != TYPEID_PLAYER)
+ return SPELL_FAILED_BAD_TARGETS;
+
uint32 glyphId = m_spellInfo->Effects[i].MiscValue;
if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyphId))
- if (m_caster->HasAura(gp->SpellId))
+ if (m_caster->ToPlayer()->HasAura(gp->SpellId))
return SPELL_FAILED_UNIQUE_GLYPH;
break;
}
@@ -5325,7 +5434,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;
@@ -5335,7 +5443,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
if (!pet->GetCurrentFoodBenefitLevel(foodItem->GetTemplate()->ItemLevel))
return SPELL_FAILED_FOOD_LOWLEVEL;
- if (m_caster->IsInCombat() || pet->IsInCombat())
+ if (m_caster->ToPlayer()->IsInCombat() || pet->IsInCombat())
return SPELL_FAILED_AFFECTING_COMBAT;
break;
@@ -5352,14 +5460,18 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
}
case SPELL_EFFECT_CHARGE:
{
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return SPELL_FAILED_BAD_TARGETS;
+
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR)
{
// Warbringer - can't be handled in proc system - should be done before checkcast root check and charge effect process
- if (strict && m_caster->IsScriptOverriden(m_spellInfo, 6953))
- m_caster->RemoveMovementImpairingAuras(true);
+ if (strict && unitCaster->IsScriptOverriden(m_spellInfo, 6953))
+ unitCaster->RemoveMovementImpairingAuras(true);
}
- if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURAS) && m_caster->HasUnitState(UNIT_STATE_ROOT))
+ if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURAS) && unitCaster->HasUnitState(UNIT_STATE_ROOT))
return SPELL_FAILED_ROOTED;
if (GetSpellInfo()->NeedsExplicitUnitTarget())
@@ -5369,13 +5481,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 = Trinity::make_unique<PathGenerator>(m_caster);
+ m_preGeneratedPath = Trinity::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);
@@ -5487,27 +5599,34 @@ 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(m_spellInfo->Effects[i].MiscValueB);
if (!SummonProperties)
break;
+
switch (SummonProperties->Category)
{
case SUMMON_CATEGORY_PET:
- if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET) && m_caster->GetPetGUID())
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET) && unitCaster->GetPetGUID())
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
- // intentional missing break, check both GetPetGUID() and GetCharmGUID for SUMMON_CATEGORY_PET
+ // intentional missing break, check both GetPetGUID() and GetCharmGUID for SUMMON_CATEGORY_PET
case SUMMON_CATEGORY_PUPPET:
- if (m_caster->GetCharmGUID())
+ if (unitCaster->GetCharmGUID())
return SPELL_FAILED_ALREADY_HAVE_CHARM;
break;
}
@@ -5526,19 +5645,23 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
}
case SPELL_EFFECT_SUMMON_PET:
{
- if (m_caster->GetPetGUID()) //let warlock do a replacement summon
+ Unit* unitCaster = m_caster->ToUnit();
+ if (!unitCaster)
+ return SPELL_FAILED_BAD_TARGETS;
+
+ if (unitCaster->GetPetGUID()) //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())
+ if (unitCaster->GetCharmGUID())
return SPELL_FAILED_ALREADY_HAVE_CHARM;
break;
}
@@ -5546,7 +5669,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());
@@ -5583,22 +5707,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)
@@ -5636,9 +5757,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;
@@ -5648,7 +5773,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;
}
@@ -5685,16 +5814,20 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
case SPELL_AURA_MOD_CHARM:
case SPELL_AURA_AOE_CHARM:
{
- if (m_caster->GetCharmerGUID())
+ Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
+ if (!unitCaster)
+ return SPELL_FAILED_BAD_TARGETS;
+
+ if (unitCaster->GetCharmerGUID())
return SPELL_FAILED_CHARMED;
if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_CHARM
|| m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_POSSESS)
{
- if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET) && m_caster->GetPetGUID())
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR1_DISMISS_PET) && unitCaster->GetPetGUID())
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
- if (m_caster->GetCharmGUID())
+ if (unitCaster->GetCharmGUID())
return SPELL_FAILED_ALREADY_HAVE_CHARM;
}
@@ -5712,7 +5845,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
if (target->GetOwner() && target->GetOwner()->GetTypeId() == TYPEID_PLAYER)
return SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED;
- int32 value = CalculateDamage(i, target);
+ int32 value = CalculateDamage(i);
if (value && int32(target->getLevel()) > value)
return SPELL_FAILED_HIGHLEVEL;
}
@@ -5721,20 +5854,23 @@ 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->AreaGroupId)
+ if (unitCaster->GetTypeId() == TYPEID_PLAYER && !allowMount && !m_spellInfo->AreaGroupId)
return SPELL_FAILED_NO_MOUNTS_ALLOWED;
- if (m_caster->IsInDisallowedMountForm())
+ if (unitCaster->IsInDisallowedMountForm())
return SPELL_FAILED_NOT_SHAPESHIFT;
-
break;
}
case SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS:
@@ -5745,7 +5881,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:
@@ -5775,7 +5910,6 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
if (m_targets.GetUnitTarget()->GetPowerType() != POWER_MANA)
return SPELL_FAILED_BAD_TARGETS;
-
break;
}
default:
@@ -5793,7 +5927,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;
@@ -5810,15 +5943,18 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
// check if caster has at least 1 combo point on target for spells that require combo points
if (m_needComboPoints)
{
- if (m_spellInfo->NeedsExplicitUnitTarget())
+ if (Unit* unitCaster = m_caster->ToUnit())
{
- if (!m_caster->GetComboPoints(m_targets.GetUnitTarget()))
- return SPELL_FAILED_NO_COMBO_POINTS;
- }
- else
- {
- if (!m_caster->GetComboPoints())
- return SPELL_FAILED_NO_COMBO_POINTS;
+ if (m_spellInfo->NeedsExplicitUnitTarget())
+ {
+ if (!unitCaster->GetComboPoints(m_targets.GetUnitTarget()))
+ return SPELL_FAILED_NO_COMBO_POINTS;
+ }
+ else
+ {
+ if (!unitCaster->GetComboPoints())
+ return SPELL_FAILED_NO_COMBO_POINTS;
+ }
}
}
@@ -5828,7 +5964,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?)
@@ -5860,7 +5997,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);
@@ -5868,6 +6005,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;
@@ -5886,22 +6027,22 @@ SpellCastResult Spell::CheckCasterAuras(uint32* param1) const
// Glyph of Pain Suppression
// there is no other way to handle it
- if (m_spellInfo->Id == 33206 && !m_caster->HasAura(63248))
+ if (m_spellInfo->Id == 33206 && !unitCaster->HasAura(63248))
usableWhileStunned = false;
// Check whether the cast should be prevented by any state you might have.
SpellCastResult result = SPELL_CAST_OK;
// Get unit state
- uint32 const unitflag = m_caster->GetUInt32Value(UNIT_FIELD_FLAGS);
+ uint32 const unitflag = unitCaster->GetUInt32Value(UNIT_FIELD_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())
+ if (unitCaster->GetCharmerGUID())
{
- 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;
}
*/
@@ -5910,7 +6051,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();
@@ -5996,8 +6137,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;
@@ -6055,9 +6200,9 @@ bool Spell::CheckSpellCancelsConfuse(uint32* param1) const
return CheckSpellCancelsAuraEffect(SPELL_AURA_MOD_CONFUSE, param1);
}
-int32 Spell::CalculateDamage(uint8 i, Unit const* target) const
+int32 Spell::CalculateDamage(uint8 effIndex) const
{
- return m_caster->CalculateSpellDamage(target, m_spellInfo, i, &m_spellValue->EffectBasePoints[i]);
+ return m_caster->CalculateSpellDamage(m_spellInfo, effIndex, m_spellValue->EffectBasePoints + effIndex);
}
bool Spell::CanAutoCast(Unit* target)
@@ -6175,24 +6320,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->type & 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->type & 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);
@@ -6201,14 +6351,13 @@ std::pair<float, float> Spell::GetMinMaxRange(bool strict) const
{
rangeMod = m_caster->GetCombatReach() + (target ? target->GetCombatReach() : m_caster->GetCombatReach());
-
if (minRange > 0.0f && !(m_spellInfo->RangeEntry->type & SPELL_RANGE_RANGED))
minRange += rangeMod;
}
}
- if (target && m_caster->isMoving() && target->isMoving() && !m_caster->IsWalking() && !target->IsWalking() &&
- (m_spellInfo->RangeEntry->type & SPELL_RANGE_MELEE || target->GetTypeId() == TYPEID_PLAYER))
+ if (target && unitCaster && unitCaster->isMoving() && target->isMoving() && !unitCaster->IsWalking() && !target->IsWalking() &&
+ ((m_spellInfo->RangeEntry->type & SPELL_RANGE_MELEE) || target->GetTypeId() == TYPEID_PLAYER))
rangeMod += 8.0f / 3.0f;
}
@@ -6221,11 +6370,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;
@@ -6233,7 +6386,7 @@ SpellCastResult Spell::CheckPower() const
// health as power used - need check health amount
if (m_spellInfo->PowerType == POWER_HEALTH)
{
- if (int32(m_caster->GetHealth()) <= m_powerCost)
+ if (int32(unitCaster->GetHealth()) <= m_powerCost)
return SPELL_FAILED_CASTER_AURASTATE;
return SPELL_CAST_OK;
}
@@ -6254,7 +6407,7 @@ SpellCastResult Spell::CheckPower() const
// Check power amount
Powers powerType = Powers(m_spellInfo->PowerType);
- if (int32(m_caster->GetPower(powerType)) < m_powerCost)
+ if (int32(unitCaster->GetPower(powerType)) < m_powerCost)
return SPELL_FAILED_NO_POWER;
else
return SPELL_CAST_OK;
@@ -6363,7 +6516,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.
@@ -6449,24 +6602,24 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
case SPELL_EFFECT_CREATE_ITEM_2:
{
// 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() && m_spellInfo->Effects[i].ItemType)
+ Unit* target = m_targets.GetUnitTarget() ? m_targets.GetUnitTarget() : player;
+ if (target->GetTypeId() == TYPEID_PLAYER && !IsTriggered() && m_spellInfo->Effects[i].ItemType)
{
ItemPosCountVec dest;
-
InventoryResult msg = target->ToPlayer()->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->Effects[i].ItemType, 1);
if (msg != EQUIP_ERR_OK)
{
- ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(m_spellInfo->Effects[i].ItemType);
+ ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(m_spellInfo->Effects[i].ItemType);
/// @todo Needs review
- if (pProto && !(pProto->ItemLimitCategory))
+ if (itemTemplate && !itemTemplate->ItemLimitCategory)
{
player->SendEquipError(msg, nullptr, nullptr, m_spellInfo->Effects[i].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(m_spellInfo->Effects[i].ItemType)))
{
@@ -6474,7 +6627,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
return SPELL_FAILED_DONT_REPORT;
}
else
- player->CastSpell(m_caster, m_spellInfo->Effects[EFFECT_1].CalcValue(), false); // move this to anywhere
+ player->CastSpell(player, m_spellInfo->Effects[EFFECT_1].CalcValue(), false); // move this to anywhere
return SPELL_FAILED_DONT_REPORT;
}
}
@@ -6486,7 +6639,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
&& (m_targets.GetItemTarget()->IsWeaponVellum() || m_targets.GetItemTarget()->IsArmorVellum()))
{
// 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()->Flags & ITEM_FLAG_NO_REAGENT_COST)
@@ -6551,7 +6704,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;
@@ -6566,7 +6719,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 = m_spellInfo->Effects[i].MiscValue;
SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
@@ -6595,7 +6748,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
return SPELL_FAILED_CANT_BE_DISENCHANTED;
// prevent disenchanting in trade slot
- if (m_targets.GetItemTarget()->GetOwnerGUID() != m_caster->GetGUID())
+ if (m_targets.GetItemTarget()->GetOwnerGUID() != player->GetGUID())
return SPELL_FAILED_CANT_BE_DISENCHANTED;
ItemTemplate const* itemProto = m_targets.GetItemTarget()->GetTemplate();
@@ -6626,7 +6779,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
if (!(item->GetTemplate()->Flags & 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()->RequiredSkillRank;
@@ -6657,7 +6810,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
if (!(item->GetTemplate()->Flags & 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()->RequiredSkillRank;
@@ -6685,15 +6838,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()->SubClass)
+ switch (item->GetTemplate()->SubClass)
{
case ITEM_SUBCLASS_WEAPON_THROWN:
{
- uint32 ammo = pItem->GetEntry();
+ uint32 const ammo = item->GetEntry();
if (!player->HasItemCount(ammo))
return SPELL_FAILED_NO_AMMO;
break;
@@ -6702,11 +6855,11 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
case ITEM_SUBCLASS_WEAPON_BOW:
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
{
- uint32 ammo = player->GetUInt32Value(PLAYER_AMMO_ID);
+ uint32 const ammo = player->GetUInt32Value(PLAYER_AMMO_ID);
if (!ammo)
{
// Requires No Ammo
- if (m_caster->HasAura(46699))
+ if (player->HasAura(46699))
break; // skip other checks
return SPELL_FAILED_NO_AMMO;
@@ -6720,7 +6873,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
return SPELL_FAILED_NO_AMMO;
// check ammo ws. weapon compatibility
- switch (pItem->GetTemplate()->SubClass)
+ switch (item->GetTemplate()->SubClass)
{
case ITEM_SUBCLASS_WEAPON_BOW:
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
@@ -6773,9 +6926,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())
@@ -6808,24 +6961,24 @@ 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
+ // spells not losing casting time
+ if (!(m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_PUSH_BACK))
return;
- // spells not loosing casting time (slam, dynamites, bombs..)
- //if (!(m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_DAMAGE))
- // return;
+ 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->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
- delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
+ if (Player* player = unitCaster->GetSpellModOwner())
+ player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
+ delayReduce += unitCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
if (delayReduce >= 100)
return;
@@ -6839,21 +6992,27 @@ 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);
-
WorldPacket data(SMSG_SPELL_DELAYED, 8+4);
- data << m_caster->GetPackGUID();
+ data << unitCaster->GetPackGUID();
data << uint32(delaytime);
- m_caster->SendMessageToSet(&data, true);
+ unitCaster->SendMessageToSet(&data, 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 (m_spellState != SPELL_STATE_CASTING)
return;
- if (isDelayableNoMore()) // Spells may only be delayed twice
+ // spells not losing channeling time
+ if (!(m_spellInfo->ChannelInterruptFlags & CHANNEL_FLAG_DELAY))
+ return;
+
+ if (IsDelayableNoMore()) // Spells may only be delayed twice
return;
//check pushback reduce
@@ -6861,9 +7020,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->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
- delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
+ if (Player* player = unitCaster->GetSpellModOwner())
+ player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
+ delayReduce += unitCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
if (delayReduce >= 100)
return;
@@ -6877,15 +7038,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);
@@ -6894,7 +7053,7 @@ void Spell::DelayedChannel()
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);
@@ -6969,7 +7128,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* lo
return false;
if (target->GetCharmerGUID())
return false;
- if (int32 value = CalculateDamage(eff, target))
+ if (int32 value = CalculateDamage(eff))
if ((int32)target->getLevel() > value)
return false;
break;
@@ -7247,12 +7406,18 @@ void Spell::HandleLaunchPhase()
HandleEffects(nullptr, nullptr, nullptr, i, SPELL_EFFECT_HANDLE_LAUNCH);
}
- bool usesAmmo = m_spellInfo->HasAttribute(SPELL_ATTR0_CU_DIRECT_DAMAGE);
- if (m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_CONSUME_NO_AMMO, m_spellInfo))
- usesAmmo = false;
+ bool usesAmmo;
+ if (Player* player = m_caster->ToPlayer())
+ {
+ usesAmmo = m_spellInfo->HasAttribute(SPELL_ATTR0_CU_DIRECT_DAMAGE);
+ if (player->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_CONSUME_NO_AMMO, m_spellInfo))
+ usesAmmo = false;
- // do not consume ammo anymore for Hunter's volley spell
- if (IsTriggered() && m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && m_spellInfo->IsTargetingArea())
+ // do not consume ammo anymore for Hunter's volley spell
+ if (IsTriggered() && m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && m_spellInfo->IsTargetingArea())
+ usesAmmo = false;
+ }
+ else
usesAmmo = false;
PrepareTargetProcessing();
@@ -7308,29 +7473,30 @@ void Spell::DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, uin
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, effIndex, SPELL_EFFECT_HANDLE_LAUNCH_TARGET);
- if (m_damage > 0)
+ if (m_originalCaster && m_damage > 0)
{
if (m_spellInfo->Effects[effIndex].IsTargetingArea() || m_spellInfo->Effects[effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[effIndex].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
uint32 targetAmount = m_UniqueTargetInfo.size();
@@ -7352,9 +7518,14 @@ void Spell::DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, uin
targetInfo.Healing += m_healing;
float critChance = m_spellValue->CriticalChance;
- if (!critChance)
- critChance = m_caster->SpellCritChanceDone(m_spellInfo, m_spellSchoolMask, m_attackType);
- targetInfo.IsCrit = roll_chance_f(unit->SpellCritChanceTaken(m_caster, m_spellInfo, m_spellSchoolMask, critChance, m_attackType));
+ if (m_originalCaster)
+ {
+ if (!critChance)
+ critChance = m_originalCaster->SpellCritChanceDone(m_spellInfo, m_spellSchoolMask, m_attackType);
+ critChance = unit->SpellCritChanceTaken(m_originalCaster, m_spellInfo, m_spellSchoolMask, critChance, m_attackType);
+ }
+
+ targetInfo.IsCrit = roll_chance_f(critChance);
}
SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue)
@@ -7753,10 +7924,14 @@ 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->IsAffectedOnSpell(m_spellInfo))
@@ -7770,7 +7945,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, auraSpellInfo, auraSpellIdx, &auraBaseAmount);
+ int32 chance = unitCaster->CalculateSpellDamage(auraSpellInfo, auraSpellIdx, &auraBaseAmount);
chance *= aurEff->GetBase()->GetStackAmount();
// build trigger and add to the list
@@ -7786,23 +7961,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)
+ 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)
return;
if (m_caster->GetTypeId() == TYPEID_PLAYER)
@@ -7823,47 +8005,44 @@ void Spell::TriggerGlobalCooldown()
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) : _caster(caster), _referer(referer), _spellInfo(spellInfo),
- _targetSelectionType(selectionType), _condList(condList)
+WorldObjectSpellTargetCheck::WorldObjectSpellTargetCheck(WorldObject* caster, WorldObject* referer, SpellInfo const* spellInfo,
+ SpellTargetCheckTypes selectionType, ConditionContainer const* condList) : _caster(caster), _referer(referer), _spellInfo(spellInfo),
+ _targetSelectionType(selectionType), _condSrcInfo(nullptr), _condList(condList)
{
if (condList)
- _condSrcInfo = new ConditionSourceInfo(nullptr, caster);
- else
- _condSrcInfo = nullptr;
+ _condSrcInfo = Trinity::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())
{
@@ -7874,6 +8053,7 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target)
return false;
}
+ Unit* refUnit = _referer->ToUnit();
if (unitTarget)
{
// do only faction checks here
@@ -7882,7 +8062,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:
@@ -7892,23 +8072,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;
// nobreak;
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;
default:
@@ -7935,8 +8121,8 @@ bool WorldObjectSpellTargetCheck::operator()(WorldObject* target)
return sConditionMgr->IsObjectMeetToConditions(*_condSrcInfo, *_condList);
}
-WorldObjectSpellNearbyTargetCheck::WorldObjectSpellNearbyTargetCheck(float range, Unit* caster, SpellInfo const* spellInfo,
- SpellTargetCheckTypes selectionType, ConditionContainer* condList)
+WorldObjectSpellNearbyTargetCheck::WorldObjectSpellNearbyTargetCheck(float range, WorldObject* caster, SpellInfo const* spellInfo,
+ SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
: WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList), _range(range), _position(caster) { }
bool WorldObjectSpellNearbyTargetCheck::operator()(WorldObject* target)
@@ -7950,11 +8136,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)
+WorldObjectSpellAreaTargetCheck::WorldObjectSpellAreaTargetCheck(float range, Position const* position, WorldObject* caster,
+ WorldObject* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
: WorldObjectSpellTargetCheck(caster, referer, spellInfo, selectionType, condList), _range(range), _position(position) { }
-bool WorldObjectSpellAreaTargetCheck::operator()(WorldObject* target)
+bool WorldObjectSpellAreaTargetCheck::operator()(WorldObject* target) const
{
if (target->ToGameObject())
{
@@ -7973,11 +8159,11 @@ bool WorldObjectSpellAreaTargetCheck::operator()(WorldObject* target)
return WorldObjectSpellTargetCheck::operator ()(target);
}
-WorldObjectSpellConeTargetCheck::WorldObjectSpellConeTargetCheck(float coneAngle, float range, Unit* caster,
- SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer* condList)
+WorldObjectSpellConeTargetCheck::WorldObjectSpellConeTargetCheck(float coneAngle, float range, WorldObject* caster,
+ SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
: WorldObjectSpellAreaTargetCheck(range, caster, caster, caster, spellInfo, selectionType, condList), _coneAngle(coneAngle) { }
-bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target)
+bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target) const
{
if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_BACK))
{
@@ -7997,10 +8183,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)
+WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Position const* position, WorldObject* caster, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
: WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList), _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))