2010-10-07 15:35:36 +02:00
/*
2020-01-02 06:44:10 +01:00
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
2010-10-07 15:35:36 +02:00
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2015-07-26 15:09:00 +02:00
#include "WorldSession.h"
2016-07-05 22:07:35 +02:00
#include "CollectionMgr.h"
2008-10-02 16:23:55 -05:00
#include "Common.h"
2017-05-18 23:52:58 +02:00
#include "DatabaseEnv.h"
2015-07-26 15:09:00 +02:00
#include "GameObjectAI.h"
#include "GameObjectPackets.h"
2017-05-18 23:52:58 +02:00
#include "Guild.h"
2012-01-18 18:13:57 +01:00
#include "GuildMgr.h"
2017-06-04 01:00:45 +02:00
#include "Item.h"
2008-10-02 16:23:55 -05:00
#include "Log.h"
2020-06-12 01:29:18 +02:00
#include "Map.h"
2015-07-26 15:09:00 +02:00
#include "Player.h"
2017-06-04 01:00:45 +02:00
#include "ObjectAccessor.h"
2015-07-26 15:09:00 +02:00
#include "ObjectMgr.h"
2010-01-19 11:36:05 +01:00
#include "ScriptMgr.h"
2015-07-26 15:09:00 +02:00
#include "Spell.h"
2011-07-31 16:43:54 +02:00
#include "SpellAuraEffects.h"
2015-07-26 15:09:00 +02:00
#include "SpellMgr.h"
2014-11-14 02:00:34 +01:00
#include "SpellPackets.h"
2015-07-26 15:09:00 +02:00
#include "Totem.h"
#include "TotemPackets.h"
2017-05-18 23:52:58 +02:00
#include "World.h"
2009-10-17 15:51:44 -07:00
2015-02-12 02:37:42 +00:00
void WorldSession :: HandleUseItemOpcode ( WorldPackets :: Spells :: UseItem & packet )
2010-08-08 20:32:14 +02:00
{
2015-02-12 02:37:42 +00:00
Player * user = _player ;
2009-10-17 15:51:44 -07:00
2009-04-03 16:42:19 -06:00
// ignore for remote control state
2019-06-23 16:44:37 +02:00
if ( user -> GetUnitBeingMoved () != user )
2009-04-03 16:42:19 -06:00
return ;
2009-10-17 15:51:44 -07:00
2015-02-12 02:37:42 +00:00
Item * item = user -> GetUseableItemByPos ( packet . PackSlot , packet . Slot );
if ( ! item )
2008-10-02 16:23:55 -05:00
{
2020-08-14 17:06:03 +02:00
user -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , nullptr , nullptr );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2015-02-12 02:37:42 +00:00
if ( item -> GetGUID () != packet . CastItem )
2008-11-20 16:16:57 -06:00
{
2020-08-14 17:06:03 +02:00
user -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , nullptr , nullptr );
2008-11-20 16:16:57 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2015-02-12 02:37:42 +00:00
ItemTemplate const * proto = item -> GetTemplate ();
2010-03-23 14:38:31 -05:00
if ( ! proto )
2008-10-02 16:23:55 -05:00
{
2020-08-14 17:06:03 +02:00
user -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , item , nullptr );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// some item classes can be used only in equipped state
2015-02-12 02:37:42 +00:00
if ( proto -> GetInventoryType () != INVTYPE_NON_EQUIP && ! item -> IsEquipped ())
2008-10-02 16:23:55 -05:00
{
2020-08-14 17:06:03 +02:00
user -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , item , nullptr );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2015-02-12 02:37:42 +00:00
InventoryResult msg = user -> CanUseItem ( item );
2010-03-23 14:38:31 -05:00
if ( msg != EQUIP_ERR_OK )
2008-10-02 16:23:55 -05:00
{
2020-08-14 17:06:03 +02:00
user -> SendEquipError ( msg , item , nullptr );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB)
2016-09-09 10:22:57 +02:00
if ( proto -> GetClass () == ITEM_CLASS_CONSUMABLE && ! ( proto -> GetFlags () & ITEM_FLAG_IGNORE_DEFAULT_ARENA_RESTRICTIONS ) && user -> InArena ())
2008-10-02 16:23:55 -05:00
{
2020-08-14 17:06:03 +02:00
user -> SendEquipError ( EQUIP_ERR_NOT_DURING_ARENA_MATCH , item , nullptr );
2010-08-04 10:34:30 +02:00
return ;
}
// don't allow items banned in arena
2015-05-01 21:56:33 -04:00
if ( proto -> GetFlags () & ITEM_FLAG_NOT_USEABLE_IN_ARENA && user -> InArena ())
2010-08-04 10:34:30 +02:00
{
2020-08-14 17:06:03 +02:00
user -> SendEquipError ( EQUIP_ERR_NOT_DURING_ARENA_MATCH , item , nullptr );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2015-02-12 02:37:42 +00:00
if ( user -> IsInCombat ())
2008-10-02 16:23:55 -05:00
{
2020-06-05 00:27:40 +02:00
for ( ItemEffectEntry const * effect : item -> GetEffects ())
2008-10-02 16:23:55 -05:00
{
2020-06-12 01:29:18 +02:00
if ( SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( effect -> SpellID , user -> GetMap () -> GetDifficultyID ()))
2008-10-02 16:23:55 -05:00
{
2011-07-28 13:21:31 +02:00
if ( ! spellInfo -> CanBeUsedInCombat ())
2008-10-02 16:23:55 -05:00
{
2020-08-14 17:06:03 +02:00
user -> SendEquipError ( EQUIP_ERR_NOT_IN_COMBAT , item , nullptr );
2008-10-02 16:23:55 -05:00
return ;
}
}
}
}
2009-10-17 15:51:44 -07:00
2016-09-10 22:20:00 +02:00
// check also BIND_ON_ACQUIRE and BIND_QUEST for .additem or .additemset case by GM (not binded at adding to inventory)
2017-05-07 16:47:49 +02:00
if ( item -> GetBonding () == BIND_ON_USE || item -> GetBonding () == BIND_ON_ACQUIRE || item -> GetBonding () == BIND_QUEST )
2008-10-02 16:23:55 -05:00
{
2015-02-12 02:37:42 +00:00
if ( ! item -> IsSoulBound ())
2008-10-02 16:23:55 -05:00
{
2015-02-12 02:37:42 +00:00
item -> SetState ( ITEM_CHANGED , user );
item -> SetBinding ( true );
2016-07-05 22:07:35 +02:00
GetCollectionMgr () -> AddItemAppearance ( item );
2008-10-02 16:23:55 -05:00
}
}
2009-10-17 15:51:44 -07:00
2021-03-21 12:05:32 +01:00
user -> RemoveAurasWithInterruptFlags ( SpellAuraInterruptFlags :: ItemUse );
2015-02-12 02:37:42 +00:00
SpellCastTargets targets ( user , packet . Cast );
2009-10-17 15:51:44 -07:00
2010-08-08 20:32:14 +02:00
// Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state.
2016-07-17 15:20:56 +02:00
if ( ! sScriptMgr -> OnItemUse ( user , item , targets , packet . Cast . CastID ))
2008-10-02 16:23:55 -05:00
{
// no script or script not process request by self
2015-02-12 02:37:42 +00:00
user -> CastItemUseSpell ( item , targets , packet . Cast . CastID , packet . Cast . Misc );
2008-10-02 16:23:55 -05:00
}
}
2009-10-17 15:51:44 -07:00
2015-03-19 21:56:03 +01:00
void WorldSession :: HandleOpenItemOpcode ( WorldPackets :: Spells :: OpenItem & packet )
2008-10-02 16:23:55 -05:00
{
2017-01-28 05:00:28 +01:00
Player * player = GetPlayer ();
2009-10-17 15:51:44 -07:00
2009-04-03 16:42:19 -06:00
// ignore for remote control state
2019-06-23 16:44:37 +02:00
if ( player -> GetUnitBeingMoved () != player )
2009-04-03 16:42:19 -06:00
return ;
2015-03-19 21:56:03 +01:00
TC_LOG_INFO ( "network" , "bagIndex: %u, slot: %u" , packet . Slot , packet . PackSlot );
2009-10-17 15:51:44 -07:00
2017-01-28 05:00:28 +01:00
// additional check, client outputs message on its own
if ( ! player -> IsAlive ())
{
player -> SendEquipError ( EQUIP_ERR_PLAYER_DEAD , nullptr , nullptr );
return ;
}
2015-03-19 21:56:03 +01:00
Item * item = player -> GetItemByPos ( packet . Slot , packet . PackSlot );
2011-12-25 18:12:58 +01:00
if ( ! item )
2008-10-02 16:23:55 -05:00
{
2017-01-28 05:00:28 +01:00
player -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , nullptr , nullptr );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-12-25 18:12:58 +01:00
ItemTemplate const * proto = item -> GetTemplate ();
2010-04-07 19:14:10 +02:00
if ( ! proto )
2008-10-02 16:23:55 -05:00
{
2017-01-28 05:00:28 +01:00
player -> SendEquipError ( EQUIP_ERR_ITEM_NOT_FOUND , item , nullptr );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-11-14 16:26:09 +01:00
// Verify that the bag is an actual bag or wrapped item that can be used "normally"
2019-06-03 20:40:34 +02:00
if ( ! ( proto -> GetFlags () & ITEM_FLAG_HAS_LOOT ) && ! item -> HasItemFlag ( ITEM_FIELD_FLAG_WRAPPED ))
2010-11-07 20:08:52 +01:00
{
2017-01-28 05:00:28 +01:00
player -> SendEquipError ( EQUIP_ERR_CLIENT_LOCKED_OUT , item , nullptr );
2016-08-11 09:10:20 +02:00
TC_LOG_ERROR ( "entities.player.cheat" , "Possible hacking attempt: Player %s [%s] tried to open item [%s, entry: %u] which is not openable!" ,
2015-03-19 21:56:03 +01:00
player -> GetName (). c_str (), player -> GetGUID (). ToString (). c_str (), item -> GetGUID (). ToString (). c_str (), proto -> GetId ());
2010-11-07 20:08:52 +01:00
return ;
}
2008-10-02 16:23:55 -05:00
// locked item
2014-12-21 13:35:43 +01:00
uint32 lockId = proto -> GetLockID ();
2010-03-23 14:38:31 -05:00
if ( lockId )
2008-10-02 16:23:55 -05:00
{
2011-09-15 14:08:17 +02:00
LockEntry const * lockInfo = sLockStore . LookupEntry ( lockId );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if ( ! lockInfo )
{
2017-01-28 05:00:28 +01:00
player -> SendEquipError ( EQUIP_ERR_ITEM_LOCKED , item , nullptr );
2014-10-22 21:22:04 +02:00
TC_LOG_ERROR ( "network" , "WORLD::OpenItem: item [%s] has an unknown lockId: %u!" , item -> GetGUID (). ToString (). c_str (), lockId );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-08-04 10:34:30 +02:00
// was not unlocked yet
2011-12-25 18:12:58 +01:00
if ( item -> IsLocked ())
2008-10-02 16:23:55 -05:00
{
2017-01-28 05:00:28 +01:00
player -> SendEquipError ( EQUIP_ERR_ITEM_LOCKED , item , nullptr );
2008-10-02 16:23:55 -05:00
return ;
}
}
2009-10-17 15:51:44 -07:00
2019-06-03 20:40:34 +02:00
if ( item -> HasItemFlag ( ITEM_FIELD_FLAG_WRAPPED )) // wrapped?
2008-10-02 16:23:55 -05:00
{
2019-07-27 01:00:37 +02:00
CharacterDatabasePreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_GIFT_BY_ITEM );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , item -> GetGUID (). GetCounter ());
2020-04-14 16:23:44 +02:00
_queryProcessor . AddCallback ( CharacterDatabase . AsyncQuery ( stmt )
2017-01-28 05:00:28 +01:00
. WithPreparedCallback ( std :: bind ( & WorldSession :: HandleOpenWrappedItemCallback , this , item -> GetPos (), item -> GetGUID (), std :: placeholders :: _1 )));
}
else
player -> SendLoot ( item -> GetGUID (), LOOT_CORPSE );
}
2012-05-30 08:01:02 +02:00
2017-01-28 05:00:28 +01:00
void WorldSession :: HandleOpenWrappedItemCallback ( uint16 pos , ObjectGuid itemGuid , PreparedQueryResult result )
{
if ( ! GetPlayer ())
return ;
2011-12-25 18:12:58 +01:00
2017-01-28 05:00:28 +01:00
Item * item = GetPlayer () -> GetItemByPos ( pos );
if ( ! item )
return ;
2011-12-25 18:12:58 +01:00
2017-01-28 05:00:28 +01:00
if ( item -> GetGUID () != itemGuid || ! item -> HasItemFlag ( ITEM_FIELD_FLAG_WRAPPED )) // during getting result, gift was swapped with another item
return ;
2011-12-25 18:12:58 +01:00
2017-01-28 05:00:28 +01:00
if ( ! result )
{
TC_LOG_ERROR ( "network" , "Wrapped item %s don't have record in character_gifts table and will deleted" , item -> GetGUID (). ToString (). c_str ());
GetPlayer () -> DestroyItem ( item -> GetBagSlot (), item -> GetSlot (), true );
return ;
2008-10-02 16:23:55 -05:00
}
2017-01-28 05:00:28 +01:00
2019-07-27 10:52:33 +02:00
CharacterDatabaseTransaction trans = CharacterDatabase . BeginTransaction ();
2017-01-28 05:00:28 +01:00
Field * fields = result -> Fetch ();
uint32 entry = fields [ 0 ]. GetUInt32 ();
uint32 flags = fields [ 1 ]. GetUInt32 ();
item -> SetGiftCreator ( ObjectGuid :: Empty );
item -> SetEntry ( entry );
item -> SetItemFlags ( ItemFieldFlags ( flags ));
2017-03-20 18:34:20 +01:00
item -> SetMaxDurability ( item -> GetTemplate () -> MaxDurability );
2017-01-28 05:00:28 +01:00
item -> SetState ( ITEM_CHANGED , GetPlayer ());
GetPlayer () -> SaveInventoryAndGoldToDB ( trans );
2019-07-27 01:00:37 +02:00
CharacterDatabasePreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_GIFT );
2017-01-28 05:00:28 +01:00
stmt -> setUInt64 ( 0 , itemGuid . GetCounter ());
trans -> Append ( stmt );
CharacterDatabase . CommitTransaction ( trans );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2015-04-01 01:44:10 +02:00
void WorldSession :: HandleGameObjectUseOpcode ( WorldPackets :: GameObject :: GameObjUse & packet )
2008-10-02 16:23:55 -05:00
{
2016-02-06 18:14:28 +01:00
if ( GameObject * obj = GetPlayer () -> GetGameObjectIfCanInteractWith ( packet . Guid ))
2013-03-09 05:20:42 +02:00
{
// ignore for remote control state
2019-06-23 16:44:37 +02:00
if ( GetPlayer () -> GetUnitBeingMoved () != GetPlayer ())
if ( ! ( GetPlayer () -> IsOnVehicle ( GetPlayer () -> GetUnitBeingMoved ()) || GetPlayer () -> IsMounted ()) && ! obj -> GetGOInfo () -> IsUsableMounted ())
2013-03-09 05:20:42 +02:00
return ;
2014-01-25 16:59:01 +01:00
obj -> Use ( GetPlayer ());
2013-03-09 05:20:42 +02:00
}
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2015-04-01 01:44:10 +02:00
void WorldSession :: HandleGameobjectReportUse ( WorldPackets :: GameObject :: GameObjReportUse & packet )
2008-12-27 11:39:40 -06:00
{
2009-04-03 16:42:19 -06:00
// ignore for remote control state
2019-06-23 16:44:37 +02:00
if ( _player -> GetUnitBeingMoved () != _player )
2009-04-03 16:42:19 -06:00
return ;
2009-10-17 15:51:44 -07:00
2016-02-06 18:14:28 +01:00
if ( GameObject * go = GetPlayer () -> GetGameObjectIfCanInteractWith ( packet . Guid ))
{
2017-06-06 20:36:01 +02:00
if ( go -> AI () -> OnReportUse ( _player ))
2016-02-06 18:14:28 +01:00
return ;
2010-11-20 13:54:45 +01:00
2021-09-08 22:07:01 +02:00
_player -> UpdateCriteria ( CriteriaType :: UseGameobject , go -> GetEntry ());
2016-02-06 18:14:28 +01:00
}
2008-12-27 11:39:40 -06:00
}
2009-10-17 15:51:44 -07:00
2015-01-30 23:58:16 +01:00
void WorldSession :: HandleCastSpellOpcode ( WorldPackets :: Spells :: CastSpell & cast )
2008-10-02 16:23:55 -05:00
{
2009-04-03 16:42:19 -06:00
// ignore for remote control state (for player case)
2019-06-23 16:44:37 +02:00
Unit * mover = _player -> GetUnitBeingMoved ();
2010-03-23 14:38:31 -05:00
if ( mover != _player && mover -> GetTypeId () == TYPEID_PLAYER )
2009-04-03 16:42:19 -06:00
return ;
2009-10-17 15:51:44 -07:00
2020-06-12 01:29:18 +02:00
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( cast . Cast . SpellID , mover -> GetMap () -> GetDifficultyID ());
2010-03-23 14:38:31 -05:00
if ( ! spellInfo )
2008-10-02 16:23:55 -05:00
{
2015-01-30 23:58:16 +01:00
TC_LOG_ERROR ( "network" , "WORLD: unknown spell id %u" , cast . Cast . SpellID );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2013-02-27 13:17:20 +01:00
if ( spellInfo -> IsPassive ())
return ;
Unit * caster = mover ;
2015-01-30 23:58:16 +01:00
if ( caster -> GetTypeId () == TYPEID_UNIT && ! caster -> ToCreature () -> HasSpell ( spellInfo -> Id ))
2009-04-03 16:42:19 -06:00
{
2013-02-27 13:17:20 +01:00
// If the vehicle creature does not have the spell but it allows the passenger to cast own spells
// change caster to player and let him cast
if ( ! _player -> IsOnVehicle ( caster ) || spellInfo -> CheckVehicle ( _player ) != SPELL_CAST_OK )
2009-04-03 16:42:19 -06:00
return ;
2013-02-27 13:17:20 +01:00
caster = _player ;
}
2019-05-02 21:53:12 +02:00
TriggerCastFlags triggerFlag = TRIGGERED_NONE ;
// client provided targets
SpellCastTargets targets ( caster , cast . Cast );
2015-05-19 02:55:53 +01:00
// check known spell or raid marker spell (which not requires player to know it)
2015-09-02 22:58:04 +02:00
if ( caster -> GetTypeId () == TYPEID_PLAYER && ! caster -> ToPlayer () -> HasActiveSpell ( spellInfo -> Id ) && ! spellInfo -> HasEffect ( SPELL_EFFECT_CHANGE_RAID_MARKER ) && ! spellInfo -> HasAttribute ( SPELL_ATTR8_RAID_MARKER ))
2019-05-02 21:53:12 +02:00
{
bool allow = false ;
// allow casting of unknown spells for special lock cases
if ( GameObject * go = targets . GetGOTarget ())
if ( go -> GetSpellForLock ( caster -> ToPlayer ()) == spellInfo )
allow = true ;
// TODO: Preparation for #23204
// allow casting of spells triggered by clientside periodic trigger auras
/*
if (caster->HasAuraTypeWithTriggerSpell(SPELL_AURA_PERIODIC_TRIGGER_SPELL_FROM_CLIENT, spellId))
{
allow = true;
triggerFlag = TRIGGERED_FULL_MASK;
}
*/
if ( ! allow )
return ;
}
2012-08-13 14:56:56 +02:00
2015-01-30 23:58:16 +01:00
// Check possible spell cast overrides
spellInfo = caster -> GetCastSpellInfo ( spellInfo );
2012-08-13 14:56:56 +02:00
2008-11-05 20:51:05 -06:00
// can't use our own spells when we're in possession of another unit,
2010-03-23 14:38:31 -05:00
if ( _player -> isPossessing ())
2008-11-05 20:51:05 -06:00
return ;
2009-10-17 15:51:44 -07:00
2018-02-14 23:11:38 -03:00
// Client is resending autoshot cast opcode when other spell is cast during shoot rotation
// Skip it to prevent "interrupt" message
// Also check targets! target may have changed and we need to interrupt current spell
if ( spellInfo -> IsAutoRepeatRangedSpell ())
if ( Spell * spell = caster -> GetCurrentSpell ( CURRENT_AUTOREPEAT_SPELL ))
if ( spell -> m_spellInfo == spellInfo && spell -> m_targets . GetUnitTargetGUID () == targets . GetUnitTargetGUID ())
return ;
2008-10-02 16:23:55 -05:00
// auto-selection buff level base at target level (in spellInfo)
2011-06-23 13:28:52 +02:00
if ( targets . GetUnitTarget ())
2008-10-02 16:23:55 -05:00
{
2017-07-29 21:40:28 +02:00
SpellInfo const * actualSpellInfo = spellInfo -> GetAuraRankForLevel ( targets . GetUnitTarget () -> GetLevelForTarget ( caster ));
2009-10-17 15:51:44 -07:00
2013-12-25 14:16:55 -03:30
// if rank not found then function return NULL but in explicit cast case original spell can be cast and later failed with appropriate error message
2010-03-23 14:38:31 -05:00
if ( actualSpellInfo )
2008-10-02 16:23:55 -05:00
spellInfo = actualSpellInfo ;
}
2009-10-17 15:51:44 -07:00
2017-02-25 22:13:00 +01:00
if ( cast . Cast . MoveUpdate )
HandleMovementOpcode ( CMSG_MOVE_STOP , * cast . Cast . MoveUpdate );
2019-05-02 21:53:12 +02:00
Spell * spell = new Spell ( caster , spellInfo , triggerFlag );
2016-06-05 14:08:53 +02:00
WorldPackets :: Spells :: SpellPrepare spellPrepare ;
spellPrepare . ClientCastID = cast . Cast . CastID ;
spellPrepare . ServerCastID = spell -> m_castId ;
SendPacket ( spellPrepare . Write ());
2017-01-13 18:54:15 +01:00
spell -> m_fromClient = true ;
2015-07-18 00:45:21 +02:00
spell -> m_misc . Raw . Data [ 0 ] = cast . Cast . Misc [ 0 ];
spell -> m_misc . Raw . Data [ 1 ] = cast . Cast . Misc [ 1 ];
2017-12-30 20:28:41 +01:00
spell -> prepare ( targets );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2015-03-13 17:19:33 +01:00
void WorldSession :: HandleCancelCastOpcode ( WorldPackets :: Spells :: CancelCast & packet )
2008-10-02 16:23:55 -05:00
{
2013-12-25 14:16:55 -03:30
if ( _player -> IsNonMeleeSpellCast ( false ))
2015-03-13 17:19:33 +01:00
_player -> InterruptNonMeleeSpells ( false , packet . SpellID , false );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2015-01-26 12:59:18 +01:00
void WorldSession :: HandleCancelAuraOpcode ( WorldPackets :: Spells :: CancelAura & cancelAura )
2008-10-02 16:23:55 -05:00
{
2020-06-12 01:29:18 +02:00
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( cancelAura . SpellID , _player -> GetMap () -> GetDifficultyID ());
2008-10-02 16:23:55 -05:00
if ( ! spellInfo )
return ;
2009-10-17 15:51:44 -07:00
2011-09-03 17:06:20 +02:00
// not allow remove spells with attr SPELL_ATTR0_CANT_CANCEL
2015-01-05 23:49:43 +02:00
if ( spellInfo -> HasAttribute ( SPELL_ATTR0_CANT_CANCEL ))
2010-07-21 14:48:44 +02:00
return ;
2013-12-25 14:16:55 -03:30
// channeled spell case (it currently cast then)
2011-07-26 23:09:28 +02:00
if ( spellInfo -> IsChanneled ())
2008-11-05 20:51:05 -06:00
{
2009-08-19 16:52:51 -05:00
if ( Spell * curSpell = _player -> GetCurrentSpell ( CURRENT_CHANNELED_SPELL ))
2015-03-22 13:47:55 +01:00
if ( curSpell -> GetSpellInfo () -> Id == uint32 ( cancelAura . SpellID ))
2009-08-19 16:52:51 -05:00
_player -> InterruptSpell ( CURRENT_CHANNELED_SPELL );
2008-10-02 16:23:55 -05:00
return ;
2008-11-21 21:00:45 -05:00
}
2009-10-17 15:51:44 -07:00
2011-09-03 17:06:20 +02:00
// non channeled case:
// don't allow remove non positive spells
// don't allow cancelling passive auras (some of them are visible)
if ( ! spellInfo -> IsPositive () || spellInfo -> IsPassive ())
return ;
2015-01-26 12:59:18 +01:00
_player -> RemoveOwnedAura ( cancelAura . SpellID , cancelAura . CasterGUID , 0 , AURA_REMOVE_BY_CANCEL );
2014-03-02 18:09:02 -05:00
// If spell being removed is a resource tracker, see if player was tracking both (herbs / minerals) and remove the other
2020-06-12 01:29:18 +02:00
if ( sWorld -> getBoolConfig ( CONFIG_ALLOW_TRACK_BOTH_RESOURCES ) && spellInfo -> HasAura ( SPELL_AURA_TRACK_RESOURCES ))
2014-03-02 18:09:02 -05:00
{
Unit :: AuraEffectList const & auraEffects = _player -> GetAuraEffectsByType ( SPELL_AURA_TRACK_RESOURCES );
if ( ! auraEffects . empty ())
{
// Build list of spell IDs to cancel. Trying to cancel the aura while iterating
// over AuraEffectList caused "incompatible iterator" errors on second pass
std :: list < uint32 > spellIDs ;
2014-09-19 03:30:02 +01:00
for ( Unit :: AuraEffectList :: const_iterator auraEffect = auraEffects . begin (); auraEffect != auraEffects . end (); ++ auraEffect )
2014-03-02 18:09:02 -05:00
spellIDs . push_back (( * auraEffect ) -> GetId ());
// Remove all auras related to resource tracking (only Herbs and Minerals in 3.3.5a)
2014-09-19 03:30:02 +01:00
for ( std :: list < uint32 >:: iterator it = spellIDs . begin (); it != spellIDs . end (); ++ it )
2015-01-26 12:59:18 +01:00
_player -> RemoveOwnedAura ( * it , cancelAura . CasterGUID , 0 , AURA_REMOVE_BY_CANCEL );
2014-03-02 18:09:02 -05:00
}
}
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2016-02-02 01:38:29 +01:00
void WorldSession :: HandlePetCancelAuraOpcode ( WorldPackets :: Spells :: PetCancelAura & packet )
2008-10-02 16:23:55 -05:00
{
2020-06-12 01:29:18 +02:00
if ( sSpellMgr -> GetSpellInfo ( packet . SpellID , DIFFICULTY_NONE ))
2008-10-02 16:23:55 -05:00
{
2016-02-02 01:38:29 +01:00
TC_LOG_ERROR ( "network" , "WORLD: unknown PET spell id %u" , packet . SpellID );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2016-02-02 01:38:29 +01:00
Creature * pet = ObjectAccessor :: GetCreatureOrPetOrVehicle ( * _player , packet . PetGUID );
2009-10-17 15:51:44 -07:00
2010-03-23 14:38:31 -05:00
if ( ! pet )
2008-10-02 16:23:55 -05:00
{
2016-02-02 01:38:29 +01:00
TC_LOG_ERROR ( "network" , "HandlePetCancelAura: Attempt to cancel an aura for non-existant %s by player '%s'" , packet . PetGUID . ToString (). c_str (), GetPlayer () -> GetName (). c_str ());
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2018-08-25 00:27:37 +02:00
if ( pet != GetPlayer () -> GetGuardianPet () && pet != GetPlayer () -> GetCharmed ())
2008-10-02 16:23:55 -05:00
{
2016-02-02 01:38:29 +01:00
TC_LOG_ERROR ( "network" , "HandlePetCancelAura: %s is not a pet of player '%s'" , packet . PetGUID . ToString (). c_str (), GetPlayer () -> GetName (). c_str ());
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2013-06-11 19:54:27 -02:30
if ( ! pet -> IsAlive ())
2008-10-02 16:23:55 -05:00
{
2020-07-02 00:07:38 +02:00
pet -> SendPetActionFeedback ( PetActionFeedback :: Dead , 0 );
2008-10-02 16:23:55 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2016-02-02 01:38:29 +01:00
pet -> RemoveOwnedAura ( packet . SpellID , ObjectGuid :: Empty , 0 , AURA_REMOVE_BY_CANCEL );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2015-04-10 00:13:44 +02:00
void WorldSession :: HandleCancelGrowthAuraOpcode ( WorldPackets :: Spells :: CancelGrowthAura & /*cancelGrowthAura*/ )
{
_player -> RemoveAurasByType ( SPELL_AURA_MOD_SCALE , []( AuraApplication const * aurApp )
{
SpellInfo const * spellInfo = aurApp -> GetBase () -> GetSpellInfo ();
return ! spellInfo -> HasAttribute ( SPELL_ATTR0_CANT_CANCEL ) && spellInfo -> IsPositive () && ! spellInfo -> IsPassive ();
});
}
void WorldSession :: HandleCancelMountAuraOpcode ( WorldPackets :: Spells :: CancelMountAura & /*cancelMountAura*/ )
{
_player -> RemoveAurasByType ( SPELL_AURA_MOUNTED , []( AuraApplication const * aurApp )
{
SpellInfo const * spellInfo = aurApp -> GetBase () -> GetSpellInfo ();
return ! spellInfo -> HasAttribute ( SPELL_ATTR0_CANT_CANCEL ) && spellInfo -> IsPositive () && ! spellInfo -> IsPassive ();
});
}
2009-10-17 15:51:44 -07:00
2015-09-27 00:05:33 +02:00
void WorldSession :: HandleCancelAutoRepeatSpellOpcode ( WorldPackets :: Spells :: CancelAutoRepeatSpell & /*cancelAutoRepeatSpell*/ )
2008-10-02 16:23:55 -05:00
{
// may be better send SMSG_CANCEL_AUTO_REPEAT?
// cancel and prepare for deleting
2009-04-28 00:06:48 -05:00
_player -> InterruptSpell ( CURRENT_AUTOREPEAT_SPELL );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2015-12-17 23:10:00 +01:00
void WorldSession :: HandleCancelChanneling ( WorldPackets :: Spells :: CancelChannelling & /*cancelChanneling*/ )
2008-10-02 16:23:55 -05:00
{
2009-08-19 16:55:35 -05:00
// ignore for remote control state (for player case)
2019-06-23 16:44:37 +02:00
Unit * mover = _player -> GetUnitBeingMoved ();
2010-03-23 14:38:31 -05:00
if ( mover != _player && mover -> GetTypeId () == TYPEID_PLAYER )
2009-08-19 16:55:35 -05:00
return ;
2009-10-17 15:51:44 -07:00
2009-08-19 16:55:35 -05:00
mover -> InterruptSpell ( CURRENT_CHANNELED_SPELL );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2015-07-26 15:09:00 +02:00
void WorldSession :: HandleTotemDestroyed ( WorldPackets :: Totem :: TotemDestroyed & totemDestroyed )
2008-10-02 16:23:55 -05:00
{
2009-04-03 16:42:19 -06:00
// ignore for remote control state
2019-06-23 16:44:37 +02:00
if ( _player -> GetUnitBeingMoved () != _player )
2009-04-03 16:42:19 -06:00
return ;
2009-10-17 15:51:44 -07:00
2015-07-26 15:09:00 +02:00
uint8 slotId = totemDestroyed . Slot ;
slotId += SUMMON_SLOT_TOTEM ;
2009-10-17 15:51:44 -07:00
2009-03-27 22:47:28 -06:00
if ( slotId >= MAX_TOTEM_SLOT )
2008-10-02 16:23:55 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-03-23 14:38:31 -05:00
if ( ! _player -> m_SummonSlot [ slotId ])
2008-10-02 16:23:55 -05:00
return ;
2009-10-17 15:51:44 -07:00
2020-09-04 13:38:24 +02:00
Creature * totem = ObjectAccessor :: GetCreature ( * _player , _player -> m_SummonSlot [ slotId ]);
2015-07-26 15:09:00 +02:00
if ( totem && totem -> IsTotem () && totem -> GetGUID () == totemDestroyed . TotemGUID )
2010-03-23 14:38:31 -05:00
totem -> ToTotem () -> UnSummon ();
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2018-02-04 00:11:10 +01:00
void WorldSession :: HandleSelfResOpcode ( WorldPackets :: Spells :: SelfRes & selfRes )
2008-10-02 16:23:55 -05:00
{
2011-09-06 14:23:53 +02:00
if ( _player -> HasAuraType ( SPELL_AURA_PREVENT_RESURRECTION ))
2011-08-21 14:38:21 +02:00
return ; // silent return, client should display error by itself and not send this opcode
2017-12-30 20:28:41 +01:00
if ( _player -> m_activePlayerData -> SelfResSpells . FindIndex ( selfRes . SpellID ) < 0 )
2018-02-04 00:11:10 +01:00
return ;
2009-10-17 15:51:44 -07:00
2017-12-30 20:28:41 +01:00
_player -> CastSpell ( _player , selfRes . SpellID , _player -> GetMap () -> GetDifficultyID ());
2019-06-03 20:40:34 +02:00
_player -> RemoveSelfResSpell ( selfRes . SpellID );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2015-07-21 00:33:36 +02:00
void WorldSession :: HandleSpellClick ( WorldPackets :: Spells :: SpellClick & spellClick )
2009-05-05 16:56:15 -05:00
{
2009-08-26 23:40:28 -05:00
// this will get something not in world. crash
2015-07-21 00:33:36 +02:00
Creature * unit = ObjectAccessor :: GetCreatureOrPetOrVehicle ( * _player , spellClick . SpellClickUnitGuid );
2009-10-17 16:20:24 -07:00
2010-03-23 14:38:31 -05:00
if ( ! unit )
2009-05-05 16:56:15 -05:00
return ;
2009-10-17 15:51:44 -07:00
2013-03-08 21:41:30 +01:00
/// @todo Unit::SetCharmedBy: 28782 is not in world but 0 is trying to charm it! -> crash
2010-04-07 19:14:10 +02:00
if ( ! unit -> IsInWorld ())
2009-08-27 11:08:55 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-03-08 19:11:02 +01:00
unit -> HandleSpellClick ( _player );
2009-05-05 16:56:15 -05:00
}
2009-10-17 15:51:44 -07:00
2015-07-21 00:33:36 +02:00
void WorldSession :: HandleMirrorImageDataRequest ( WorldPackets :: Spells :: GetMirrorImageData & getMirrorImageData )
2009-07-22 17:10:30 +02:00
{
2015-07-21 00:33:36 +02:00
ObjectGuid guid = getMirrorImageData . UnitGUID ;
2009-10-17 15:51:44 -07:00
2009-07-22 17:10:30 +02:00
// Get unit for which data is needed by client
2015-02-25 00:13:14 +01:00
Unit * unit = ObjectAccessor :: GetUnit ( * _player , guid );
2010-03-23 14:38:31 -05:00
if ( ! unit )
2009-07-22 17:10:30 +02:00
return ;
2010-03-23 14:38:31 -05:00
2011-07-31 16:43:54 +02:00
if ( ! unit -> HasAuraType ( SPELL_AURA_CLONE_CASTER ))
return ;
// Get creator of the unit (SPELL_AURA_CLONE_CASTER does not stack)
Unit * creator = unit -> GetAuraEffectsByType ( SPELL_AURA_CLONE_CASTER ). front () -> GetCaster ();
2009-07-22 17:10:30 +02:00
if ( ! creator )
return ;
2010-03-23 14:38:31 -05:00
2015-06-15 02:03:00 +03:00
if ( Player * player = creator -> ToPlayer ())
2009-07-22 17:10:30 +02:00
{
2015-07-21 00:33:36 +02:00
WorldPackets :: Spells :: MirrorImageComponentedData mirrorImageComponentedData ;
mirrorImageComponentedData . UnitGUID = guid ;
mirrorImageComponentedData . DisplayID = creator -> GetDisplayId ();
2019-07-01 21:36:32 +02:00
mirrorImageComponentedData . RaceID = creator -> GetRace ();
mirrorImageComponentedData . Gender = creator -> GetGender ();
mirrorImageComponentedData . ClassID = creator -> GetClass ();
2012-01-18 18:26:15 +01:00
2012-01-18 18:13:57 +01:00
2020-12-01 21:08:06 +01:00
for ( UF :: ChrCustomizationChoice const & customization : player -> m_playerData -> Customizations )
mirrorImageComponentedData . Customizations . push_back ( customization );
Guild * guild = player -> GetGuild ();
2015-07-21 00:33:36 +02:00
mirrorImageComponentedData . GuildGUID = ( guild ? guild -> GetGUID () : ObjectGuid :: Empty );
2015-06-15 02:03:00 +03:00
2015-07-21 00:33:36 +02:00
mirrorImageComponentedData . ItemDisplayID . reserve ( 11 );
2011-07-31 16:43:54 +02:00
static EquipmentSlots const itemSlots [] =
2009-07-22 17:10:30 +02:00
{
EQUIPMENT_SLOT_HEAD ,
EQUIPMENT_SLOT_SHOULDERS ,
EQUIPMENT_SLOT_BODY ,
EQUIPMENT_SLOT_CHEST ,
EQUIPMENT_SLOT_WAIST ,
EQUIPMENT_SLOT_LEGS ,
EQUIPMENT_SLOT_FEET ,
EQUIPMENT_SLOT_WRISTS ,
EQUIPMENT_SLOT_HANDS ,
EQUIPMENT_SLOT_TABARD ,
2015-06-21 12:04:50 +03:00
EQUIPMENT_SLOT_BACK ,
2009-07-22 17:10:30 +02:00
};
2010-03-23 14:38:31 -05:00
2009-07-22 17:10:30 +02:00
// Display items in visible slots
2016-06-05 14:08:53 +02:00
for ( EquipmentSlots slot : itemSlots )
2009-08-29 02:28:02 +02:00
{
2015-06-15 02:03:00 +03:00
uint32 itemDisplayId ;
2019-06-03 20:40:34 +02:00
if ( Item const * item = player -> GetItemByPos ( INVENTORY_SLOT_BAG_0 , slot ))
2016-07-05 22:07:35 +02:00
itemDisplayId = item -> GetDisplayId ( player );
2009-07-22 17:10:30 +02:00
else
2015-06-15 02:03:00 +03:00
itemDisplayId = 0 ;
2015-07-21 00:33:36 +02:00
mirrorImageComponentedData . ItemDisplayID . push_back ( itemDisplayId );
2009-08-29 02:28:02 +02:00
}
2015-07-21 00:33:36 +02:00
SendPacket ( mirrorImageComponentedData . Write ());
2009-07-22 17:10:30 +02:00
}
else
{
2015-07-21 00:33:36 +02:00
WorldPackets :: Spells :: MirrorImageCreatureData mirrorImageCreatureData ;
mirrorImageCreatureData . UnitGUID = guid ;
mirrorImageCreatureData . DisplayID = creator -> GetDisplayId ();
SendPacket ( mirrorImageCreatureData . Write ());
2010-03-23 14:38:31 -05:00
}
2009-07-22 17:10:30 +02:00
}
2011-04-11 21:24:02 +02:00
2016-02-03 01:25:01 +01:00
void WorldSession :: HandleMissileTrajectoryCollision ( WorldPackets :: Spells :: MissileTrajectoryCollision & packet )
2011-04-11 21:24:02 +02:00
{
2016-02-03 01:25:01 +01:00
Unit * caster = ObjectAccessor :: GetUnit ( * _player , packet . Target );
2012-06-03 05:41:30 +02:00
if ( ! caster )
return ;
2016-02-03 01:25:01 +01:00
Spell * spell = caster -> FindCurrentSpellBySpellId ( packet . SpellID );
2012-06-03 05:41:30 +02:00
if ( ! spell || ! spell -> m_targets . HasDst ())
return ;
Position pos = * spell -> m_targets . GetDstPos ();
2016-02-03 01:48:02 +01:00
pos . Relocate ( packet . CollisionPos );
2012-06-03 05:41:30 +02:00
spell -> m_targets . ModDst ( pos );
2012-05-30 08:01:02 +02:00
2017-02-06 01:10:15 +01:00
// we changed dest, recalculate flight time
spell -> RecalculateDelayMomentForDst ();
2016-02-06 23:05:55 +01:00
WorldPackets :: Spells :: NotifyMissileTrajectoryCollision notify ;
notify . Caster = packet . Target ;
notify . CastID = packet . CastID ;
notify . CollisionPos = packet . CollisionPos ;
caster -> SendMessageToSet ( notify . Write (), true );
2011-04-11 21:24:02 +02:00
}
2013-06-07 20:35:30 +02:00
2016-02-03 15:10:58 +01:00
void WorldSession :: HandleUpdateMissileTrajectory ( WorldPackets :: Spells :: UpdateMissileTrajectory & packet )
{
Unit * caster = ObjectAccessor :: GetUnit ( * _player , packet . Guid );
2020-08-14 17:06:03 +02:00
Spell * spell = caster ? caster -> GetCurrentSpell ( CURRENT_GENERIC_SPELL ) : nullptr ;
2021-11-02 22:53:56 +01:00
if ( ! spell || spell -> m_spellInfo -> Id != uint32 ( packet . SpellID ) || spell -> m_castId != packet . CastID || ! spell -> m_targets . HasDst () || ! spell -> m_targets . HasSrc ())
2016-02-03 15:10:58 +01:00
return ;
2017-05-16 22:16:21 +02:00
spell -> m_targets . ModSrc ( packet . FirePos );
spell -> m_targets . ModDst ( packet . ImpactPos );
2016-02-03 15:10:58 +01:00
spell -> m_targets . SetPitch ( packet . Pitch );
spell -> m_targets . SetSpeed ( packet . Speed );
2017-05-16 22:16:21 +02:00
if ( packet . Status )
HandleMovementOpcode ( CMSG_MOVE_STOP , * packet . Status );
2016-02-03 15:10:58 +01:00
}
2015-04-08 21:49:14 +02:00
void WorldSession :: HandleRequestCategoryCooldowns ( WorldPackets :: Spells :: RequestCategoryCooldowns & /*requestCategoryCooldowns*/ )
2013-06-07 20:35:30 +02:00
{
2015-04-18 17:29:14 +02:00
_player -> SendSpellCategoryCooldowns ();
2013-06-07 20:35:30 +02:00
}