2008-10-11 14:16:25 -05:00
/*
2009-02-04 12:42:26 +01:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2009-02-04 12:04:12 +01:00
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
2008-10-11 14:16:25 -05: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
2008-11-03 09:53:31 -06:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-11 14:16:25 -05:00
* 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, write to the Free Software
2008-11-03 09:53:31 -06:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-11 14:16:25 -05:00
*/
#include "Common.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Log.h"
#include "Opcodes.h"
#include "Spell.h"
#include "ObjectAccessor.h"
#include "CreatureAI.h"
#include "Util.h"
#include "Pet.h"
void WorldSession :: HandlePetAction ( WorldPacket & recv_data )
{
2008-12-12 11:21:28 -06:00
CHECK_PACKET_SIZE ( recv_data , 8 + 2 + 2 + 8 );
2008-10-11 14:16:25 -05:00
uint64 guid1 ;
uint16 spellid ;
uint16 flag ;
uint64 guid2 ;
recv_data >> guid1 ; //pet guid
recv_data >> spellid ;
recv_data >> flag ; //delete = 0x0700 CastSpell = C100
recv_data >> guid2 ; //tag guid
// used also for charmed creature
2008-12-12 11:21:28 -06:00
Unit * pet = ObjectAccessor :: GetUnit ( * _player , guid1 );
2009-03-09 17:56:51 -06:00
sLog . outDetail ( "HandlePetAction.Pet %u flag is %u, spellid is %u, target %u." , uint32 ( GUID_LOPART ( guid1 )), flag , spellid , uint32 ( GUID_LOPART ( guid2 )) );
2008-10-11 14:16:25 -05:00
if ( ! pet )
{
2009-03-09 17:56:51 -06:00
sLog . outError ( "Pet %u not exist." , uint32 ( GUID_LOPART ( guid1 )) );
2008-10-11 14:16:25 -05:00
return ;
}
2009-03-21 10:17:24 -06:00
if ( pet != GetPlayer () -> GetFirstControlled ())
2008-10-11 14:16:25 -05:00
{
2009-03-09 17:56:51 -06:00
sLog . outError ( "HandlePetAction.Pet %u isn't pet of player %s." , uint32 ( GUID_LOPART ( guid1 )), GetPlayer () -> GetName () );
2008-10-11 14:16:25 -05:00
return ;
}
2009-03-21 11:15:55 -06:00
//TODO: allow control charmed player?
2008-10-11 14:16:25 -05:00
if ( pet -> GetTypeId () == TYPEID_PLAYER && ! ( flag == ACT_COMMAND && spellid == COMMAND_ATTACK ))
return ;
2009-03-21 13:42:09 -06:00
if ( GetPlayer () -> m_Controlled . size () == 1 )
HandlePetActionHelper ( pet , guid1 , spellid , flag , guid2 );
else
2009-03-21 12:16:14 -06:00
{
2009-03-21 13:42:09 -06:00
//If a pet is dismissed, m_Controlled will change
std :: vector < Unit *> controlled ;
2009-04-03 16:28:15 -06:00
for ( Unit :: ControlList :: iterator itr = GetPlayer () -> m_Controlled . begin (); itr != GetPlayer () -> m_Controlled . end (); ++ itr )
2009-03-21 13:42:09 -06:00
if (( * itr ) -> GetEntry () == pet -> GetEntry () && ( * itr ) -> isAlive ())
controlled . push_back ( * itr );
for ( std :: vector < Unit *>:: iterator itr = controlled . begin (); itr != controlled . end (); ++ itr )
HandlePetActionHelper ( * itr , guid1 , spellid , flag , guid2 );
2009-03-21 12:16:14 -06:00
}
2009-03-21 11:15:55 -06:00
}
void WorldSession :: HandlePetActionHelper ( Unit * pet , uint64 guid1 , uint16 spellid , uint16 flag , uint64 guid2 )
{
2008-10-11 14:16:25 -05:00
CharmInfo * charmInfo = pet -> GetCharmInfo ();
if ( ! charmInfo )
{
sLog . outError ( "WorldSession::HandlePetAction: object " I64FMTD " is considered pet-like but doesn't have a charminfo!" , pet -> GetGUID ());
return ;
}
switch ( flag )
{
case ACT_COMMAND : //0x0700
2008-11-10 22:51:37 -06:00
// Possessed or shared vision pets are only able to attack
if (( pet -> isPossessed () || pet -> HasAuraType ( SPELL_AURA_BIND_SIGHT )) && spellid != COMMAND_ATTACK )
2008-11-08 23:32:15 -06:00
return ;
2008-10-11 14:16:25 -05:00
switch ( spellid )
{
case COMMAND_STAY : //flat=1792 //STAY
2009-03-12 14:15:44 -06:00
pet -> AttackStop ();
pet -> InterruptNonMeleeSpells ( false );
2008-10-11 14:16:25 -05:00
pet -> GetMotionMaster () -> MoveIdle ();
charmInfo -> SetCommandState ( COMMAND_STAY );
break ;
case COMMAND_FOLLOW : //spellid=1792 //FOLLOW
pet -> AttackStop ();
2009-03-12 14:15:44 -06:00
pet -> InterruptNonMeleeSpells ( false );
2008-10-11 14:16:25 -05:00
pet -> GetMotionMaster () -> MoveFollow ( _player , PET_FOLLOW_DIST , PET_FOLLOW_ANGLE );
charmInfo -> SetCommandState ( COMMAND_FOLLOW );
break ;
case COMMAND_ATTACK : //spellid=1792 //ATTACK
{
2008-11-20 20:27:04 -05:00
// Can't attack if owner is pacified
if ( _player -> HasAuraType ( SPELL_AURA_MOD_PACIFY ))
{
//pet->SendPetCastFail(spellid, SPELL_FAILED_PACIFIED);
//TODO: Send proper error message to client
return ;
}
2008-10-11 14:16:25 -05:00
// only place where pet can be player
pet -> clearUnitState ( UNIT_STAT_FOLLOW );
2009-01-21 16:18:57 -06:00
const uint64 & selguid = _player -> GetSelection ();
2008-10-11 14:16:25 -05:00
Unit * TargetUnit = ObjectAccessor :: GetUnit ( * _player , selguid );
if ( ! TargetUnit )
return ;
// not let attack friendly units.
2008-11-28 11:38:28 -06:00
if ( GetPlayer () -> IsFriendlyTo ( TargetUnit ))
return ;
// Not let attack through obstructions
2008-12-06 20:05:00 -06:00
//if(!pet->IsWithinLOSInMap(TargetUnit))
// return;
2008-10-11 14:16:25 -05:00
2009-01-21 16:18:57 -06:00
// This is true if pet has no target or has target but targets differs.
if ( pet -> getVictim () != TargetUnit )
2008-10-11 14:16:25 -05:00
{
2009-01-21 16:18:57 -06:00
if ( pet -> getVictim ())
pet -> AttackStop ();
2008-10-11 14:16:25 -05:00
2009-03-07 10:19:07 -06:00
if ( pet -> GetTypeId () != TYPEID_PLAYER && (( Creature * ) pet ) -> IsAIEnabled )
2008-10-11 14:16:25 -05:00
{
2009-03-07 10:19:07 -06:00
(( Creature * ) pet ) -> AI () -> AttackStart ( TargetUnit );
2009-01-21 16:18:57 -06:00
//10% chance to play special pet attack talk, else growl
if ((( Creature * ) pet ) -> isPet () && (( Pet * ) pet ) -> getPetType () == SUMMON_PET && pet != TargetUnit && urand ( 0 , 100 ) < 10 )
pet -> SendPetTalk (( uint32 ) PET_TALK_ATTACK );
else
{
// 90% chance for pet and 100% chance for charmed creature
pet -> SendPetAIReaction ( guid1 );
}
2008-10-11 14:16:25 -05:00
}
2009-01-21 16:18:57 -06:00
else // charmed player
{
if ( pet -> getVictim () && pet -> getVictim () != TargetUnit )
pet -> AttackStop ();
2008-11-07 18:46:25 -06:00
2009-01-21 16:18:57 -06:00
pet -> Attack ( TargetUnit , true );
pet -> SendPetAIReaction ( guid1 );
}
2008-10-11 14:16:25 -05:00
}
break ;
}
case COMMAND_ABANDON : // abandon (hunter pet) or dismiss (summoned pet)
if ((( Creature * ) pet ) -> isPet ())
{
Pet * p = ( Pet * ) pet ;
if ( p -> getPetType () == HUNTER_PET )
_player -> RemovePet ( p , PET_SAVE_AS_DELETED );
else
//dismissing a summoned pet is like killing them (this prevents returning a soulshard...)
p -> setDeathState ( CORPSE );
}
2008-11-05 20:51:05 -06:00
else // charmed or possessed
2009-03-20 14:01:46 -06:00
_player -> StopCastingCharm ();
2008-10-11 14:16:25 -05:00
break ;
default :
2009-03-09 17:56:51 -06:00
sLog . outError ( "WORLD: unknown PET flag Action %i and spellid %i." , flag , spellid );
2008-10-11 14:16:25 -05:00
}
break ;
case ACT_REACTION : // 0x600
switch ( spellid )
{
case REACT_PASSIVE : //passive
case REACT_DEFENSIVE : //recovery
case REACT_AGGRESSIVE : //activete
2009-03-05 18:48:56 -06:00
if ( pet -> GetTypeId () == TYPEID_UNIT )
(( Creature * ) pet ) -> SetReactState ( ReactStates ( spellid ) );
2008-10-11 14:16:25 -05:00
break ;
}
break ;
2008-12-24 09:58:26 -06:00
case ACT_DISABLED : // 0x8100 spell (disabled), ignore
case ACT_PASSIVE : // 0x0100
case ACT_ENABLED : // 0xC100 spell
2008-10-11 14:16:25 -05:00
{
2009-01-21 16:18:57 -06:00
Unit * unit_target = NULL ;
2008-10-29 18:06:01 -05:00
if ((( Creature * ) pet ) -> GetGlobalCooldown () > 0 )
return ;
2009-01-21 16:18:57 -06:00
if ( guid2 )
unit_target = ObjectAccessor :: GetUnit ( * _player , guid2 );
2008-10-11 14:16:25 -05:00
// do not cast unknown spells
SpellEntry const * spellInfo = sSpellStore . LookupEntry ( spellid );
if ( ! spellInfo )
{
2009-03-09 17:56:51 -06:00
sLog . outError ( "WORLD: unknown PET spell id %i" , spellid );
2008-10-11 14:16:25 -05:00
return ;
}
for ( uint32 i = 0 ; i < 3 ; i ++ )
{
if ( spellInfo -> EffectImplicitTargetA [ i ] == TARGET_ALL_ENEMY_IN_AREA || spellInfo -> EffectImplicitTargetA [ i ] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || spellInfo -> EffectImplicitTargetA [ i ] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED )
return ;
}
// do not cast not learned spells
if ( ! pet -> HasSpell ( spellid ) || IsPassiveSpell ( spellid ))
return ;
pet -> clearUnitState ( UNIT_STAT_FOLLOW );
Spell * spell = new Spell ( pet , spellInfo , false );
2009-03-16 12:00:14 -06:00
SpellCastResult result = spell -> CheckPetCast ( unit_target );
2008-10-11 14:16:25 -05:00
2009-01-21 16:18:57 -06:00
//auto turn to target unless possessed
2008-11-05 20:51:05 -06:00
if ( result == SPELL_FAILED_UNIT_NOT_INFRONT && ! pet -> isPossessed ())
2008-10-11 14:16:25 -05:00
{
2009-04-27 18:42:35 -05:00
if ( unit_target )
{
pet -> SetInFront ( unit_target );
if ( unit_target -> GetTypeId () == TYPEID_PLAYER )
pet -> SendUpdateToPlayer ( ( Player * ) unit_target );
}
else if ( Unit * unit_target2 = spell -> m_targets . getUnitTarget ())
{
pet -> SetInFront ( unit_target2 );
if ( unit_target2 -> GetTypeId () == TYPEID_PLAYER )
pet -> SendUpdateToPlayer ( ( Player * ) unit_target2 );
}
if ( Unit * powner = pet -> GetCharmerOrOwner ())
2008-10-11 14:16:25 -05:00
if ( powner -> GetTypeId () == TYPEID_PLAYER )
pet -> SendUpdateToPlayer (( Player * ) powner );
2009-03-16 12:00:14 -06:00
result = SPELL_CAST_OK ;
2008-10-11 14:16:25 -05:00
}
2009-03-16 12:00:14 -06:00
if ( result == SPELL_CAST_OK )
2008-10-11 14:16:25 -05:00
{
(( Creature * ) pet ) -> AddCreatureSpellCooldown ( spellid );
if ((( Creature * ) pet ) -> isPet ())
(( Pet * ) pet ) -> CheckLearning ( spellid );
unit_target = spell -> m_targets . getUnitTarget ();
//10% chance to play special pet attack talk, else growl
//actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
if ((( Creature * ) pet ) -> isPet () && ((( Pet * ) pet ) -> getPetType () == SUMMON_PET ) && ( pet != unit_target ) && ( urand ( 0 , 100 ) < 10 ))
pet -> SendPetTalk (( uint32 ) PET_TALK_SPECIAL_SPELL );
else
{
pet -> SendPetAIReaction ( guid1 );
}
2008-11-05 20:51:05 -06:00
if ( unit_target && ! GetPlayer () -> IsFriendlyTo ( unit_target ) && ! pet -> isPossessed ())
2008-10-11 14:16:25 -05:00
{
2009-01-21 16:18:57 -06:00
// This is true if pet has no target or has target but targets differs.
if ( pet -> getVictim () != unit_target )
{
if ( pet -> getVictim ())
pet -> AttackStop ();
pet -> GetMotionMaster () -> Clear ();
2009-03-06 18:09:01 -06:00
if ((( Creature * ) pet ) -> IsAIEnabled )
2009-01-21 16:18:57 -06:00
(( Creature * ) pet ) -> AI () -> AttackStart ( unit_target );
}
2008-10-11 14:16:25 -05:00
}
spell -> prepare ( & ( spell -> m_targets ));
}
else
{
2008-11-05 20:51:05 -06:00
if ( pet -> isPossessed ())
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_CAST_FAILED , ( 4 + 1 + 1 ));
2008-12-24 09:58:26 -06:00
data << uint8 ( 0 ) << uint32 ( spellid ) << uint8 ( result );
2008-10-11 14:16:25 -05:00
switch ( result )
{
case SPELL_FAILED_REQUIRES_SPELL_FOCUS :
data << uint32 ( spellInfo -> RequiresSpellFocus );
break ;
}
SendPacket ( & data );
}
else
pet -> SendPetCastFail ( spellid , result );
if ( ! (( Creature * ) pet ) -> HasSpellCooldown ( spellid ))
pet -> SendPetClearCooldown ( spellid );
spell -> finish ( false );
delete spell ;
}
break ;
}
default :
2009-03-09 17:56:51 -06:00
sLog . outError ( "WORLD: unknown PET flag Action %i and spellid %i." , flag , spellid );
2008-10-11 14:16:25 -05:00
}
}
void WorldSession :: HandlePetNameQuery ( WorldPacket & recv_data )
{
CHECK_PACKET_SIZE ( recv_data , 4 + 8 );
2009-03-09 17:56:51 -06:00
sLog . outDetail ( "HandlePetNameQuery. CMSG_PET_NAME_QUERY" );
2008-10-11 14:16:25 -05:00
uint32 petnumber ;
uint64 petguid ;
recv_data >> petnumber ;
recv_data >> petguid ;
SendPetNameQuery ( petguid , petnumber );
}
void WorldSession :: SendPetNameQuery ( uint64 petguid , uint32 petnumber )
{
2009-01-24 11:28:00 -06:00
Creature * pet = ObjectAccessor :: GetCreatureOrPetOrVehicle ( * _player , petguid );
2008-10-11 14:16:25 -05:00
if ( ! pet || ! pet -> GetCharmInfo () || pet -> GetCharmInfo () -> GetPetNumber () != petnumber )
return ;
std :: string name = pet -> GetName ();
WorldPacket data ( SMSG_PET_NAME_QUERY_RESPONSE , ( 4 + 4 + name . size () + 1 ));
data << uint32 ( petnumber );
data << name . c_str ();
data << uint32 ( pet -> GetUInt32Value ( UNIT_FIELD_PET_NAME_TIMESTAMP ));
if ( pet -> isPet () && (( Pet * ) pet ) -> GetDeclinedNames () )
{
data << uint8 ( 1 );
for ( int i = 0 ; i < MAX_DECLINED_NAME_CASES ; ++ i )
data << (( Pet * ) pet ) -> GetDeclinedNames () -> name [ i ];
}
else
data << uint8 ( 0 );
_player -> GetSession () -> SendPacket ( & data );
}
void WorldSession :: HandlePetSetAction ( WorldPacket & recv_data )
{
2008-12-12 11:21:28 -06:00
CHECK_PACKET_SIZE ( recv_data , 8 + 4 + 2 + 2 );
2008-10-11 14:16:25 -05:00
2009-03-09 17:56:51 -06:00
sLog . outDetail ( "HandlePetSetAction. CMSG_PET_SET_ACTION" );
2008-10-11 14:16:25 -05:00
uint64 petguid ;
uint32 position ;
uint16 spell_id ;
uint16 act_state ;
uint8 count ;
recv_data >> petguid ;
2009-03-21 10:17:24 -06:00
Unit * pet = ObjectAccessor :: GetUnit ( * _player , petguid );
2008-10-11 14:16:25 -05:00
2009-03-21 10:17:24 -06:00
if ( ! pet || pet != _player -> GetFirstControlled ())
2008-10-11 14:16:25 -05:00
{
2009-03-09 17:56:51 -06:00
sLog . outError ( "HandlePetSetAction: Unknown pet or pet owner." );
2008-10-11 14:16:25 -05:00
return ;
}
CharmInfo * charmInfo = pet -> GetCharmInfo ();
if ( ! charmInfo )
{
sLog . outError ( "WorldSession::HandlePetSetAction: object " I64FMTD " is considered pet-like but doesn't have a charminfo!" , pet -> GetGUID ());
return ;
}
count = ( recv_data . size () == 24 ) ? 2 : 1 ;
for ( uint8 i = 0 ; i < count ; i ++ )
{
recv_data >> position ;
recv_data >> spell_id ;
recv_data >> act_state ;
2009-03-09 17:56:51 -06:00
sLog . outDetail ( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X" , _player -> GetName (), position , spell_id , act_state );
2008-10-11 14:16:25 -05:00
//if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add
2008-12-24 09:58:26 -06:00
if ( ! (( act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE ) && spell_id && ! pet -> HasSpell ( spell_id )))
2008-10-11 14:16:25 -05:00
{
//sign for autocast
if ( act_state == ACT_ENABLED && spell_id )
{
2009-03-28 11:56:45 -06:00
if ( pet -> GetTypeId () == TYPEID_UNIT && (( Creature * ) pet ) -> isPet ())
2008-10-11 14:16:25 -05:00
(( Pet * ) pet ) -> ToggleAutocast ( spell_id , true );
2009-03-28 11:56:45 -06:00
else
charmInfo -> ToggleCreatureAutocast ( spell_id , true );
2008-10-11 14:16:25 -05:00
}
//sign for no/turn off autocast
else if ( act_state == ACT_DISABLED && spell_id )
{
2009-03-28 11:56:45 -06:00
if ( pet -> GetTypeId () == TYPEID_UNIT && (( Creature * ) pet ) -> isPet ())
2008-10-11 14:16:25 -05:00
(( Pet * ) pet ) -> ToggleAutocast ( spell_id , false );
2009-03-28 11:56:45 -06:00
else
charmInfo -> ToggleCreatureAutocast ( spell_id , false );
2008-10-11 14:16:25 -05:00
}
charmInfo -> GetActionBarEntry ( position ) -> Type = act_state ;
charmInfo -> GetActionBarEntry ( position ) -> SpellOrAction = spell_id ;
}
}
}
void WorldSession :: HandlePetRename ( WorldPacket & recv_data )
{
2008-11-03 09:53:31 -06:00
CHECK_PACKET_SIZE ( recv_data , 8 + 1 );
2008-10-11 14:16:25 -05:00
2009-03-09 17:56:51 -06:00
sLog . outDetail ( "HandlePetRename. CMSG_PET_RENAME" );
2008-10-11 14:16:25 -05:00
uint64 petguid ;
uint8 isdeclined ;
std :: string name ;
DeclinedName declinedname ;
recv_data >> petguid ;
recv_data >> name ;
2008-11-03 09:53:31 -06:00
CHECK_PACKET_SIZE ( recv_data , recv_data . rpos () + 1 );
2008-10-11 14:16:25 -05:00
recv_data >> isdeclined ;
Pet * pet = ObjectAccessor :: GetPet ( petguid );
// check it!
if ( ! pet || ! pet -> isPet () || (( Pet * ) pet ) -> getPetType () != HUNTER_PET ||
pet -> GetByteValue ( UNIT_FIELD_BYTES_2 , 2 ) != UNIT_RENAME_ALLOWED ||
pet -> GetOwnerGUID () != _player -> GetGUID () || ! pet -> GetCharmInfo () )
return ;
2008-11-03 09:53:31 -06:00
if ( ! ObjectMgr :: IsValidPetName ( name ))
2008-10-11 14:16:25 -05:00
{
2008-11-03 09:53:31 -06:00
SendPetNameInvalid ( PET_NAME_INVALID , name , NULL );
2008-10-11 14:16:25 -05:00
return ;
}
2008-11-03 09:53:31 -06:00
if ( objmgr . IsReservedName ( name ))
{
SendPetNameInvalid ( PET_NAME_RESERVED , name , NULL );
return ;
}
2008-10-11 14:16:25 -05:00
pet -> SetName ( name );
Unit * owner = pet -> GetOwner ();
if ( owner && ( owner -> GetTypeId () == TYPEID_PLAYER ) && (( Player * ) owner ) -> GetGroup ())
(( Player * ) owner ) -> SetGroupUpdateFlag ( GROUP_UPDATE_FLAG_PET_NAME );
pet -> SetByteValue ( UNIT_FIELD_BYTES_2 , 2 , UNIT_RENAME_NOT_ALLOWED );
if ( isdeclined )
{
for ( int i = 0 ; i < MAX_DECLINED_NAME_CASES ; ++ i )
2008-11-03 09:53:31 -06:00
{
CHECK_PACKET_SIZE ( recv_data , recv_data . rpos () + 1 );
2008-10-11 14:16:25 -05:00
recv_data >> declinedname . name [ i ];
2008-11-03 09:53:31 -06:00
}
2008-10-11 14:16:25 -05:00
std :: wstring wname ;
2008-11-03 09:53:31 -06:00
Utf8toWStr ( name , wname );
2008-10-11 14:16:25 -05:00
if ( ! ObjectMgr :: CheckDeclinedNames ( GetMainPartOfName ( wname , 0 ), declinedname ))
{
2008-11-03 09:53:31 -06:00
SendPetNameInvalid ( PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME , name , & declinedname );
2008-10-11 14:16:25 -05:00
return ;
}
}
CharacterDatabase . BeginTransaction ();
if ( isdeclined )
{
for ( int i = 0 ; i < MAX_DECLINED_NAME_CASES ; ++ i )
CharacterDatabase . escape_string ( declinedname . name [ i ]);
CharacterDatabase . PExecute ( "DELETE FROM character_pet_declinedname WHERE owner = '%u' AND id = '%u'" , _player -> GetGUIDLow (), pet -> GetCharmInfo () -> GetPetNumber ());
CharacterDatabase . PExecute ( "INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u','%u','%s','%s','%s','%s','%s')" ,
2008-11-03 09:53:31 -06:00
pet -> GetCharmInfo () -> GetPetNumber (), _player -> GetGUIDLow (), declinedname . name [ 0 ]. c_str (), declinedname . name [ 1 ]. c_str (), declinedname . name [ 2 ]. c_str (), declinedname . name [ 3 ]. c_str (), declinedname . name [ 4 ]. c_str ());
2008-10-11 14:16:25 -05:00
}
CharacterDatabase . escape_string ( name );
2008-11-03 09:53:31 -06:00
CharacterDatabase . PExecute ( "UPDATE character_pet SET name = '%s', renamed = '1' WHERE owner = '%u' AND id = '%u'" , name . c_str (), _player -> GetGUIDLow (), pet -> GetCharmInfo () -> GetPetNumber ());
2008-10-11 14:16:25 -05:00
CharacterDatabase . CommitTransaction ();
pet -> SetUInt32Value ( UNIT_FIELD_PET_NAME_TIMESTAMP , time ( NULL ));
}
void WorldSession :: HandlePetAbandon ( WorldPacket & recv_data )
{
2008-11-03 09:53:31 -06:00
CHECK_PACKET_SIZE ( recv_data , 8 );
2008-10-11 14:16:25 -05:00
uint64 guid ;
recv_data >> guid ; //pet guid
sLog . outDetail ( "HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u" , GUID_LOPART ( guid ) );
// pet/charmed
2009-01-24 11:28:00 -06:00
Creature * pet = ObjectAccessor :: GetCreatureOrPetOrVehicle ( * _player , guid );
2008-10-11 14:16:25 -05:00
if ( pet )
{
if ( pet -> isPet ())
{
if ( pet -> GetGUID () == _player -> GetPetGUID ())
{
uint32 feelty = pet -> GetPower ( POWER_HAPPINESS );
pet -> SetPower ( POWER_HAPPINESS ,( feelty - 50000 ) > 0 ? ( feelty - 50000 ) : 0 );
}
_player -> RemovePet (( Pet * ) pet , PET_SAVE_AS_DELETED );
}
else if ( pet -> GetGUID () == _player -> GetCharmGUID ())
2009-03-20 14:01:46 -06:00
_player -> StopCastingCharm ();
2008-10-11 14:16:25 -05:00
}
}
void WorldSession :: HandlePetUnlearnOpcode ( WorldPacket & recvPacket )
{
CHECK_PACKET_SIZE ( recvPacket , 8 );
sLog . outDetail ( "CMSG_PET_UNLEARN" );
uint64 guid ;
2009-01-20 19:59:43 -06:00
recvPacket >> guid ; // Pet guid
2008-10-11 14:16:25 -05:00
Pet * pet = _player -> GetPet ();
2009-01-20 19:59:43 -06:00
if ( ! pet || pet -> getPetType () != HUNTER_PET || pet -> m_usedTalentCount == 0 )
2008-10-11 14:16:25 -05:00
return ;
if ( guid != pet -> GetGUID ())
{
2009-03-09 17:56:51 -06:00
sLog . outError ( "HandlePetUnlearnOpcode.Pet %u isn't pet of player %s ." , uint32 ( GUID_LOPART ( guid )), GetPlayer () -> GetName () );
2008-10-11 14:16:25 -05:00
return ;
}
CharmInfo * charmInfo = pet -> GetCharmInfo ();
if ( ! charmInfo )
{
sLog . outError ( "WorldSession::HandlePetUnlearnOpcode: object " I64FMTD " is considered pet-like but doesn't have a charminfo!" , pet -> GetGUID ());
return ;
}
2009-01-20 19:59:43 -06:00
pet -> resetTalents ();
2008-10-11 14:16:25 -05:00
}
void WorldSession :: HandlePetSpellAutocastOpcode ( WorldPacket & recvPacket )
{
CHECK_PACKET_SIZE ( recvPacket , 8 + 2 + 2 + 1 );
sLog . outDetail ( "CMSG_PET_SPELL_AUTOCAST" );
uint64 guid ;
uint16 spellid ;
uint16 spellid2 ; //maybe second spell, automatically toggled off when first toggled on?
uint8 state ; //1 for on, 0 for off
recvPacket >> guid >> spellid >> spellid2 >> state ;
2009-03-27 22:47:28 -06:00
if ( ! _player -> GetGuardianPet () && ! _player -> GetCharm ())
2008-10-11 14:16:25 -05:00
return ;
if ( ObjectAccessor :: FindPlayer ( guid ))
return ;
2009-01-24 11:28:00 -06:00
Creature * pet = ObjectAccessor :: GetCreatureOrPetOrVehicle ( * _player , guid );
2008-10-11 14:16:25 -05:00
2009-03-27 22:47:28 -06:00
if ( ! pet || ( pet != _player -> GetGuardianPet () && pet != _player -> GetCharm ()))
2008-10-11 14:16:25 -05:00
{
2009-03-09 17:56:51 -06:00
sLog . outError ( "HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s ." , uint32 ( GUID_LOPART ( guid )), GetPlayer () -> GetName () );
2008-10-11 14:16:25 -05:00
return ;
}
// do not add not learned spells/ passive spells
2009-03-21 18:05:43 -06:00
if ( ! pet -> HasSpell ( spellid ) || IsAutocastableSpell ( spellid ))
2008-10-11 14:16:25 -05:00
return ;
CharmInfo * charmInfo = pet -> GetCharmInfo ();
if ( ! charmInfo )
{
sLog . outError ( "WorldSession::HandlePetSpellAutocastOpcod: object " I64FMTD " is considered pet-like but doesn't have a charminfo!" , pet -> GetGUID ());
return ;
}
2009-03-28 11:56:45 -06:00
if ( pet -> isPet ())
2008-10-11 14:16:25 -05:00
(( Pet * ) pet ) -> ToggleAutocast ( spellid , state );
2009-03-28 11:56:45 -06:00
else
pet -> GetCharmInfo () -> ToggleCreatureAutocast ( spellid , state );
2008-10-11 14:16:25 -05:00
for ( uint8 i = 0 ; i < 10 ; ++ i )
{
if (( charmInfo -> GetActionBarEntry ( i ) -> Type == ACT_ENABLED || charmInfo -> GetActionBarEntry ( i ) -> Type == ACT_DISABLED ) && spellid == charmInfo -> GetActionBarEntry ( i ) -> SpellOrAction )
charmInfo -> GetActionBarEntry ( i ) -> Type = state ? ACT_ENABLED : ACT_DISABLED ;
}
}
2008-11-03 09:53:31 -06:00
void WorldSession :: HandlePetCastSpellOpcode ( WorldPacket & recvPacket )
2008-10-11 14:16:25 -05:00
{
sLog . outDetail ( "WORLD: CMSG_PET_CAST_SPELL" );
2008-12-24 09:58:26 -06:00
CHECK_PACKET_SIZE ( recvPacket , 8 + 1 + 4 + 1 );
2008-10-11 14:16:25 -05:00
uint64 guid ;
uint32 spellid ;
2008-12-24 09:58:26 -06:00
uint8 cast_count ;
uint8 unk_flags ; // flags (if 0x02 - some additional data are received)
recvPacket >> guid >> cast_count >> spellid >> unk_flags ;
2008-10-11 14:16:25 -05:00
2008-12-24 09:58:26 -06:00
sLog . outDebug ( "WORLD: CMSG_PET_CAST_SPELL, cast_count: %u, spellid %u, unk_flags %u" , cast_count , spellid , unk_flags );
2008-10-11 14:16:25 -05:00
2008-11-05 20:51:05 -06:00
// This opcode is also sent from charmed and possessed units (players and creatures)
2009-03-27 22:47:28 -06:00
if ( ! _player -> GetGuardianPet () && ! _player -> GetCharm ())
2008-10-11 14:16:25 -05:00
return ;
2008-11-05 20:51:05 -06:00
Unit * caster = ObjectAccessor :: GetUnit ( * _player , guid );
2008-10-11 14:16:25 -05:00
2009-03-27 22:47:28 -06:00
if ( ! caster || ( caster != _player -> GetGuardianPet () && caster != _player -> GetCharm ()))
2008-10-11 14:16:25 -05:00
{
2009-03-09 17:56:51 -06:00
sLog . outError ( "HandlePetCastSpellOpcode: Pet %u isn't pet of player %s ." , uint32 ( GUID_LOPART ( guid )), GetPlayer () -> GetName () );
2008-10-11 14:16:25 -05:00
return ;
}
2008-11-05 20:51:05 -06:00
if ( caster -> GetTypeId () == TYPEID_UNIT && (( Creature * ) caster ) -> GetGlobalCooldown () > 0 )
2008-10-29 18:06:01 -05:00
return ;
2008-10-11 14:16:25 -05:00
SpellEntry const * spellInfo = sSpellStore . LookupEntry ( spellid );
if ( ! spellInfo )
{
2009-03-09 17:56:51 -06:00
sLog . outError ( "WORLD: unknown PET spell id %i" , spellid );
2008-10-11 14:16:25 -05:00
return ;
}
// do not cast not learned spells
2008-11-05 20:51:05 -06:00
if ( ! caster -> HasSpell ( spellid ) || IsPassiveSpell ( spellid ))
2008-10-11 14:16:25 -05:00
return ;
SpellCastTargets targets ;
2008-11-05 20:51:05 -06:00
if ( ! targets . read ( & recvPacket , caster ))
2008-10-11 14:16:25 -05:00
return ;
2008-11-05 20:51:05 -06:00
caster -> clearUnitState ( UNIT_STAT_FOLLOW );
2008-10-11 14:16:25 -05:00
2008-11-05 20:51:05 -06:00
Spell * spell = new Spell ( caster , spellInfo , false );
2008-12-24 09:58:26 -06:00
spell -> m_cast_count = cast_count ; // probably pending spell cast
2008-10-11 14:16:25 -05:00
spell -> m_targets = targets ;
2009-03-16 12:00:14 -06:00
SpellCastResult result = spell -> CheckPetCast ( NULL );
if ( result == SPELL_CAST_OK )
2008-10-11 14:16:25 -05:00
{
2008-11-05 20:51:05 -06:00
if ( caster -> GetTypeId () == TYPEID_UNIT )
2008-10-11 14:16:25 -05:00
{
2008-11-05 20:51:05 -06:00
Creature * pet = ( Creature * ) caster ;
pet -> AddCreatureSpellCooldown ( spellid );
if ( pet -> isPet ())
{
Pet * p = ( Pet * ) pet ;
p -> CheckLearning ( spellid );
// 10% chance to play special pet attack talk, else growl
// actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
if ( p -> getPetType () == SUMMON_PET && ( urand ( 0 , 100 ) < 10 ))
pet -> SendPetTalk (( uint32 ) PET_TALK_SPECIAL_SPELL );
else
pet -> SendPetAIReaction ( guid );
}
2008-10-11 14:16:25 -05:00
}
spell -> prepare ( & ( spell -> m_targets ));
}
else
{
2008-11-05 20:51:05 -06:00
caster -> SendPetCastFail ( spellid , result );
if ( caster -> GetTypeId () == TYPEID_PLAYER )
{
if ( ! (( Player * ) caster ) -> HasSpellCooldown ( spellid ))
caster -> SendPetClearCooldown ( spellid );
}
else
{
if ( ! (( Creature * ) caster ) -> HasSpellCooldown ( spellid ))
caster -> SendPetClearCooldown ( spellid );
}
2008-10-11 14:16:25 -05:00
spell -> finish ( false );
delete spell ;
}
}
2008-11-03 09:53:31 -06:00
2008-12-12 11:21:28 -06:00
void WorldSession :: SendPetNameInvalid ( uint32 error , const std :: string & name , DeclinedName * declinedName )
2008-11-03 09:53:31 -06:00
{
WorldPacket data ( SMSG_PET_NAME_INVALID , 4 + name . size () + 1 + 1 );
data << uint32 ( error );
data << name ;
if ( declinedName )
{
data << uint8 ( 1 );
for ( uint32 i = 0 ; i < MAX_DECLINED_NAME_CASES ; ++ i )
data << declinedName -> name [ i ];
}
else
data << uint8 ( 0 );
SendPacket ( & data );
}
2008-12-24 09:58:26 -06:00
void WorldSession :: HandlePetLearnTalent ( WorldPacket & recv_data )
{
sLog . outDebug ( "WORLD: CMSG_PET_LEARN_TALENT" );
CHECK_PACKET_SIZE ( recv_data , 8 + 4 + 4 );
uint64 guid ;
uint32 talent_id , requested_rank ;
recv_data >> guid >> talent_id >> requested_rank ;
2009-03-21 14:53:38 -06:00
_player -> LearnPetTalent ( guid , talent_id , requested_rank );
2009-02-18 22:39:00 +01:00
}