Core/Spells: Store explicit unit, corpse and GO targets in one variable, because both client and server can't handle more than one explicit object target; Add spell explicit target validation.
This commit is contained in:
@@ -328,6 +328,9 @@ class Object
|
||||
const Unit* ToUnit() const {if (GetTypeId() == TYPEID_UNIT || GetTypeId() == TYPEID_PLAYER) return (const Unit*)((Unit*)this); else return NULL; }
|
||||
GameObject* ToGameObject(){ if (GetTypeId() == TYPEID_GAMEOBJECT) return reinterpret_cast<GameObject*>(this); else return NULL; }
|
||||
const GameObject* ToGameObject() const {if (GetTypeId() == TYPEID_GAMEOBJECT) return (const GameObject*)((GameObject*)this); else return NULL; }
|
||||
|
||||
Corpse* ToCorpse(){ if (GetTypeId() == TYPEID_CORPSE) return reinterpret_cast<Corpse*>(this); else return NULL; }
|
||||
const Corpse* ToCorpse() const {if (GetTypeId() == TYPEID_CORPSE) return (const Corpse*)((Corpse*)this); else return NULL; }
|
||||
protected:
|
||||
|
||||
Object ();
|
||||
|
||||
+118
-160
@@ -58,13 +58,10 @@ extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS];
|
||||
|
||||
SpellCastTargets::SpellCastTargets() : m_elevation(0), m_speed(0)
|
||||
{
|
||||
m_unitTarget = NULL;
|
||||
m_objectTarget = NULL;
|
||||
m_itemTarget = NULL;
|
||||
m_GOTarget = NULL;
|
||||
|
||||
m_unitTargetGUID = 0;
|
||||
m_GOTargetGUID = 0;
|
||||
m_CorpseTargetGUID = 0;
|
||||
m_objectTargetGUID = 0;
|
||||
m_itemTargetGUID = 0;
|
||||
m_itemTargetEntry = 0;
|
||||
|
||||
@@ -89,18 +86,12 @@ void SpellCastTargets::Read(ByteBuffer& data, Unit* caster)
|
||||
if (m_targetMask == TARGET_FLAG_NONE)
|
||||
return;
|
||||
|
||||
if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_UNIT_MINIPET))
|
||||
data.readPackGUID(m_unitTargetGUID);
|
||||
|
||||
if (m_targetMask & (TARGET_FLAG_GAMEOBJECT))
|
||||
data.readPackGUID(m_GOTargetGUID);
|
||||
if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_UNIT_MINIPET | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_CORPSE_ALLY))
|
||||
data.readPackGUID(m_objectTargetGUID);
|
||||
|
||||
if (m_targetMask & (TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM))
|
||||
data.readPackGUID(m_itemTargetGUID);
|
||||
|
||||
if (m_targetMask & (TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_CORPSE_ALLY))
|
||||
data.readPackGUID(m_CorpseTargetGUID);
|
||||
|
||||
if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
|
||||
{
|
||||
data.readPackGUID(m_srcTransGUID);
|
||||
@@ -146,26 +137,7 @@ void SpellCastTargets::Write(ByteBuffer& data)
|
||||
data << uint32(m_targetMask);
|
||||
|
||||
if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_MINIPET))
|
||||
{
|
||||
if (m_targetMask & TARGET_FLAG_UNIT)
|
||||
{
|
||||
if (m_unitTarget)
|
||||
data.append(m_unitTarget->GetPackGUID());
|
||||
else
|
||||
data << uint8(0);
|
||||
}
|
||||
else if (m_targetMask & TARGET_FLAG_GAMEOBJECT)
|
||||
{
|
||||
if (m_GOTarget)
|
||||
data.append(m_GOTarget->GetPackGUID());
|
||||
else
|
||||
data << uint8(0);
|
||||
}
|
||||
else if (m_targetMask & (TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_CORPSE_ENEMY))
|
||||
data.appendPackGUID(m_CorpseTargetGUID);
|
||||
else
|
||||
data << uint8(0);
|
||||
}
|
||||
data.appendPackGUID(m_objectTargetGUID);
|
||||
|
||||
if (m_targetMask & (TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM))
|
||||
{
|
||||
@@ -197,44 +169,101 @@ void SpellCastTargets::Write(ByteBuffer& data)
|
||||
data << m_strTarget;
|
||||
}
|
||||
|
||||
uint64 SpellCastTargets::GetUnitTargetGUID() const
|
||||
{
|
||||
switch (GUID_HIPART(m_objectTargetGUID))
|
||||
{
|
||||
case HIGHGUID_PLAYER:
|
||||
case HIGHGUID_VEHICLE:
|
||||
case HIGHGUID_UNIT:
|
||||
case HIGHGUID_PET:
|
||||
return m_objectTargetGUID;
|
||||
default:
|
||||
return 0LL;
|
||||
}
|
||||
}
|
||||
|
||||
Unit* SpellCastTargets::GetUnitTarget() const
|
||||
{
|
||||
if (m_objectTarget)
|
||||
return m_objectTarget->ToUnit();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SpellCastTargets::SetUnitTarget(Unit* target)
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
m_unitTarget = target;
|
||||
m_unitTargetGUID = target->GetGUID();
|
||||
m_objectTarget = target;
|
||||
m_objectTargetGUID = target->GetGUID();
|
||||
m_targetMask |= TARGET_FLAG_UNIT;
|
||||
}
|
||||
|
||||
void SpellCastTargets::RemoveUnitTarget()
|
||||
uint64 SpellCastTargets::GetGOTargetGUID() const
|
||||
{
|
||||
m_unitTarget = NULL;
|
||||
m_unitTargetGUID = 0LL;
|
||||
m_targetMask &= ~(TARGET_FLAG_UNIT | TARGET_FLAG_UNIT_MINIPET);
|
||||
switch (GUID_HIPART(m_objectTargetGUID))
|
||||
{
|
||||
case HIGHGUID_TRANSPORT:
|
||||
case HIGHGUID_MO_TRANSPORT:
|
||||
case HIGHGUID_GAMEOBJECT:
|
||||
return m_objectTargetGUID;
|
||||
default:
|
||||
return 0LL;
|
||||
}
|
||||
}
|
||||
|
||||
GameObject* SpellCastTargets::GetGOTarget() const
|
||||
{
|
||||
if (m_objectTarget)
|
||||
return m_objectTarget->ToGameObject();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void SpellCastTargets::SetGOTarget(GameObject* target)
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
m_GOTarget = target;
|
||||
m_GOTargetGUID = target->GetGUID();
|
||||
m_objectTarget = target;
|
||||
m_objectTargetGUID = target->GetGUID();
|
||||
m_targetMask |= TARGET_FLAG_GAMEOBJECT;
|
||||
}
|
||||
|
||||
void SpellCastTargets::RemoveGOTarget()
|
||||
uint64 SpellCastTargets::GetCorpseTargetGUID() const
|
||||
{
|
||||
m_GOTarget = NULL;
|
||||
m_GOTargetGUID = 0LL;
|
||||
m_targetMask &= ~(TARGET_FLAG_GAMEOBJECT);
|
||||
switch (GUID_HIPART(m_objectTargetGUID))
|
||||
{
|
||||
case HIGHGUID_CORPSE:
|
||||
return m_objectTargetGUID;
|
||||
default:
|
||||
return 0LL;
|
||||
}
|
||||
}
|
||||
|
||||
void SpellCastTargets::RemoveCorpseTarget()
|
||||
Corpse* SpellCastTargets::GetCorpseTarget() const
|
||||
{
|
||||
m_CorpseTargetGUID = 0;
|
||||
m_targetMask &= ~(TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_CORPSE_ALLY);
|
||||
if (m_objectTarget)
|
||||
return m_objectTarget->ToCorpse();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WorldObject* SpellCastTargets::GetObjectTarget() const
|
||||
{
|
||||
return m_objectTarget;
|
||||
}
|
||||
|
||||
uint64 SpellCastTargets::GetObjectTargetGUID() const
|
||||
{
|
||||
return m_objectTargetGUID;
|
||||
}
|
||||
|
||||
void SpellCastTargets::RemoveObjectTarget()
|
||||
{
|
||||
m_objectTarget = NULL;
|
||||
m_objectTargetGUID = 0LL;
|
||||
m_targetMask &= ~(TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_GAMEOBJECT_MASK);
|
||||
}
|
||||
|
||||
void SpellCastTargets::SetItemTarget(Item* item)
|
||||
@@ -370,8 +399,7 @@ void SpellCastTargets::RemoveDst()
|
||||
|
||||
void SpellCastTargets::Update(Unit* caster)
|
||||
{
|
||||
m_GOTarget = m_GOTargetGUID ? caster->GetMap()->GetGameObject(m_GOTargetGUID) : NULL;
|
||||
m_unitTarget = m_unitTargetGUID ? (m_unitTargetGUID == caster->GetGUID() ? caster : ObjectAccessor::GetUnit(*caster, m_unitTargetGUID)) : NULL;
|
||||
m_objectTarget = m_objectTargetGUID ? ((m_objectTargetGUID == caster->GetGUID()) ? caster : ObjectAccessor::GetWorldObject(*caster, m_objectTargetGUID)) : NULL;
|
||||
|
||||
m_itemTarget = NULL;
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER)
|
||||
@@ -411,28 +439,21 @@ void SpellCastTargets::Update(Unit* caster)
|
||||
void SpellCastTargets::OutDebug() const
|
||||
{
|
||||
if (!m_targetMask)
|
||||
sLog->outString("TARGET_FLAG_NONE");
|
||||
sLog->outString("No targets");
|
||||
|
||||
if (m_targetMask & TARGET_FLAG_UNIT)
|
||||
sLog->outString("TARGET_FLAG_UNIT: " UI64FMTD, m_unitTargetGUID);
|
||||
if (m_targetMask & TARGET_FLAG_UNIT_MINIPET)
|
||||
sLog->outString("TARGET_FLAG_UNIT_MINIPET: " UI64FMTD, m_unitTargetGUID);
|
||||
if (m_targetMask & TARGET_FLAG_GAMEOBJECT)
|
||||
sLog->outString("TARGET_FLAG_GAMEOBJECT: " UI64FMTD, m_GOTargetGUID);
|
||||
if (m_targetMask & TARGET_FLAG_CORPSE_ENEMY)
|
||||
sLog->outString("TARGET_FLAG_CORPSE_ENEMY: " UI64FMTD, m_CorpseTargetGUID);
|
||||
if (m_targetMask & TARGET_FLAG_CORPSE_ALLY)
|
||||
sLog->outString("TARGET_FLAG_CORPSE_ALLY: " UI64FMTD, m_CorpseTargetGUID);
|
||||
sLog->outString("target mask: %u", m_targetMask);
|
||||
if (m_targetMask & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_GAMEOBJECT_MASK))
|
||||
sLog->outString("Object target: " UI64FMTD, m_objectTargetGUID);
|
||||
if (m_targetMask & TARGET_FLAG_ITEM)
|
||||
sLog->outString("TARGET_FLAG_ITEM: " UI64FMTD, m_itemTargetGUID);
|
||||
sLog->outString("Item target: " UI64FMTD, m_itemTargetGUID);
|
||||
if (m_targetMask & TARGET_FLAG_TRADE_ITEM)
|
||||
sLog->outString("TARGET_FLAG_TRADE_ITEM: " UI64FMTD, m_itemTargetGUID);
|
||||
sLog->outString("Trade item target: " UI64FMTD, m_itemTargetGUID);
|
||||
if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
|
||||
sLog->outString("TARGET_FLAG_SOURCE_LOCATION: transport guid:" UI64FMTD " trans offset: %s position: %s", m_srcTransGUID, m_srcTransOffset.ToString().c_str(), m_srcPos.ToString().c_str());
|
||||
sLog->outString("Source location: transport guid:" UI64FMTD " trans offset: %s position: %s", m_srcTransGUID, m_srcTransOffset.ToString().c_str(), m_srcPos.ToString().c_str());
|
||||
if (m_targetMask & TARGET_FLAG_DEST_LOCATION)
|
||||
sLog->outString("TARGET_FLAG_DEST_LOCATION: transport guid:" UI64FMTD " trans offset: %s position: %s", m_dstTransGUID, m_dstTransOffset.ToString().c_str(), m_dstPos.ToString().c_str());
|
||||
sLog->outString("Destination location: transport guid:" UI64FMTD " trans offset: %s position: %s", m_dstTransGUID, m_dstTransOffset.ToString().c_str(), m_dstPos.ToString().c_str());
|
||||
if (m_targetMask & TARGET_FLAG_STRING)
|
||||
sLog->outString("TARGET_FLAG_STRING: %s", m_strTarget.c_str());
|
||||
sLog->outString("String: %s", m_strTarget.c_str());
|
||||
sLog->outString("speed: %f", m_speed);
|
||||
sLog->outString("elevation: %f", m_elevation);
|
||||
}
|
||||
@@ -608,19 +629,27 @@ void Spell::InitExplicitTargets(SpellCastTargets const& targets)
|
||||
// this also makes sure that we correctly send explicit targets to client (removes redundant data)
|
||||
uint32 neededTargets = m_spellInfo->GetExplicitTargetMask();
|
||||
|
||||
// check if spell needs unit target (allow spells with corpse flag to accept unit targets - unit target is sent by client when corpse not yet released)
|
||||
if (neededTargets & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK))
|
||||
if (WorldObject* target = m_targets.GetObjectTarget())
|
||||
{
|
||||
Unit* target = targets.GetUnitTarget();
|
||||
|
||||
if (!target)
|
||||
// check if object target is valid with needed target flags
|
||||
// for unit case allow corpse target mask because player with not released corpse is a unit target
|
||||
if ((target->ToUnit() && !(neededTargets & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK)))
|
||||
|| (target->ToGameObject() && !(neededTargets & TARGET_FLAG_GAMEOBJECT_MASK))
|
||||
|| (target->ToCorpse() && !(neededTargets & TARGET_FLAG_CORPSE_MASK)))
|
||||
m_targets.RemoveObjectTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to select correct unit target if not provided by client or by serverside cast
|
||||
if (neededTargets & (TARGET_FLAG_UNIT_MASK))
|
||||
{
|
||||
Unit* target = NULL;
|
||||
// try to use player selection as a target
|
||||
if (Player* playerCaster = m_caster->ToPlayer())
|
||||
{
|
||||
// selection has to be found and to be valid target for the spell
|
||||
if (Unit* selectedUnit = ObjectAccessor::GetUnit(*m_caster, playerCaster->GetSelection()))
|
||||
if (IsValidSingleTargetSpell(selectedUnit))
|
||||
if (m_spellInfo->CheckExplicitTarget(m_caster, selectedUnit) == SPELL_CAST_OK)
|
||||
target = selectedUnit;
|
||||
}
|
||||
// try to use attacked unit as a target
|
||||
@@ -629,17 +658,10 @@ void Spell::InitExplicitTargets(SpellCastTargets const& targets)
|
||||
// didn't find anything - let's use self as target
|
||||
if (!target && neededTargets & (TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY | TARGET_FLAG_UNIT_ALLY | TARGET_FLAG_UNIT))
|
||||
target = m_caster;
|
||||
|
||||
m_targets.SetUnitTarget(target);
|
||||
}
|
||||
m_targets.SetUnitTarget(target);
|
||||
}
|
||||
else
|
||||
m_targets.RemoveUnitTarget();
|
||||
|
||||
if (!(neededTargets & TARGET_FLAG_GAMEOBJECT_MASK))
|
||||
m_targets.RemoveGOTarget();
|
||||
|
||||
if (!(neededTargets & TARGET_FLAG_CORPSE_MASK))
|
||||
m_targets.RemoveCorpseTarget();
|
||||
|
||||
// check if spell needs dst target
|
||||
if (neededTargets & TARGET_FLAG_DEST_LOCATION)
|
||||
@@ -746,15 +768,15 @@ void Spell::SelectSpellTargets()
|
||||
AddUnitTarget(target, i, false);
|
||||
}
|
||||
break;
|
||||
case SPELL_EFFECT_SKIN_PLAYER_CORPSE:
|
||||
case SPELL_EFFECT_RESURRECT_NEW:
|
||||
if (m_targets.GetUnitTarget())
|
||||
AddUnitTarget(m_targets.GetUnitTarget(), i, false);
|
||||
if (m_targets.GetCorpseTargetGUID())
|
||||
if (WorldObject* target = m_targets.GetObjectTarget())
|
||||
{
|
||||
Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster, m_targets.GetCorpseTargetGUID());
|
||||
if (corpse)
|
||||
if (Unit* unitTarget = target->ToUnit())
|
||||
AddUnitTarget(unitTarget, i, false);
|
||||
else if (Corpse* corpseTarget = target->ToCorpse())
|
||||
{
|
||||
Player* owner = ObjectAccessor::FindPlayer(corpse->GetOwnerGUID());
|
||||
Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID());
|
||||
if (owner)
|
||||
AddUnitTarget(owner, i, false);
|
||||
}
|
||||
@@ -786,20 +808,6 @@ void Spell::SelectSpellTargets()
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SPELL_EFFECT_SKIN_PLAYER_CORPSE:
|
||||
if (m_targets.GetUnitTarget())
|
||||
AddUnitTarget(m_targets.GetUnitTarget(), i, false);
|
||||
else if (m_targets.GetCorpseTargetGUID())
|
||||
{
|
||||
Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster, m_targets.GetCorpseTargetGUID());
|
||||
if (corpse)
|
||||
{
|
||||
Player* owner = ObjectAccessor::FindPlayer(corpse->GetOwnerGUID());
|
||||
if (owner)
|
||||
AddUnitTarget(owner, i, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
AddUnitTarget(m_caster, i, false);
|
||||
break;
|
||||
@@ -2095,12 +2103,10 @@ void Spell::SelectEffectTargets(uint32 i, SpellImplicitTargetInfo const& cur)
|
||||
case TARGET_UNIT_TARGET_RAID:
|
||||
case TARGET_UNIT_TARGET_PARTY:
|
||||
case TARGET_UNIT_TARGET_MINIPET:
|
||||
if (IsValidSingleTargetSpell(target))
|
||||
AddUnitTarget(target, i, false);
|
||||
AddUnitTarget(target, i, false);
|
||||
break;
|
||||
case TARGET_UNIT_TARGET_PASSENGER:
|
||||
if (target->IsOnVehicle(m_caster))
|
||||
AddUnitTarget(target, i, false);
|
||||
AddUnitTarget(target, i, false);
|
||||
break;
|
||||
case TARGET_UNIT_LASTTARGET_AREA_PARTY:
|
||||
case TARGET_UNIT_TARGET_AREA_RAID_CLASS:
|
||||
@@ -4166,13 +4172,7 @@ void Spell::SendChannelUpdate(uint32 time)
|
||||
|
||||
void Spell::SendChannelStart(uint32 duration)
|
||||
{
|
||||
uint64 channelTarget = 0;
|
||||
if (m_targets.GetUnitTargetGUID())
|
||||
channelTarget = m_targets.GetUnitTargetGUID();
|
||||
else if (m_targets.GetGOTargetGUID())
|
||||
channelTarget = m_targets.GetGOTargetGUID();
|
||||
else if (m_targets.GetCorpseTargetGUID())
|
||||
channelTarget = m_targets.GetCorpseTargetGUID();
|
||||
uint64 channelTarget = m_targets.GetObjectTargetGUID();
|
||||
|
||||
WorldPacket data(MSG_CHANNEL_START, (8+4+4));
|
||||
data.append(m_caster->GetPackGUID());
|
||||
@@ -4708,6 +4708,12 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
return SPELL_FAILED_DONT_REPORT;
|
||||
}
|
||||
|
||||
{
|
||||
SpellCastResult castResult = m_spellInfo->CheckExplicitTarget(m_caster, m_targets.GetObjectTarget());
|
||||
if (castResult != SPELL_CAST_OK)
|
||||
return castResult;
|
||||
}
|
||||
|
||||
if (Unit* target = m_targets.GetUnitTarget())
|
||||
{
|
||||
SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, false);
|
||||
@@ -5447,15 +5453,6 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
|
||||
}
|
||||
}
|
||||
|
||||
Unit* _target = m_targets.GetUnitTarget();
|
||||
|
||||
// for target dead/target not valid
|
||||
if (_target)
|
||||
{
|
||||
if (!IsValidSingleTargetSpell(_target))
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
|
||||
// cooldown
|
||||
if (Creature const* creatureCaster = m_caster->ToCreature())
|
||||
if (creatureCaster->HasSpellCooldown(m_spellInfo->Id))
|
||||
@@ -6564,45 +6561,6 @@ bool SpellEvent::IsDeletable() const
|
||||
return m_Spell->IsDeletable();
|
||||
}
|
||||
|
||||
bool Spell::IsValidSingleTargetEffect(Unit const* target, Targets type) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case TARGET_UNIT_TARGET_ENEMY:
|
||||
return !m_caster->IsFriendlyTo(target);
|
||||
case TARGET_UNIT_TARGET_ALLY:
|
||||
case TARGET_UNIT_LASTTARGET_AREA_PARTY:
|
||||
return m_caster->IsFriendlyTo(target);
|
||||
case TARGET_UNIT_TARGET_PARTY:
|
||||
return m_caster != target && m_caster->IsInPartyWith(target);
|
||||
case TARGET_UNIT_TARGET_RAID:
|
||||
return m_caster->IsInRaidWith(target);
|
||||
case TARGET_UNIT_TARGET_MINIPET:
|
||||
return target->GetGUID() == m_caster->GetCritterGUID();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Spell::IsValidSingleTargetSpell(Unit const* target) const
|
||||
{
|
||||
if (target->GetMapId() == MAPID_INVALID)
|
||||
{
|
||||
sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell::IsValidSingleTargetSpell - a spell was cast on '%s' (GUIDLow: %u), but they have an invalid map id!", target->GetName(), target->GetGUIDLow());
|
||||
return false;
|
||||
}
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (!IsValidSingleTargetEffect(target, m_spellInfo->Effects[i].TargetA.GetTarget()))
|
||||
return false;
|
||||
// Need to check B?
|
||||
//if (!IsValidSingleTargetEffect(m_spellInfo->Effects[i].TargetB, target)
|
||||
// return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const
|
||||
{
|
||||
if (target->isAlive())
|
||||
|
||||
@@ -104,18 +104,20 @@ class SpellCastTargets
|
||||
uint32 GetTargetMask() const { return m_targetMask; }
|
||||
void SetTargetMask(uint32 newMask) { m_targetMask = newMask; }
|
||||
|
||||
uint64 GetUnitTargetGUID() const { return m_unitTargetGUID; }
|
||||
Unit* GetUnitTarget() const { return m_unitTarget; }
|
||||
uint64 GetUnitTargetGUID() const;
|
||||
Unit* GetUnitTarget() const;
|
||||
void SetUnitTarget(Unit* target);
|
||||
void RemoveUnitTarget();
|
||||
|
||||
uint64 GetGOTargetGUID() const { return m_GOTargetGUID; }
|
||||
GameObject* GetGOTarget() const { return m_GOTarget; }
|
||||
uint64 GetGOTargetGUID() const;
|
||||
GameObject* GetGOTarget() const;
|
||||
void SetGOTarget(GameObject* target);
|
||||
void RemoveGOTarget();
|
||||
|
||||
uint64 GetCorpseTargetGUID() const { return m_CorpseTargetGUID; }
|
||||
void RemoveCorpseTarget();
|
||||
uint64 GetCorpseTargetGUID() const;
|
||||
Corpse* GetCorpseTarget() const;
|
||||
|
||||
WorldObject* GetObjectTarget() const;
|
||||
uint64 GetObjectTargetGUID() const;
|
||||
void RemoveObjectTarget();
|
||||
|
||||
uint64 GetItemTargetGUID() const { return m_itemTargetGUID; }
|
||||
Item* GetItemTarget() const { return m_itemTarget; }
|
||||
@@ -139,7 +141,6 @@ class SpellCastTargets
|
||||
void ModDst(Position const& pos);
|
||||
void RemoveDst();
|
||||
|
||||
bool IsEmpty() const { return m_GOTargetGUID == 0 && m_unitTargetGUID == 0 && m_itemTarget == 0 && m_CorpseTargetGUID == 0; }
|
||||
bool HasSrc() const { return GetTargetMask() & TARGET_FLAG_SOURCE_LOCATION; }
|
||||
bool HasDst() const { return GetTargetMask() & TARGET_FLAG_DEST_LOCATION; }
|
||||
bool HasTraj() const { return m_speed != 0; }
|
||||
@@ -159,15 +160,12 @@ class SpellCastTargets
|
||||
private:
|
||||
uint32 m_targetMask;
|
||||
|
||||
// objects (can be used at spell creating and after Update at casting
|
||||
Unit* m_unitTarget;
|
||||
GameObject* m_GOTarget;
|
||||
// objects (can be used at spell creating and after Update at casting)
|
||||
WorldObject* m_objectTarget;
|
||||
Item* m_itemTarget;
|
||||
|
||||
// object GUID/etc, can be used always
|
||||
uint64 m_unitTargetGUID;
|
||||
uint64 m_GOTargetGUID;
|
||||
uint64 m_CorpseTargetGUID;
|
||||
uint64 m_objectTargetGUID;
|
||||
uint64 m_itemTargetGUID;
|
||||
uint32 m_itemTargetEntry;
|
||||
|
||||
@@ -602,8 +600,6 @@ class Spell
|
||||
void SearchGOAreaTarget(std::list<GameObject*> &gobjectList, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry = 0);
|
||||
void SearchChainTarget(std::list<Unit*> &unitList, float radius, uint32 unMaxTargets, SpellTargets TargetType);
|
||||
WorldObject* SearchNearbyTarget(float range, SpellTargets TargetType, SpellEffIndex effIndex);
|
||||
bool IsValidSingleTargetEffect(Unit const* target, Targets type) const;
|
||||
bool IsValidSingleTargetSpell(Unit const* target) const;
|
||||
bool IsValidDeadOrAliveTarget(Unit const* target) const;
|
||||
void CalculateDamageDoneForAllTargets();
|
||||
int32 CalculateDamageDone(Unit *unit, const uint32 effectMask, float *multiplier);
|
||||
|
||||
@@ -1705,6 +1705,44 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, Unit const* target, b
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
SpellCastResult SpellInfo::CheckExplicitTarget(Unit const* caster, WorldObject const* target) const
|
||||
{
|
||||
uint32 neededTargets = GetExplicitTargetMask();
|
||||
if (!target)
|
||||
{
|
||||
if (neededTargets & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_GAMEOBJECT_MASK | TARGET_FLAG_CORPSE_MASK))
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
if (Unit const* unitTarget = target->ToUnit())
|
||||
{
|
||||
if (neededTargets & (TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT_ALLY | TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY | TARGET_FLAG_UNIT_MINIPET | TARGET_FLAG_UNIT_PASSENGER))
|
||||
{
|
||||
if (neededTargets & TARGET_FLAG_UNIT_ENEMY)
|
||||
if (!caster->IsFriendlyTo(unitTarget))
|
||||
return SPELL_CAST_OK;
|
||||
if (neededTargets & TARGET_FLAG_UNIT_ALLY)
|
||||
if (caster->IsFriendlyTo(unitTarget))
|
||||
return SPELL_CAST_OK;
|
||||
if (neededTargets & TARGET_FLAG_UNIT_PARTY)
|
||||
if (caster->IsInPartyWith(unitTarget))
|
||||
return SPELL_CAST_OK;
|
||||
if (neededTargets & TARGET_FLAG_UNIT_RAID)
|
||||
if (caster->IsInRaidWith(unitTarget))
|
||||
return SPELL_CAST_OK;
|
||||
if (neededTargets & TARGET_FLAG_UNIT_MINIPET)
|
||||
if (unitTarget->GetGUID() == caster->GetCritterGUID())
|
||||
return SPELL_CAST_OK;
|
||||
if (neededTargets & TARGET_FLAG_UNIT_PASSENGER)
|
||||
if (unitTarget->IsOnVehicle(caster))
|
||||
return SPELL_CAST_OK;
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
}
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
bool SpellInfo::CheckTargetCreatureType(Unit const* target) const
|
||||
{
|
||||
// Curse of Doom & Exorcism: not find another way to fix spell target check :/
|
||||
|
||||
@@ -441,6 +441,7 @@ public:
|
||||
SpellCastResult CheckShapeshift(uint32 form) const;
|
||||
SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL) const;
|
||||
SpellCastResult CheckTarget(Unit const* caster, Unit const* target, bool implicit = true) const;
|
||||
SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target) const;
|
||||
bool CheckTargetCreatureType(Unit const* target) const;
|
||||
|
||||
SpellSchoolMask GetSchoolMask() const;
|
||||
|
||||
Reference in New Issue
Block a user