Core/Spells: Implement recently discovered target check attributes and move most of target checks to SpellInfo::CheckTarget function.
This commit is contained in:
@@ -996,12 +996,12 @@ void Creature::SetLootRecipient(Unit *unit)
|
||||
}
|
||||
|
||||
// return true if this creature is tapped by the player or by a member of his group.
|
||||
bool Creature::isTappedBy(Player* player) const
|
||||
bool Creature::isTappedBy(Player const* player) const
|
||||
{
|
||||
if (player->GetGUID() == m_lootRecipient)
|
||||
return true;
|
||||
|
||||
Group* playerGroup = player->GetGroup();
|
||||
Group const* playerGroup = player->GetGroup();
|
||||
if (!playerGroup || playerGroup != GetLootRecipientGroup()) // if we dont have a group we arent the recipient
|
||||
return false; // if creature doesnt have group bound it means it was solo killed by someone else
|
||||
|
||||
@@ -1947,7 +1947,7 @@ bool Creature::_IsTargetAcceptable(const Unit* target) const
|
||||
|
||||
// if the target cannot be attacked, the target is not acceptable
|
||||
if (IsFriendlyTo(target)
|
||||
|| !target->isAttackableByAOE()
|
||||
|| !target->isTargetableForAttack(false)
|
||||
|| (m_vehicle && (IsOnVehicle(target) || m_vehicle->GetBase()->IsOnVehicle(target))))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -555,10 +555,10 @@ class Creature : public Unit, public GridObject<Creature>
|
||||
Loot loot;
|
||||
bool lootForPickPocketed;
|
||||
bool lootForBody;
|
||||
Player *GetLootRecipient() const;
|
||||
Group *GetLootRecipientGroup() const;
|
||||
Player* GetLootRecipient() const;
|
||||
Group* GetLootRecipientGroup() const;
|
||||
bool hasLootRecipient() const { return m_lootRecipient || m_lootRecipientGroup; }
|
||||
bool isTappedBy(Player* player) const; // return true if the creature is tapped by the player or a member of his party.
|
||||
bool isTappedBy(Player const* player) const; // return true if the creature is tapped by the player or a member of his party.
|
||||
|
||||
void SetLootRecipient (Unit* unit);
|
||||
void AllLootRemovedFromCorpse();
|
||||
|
||||
@@ -12255,10 +12255,16 @@ void Unit::ClearInCombat()
|
||||
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
|
||||
}
|
||||
|
||||
// TODO: remove this function
|
||||
bool Unit::isTargetableForAttack() const
|
||||
bool Unit::isTargetableForAttack(bool checkFakeDeath) const
|
||||
{
|
||||
return isAttackableByAOE() && !HasUnitState(UNIT_STAT_DIED);
|
||||
if (HasFlag(UNIT_FIELD_FLAGS,
|
||||
UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE))
|
||||
return false;
|
||||
|
||||
if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->isGameMaster())
|
||||
return false;
|
||||
|
||||
return !HasUnitState(UNIT_STAT_UNATTACKABLE) && (!checkFakeDeath || !HasUnitState(UNIT_STAT_DIED));
|
||||
}
|
||||
|
||||
bool Unit::canAttack(Unit const* target, bool force) const
|
||||
@@ -12285,7 +12291,7 @@ bool Unit::canAttack(Unit const* target, bool force) const
|
||||
else if (!IsHostileTo(target))
|
||||
return false;
|
||||
|
||||
if (!target->isAttackableByAOE())
|
||||
if (!target->isTargetableForAttack(false))
|
||||
return false;
|
||||
|
||||
if (target->HasUnitState(UNIT_STAT_DIED))
|
||||
@@ -12308,27 +12314,6 @@ bool Unit::canAttack(Unit const* target, bool force) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Unit::isAttackableByAOE(SpellInfo const* spellProto) const
|
||||
{
|
||||
bool targetMustBeDead = spellProto ? bool(spellProto->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS) : false;
|
||||
bool targetCanBeDead = spellProto ? bool(spellProto->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD) : false;
|
||||
|
||||
if (targetMustBeDead && isAlive())
|
||||
return false;
|
||||
|
||||
if (!targetMustBeDead && !targetCanBeDead && !isAlive())
|
||||
return false;
|
||||
|
||||
if (HasFlag(UNIT_FIELD_FLAGS,
|
||||
UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE))
|
||||
return false;
|
||||
|
||||
if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->isGameMaster())
|
||||
return false;
|
||||
|
||||
return !HasUnitState(UNIT_STAT_UNATTACKABLE);
|
||||
}
|
||||
|
||||
int32 Unit::ModifyHealth(int32 dVal)
|
||||
{
|
||||
int32 gain = 0;
|
||||
|
||||
@@ -395,10 +395,7 @@ enum TriggerCastFlags
|
||||
TRIGGERED_IGNORE_SET_FACING = 0x00000200, //! Will not adjust facing to target (if any)
|
||||
TRIGGERED_IGNORE_SHAPESHIFT = 0x00000400, //! Will ignore shapeshift checks
|
||||
TRIGGERED_IGNORE_CASTER_AURASTATE = 0x00000800, //! Will ignore caster aura states including combat requirements and death state
|
||||
TRIGGERED_IGNORE_TARGET_AURASTATE = 0x00001000, //! Will ignore target aura states
|
||||
TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE = 0x00002000, //! Will ignore mounted/on vehicle restrictions
|
||||
TRIGGERED_IGNORE_TARGET_DETECTABILITY = 0x00004000, //! Will ignore canSeeOrDetect
|
||||
TRIGGERED_IGNORE_LOS = 0x00008000, //! Will ignore LOS to target
|
||||
TRIGGERED_IGNORE_CASTER_AURAS = 0x00010000, //! Will ignore caster aura restrictions or requirements
|
||||
TRIGGERED_DISALLOW_PROC_EVENTS = 0x00020000, //! Disallows proc events from triggered spell (default)
|
||||
TRIGGERED_DONT_REPORT_CAST_ERROR = 0x00040000, //! Will return SPELL_FAILED_DONT_REPORT in CheckCast functions
|
||||
@@ -471,7 +468,7 @@ enum DeathState
|
||||
|
||||
enum UnitState
|
||||
{
|
||||
UNIT_STAT_DIED = 0x00000001,
|
||||
UNIT_STAT_DIED = 0x00000001, // player has fake death aura
|
||||
UNIT_STAT_MELEE_ATTACKING = 0x00000002, // player is melee attacking someone
|
||||
//UNIT_STAT_MELEE_ATTACK_BY = 0x00000004, // player is melee attack by someone
|
||||
UNIT_STAT_STUNNED = 0x00000008,
|
||||
@@ -1547,7 +1544,7 @@ class Unit : public WorldObject
|
||||
|
||||
bool isFrozen() const;
|
||||
|
||||
bool isTargetableForAttack() const;
|
||||
bool isTargetableForAttack(bool checkFakeDeath = true) const;
|
||||
bool isAttackableByAOE(SpellInfo const* spellProto = NULL) const;
|
||||
bool canAttack(Unit const* target, bool force = true) const;
|
||||
virtual bool IsInWater() const;
|
||||
|
||||
@@ -337,7 +337,7 @@ enum SpellAttr2
|
||||
{
|
||||
SPELL_ATTR2_CAN_TARGET_DEAD = 0x00000001, // 0 can target dead unit or corpse
|
||||
SPELL_ATTR2_UNK1 = 0x00000002, // 1 ? many triggered spells have this flag
|
||||
SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS = 0x00000004, // 2 26368 4.0.1 dbc change (NYI)
|
||||
SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS = 0x00000004, // 2 26368 4.0.1 dbc change
|
||||
SPELL_ATTR2_UNK3 = 0x00000008, // 3
|
||||
SPELL_ATTR2_DISPLAY_IN_STANCE_BAR = 0x00000010, // 4 client displays icon in stance bar when learned, even if not shapeshift
|
||||
SPELL_ATTR2_AUTOREPEAT_FLAG = 0x00000020, // 5
|
||||
@@ -383,7 +383,7 @@ enum SpellAttr3
|
||||
SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2 = 0x00000200, // 9 triggered from effect?
|
||||
SPELL_ATTR3_MAIN_HAND = 0x00000400, // 10 Main hand weapon required
|
||||
SPELL_ATTR3_BATTLEGROUND = 0x00000800, // 11 Can casted only on battleground
|
||||
SPELL_ATTR3_ONLY_TARGET_GHOSTS = 0x00001000, // 12
|
||||
SPELL_ATTR3_ONLY_TARGET_GHOSTS = 0x00001000, // 12
|
||||
SPELL_ATTR3_UNK13 = 0x00002000, // 13
|
||||
SPELL_ATTR3_UNK14 = 0x00004000, // 14 "Honorless Target" only this spells have this flag
|
||||
SPELL_ATTR3_UNK15 = 0x00008000, // 15 Auto Shoot, Shoot, Throw, - this is autoshot flag
|
||||
@@ -482,7 +482,7 @@ enum SpellAttr6
|
||||
SPELL_ATTR6_DONT_DISPLAY_COOLDOWN = 0x00000001, // 0 client doesn't display cooldown in tooltip for these spells
|
||||
SPELL_ATTR6_ONLY_IN_ARENA = 0x00000002, // 1 only usable in arena
|
||||
SPELL_ATTR6_IGNORE_CASTER_AURAS = 0x00000004, // 2
|
||||
SPELL_ATTR6_CAN_TARGET_INVISIBLE = 0x00000008, // 3 (NYI) ignore visibility requirement for spell target (phases, invisibility, etc.)
|
||||
SPELL_ATTR6_UNK3 = 0x00000008, // 3
|
||||
SPELL_ATTR6_UNK4 = 0x00000010, // 4
|
||||
SPELL_ATTR6_UNK5 = 0x00000020, // 5
|
||||
SPELL_ATTR6_UNK6 = 0x00000040, // 6
|
||||
@@ -492,7 +492,7 @@ enum SpellAttr6
|
||||
SPELL_ATTR6_CAN_TARGET_POSSESSED_FRIENDS = 0x00000400, // 10 NYI!
|
||||
SPELL_ATTR6_NOT_IN_RAID_INSTANCE = 0x00000800, // 11 not usable in raid instance
|
||||
SPELL_ATTR6_CASTABLE_WHILE_ON_VEHICLE = 0x00001000, // 12 castable while caster is on vehicle
|
||||
SPELL_ATTR6_UNK13 = 0x00002000, // 13
|
||||
SPELL_ATTR6_CAN_TARGET_INVISIBLE = 0x00002000, // 13 ignore visibility requirement for spell target (phases, invisibility, etc.)
|
||||
SPELL_ATTR6_UNK14 = 0x00004000, // 14
|
||||
SPELL_ATTR6_UNK15 = 0x00008000, // 15 not set in 3.0.3
|
||||
SPELL_ATTR6_UNK16 = 0x00010000, // 16
|
||||
@@ -503,7 +503,7 @@ enum SpellAttr6
|
||||
SPELL_ATTR6_CLIENT_UI_TARGET_EFFECTS = 0x00200000, // 21 it's only client-side attribute
|
||||
SPELL_ATTR6_UNK22 = 0x00400000, // 22
|
||||
SPELL_ATTR6_UNK23 = 0x00800000, // 23
|
||||
SPELL_ATTR6_CAN_TARGET_UNTARGETABLE = 0x01000000, // 24 NYI!
|
||||
SPELL_ATTR6_CAN_TARGET_UNTARGETABLE = 0x01000000, // 24
|
||||
SPELL_ATTR6_UNK25 = 0x02000000, // 25
|
||||
SPELL_ATTR6_UNK26 = 0x04000000, // 26
|
||||
SPELL_ATTR6_UNK27 = 0x08000000, // 27
|
||||
|
||||
@@ -631,7 +631,7 @@ void Spell::SelectSpellTargets()
|
||||
if (effectTargetType != SPELL_REQUIRE_UNIT)
|
||||
{
|
||||
if (effectTargetType == SPELL_REQUIRE_CASTER)
|
||||
AddUnitTarget(m_caster, i);
|
||||
AddUnitTarget(m_caster, i, false);
|
||||
else if (effectTargetType == SPELL_REQUIRE_ITEM)
|
||||
if (m_targets.GetItemTarget())
|
||||
AddItemTarget(m_targets.GetItemTarget(), i);
|
||||
@@ -642,7 +642,7 @@ void Spell::SelectSpellTargets()
|
||||
{
|
||||
if (!m_spellInfo->GetMaxRange(true))
|
||||
{
|
||||
AddUnitTarget(m_caster, i);
|
||||
AddUnitTarget(m_caster, i, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -692,9 +692,9 @@ void Spell::SelectSpellTargets()
|
||||
}
|
||||
default:
|
||||
if (m_targets.GetUnitTarget())
|
||||
AddUnitTarget(m_targets.GetUnitTarget(), i);
|
||||
AddUnitTarget(m_targets.GetUnitTarget(), i, false);
|
||||
else
|
||||
AddUnitTarget(m_caster, i);
|
||||
AddUnitTarget(m_caster, i, false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -711,10 +711,10 @@ void Spell::SelectSpellTargets()
|
||||
case SPELL_EFFECT_LEARN_SPELL:
|
||||
case SPELL_EFFECT_SEND_TAXI:
|
||||
if (m_targets.GetUnitTarget())
|
||||
AddUnitTarget(m_targets.GetUnitTarget(), i);
|
||||
AddUnitTarget(m_targets.GetUnitTarget(), i, false);
|
||||
// Triggered spells have additional spell targets - cast them even if no explicit unit target is given (required for spell 50516 for example)
|
||||
else if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_TRIGGER_SPELL)
|
||||
AddUnitTarget(m_caster, i);
|
||||
AddUnitTarget(m_caster, i, false);
|
||||
break;
|
||||
case SPELL_EFFECT_SUMMON_RAF_FRIEND:
|
||||
case SPELL_EFFECT_SUMMON_PLAYER:
|
||||
@@ -722,12 +722,12 @@ void Spell::SelectSpellTargets()
|
||||
{
|
||||
Player* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetSelection());
|
||||
if (target)
|
||||
AddUnitTarget(target, i);
|
||||
AddUnitTarget(target, i, false);
|
||||
}
|
||||
break;
|
||||
case SPELL_EFFECT_RESURRECT_NEW:
|
||||
if (m_targets.GetUnitTarget())
|
||||
AddUnitTarget(m_targets.GetUnitTarget(), i);
|
||||
AddUnitTarget(m_targets.GetUnitTarget(), i, false);
|
||||
if (m_targets.GetCorpseTargetGUID())
|
||||
{
|
||||
Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster, m_targets.GetCorpseTargetGUID());
|
||||
@@ -735,7 +735,7 @@ void Spell::SelectSpellTargets()
|
||||
{
|
||||
Player* owner = ObjectAccessor::FindPlayer(corpse->GetOwnerGUID());
|
||||
if (owner)
|
||||
AddUnitTarget(owner, i);
|
||||
AddUnitTarget(owner, i, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -746,7 +746,7 @@ void Spell::SelectSpellTargets()
|
||||
case SPELL_EFFECT_FEED_PET:
|
||||
case SPELL_EFFECT_DESTROY_ALL_TOTEMS:
|
||||
case SPELL_EFFECT_KILL_CREDIT2: // only one spell: 42793
|
||||
AddUnitTarget(m_caster, i);
|
||||
AddUnitTarget(m_caster, i, false);
|
||||
break;
|
||||
case SPELL_EFFECT_LEARN_PET_SPELL:
|
||||
if (Guardian* pet = m_caster->GetGuardianPet())
|
||||
@@ -757,17 +757,17 @@ void Spell::SelectSpellTargets()
|
||||
{
|
||||
case SPELL_AURA_ADD_FLAT_MODIFIER: // some spell mods auras have 0 target modes instead expected TARGET_UNIT_CASTER(1) (and present for other ranks for same spell for example)
|
||||
case SPELL_AURA_ADD_PCT_MODIFIER:
|
||||
AddUnitTarget(m_caster, i);
|
||||
AddUnitTarget(m_caster, i, false);
|
||||
break;
|
||||
default: // apply to target in other case
|
||||
if (m_targets.GetUnitTarget())
|
||||
AddUnitTarget(m_targets.GetUnitTarget(), i);
|
||||
AddUnitTarget(m_targets.GetUnitTarget(), i, false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SPELL_EFFECT_SKIN_PLAYER_CORPSE:
|
||||
if (m_targets.GetUnitTarget())
|
||||
AddUnitTarget(m_targets.GetUnitTarget(), i);
|
||||
AddUnitTarget(m_targets.GetUnitTarget(), i), false;
|
||||
else if (m_targets.GetCorpseTargetGUID())
|
||||
{
|
||||
Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster, m_targets.GetCorpseTargetGUID());
|
||||
@@ -775,12 +775,12 @@ void Spell::SelectSpellTargets()
|
||||
{
|
||||
Player* owner = ObjectAccessor::FindPlayer(corpse->GetOwnerGUID());
|
||||
if (owner)
|
||||
AddUnitTarget(owner, i);
|
||||
AddUnitTarget(owner, i, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
AddUnitTarget(m_caster, i);
|
||||
AddUnitTarget(m_caster, i, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -926,12 +926,15 @@ void Spell::CleanupTargetList()
|
||||
m_delayMoment = 0;
|
||||
}
|
||||
|
||||
void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)
|
||||
void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex, bool checkIfValid /*=true*/)
|
||||
{
|
||||
if (!m_spellInfo->Effects[effIndex].IsEffect())
|
||||
return;
|
||||
|
||||
if (!CheckTarget(pVictim, effIndex))
|
||||
if (checkIfValid)
|
||||
if (m_spellInfo->CheckTarget(m_caster, pVictim, true) != SPELL_CAST_OK)
|
||||
return;
|
||||
if (!CheckEffectTarget(pVictim, effIndex))
|
||||
return;
|
||||
|
||||
// Check for effect immune skip if immuned
|
||||
@@ -1022,12 +1025,6 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)
|
||||
m_UniqueTargetInfo.push_back(target);
|
||||
}
|
||||
|
||||
void Spell::AddUnitTarget(uint64 unitGUID, uint32 effIndex)
|
||||
{
|
||||
if (Unit* unit = m_caster->GetGUID() == unitGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, unitGUID))
|
||||
AddUnitTarget(unit, effIndex);
|
||||
}
|
||||
|
||||
void Spell::AddGOTarget(GameObject* go, uint32 effIndex)
|
||||
{
|
||||
if (!m_spellInfo->Effects[effIndex].IsEffect())
|
||||
@@ -1851,15 +1848,9 @@ void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, SpellNo
|
||||
|
||||
Trinity::SpellNotifierCreatureAndPlayer notifier(m_caster, TagUnitMap, radius, type, TargetType, pos, entry, m_spellInfo);
|
||||
if ((m_spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS) || (TargetType == SPELL_TARGETS_ENTRY && !entry))
|
||||
{
|
||||
m_caster->GetMap()->VisitWorld(pos->m_positionX, pos->m_positionY, radius, notifier);
|
||||
TagUnitMap.remove_if(Trinity::ObjectTypeIdCheck(TYPEID_PLAYER, false)); // above line will select also pets and totems, remove them
|
||||
}
|
||||
else
|
||||
m_caster->GetMap()->VisitAll(pos->m_positionX, pos->m_positionY, radius, notifier);
|
||||
|
||||
if (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_EXCLUDE_SELF)
|
||||
TagUnitMap.remove(m_caster);
|
||||
}
|
||||
|
||||
void Spell::SearchGOAreaTarget(std::list<GameObject*> &TagGOMap, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry)
|
||||
@@ -2000,7 +1991,7 @@ void Spell::SelectEffectTargets(uint32 i, SpellImplicitTargetInfo const& cur)
|
||||
switch(cur.GetTarget())
|
||||
{
|
||||
case TARGET_UNIT_CASTER:
|
||||
AddUnitTarget(m_caster, i);
|
||||
AddUnitTarget(m_caster, i, false);
|
||||
break;
|
||||
case TARGET_DEST_CASTER_FISHING:
|
||||
{
|
||||
@@ -2079,17 +2070,17 @@ void Spell::SelectEffectTargets(uint32 i, SpellImplicitTargetInfo const& cur)
|
||||
pushType = PUSH_CHAIN;
|
||||
break;
|
||||
case TARGET_UNIT_TARGET_ALLY:
|
||||
AddUnitTarget(target, i);
|
||||
AddUnitTarget(target, i, false);
|
||||
break;
|
||||
case TARGET_UNIT_TARGET_RAID:
|
||||
case TARGET_UNIT_TARGET_PARTY:
|
||||
case TARGET_UNIT_TARGET_MINIPET:
|
||||
if (IsValidSingleTargetSpell(target))
|
||||
AddUnitTarget(target, i);
|
||||
AddUnitTarget(target, i, false);
|
||||
break;
|
||||
case TARGET_UNIT_TARGET_PASSENGER:
|
||||
if (target->IsOnVehicle(m_caster))
|
||||
AddUnitTarget(target, i);
|
||||
AddUnitTarget(target, i, false);
|
||||
break;
|
||||
case TARGET_UNIT_LASTTARGET_AREA_PARTY:
|
||||
case TARGET_UNIT_TARGET_AREA_RAID_CLASS:
|
||||
@@ -2443,10 +2434,10 @@ void Spell::SelectEffectTargets(uint32 i, SpellImplicitTargetInfo const& cur)
|
||||
CallScriptAfterUnitTargetSelectHandlers(unitList, SpellEffIndex(i));
|
||||
|
||||
for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr)
|
||||
AddUnitTarget(*itr, i);
|
||||
AddUnitTarget(*itr, i, false);
|
||||
}
|
||||
else
|
||||
AddUnitTarget(target, i);
|
||||
AddUnitTarget(target, i, false);
|
||||
}
|
||||
else if (pushType)
|
||||
{
|
||||
@@ -2803,7 +2794,7 @@ void Spell::SelectEffectTargets(uint32 i, SpellImplicitTargetInfo const& cur)
|
||||
CallScriptAfterUnitTargetSelectHandlers(unitList, SpellEffIndex(i));
|
||||
|
||||
for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr)
|
||||
AddUnitTarget(*itr, i);
|
||||
AddUnitTarget(*itr, i, false);
|
||||
}
|
||||
|
||||
if (!gobjectList.empty())
|
||||
@@ -4758,69 +4749,27 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
|
||||
if (target)
|
||||
{
|
||||
// target state requirements (not allowed state), apply to self also
|
||||
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_TARGET_AURASTATE) && m_spellInfo->TargetAuraStateNot && target->HasAuraState(AuraStateType(m_spellInfo->TargetAuraStateNot), m_spellInfo, m_caster))
|
||||
return SPELL_FAILED_TARGET_AURASTATE;
|
||||
|
||||
if (m_spellInfo->TargetAuraSpell && !target->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->TargetAuraSpell, m_caster)))
|
||||
return SPELL_FAILED_TARGET_AURASTATE;
|
||||
|
||||
if (m_spellInfo->ExcludeTargetAuraSpell && target->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->ExcludeTargetAuraSpell, m_caster)))
|
||||
return SPELL_FAILED_TARGET_AURASTATE;
|
||||
|
||||
if (!IsTriggered() && target == m_caster && m_spellInfo->AttributesEx & SPELL_ATTR1_CANT_TARGET_SELF)
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
bool non_caster_target = target != m_caster && m_spellInfo->IsRequiringSelectedTarget();
|
||||
|
||||
if (non_caster_target)
|
||||
if (target != m_caster && m_spellInfo->IsRequiringSelectedTarget())
|
||||
{
|
||||
// target state requirements (apply to non-self only), to allow cast affects to self like Dirty Deeds
|
||||
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_TARGET_AURASTATE) && m_spellInfo->TargetAuraState && !target->HasAuraState(AuraStateType(m_spellInfo->TargetAuraState), m_spellInfo, m_caster))
|
||||
return SPELL_FAILED_TARGET_AURASTATE;
|
||||
|
||||
// Not allow casting on flying player or on vehicle player (if caster isnt vehicle)
|
||||
if (target->HasUnitState(UNIT_STAT_IN_FLIGHT) /*|| (target->HasUnitState(UNIT_STAT_ONVEHICLE) && target->GetVehicleBase() != m_caster)*/)
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_TARGET_DETECTABILITY) && !m_caster->canSeeOrDetect(target))
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
// Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells)
|
||||
if (m_spellInfo->AttributesEx2 & SPELL_ATTR2_CANT_TARGET_TAPPED)
|
||||
if (Creature *targetCreature = target->ToCreature())
|
||||
if (targetCreature->hasLootRecipient() && !targetCreature->isTappedBy(m_caster->ToPlayer()))
|
||||
return SPELL_FAILED_CANT_CAST_ON_TAPPED;
|
||||
|
||||
if (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_PICKPOCKET)
|
||||
{
|
||||
if (target->GetTypeId() == TYPEID_PLAYER)
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
else if ((target->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) == 0)
|
||||
return SPELL_FAILED_TARGET_NO_POCKETS;
|
||||
}
|
||||
|
||||
// Not allow disarm unarmed player
|
||||
if (m_spellInfo->Mechanic == MECHANIC_DISARM)
|
||||
{
|
||||
if (target->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
Player* player = target->ToPlayer();
|
||||
if (!player->GetWeaponForAttack(BASE_ATTACK) || !player->IsUseEquipedWeapon(true))
|
||||
return SPELL_FAILED_TARGET_NO_WEAPONS;
|
||||
}
|
||||
else if (!target->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID))
|
||||
return SPELL_FAILED_TARGET_NO_WEAPONS;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_LOS) && VMAP::VMapFactory::checkSpellForLoS(m_spellInfo->Id) && !m_caster->IsWithinLOSInMap(target))
|
||||
return SPELL_FAILED_LINE_OF_SIGHT;
|
||||
|
||||
SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, false);
|
||||
if (castResult != SPELL_CAST_OK)
|
||||
return castResult;
|
||||
}
|
||||
else if (m_caster == target)
|
||||
|
||||
if (target != m_caster)
|
||||
{
|
||||
// Must be behind the target
|
||||
if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET) && target->HasInArc(static_cast<float>(M_PI), m_caster))
|
||||
return SPELL_FAILED_NOT_BEHIND;
|
||||
|
||||
// Target must be facing you
|
||||
if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER) && !target->HasInArc(static_cast<float>(M_PI), m_caster))
|
||||
return SPELL_FAILED_NOT_INFRONT;
|
||||
|
||||
if (!(m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && VMAP::VMapFactory::checkSpellForLoS(m_spellInfo->Id) && !m_caster->IsWithinLOSInMap(target))
|
||||
return SPELL_FAILED_LINE_OF_SIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER) // Target - is player caster
|
||||
{
|
||||
@@ -4843,7 +4792,7 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
}
|
||||
}
|
||||
|
||||
// check pet presents
|
||||
// check pet presence
|
||||
for (int j = 0; j < MAX_SPELL_EFFECTS; ++j)
|
||||
{
|
||||
if (m_spellInfo->Effects[j].TargetA.GetTarget() == TARGET_UNIT_PET)
|
||||
@@ -4859,36 +4808,6 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check creature type
|
||||
// ignore self casts (including area casts when caster selected as target)
|
||||
if (non_caster_target)
|
||||
{
|
||||
if (!CheckTargetCreatureType(target))
|
||||
{
|
||||
if (target->GetTypeId() == TYPEID_PLAYER)
|
||||
return SPELL_FAILED_TARGET_IS_PLAYER;
|
||||
else
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
|
||||
// Must be behind the target
|
||||
if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET) && target->HasInArc(static_cast<float>(M_PI), m_caster))
|
||||
return SPELL_FAILED_NOT_BEHIND;
|
||||
|
||||
// Target must be facing you
|
||||
if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER) && !target->HasInArc(static_cast<float>(M_PI), m_caster))
|
||||
return SPELL_FAILED_NOT_INFRONT;
|
||||
|
||||
// Target must not be in combat
|
||||
if (m_spellInfo->AttributesEx & SPELL_ATTR1_CANT_TARGET_IN_COMBAT && target->isInCombat())
|
||||
return SPELL_FAILED_TARGET_AFFECTING_COMBAT;
|
||||
}
|
||||
|
||||
if (target)
|
||||
if (m_spellInfo->IsPositive())
|
||||
if (target->IsImmunedToSpell(m_spellInfo))
|
||||
return SPELL_FAILED_TARGET_AURASTATE;
|
||||
}
|
||||
|
||||
// Spell casted only on battleground
|
||||
@@ -6474,37 +6393,6 @@ void Spell::UpdatePointers()
|
||||
m_targets.Update(m_caster);
|
||||
}
|
||||
|
||||
bool Spell::CheckTargetCreatureType(Unit* target) const
|
||||
{
|
||||
uint32 spellCreatureTargetMask = m_spellInfo->TargetCreatureType;
|
||||
|
||||
// Curse of Doom & Exorcism: not find another way to fix spell target check :/
|
||||
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 1179)
|
||||
{
|
||||
// not allow cast at player
|
||||
if (target->GetTypeId() == TYPEID_PLAYER)
|
||||
return false;
|
||||
|
||||
spellCreatureTargetMask = 0x7FF;
|
||||
}
|
||||
|
||||
// Dismiss Pet and Taming Lesson skipped
|
||||
if (m_spellInfo->Id == 2641 || m_spellInfo->Id == 23356)
|
||||
spellCreatureTargetMask = 0;
|
||||
|
||||
// Polymorph and Grounding Totem
|
||||
if (target->GetEntry() == 5925 && m_spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (m_spellInfo->SpellFamilyFlags[0] & 0x1000000) && m_spellInfo->Effects[0].ApplyAuraName == SPELL_AURA_MOD_CONFUSE)
|
||||
return true;
|
||||
|
||||
if (spellCreatureTargetMask)
|
||||
{
|
||||
uint32 TargetCreatureType = target->GetCreatureTypeMask();
|
||||
|
||||
return !TargetCreatureType || (spellCreatureTargetMask & TargetCreatureType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CurrentSpellTypes Spell::GetCurrentContainer()
|
||||
{
|
||||
if (IsNextMeleeSwingSpell())
|
||||
@@ -6517,52 +6405,10 @@ CurrentSpellTypes Spell::GetCurrentContainer()
|
||||
return(CURRENT_GENERIC_SPELL);
|
||||
}
|
||||
|
||||
bool Spell::CheckTarget(Unit* target, uint32 eff)
|
||||
bool Spell::CheckEffectTarget(Unit const* target, uint32 eff) const
|
||||
{
|
||||
// Check targets for creature type mask and remove not appropriate (skip explicit self target case, maybe need other explicit targets)
|
||||
if (m_spellInfo->Effects[eff].TargetA.GetTarget() != TARGET_UNIT_CASTER)
|
||||
{
|
||||
if (!CheckTargetCreatureType(target))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check Aura spell req (need for AoE spells)
|
||||
if (m_spellInfo->TargetAuraSpell && !target->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->TargetAuraSpell, m_caster)))
|
||||
return false;
|
||||
if (m_spellInfo->ExcludeTargetAuraSpell && target->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->ExcludeTargetAuraSpell, m_caster)))
|
||||
return false;
|
||||
|
||||
// Check targets for not_selectable unit flag and remove
|
||||
// A player can cast spells on his pet (or other controlled unit) though in any state
|
||||
if (target != m_caster && target->GetCharmerOrOwnerGUID() != m_caster->GetGUID())
|
||||
{
|
||||
// any unattackable target skipped
|
||||
if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
|
||||
return false;
|
||||
|
||||
// unselectable targets skipped in all cases except TARGET_UNIT_NEARBY_ENTRY targeting
|
||||
// in case TARGET_UNIT_NEARBY_ENTRY target selected by server always and can't be cheated
|
||||
/*if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE) &&
|
||||
m_spellInfo->EffectImplicitTargetA[eff] != TARGET_UNIT_NEARBY_ENTRY &&
|
||||
m_spellInfo->EffectImplicitTargetB[eff] != TARGET_UNIT_NEARBY_ENTRY)
|
||||
return false;*/
|
||||
}
|
||||
|
||||
//Check player targets and remove if in GM mode or GM invisibility (for not self casting case)
|
||||
if (target != m_caster && target->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (!target->ToPlayer()->IsVisible())
|
||||
return false;
|
||||
|
||||
if (target->ToPlayer()->isGameMaster() && !m_spellInfo->IsPositive())
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(m_spellInfo->Effects[eff].ApplyAuraName)
|
||||
{
|
||||
case SPELL_AURA_NONE:
|
||||
default:
|
||||
break;
|
||||
case SPELL_AURA_MOD_POSSESS:
|
||||
case SPELL_AURA_MOD_CHARM:
|
||||
case SPELL_AURA_MOD_POSSESS_PET:
|
||||
@@ -6573,26 +6419,21 @@ bool Spell::CheckTarget(Unit* target, uint32 eff)
|
||||
return false;
|
||||
if (target->GetCharmerGUID())
|
||||
return false;
|
||||
if (int32 damage = CalculateDamage(eff, target))
|
||||
if (int32 damage = m_spellInfo->Effects[eff].CalcValue())
|
||||
if ((int32)target->getLevel() > damage)
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//Do not do further checks for triggered spells
|
||||
if (IsTriggered())
|
||||
if (m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS)
|
||||
return true;
|
||||
|
||||
// todo: shit below shouldn't be here, but it's temporary
|
||||
//Check targets for LOS visibility (except spells without range limitations)
|
||||
switch(m_spellInfo->Effects[eff].Effect)
|
||||
{
|
||||
case SPELL_EFFECT_SUMMON_RAF_FRIEND:
|
||||
case SPELL_EFFECT_SUMMON_PLAYER: // from anywhere
|
||||
break;
|
||||
case SPELL_EFFECT_DUMMY:
|
||||
if (m_spellInfo->Id != 20577) // Cannibalize
|
||||
break;
|
||||
//fall through
|
||||
case SPELL_EFFECT_RESURRECT_NEW:
|
||||
// player far away, maybe his corpse near?
|
||||
if (target != m_caster && !target->IsWithinLOSInMap(m_caster))
|
||||
@@ -6620,8 +6461,6 @@ bool Spell::CheckTarget(Unit* target, uint32 eff)
|
||||
caster = m_caster->GetMap()->GetGameObject(m_originalCasterGUID);
|
||||
if (!caster)
|
||||
caster = m_caster;
|
||||
if (target->GetEntry() == 5925)
|
||||
return true;
|
||||
if (target != m_caster && !target->IsWithinLOSInMap(caster))
|
||||
return false;
|
||||
break;
|
||||
|
||||
@@ -429,7 +429,7 @@ class Spell
|
||||
|
||||
template<typename T> WorldObject* FindCorpseUsing();
|
||||
|
||||
bool CheckTarget(Unit* target, uint32 eff);
|
||||
bool CheckEffectTarget(Unit const* target, uint32 eff) const;
|
||||
bool CanAutoCast(Unit* target);
|
||||
void CheckSrc() { if (!m_targets.HasSrc()) m_targets.SetSrc(*m_caster); }
|
||||
void CheckDst() { if (!m_targets.HasDst()) m_targets.SetDst(*m_caster); }
|
||||
@@ -498,8 +498,6 @@ class Spell
|
||||
|
||||
void UpdatePointers(); // must be used at call Spell code after time delay (non triggered spell cast/update spell call/etc)
|
||||
|
||||
bool CheckTargetCreatureType(Unit* target) const;
|
||||
|
||||
void CleanupTargetList();
|
||||
|
||||
void SetSpellValue(SpellValueMod mod, int32 value);
|
||||
@@ -614,8 +612,7 @@ class Spell
|
||||
};
|
||||
std::list<ItemTargetInfo> m_UniqueItemInfo;
|
||||
|
||||
void AddUnitTarget(Unit* target, uint32 effIndex);
|
||||
void AddUnitTarget(uint64 unitGUID, uint32 effIndex);
|
||||
void AddUnitTarget(Unit* target, uint32 effIndex, bool checkIfValid = true);
|
||||
void AddGOTarget(GameObject* target, uint32 effIndex);
|
||||
void AddGOTarget(uint64 goGUID, uint32 effIndex);
|
||||
void AddItemTarget(Item* target, uint32 effIndex);
|
||||
@@ -706,7 +703,6 @@ namespace Trinity
|
||||
const Unit* const i_source;
|
||||
uint32 i_entry;
|
||||
const Position * const i_pos;
|
||||
bool i_requireDeadTarget;
|
||||
SpellInfo const* i_spellProto;
|
||||
|
||||
SpellNotifierCreatureAndPlayer(Unit *source, std::list<Unit*> &data, float radius, SpellNotifyPushType type,
|
||||
@@ -719,13 +715,11 @@ namespace Trinity
|
||||
|
||||
template<class T> inline void Visit(GridRefManager<T>& m)
|
||||
{
|
||||
i_requireDeadTarget = i_spellProto ? bool(i_spellProto->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS) : false;
|
||||
|
||||
for (typename GridRefManager<T>::iterator itr = m.begin(); itr != m.end(); ++itr)
|
||||
{
|
||||
Unit* target = (Unit*)itr->getSource();
|
||||
|
||||
if (!i_source->canSeeOrDetect(target, true))
|
||||
if (i_spellProto->CheckTarget(i_source, target, true) != SPELL_CAST_OK)
|
||||
continue;
|
||||
|
||||
switch (i_TargetType)
|
||||
@@ -733,8 +727,6 @@ namespace Trinity
|
||||
case SPELL_TARGETS_ENEMY:
|
||||
if (target->isTotem())
|
||||
continue;
|
||||
if (!target->isAttackableByAOE(i_spellProto))
|
||||
continue;
|
||||
if (i_source->IsControlledByPlayer())
|
||||
{
|
||||
if (i_source->IsFriendlyTo(target))
|
||||
@@ -751,12 +743,6 @@ namespace Trinity
|
||||
continue;
|
||||
if (!i_source->IsFriendlyTo(target))
|
||||
continue;
|
||||
if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
|
||||
continue;
|
||||
if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->isGameMaster())
|
||||
continue;
|
||||
if (target->isAlive() == i_requireDeadTarget)
|
||||
continue;
|
||||
break;
|
||||
case SPELL_TARGETS_ENTRY:
|
||||
if (target->GetEntry()!= i_entry)
|
||||
|
||||
@@ -1486,6 +1486,127 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
SpellCastResult SpellInfo::CheckTarget(Unit const* caster, Unit const* target, bool implicit) const
|
||||
{
|
||||
if (AttributesEx & SPELL_ATTR1_CANT_TARGET_SELF && caster == target)
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
if (AttributesEx & SPELL_ATTR1_CANT_TARGET_IN_COMBAT && target->isInCombat())
|
||||
return SPELL_FAILED_TARGET_AFFECTING_COMBAT;
|
||||
|
||||
if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS && !target->ToPlayer())
|
||||
return SPELL_FAILED_TARGET_NOT_PLAYER;
|
||||
|
||||
if (!(AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD) && !target->isAlive())
|
||||
return SPELL_FAILED_TARGETS_DEAD;
|
||||
|
||||
if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS && !(target->ToPlayer() && !target->isAlive()))
|
||||
return SPELL_FAILED_TARGET_NOT_GHOST;
|
||||
|
||||
if (AttributesEx6 & SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED && !target->CanFreeMove())
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
// check visibility - ignore stealth for implicit (area) targets
|
||||
if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE) && !caster->canSeeOrDetect(target, implicit))
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
//if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_POSSESSED_FRIENDS)
|
||||
|
||||
if (!CheckTargetCreatureType(target))
|
||||
{
|
||||
if (target->GetTypeId() == TYPEID_PLAYER)
|
||||
return SPELL_FAILED_TARGET_IS_PLAYER;
|
||||
else
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
|
||||
// check UNIT_FLAG_NON_ATTACKABLE flag - a player can cast spells on his pet (or other controlled unit) though in any state
|
||||
if (target != caster && target->GetCharmerOrOwnerGUID() != caster->GetGUID())
|
||||
{
|
||||
// any unattackable target skipped
|
||||
if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE))
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
|
||||
// check GM mode and GM invisibility - only for player casts (npc casts are controlled by AI)
|
||||
if (target != caster && caster->IsControlledByPlayer() && target->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (!target->ToPlayer()->IsVisible())
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
if (target->ToPlayer()->isGameMaster())
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
|
||||
// not allow casting on flying player
|
||||
if (target->HasUnitState(UNIT_STAT_IN_FLIGHT))
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
if (TargetAuraState && !target->HasAuraState(AuraStateType(TargetAuraState), this, caster))
|
||||
return SPELL_FAILED_TARGET_AURASTATE;
|
||||
|
||||
if (TargetAuraStateNot && target->HasAuraState(AuraStateType(TargetAuraStateNot), this, caster))
|
||||
return SPELL_FAILED_TARGET_AURASTATE;
|
||||
|
||||
if (TargetAuraSpell && !target->HasAura(sSpellMgr->GetSpellIdForDifficulty(TargetAuraSpell, caster)))
|
||||
return SPELL_FAILED_TARGET_AURASTATE;
|
||||
|
||||
if (ExcludeTargetAuraSpell && target->HasAura(sSpellMgr->GetSpellIdForDifficulty(ExcludeTargetAuraSpell, caster)))
|
||||
return SPELL_FAILED_TARGET_AURASTATE;
|
||||
|
||||
if (caster != target)
|
||||
{
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
// Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells)
|
||||
if (AttributesEx2 & SPELL_ATTR2_CANT_TARGET_TAPPED)
|
||||
if (Creature const* targetCreature = target->ToCreature())
|
||||
if (targetCreature->hasLootRecipient() && !targetCreature->isTappedBy(caster->ToPlayer()))
|
||||
return SPELL_FAILED_CANT_CAST_ON_TAPPED;
|
||||
|
||||
if (AttributesCu & SPELL_ATTR0_CU_PICKPOCKET)
|
||||
{
|
||||
if (target->GetTypeId() == TYPEID_PLAYER)
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
else if ((target->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) == 0)
|
||||
return SPELL_FAILED_TARGET_NO_POCKETS;
|
||||
}
|
||||
|
||||
// Not allow disarm unarmed player
|
||||
if (Mechanic == MECHANIC_DISARM)
|
||||
{
|
||||
if (target->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
Player const* player = target->ToPlayer();
|
||||
if (!player->GetWeaponForAttack(BASE_ATTACK) || !player->IsUseEquipedWeapon(true))
|
||||
return SPELL_FAILED_TARGET_NO_WEAPONS;
|
||||
}
|
||||
else if (!target->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID))
|
||||
return SPELL_FAILED_TARGET_NO_WEAPONS;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
bool SpellInfo::CheckTargetCreatureType(Unit const* target) const
|
||||
{
|
||||
// Curse of Doom & Exorcism: not find another way to fix spell target check :/
|
||||
if (SpellFamilyName == SPELLFAMILY_WARLOCK && Category == 1179)
|
||||
{
|
||||
// not allow cast at player
|
||||
if (target->GetTypeId() == TYPEID_PLAYER)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
uint32 creatureType = target->GetCreatureTypeMask();
|
||||
return !TargetCreatureType || !creatureType || (creatureType & TargetCreatureType);
|
||||
}
|
||||
|
||||
SpellSchoolMask SpellInfo::GetSchoolMask() const
|
||||
{
|
||||
return SpellSchoolMask(SchoolMask);
|
||||
|
||||
@@ -159,7 +159,6 @@ enum SpellCustomAttributes
|
||||
SPELL_ATTR0_CU_DIRECT_DAMAGE = 0x00000100,
|
||||
SPELL_ATTR0_CU_CHARGE = 0x00000200,
|
||||
SPELL_ATTR0_CU_PICKPOCKET = 0x00000400,
|
||||
SPELL_ATTR0_CU_EXCLUDE_SELF = 0x00000800,
|
||||
SPELL_ATTR0_CU_NEGATIVE_EFF0 = 0x00001000,
|
||||
SPELL_ATTR0_CU_NEGATIVE_EFF1 = 0x00002000,
|
||||
SPELL_ATTR0_CU_NEGATIVE_EFF2 = 0x00004000,
|
||||
@@ -403,6 +402,8 @@ 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;
|
||||
bool CheckTargetCreatureType(Unit const* target) const;
|
||||
|
||||
SpellSchoolMask GetSchoolMask() const;
|
||||
uint32 GetAllEffectsMechanicMask() const;
|
||||
|
||||
@@ -430,7 +430,7 @@ void SpellMgr::SetSpellDifficultyId(uint32 spellId, uint32 id)
|
||||
mSpellDifficultySearcherMap[spellId] = id;
|
||||
}
|
||||
|
||||
uint32 SpellMgr::GetSpellIdForDifficulty(uint32 spellId, Unit* caster) const
|
||||
uint32 SpellMgr::GetSpellIdForDifficulty(uint32 spellId, Unit const* caster) const
|
||||
{
|
||||
if (!GetSpellInfo(spellId))
|
||||
return spellId;
|
||||
@@ -472,7 +472,7 @@ uint32 SpellMgr::GetSpellIdForDifficulty(uint32 spellId, Unit* caster) const
|
||||
return uint32(difficultyEntry->SpellID[mode]);
|
||||
}
|
||||
|
||||
SpellInfo const* SpellMgr::GetSpellForDifficultyFromSpell(SpellInfo const* spell, Unit* caster) const
|
||||
SpellInfo const* SpellMgr::GetSpellForDifficultyFromSpell(SpellInfo const* spell, Unit const* caster) const
|
||||
{
|
||||
uint32 newSpellId = GetSpellIdForDifficulty(spell->Id, caster);
|
||||
SpellInfo const* newSpell = GetSpellInfo(newSpellId);
|
||||
@@ -2774,21 +2774,6 @@ void SpellMgr::LoadSpellCustomAttr()
|
||||
// ONLY SPELLS WITH SPELLFAMILY_GENERIC and EFFECT_SCHOOL_DAMAGE
|
||||
spellInfo->AttributesCu |= SPELL_ATTR0_CU_SHARE_DAMAGE;
|
||||
break;
|
||||
case 27820: // Mana Detonation
|
||||
case 69782: // Ooze Flood
|
||||
case 69796: // Ooze Flood
|
||||
case 69798: // Ooze Flood
|
||||
case 69801: // Ooze Flood
|
||||
case 69538: // Ooze Combine
|
||||
case 69553: // Ooze Combine
|
||||
case 69610: // Ooze Combine
|
||||
case 71447: // Bloodbolt Splash
|
||||
case 71481: // Bloodbolt Splash
|
||||
case 71482: // Bloodbolt Splash
|
||||
case 71483: // Bloodbolt Splash
|
||||
case 71390: // Pact of the Darkfallen
|
||||
spellInfo->AttributesCu |= SPELL_ATTR0_CU_EXCLUDE_SELF;
|
||||
break;
|
||||
case 18500: // Wing Buffet
|
||||
case 33086: // Wild Bite
|
||||
case 49749: // Piercing Blow
|
||||
@@ -3105,9 +3090,6 @@ void SpellMgr::LoadDbcDataCorrections()
|
||||
case 27937: // Anchor to Skulls
|
||||
spellInfo->rangeIndex = 13;
|
||||
break;
|
||||
case 48743: // Death Pact
|
||||
spellInfo->AttributesEx &= ~SPELL_ATTR1_CANT_TARGET_SELF;
|
||||
break;
|
||||
// target allys instead of enemies, target A is src_caster, spells with effect like that have ally target
|
||||
// this is the only known exception, probably just wrong data
|
||||
case 29214: // Wrath of the Plaguebringer
|
||||
|
||||
@@ -550,8 +550,8 @@ class SpellMgr
|
||||
// Spell difficulty
|
||||
uint32 GetSpellDifficultyId(uint32 spellId) const;
|
||||
void SetSpellDifficultyId(uint32 spellId, uint32 id);
|
||||
uint32 GetSpellIdForDifficulty(uint32 spellId, Unit* caster) const;
|
||||
SpellInfo const* GetSpellForDifficultyFromSpell(SpellInfo const* spell, Unit* caster) const;
|
||||
uint32 GetSpellIdForDifficulty(uint32 spellId, Unit const* caster) const;
|
||||
SpellInfo const* GetSpellForDifficultyFromSpell(SpellInfo const* spell, Unit const* caster) const;
|
||||
|
||||
// Spell Ranks table
|
||||
SpellChainNode const* GetSpellChainNode(uint32 spell_id) const;
|
||||
|
||||
Reference in New Issue
Block a user