aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/server/game/AI/CoreAI/PetAI.cpp3
-rwxr-xr-xsrc/server/game/DataStores/DBCStructure.h2
-rwxr-xr-xsrc/server/game/DataStores/DBCfmt.h2
-rwxr-xr-xsrc/server/game/Entities/Object/Object.h4
-rwxr-xr-xsrc/server/game/Entities/Player/Player.cpp18
-rwxr-xr-xsrc/server/game/Entities/Player/Player.h7
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp35
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h9
-rwxr-xr-xsrc/server/game/Handlers/MiscHandler.cpp6
-rwxr-xr-xsrc/server/game/Handlers/MovementHandler.cpp25
-rw-r--r--src/server/game/Handlers/VehicleHandler.cpp17
-rwxr-xr-xsrc/server/game/Server/Protocol/Opcodes.h2
-rwxr-xr-xsrc/server/game/Server/WorldSession.cpp38
-rwxr-xr-xsrc/server/game/Spells/Auras/SpellAuraEffects.cpp42
-rwxr-xr-xsrc/server/game/Spells/Spell.cpp10
15 files changed, 176 insertions, 44 deletions
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp
index eedba4d8b7e..295768f9d3e 100755
--- a/src/server/game/AI/CoreAI/PetAI.cpp
+++ b/src/server/game/AI/CoreAI/PetAI.cpp
@@ -278,6 +278,7 @@ void PetAI::KilledUnit(Unit* victim)
// next target selection
me->AttackStop();
me->GetCharmInfo()->SetIsCommandAttack(false);
+ me->SendMeleeAttackStop(); // Stops the pet's 'Attack' button from flashing
Unit* nextTarget = SelectNextTarget();
@@ -457,7 +458,7 @@ bool PetAI::CanAttack(Unit* target)
// Stay - can attack if target is within range or commanded to
if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY))
- return (me->IsWithinMeleeRange(target, MIN_MELEE_REACH) || me->GetCharmInfo()->IsCommandAttack());
+ return (me->IsWithinMeleeRange(target, MELEE_RANGE) || me->GetCharmInfo()->IsCommandAttack());
// Follow
if (me->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW))
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index d25578e304a..38e8c957681 100755
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -1396,7 +1396,7 @@ struct ScalingStatValuesEntry
uint32 spellPower; // 16 spell power for level
uint32 ssdMultiplier2; // 17 there's data from 3.1 dbc ssdMultiplier[3]
uint32 ssdMultiplier3; // 18 3.3
- uint32 armorMod2[5]; // 20-23 Armor for level
+ uint32 armorMod2[5]; // 19-23 Armor for level
uint32 getssdMultiplier(uint32 mask) const
{
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index ce887cac09b..39d031e96f9 100755
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -91,7 +91,7 @@ const char QuestFactionRewardfmt[]="niiiiiiiiii";
const char PvPDifficultyfmt[]="diiiii";
const char RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii";
const char ScalingStatDistributionfmt[]="niiiiiiiiiiiiiiiiiiiii";
-const char ScalingStatValuesfmt[]="iniiiiiiiiiiiiiiiiixiiii";
+const char ScalingStatValuesfmt[]="iniiiiiiiiiiiiiiiiiiiiii";
const char SkillLinefmt[]="nixssssssssssssssssxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxi";
const char SkillLineAbilityfmt[]="niiiixxiiiiixx";
const char SoundEntriesfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index fd8deb1b841..24ddd7973ab 100755
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -482,6 +482,9 @@ struct MovementInfo
// spline
float splineElevation;
+ //! Server side only:
+ bool Violated;
+
MovementInfo()
{
pos.Relocate(0, 0, 0, 0);
@@ -494,6 +497,7 @@ struct MovementInfo
t_guid = 0;
t_pos.Relocate(0, 0, 0, 0);
t_seat = -1;
+ Violated = false;
}
uint32 GetMovementFlags() { return flags; }
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index f0b974fa673..ffa216dd605 100755
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -25173,3 +25173,21 @@ bool Player::SetHover(bool enable)
return true;
}
+
+void Player::SendMovementSetCanFly(bool apply)
+{
+ WorldPacket data(apply ? SMSG_MOVE_SET_CAN_FLY : SMSG_MOVE_UNSET_CAN_FLY, 12);
+ data.append(GetPackGUID());
+ data << uint32(0); //! movement counter
+ SendDirectMessage(&data);
+}
+
+void Player::SendMovementSetCanTransitionBetweenSwimAndFly(bool apply)
+{
+ WorldPacket data(apply ?
+ SMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY :
+ SMSG_MOVE_UNSET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY, 12);
+ data.append(GetPackGUID());
+ data << uint32(0); //! movement counter
+ SendDirectMessage(&data);
+}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 7f6b2322e93..a238247b3c1 100755
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2483,6 +2483,13 @@ class Player : public Unit, public GridObject<Player>
#pragma region Player Movement
+
+ /*! These methods send different packets to the client in apply and unapply case.
+ These methods are only sent to the current unit.
+ */
+ void SendMovementSetCanFly(bool apply);
+ void SendMovementSetCanTransitionBetweenSwimAndFly(bool apply);
+
bool CanFly() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY); }
//! Return collision height sent to client
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index b60abc18753..1bf8334ae79 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -17043,6 +17043,8 @@ void Unit::_ExitVehicle(Position const* exitPosition)
else
pos = *exitPosition;
+ AddUnitState(UNIT_STATE_MOVE);
+
if (GetTypeId() == TYPEID_PLAYER)
ToPlayer()->SetFallInformation(0, GetPositionZ());
else if (HasUnitMovementFlag(MOVEMENTFLAG_ROOT))
@@ -17541,3 +17543,36 @@ void Unit::SendMovementFeatherFall()
BuildMovementPacket(&data);
SendMessageToSet(&data, true);
}
+
+void Unit::SendMovementGravityChange()
+{
+ WorldPacket data(MSG_MOVE_GRAVITY_CHNG, 64);
+ data.append(GetPackGUID());
+ BuildMovementPacket(&data);
+ SendMessageToSet(&data, true);
+}
+
+void Unit::SendMovementCanFlyChange()
+{
+ /*!
+ if ( a3->MoveFlags & MOVEMENTFLAG_CAN_FLY )
+ {
+ v4->MoveFlags |= 0x1000000u;
+ result = 1;
+ }
+ else
+ {
+ if ( v4->MoveFlags & MOVEMENTFLAG_FLYING )
+ CMovement::DisableFlying(v4);
+ v4->MoveFlags &= 0xFEFFFFFFu;
+ result = 1;
+ }
+ */
+ if (GetTypeId() == TYPEID_PLAYER)
+ ToPlayer()->SendMovementSetCanFly(CanFly());
+
+ WorldPacket data(MSG_MOVE_UPDATE_CAN_FLY, 64);
+ data.append(GetPackGUID());
+ BuildMovementPacket(&data);
+ SendMessageToSet(&data, true);
+}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index f09bf89a9c7..0e24fdffa9d 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1631,9 +1631,18 @@ class Unit : public WorldObject
//void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL);
void SendMonsterMoveTransport(Unit* vehicleOwner);
void SendMovementFlagUpdate();
+
+ /*! These methods send the same packet to the client in apply and unapply case.
+ The client-side interpretation of this packet depends on the presence of relevant movementflags
+ which are sent with movementinfo. Furthermore, these packets are broadcast to nearby players as well
+ as the current unit.
+ */
void SendMovementHover();
void SendMovementFeatherFall();
void SendMovementWaterWalking();
+ void SendMovementGravityChange();
+ void SendMovementCanFlyChange();
+
bool IsLevitating() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);}
bool IsWalking() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING);}
virtual bool SetWalk(bool enable);
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index aaa41ec3519..319cd96c332 100755
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -1621,6 +1621,12 @@ void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket & recv_data)
recv_data.read_skip<float>(); // unk2
+ if (movementInfo.Violated)
+ {
+ recv_data.rfinish();
+ return;
+ }
+
_player->m_mover->m_movementInfo.flags = movementInfo.GetMovementFlags();
}
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index 7d1233c8f70..55c55ffb246 100755
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -278,6 +278,14 @@ void WorldSession::HandleMovementOpcodes(WorldPacket & recv_data)
return;
}
+ //! If some anti-cheat checks in WorldSession::ReadMovementInfo failed, do not process
+ //! the change of movement server-sided.
+ if (movementInfo.Violated)
+ {
+ recv_data.rfinish();
+ return;
+ }
+
/* handle special cases */
if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT)
{
@@ -485,9 +493,16 @@ void WorldSession::HandleMoveNotActiveMover(WorldPacket &recv_data)
recv_data.readPackGUID(old_mover_guid);
MovementInfo mi;
- mi.guid = old_mover_guid;
ReadMovementInfo(recv_data, &mi);
+ if (mi.Violated)
+ {
+ recv_data.rfinish();
+ return;
+ }
+
+ mi.guid = old_mover_guid;
+
_player->m_movementInfo = mi;
}
@@ -513,6 +528,13 @@ void WorldSession::HandleMoveKnockBackAck(WorldPacket & recv_data)
MovementInfo movementInfo;
ReadMovementInfo(recv_data, &movementInfo);
+
+ if (movementInfo.Violated)
+ {
+ recv_data.rfinish();
+ return;
+ }
+
_player->m_movementInfo = movementInfo;
WorldPacket data(MSG_MOVE_KNOCK_BACK, 66);
@@ -571,3 +593,4 @@ void WorldSession::HandleSummonResponseOpcode(WorldPacket& recv_data)
_player->SummonIfPossible(agree);
}
+#undef IF_VIOLATED_RETURN \ No newline at end of file
diff --git a/src/server/game/Handlers/VehicleHandler.cpp b/src/server/game/Handlers/VehicleHandler.cpp
index ce4f6ccb8fe..161571998a1 100644
--- a/src/server/game/Handlers/VehicleHandler.cpp
+++ b/src/server/game/Handlers/VehicleHandler.cpp
@@ -43,6 +43,12 @@ void WorldSession::HandleDismissControlledVehicle(WorldPacket &recv_data)
mi.guid = guid;
ReadMovementInfo(recv_data, &mi);
+ if (mi.Violated)
+ {
+ recv_data.rfinish();
+ return;
+ }
+
_player->m_movementInfo = mi;
_player->ExitVehicle();
@@ -81,7 +87,16 @@ void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket &recv_data)
uint64 guid; // current vehicle guid
recv_data.readPackGUID(guid);
- ReadMovementInfo(recv_data, &vehicle_base->m_movementInfo);
+ MovementInfo movementInfo;
+ ReadMovementInfo(recv_data, &movementInfo);
+
+ if (movementInfo.Violated)
+ {
+ recv_data.rfinish();
+ return;
+ }
+
+ vehicle_base->m_movementInfo = movementInfo;
uint64 accessory; // accessory guid
recv_data.readPackGUID(accessory);
diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h
index 775b832d79a..ab6ba7e7796 100755
--- a/src/server/game/Server/Protocol/Opcodes.h
+++ b/src/server/game/Server/Protocol/Opcodes.h
@@ -1344,7 +1344,7 @@ enum Opcodes
CMSG_COMMENTATOR_SKIRMISH_QUEUE_COMMAND = 0x51B,
SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT1 = 0x51C,
SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT2 = 0x51D,
- SMSG_COMPRESSED_UNKNOWN_1310 = 0x51E, // some compressed packet?
+ SMSG_MULTIPLE_MOVES = 0x51E, // uncompressed version of SMSG_COMPRESSED_MOVES
NUM_MSG_TYPES = 0x51F
};
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 84907937de5..6ae9f4f6781 100755
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -807,48 +807,66 @@ void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo* mi)
if (mi->HasMovementFlag(MOVEMENTFLAG_SPLINE_ELEVATION))
data >> mi->splineElevation;
+ //! Anti-cheat checks. Please keep them in seperate if() blocks to maintain a clear overview.
+ #define VIOLATE_AND_RETURN \
+ mi->Violated = true; \
+ return; \
+
/*! This must be a packet spoofing attempt. MOVEMENTFLAG_ROOT sent from the client is not valid,
and when used in conjunction with any of the moving movement flags such as MOVEMENTFLAG_FORWARD
it will freeze clients that receive this player's movement info.
*/
if (mi->HasMovementFlag(MOVEMENTFLAG_ROOT))
- mi->flags &= ~MOVEMENTFLAG_ROOT;
+ VIOLATE_AND_RETURN;
//! Cannot hover and jump at the same time
if (mi->HasMovementFlag(MOVEMENTFLAG_HOVER) && mi->HasMovementFlag(MOVEMENTFLAG_JUMPING))
- mi->flags &= ~MOVEMENTFLAG_JUMPING;
+ VIOLATE_AND_RETURN;
//! Cannot ascend and descend at the same time
if (mi->HasMovementFlag(MOVEMENTFLAG_ASCENDING) && mi->HasMovementFlag(MOVEMENTFLAG_DESCENDING))
- mi->flags &= ~(MOVEMENTFLAG_ASCENDING | MOVEMENTFLAG_DESCENDING);
+ VIOLATE_AND_RETURN;
//! Cannot move left and right at the same time
if (mi->HasMovementFlag(MOVEMENTFLAG_LEFT) && mi->HasMovementFlag(MOVEMENTFLAG_RIGHT))
- mi->flags &= ~(MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT);
+ VIOLATE_AND_RETURN;
//! Cannot strafe left and right at the same time
if (mi->HasMovementFlag(MOVEMENTFLAG_STRAFE_LEFT) && mi->HasMovementFlag(MOVEMENTFLAG_STRAFE_RIGHT))
- mi->flags &= ~(MOVEMENTFLAG_STRAFE_LEFT | MOVEMENTFLAG_STRAFE_RIGHT);
+ VIOLATE_AND_RETURN;
//! Cannot pitch up and down at the same time
if (mi->HasMovementFlag(MOVEMENTFLAG_PITCH_UP) && mi->HasMovementFlag(MOVEMENTFLAG_PITCH_DOWN))
- mi->flags &= ~(MOVEMENTFLAG_PITCH_UP | MOVEMENTFLAG_PITCH_DOWN);
+ VIOLATE_AND_RETURN;
//! Cannot move forwards and backwards at the same time
if (mi->HasMovementFlag(MOVEMENTFLAG_FORWARD) && mi->HasMovementFlag(MOVEMENTFLAG_BACKWARD))
- mi->flags &= ~(MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_BACKWARD);
+ VIOLATE_AND_RETURN;
//! Cannot walk on water without SPELL_AURA_WATER_WALK
if (mi->HasMovementFlag(MOVEMENTFLAG_WATERWALKING) && !GetPlayer()->HasAuraType(SPELL_AURA_WATER_WALK))
- mi->flags &= ~MOVEMENTFLAG_WATERWALKING;
+ VIOLATE_AND_RETURN;
//! Cannot feather fall without SPELL_AURA_FEATHER_FALL
if (mi->HasMovementFlag(MOVEMENTFLAG_FALLING_SLOW) && !GetPlayer()->HasAuraType(SPELL_AURA_FEATHER_FALL))
- mi->flags &= ~MOVEMENTFLAG_FALLING_SLOW;
+ VIOLATE_AND_RETURN;
//! Cannot hover without SPELL_AURA_HOVER
if (mi->HasMovementFlag(MOVEMENTFLAG_HOVER) && !GetPlayer()->HasAuraType(SPELL_AURA_HOVER))
- mi->flags &= ~MOVEMENTFLAG_HOVER;
+ VIOLATE_AND_RETURN;
+
+ /*! Cannot fly if no fly auras present. Exception is being a GM.
+ Note that we check for account level instead of Player::IsGameMaster() because in some
+ situations it may be feasable to use .gm fly on as a GM without having .gm on,
+ e.g. aerial combat.
+ */
+
+ if (mi->HasMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY) && GetSecurity() == SEC_PLAYER &&
+ !GetPlayer()->m_mover->HasAuraType(SPELL_AURA_FLY) &&
+ !GetPlayer()->m_mover->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED))
+ VIOLATE_AND_RETURN;
+
+ #undef VIOLATE_AND_RETURN
}
void WorldSession::WriteMovementInfo(WorldPacket* data, MovementInfo* mi)
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index ddef7fdd749..1e0d1e3b08d 100755
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -2844,21 +2844,14 @@ void AuraEffect::HandleAuraAllowFlight(AuraApplication const* aurApp, uint8 mode
return;
}
- if (target->GetTypeId() == TYPEID_UNIT)
- target->SetCanFly(apply);
+ //! Not entirely sure if this should be sent for creatures as well, but I don't think so.
+ target->SetCanFly(apply);
+ Player* player = target->ToPlayer();
+ if (!player)
+ player = target->m_movedPlayer;
- if (Player* player = target->m_movedPlayer)
- {
- // allow flying
- WorldPacket data;
- if (apply)
- data.Initialize(SMSG_MOVE_SET_CAN_FLY, 12);
- else
- data.Initialize(SMSG_MOVE_UNSET_CAN_FLY, 12);
- data.append(target->GetPackGUID());
- data << uint32(0); // movement counter
- player->SendDirectMessage(&data);
- }
+ if (player)
+ player->SendMovementCanFlyChange();
}
void AuraEffect::HandleAuraWaterWalk(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -3231,25 +3224,22 @@ void AuraEffect::HandleAuraModIncreaseFlightSpeed(AuraApplication const* aurApp,
Unit* target = aurApp->GetTarget();
- // Enable Fly mode for flying mounts
+ //! Update ability to fly
if (GetAuraType() == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED)
{
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
if (mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK && (apply || (!target->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !target->HasAuraType(SPELL_AURA_FLY))))
{
- if (Player* player = target->m_movedPlayer)
- {
- WorldPacket data;
- if (apply)
- data.Initialize(SMSG_MOVE_SET_CAN_FLY, 12);
- else
- data.Initialize(SMSG_MOVE_UNSET_CAN_FLY, 12);
- data.append(player->GetPackGUID());
- data << uint32(0); // unknown
- player->SendDirectMessage(&data);
- }
+ target->SetCanFly(apply);
+ Player* player = target->ToPlayer();
+ if (!player)
+ player = target->m_movedPlayer;
+
+ if (player)
+ player->SendMovementCanFlyChange();
}
+ //! Someone should clean up these hacks and remove it from this function. It doesn't even belong here.
if (mode & AURA_EFFECT_HANDLE_REAL)
{
//Players on flying mounts must be immune to polymorph
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 0b05db07d38..21d49ccf151 100755
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -4956,10 +4956,11 @@ SpellCastResult Spell::CheckCast(bool strict)
return castResult;
bool hasDispellableAura = false;
+ bool hasNonDispelEffect = false;
for (int i = 0; i < MAX_SPELL_EFFECTS; i++)
if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_DISPEL)
{
- if (m_spellInfo->Effects[i].IsTargetingArea())
+ if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->AttributesEx & SPELL_ATTR1_MELEE_COMBAT_START)
{
hasDispellableAura = true;
break;
@@ -4976,8 +4977,13 @@ SpellCastResult Spell::CheckCast(bool strict)
}
}
}
+ else if (m_spellInfo->Effects[i].IsEffect())
+ {
+ hasNonDispelEffect = true;
+ break;
+ }
- if (!hasDispellableAura && m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL))
+ if (!hasNonDispelEffect && !hasDispellableAura && m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL))
return SPELL_FAILED_NOTHING_TO_DISPEL;
for (int i = 0; i < MAX_SPELL_EFFECTS; i++)