2010-10-07 15:35:36 +02:00
/*
2012-01-01 00:32:13 +01:00
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
2010-10-07 15:35:36 +02:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* 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-11 14:16:25 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
#include "Common.h"
2009-06-04 21:41:07 +02:00
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
2011-05-03 15:01:10 +02:00
#include "ArenaTeamMgr.h"
2011-05-04 10:08:09 +02:00
#include "GuildMgr.h"
2010-08-16 09:51:37 +02:00
#include "SystemConfig.h"
2009-06-04 21:41:07 +02:00
#include "World.h"
2008-10-11 14:16:25 -05:00
#include "WorldPacket.h"
#include "WorldSession.h"
2010-06-08 17:01:03 -06:00
#include "DatabaseEnv.h"
2009-06-04 21:41:07 +02:00
#include "ArenaTeam.h"
#include "Chat.h"
#include "Group.h"
#include "Guild.h"
#include "Language.h"
#include "Log.h"
#include "Opcodes.h"
#include "Player.h"
2008-10-11 14:16:25 -05:00
#include "PlayerDump.h"
2009-06-04 21:41:07 +02:00
#include "SharedDefines.h"
2008-10-11 14:16:25 -05:00
#include "SocialMgr.h"
2009-06-04 21:41:07 +02:00
#include "UpdateMask.h"
2008-10-11 14:16:25 -05:00
#include "Util.h"
2010-01-19 11:36:05 +01:00
#include "ScriptMgr.h"
2010-09-05 13:12:24 -07:00
#include "Battleground.h"
2011-09-08 15:11:55 +02:00
#include "AccountMgr.h"
2011-11-28 23:06:50 -03:00
#include "DBCStores.h"
2012-01-14 17:37:28 +01:00
#include "LFGMgr.h"
2009-10-17 15:51:44 -07:00
2010-08-18 02:25:52 +02:00
class LoginQueryHolder : public SQLQueryHolder
2008-10-11 14:16:25 -05:00
{
private :
uint32 m_accountId ;
uint64 m_guid ;
public :
LoginQueryHolder ( uint32 accountId , uint64 guid )
: m_accountId ( accountId ), m_guid ( guid ) { }
uint64 GetGuid () const { return m_guid ; }
uint32 GetAccountId () const { return m_accountId ; }
bool Initialize ();
};
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool LoginQueryHolder :: Initialize ()
{
SetSize ( MAX_PLAYER_LOGIN_QUERY );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool res = true ;
2010-09-20 18:20:40 +02:00
uint32 lowGuid = GUID_LOPART ( m_guid );
PreparedStatement * stmt = NULL ;
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADFROM , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_GROUP_MEMBER );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADGROUP , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_INSTANCE );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_AURAS );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADAURAS , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_SPELL );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADSPELLS , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_QUESTSTATUS );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADQUESTSTATUS , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_DAILYQUESTSTATUS );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS , stmt );
2012-01-03 08:37:21 -05:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
2012-01-03 08:37:21 -05:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADWEEKLYQUESTSTATUS , stmt );
2010-09-20 18:20:40 +02:00
2012-01-03 08:37:21 -05:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_SEASONALQUESTSTATUS );
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADSEASONALQUESTSTATUS , stmt );
2010-09-20 18:20:40 +02:00
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_REPUTATION );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADREPUTATION , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_INVENTORY );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADINVENTORY , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_ACTIONS );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADACTIONS , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_MAILCOUNT );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
stmt -> setUInt64 ( 1 , uint64 ( time ( NULL )));
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADMAILCOUNT , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_MAILDATE );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADMAILDATE , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_SOCIALLIST );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADSOCIALLIST , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_HOMEBIND );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADHOMEBIND , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_SPELLCOOLDOWNS );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS , stmt );
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
if ( sWorld -> getBoolConfig ( CONFIG_DECLINED_NAMES_USED ))
2010-09-20 18:20:40 +02:00
{
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_DECLINEDNAMES );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES , stmt );
}
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_GUILD_MEMBER );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADGUILD , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_ARENAINFO );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADARENAINFO , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_ACHIEVEMENTS );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_CRITERIAPROGRESS );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_EQUIPMENTSETS );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_BGDATA );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADBGDATA , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_GLYPHS );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADGLYPHS , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_TALENTS );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADTALENTS , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_PLAYER_ACCOUNT_DATA );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADACCOUNTDATA , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_SKILLS );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADSKILLS , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_RANDOMBG );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADRANDOMBG , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_BANNED );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADBANNED , stmt );
2009-10-17 15:51:44 -07:00
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_QUESTSTATUSREW );
2010-12-26 04:16:18 +01:00
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADQUESTSTATUSREW , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES );
2011-01-24 11:20:30 +01:00
stmt -> setUInt32 ( 0 , m_accountId );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOADINSTANCELOCKTIMES , stmt );
2012-01-14 17:37:28 +01:00
2008-10-11 14:16:25 -05:00
return res ;
}
2009-10-17 15:51:44 -07:00
2011-12-18 20:55:59 +01:00
void WorldSession :: HandleCharEnum ( PreparedQueryResult result )
2008-10-11 14:16:25 -05:00
{
2011-11-20 18:28:18 +01:00
WorldPacket data ( SMSG_CHAR_ENUM , 270 );
2009-10-17 15:51:44 -07:00
2011-11-20 18:28:18 +01:00
data << uint8 ( 0x80 ); // 0 causes the client to free memory of charlist
data << uint32 ( 0 ); // number of characters
data << uint32 ( 0 ); // unk loop counter
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
if ( result )
2008-10-11 14:16:25 -05:00
{
2011-11-20 18:28:18 +01:00
typedef std :: pair < uint32 , uint64 > Guids ;
std :: vector < Guids > guidsVect ;
ByteBuffer buffer ;
_allowedCharsToLogin . clear ();
2008-10-11 14:16:25 -05:00
do
{
2011-11-20 18:28:18 +01:00
uint32 GuidLow = ( * result )[ 0 ]. GetUInt32 ();
uint64 GuildGuid = ( * result )[ 13 ]. GetUInt32 (); //TODO: store as uin64
guidsVect . push_back ( std :: make_pair ( GuidLow , GuildGuid ));
sLog -> outDetail ( "Loading char guid %u from account %u." , GuidLow , GetAccountId ());
if ( ! Player :: BuildEnumData ( result , & buffer ))
2011-04-01 03:11:57 +02:00
{
2011-11-20 18:28:18 +01:00
sLog -> outError ( "Building enum data for SMSG_CHAR_ENUM has failed, aborting" );
return ;
2011-04-01 03:11:57 +02:00
}
2011-11-20 18:28:18 +01:00
_allowedCharsToLogin . insert ( GuidLow );
2008-10-11 14:16:25 -05:00
}
2010-04-07 22:59:46 +02:00
while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2011-11-20 18:28:18 +01:00
for ( std :: vector < Guids >:: iterator itr = guidsVect . begin (); itr != guidsVect . end (); ++ itr )
{
uint32 GuidLow = ( * itr ). first ;
uint64 GuildGuid = ( * itr ). second ;
uint8 Guid0 = uint8 ( GuidLow );
uint8 Guid1 = uint8 ( GuidLow >> 8 );
uint8 Guid2 = uint8 ( GuidLow >> 16 );
uint8 Guid3 = uint8 ( GuidLow >> 24 );
for ( uint8 i = 0 ; i < 17 ; ++ i )
{
switch ( i )
{
//case 14:
// data.writeBit(1);//unk
// break;
2011-11-27 17:46:05 +01:00
case 11 : data . WriteBit ( Guid0 ? 1 : 0 ); break ;
case 12 : data . WriteBit ( Guid1 ? 1 : 0 ); break ;
case 9 : data . WriteBit ( Guid2 ? 1 : 0 ); break ;
case 8 : data . WriteBit ( Guid3 ? 1 : 0 ); break ;
2011-11-20 18:28:18 +01:00
/*case 15:
if(uint8(GuildGuid))
data.writeBit(1);
break;
case 4:
if(uint8(GuildGuid >> 8))
data.writeBit(1);
break;
case 13:
if(uint8(GuildGuid >> 16))
data.writeBit(1);
break;
case 2:
if(uint8(GuildGuid >> 24))
data.writeBit(1);
break;*/
/*case 0:
if(uint8(GuildGuid >> 32))
data.writeBit(1);
break;
case 0:
if(uint8(GuildGuid >> 40))
data.writeBit(1);
break;*/
/*case 5:
if(uint8(GuildGuid >> 48))
data.writeBit(1);
break;
case 3:
if(uint8(GuildGuid >> 56))
data.writeBit(1);
break;*/
default :
2011-11-27 17:46:05 +01:00
data . WriteBit ( 0 );
2011-11-20 18:28:18 +01:00
break ;
}
}
}
2011-11-27 17:46:05 +01:00
data . FlushBits ();
2011-11-20 18:28:18 +01:00
data . append ( buffer );
data . put < uint32 > ( 1 , guidsVect . size ());
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession :: HandleCharEnumOpcode ( WorldPacket & /*recv_data*/ )
2008-10-11 14:16:25 -05:00
{
2010-09-19 17:02:14 +02:00
// remove expired bans
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_EXPIRED_BANS );
CharacterDatabase . Execute ( stmt );
2008-10-11 14:16:25 -05:00
/// get all the data necessary for loading all characters (along with their pets) on the account
2011-12-18 20:55:59 +01:00
if ( sWorld -> getBoolConfig ( CONFIG_DECLINED_NAMES_USED ))
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_ENUM_DECLINED_NAME );
2011-12-18 20:55:59 +01:00
else
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_ENUM );
2011-12-18 20:55:59 +01:00
stmt -> setUInt8 ( 0 , PET_SAVE_AS_CURRENT );
stmt -> setUInt32 ( 1 , GetAccountId ());
_charEnumCallback = CharacterDatabase . AsyncQuery ( stmt );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession :: HandleCharCreateOpcode ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
std :: string name ;
2011-04-29 20:47:02 +02:00
uint8 race_ , class_ ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recv_data >> name ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recv_data >> race_ ;
recv_data >> class_ ;
2009-10-17 15:51:44 -07:00
2011-04-29 16:48:15 +06:00
// extract other data required for player creating
uint8 gender , skin , face , hairStyle , hairColor , facialHair , outfitId ;
recv_data >> gender >> skin >> face ;
recv_data >> hairStyle >> hairColor >> facialHair >> outfitId ;
2008-10-11 14:16:25 -05:00
WorldPacket data ( SMSG_CHAR_CREATE , 1 ); // returned with diff.values in all cases
2009-10-17 15:51:44 -07:00
2011-09-08 15:11:55 +02:00
if ( AccountMgr :: IsPlayerAccount ( GetSecurity ()))
2008-10-11 14:16:25 -05:00
{
2010-12-23 23:25:44 +01:00
if ( uint32 mask = sWorld -> getIntConfig ( CONFIG_CHARACTER_CREATING_DISABLED ))
2008-10-11 14:16:25 -05:00
{
bool disabled = false ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 team = Player :: TeamForRace ( race_ );
2011-04-29 16:48:15 +06:00
switch ( team )
2008-10-11 14:16:25 -05:00
{
2011-04-29 16:48:15 +06:00
case ALLIANCE : disabled = mask & ( 1 << 0 ); break ;
case HORDE : disabled = mask & ( 1 << 1 ); break ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( disabled )
2008-10-11 14:16:25 -05:00
{
data << ( uint8 ) CHAR_CREATE_DISABLED ;
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-10-11 14:16:25 -05:00
return ;
}
}
}
2009-10-17 15:51:44 -07:00
2008-10-20 12:23:56 -05:00
ChrClassesEntry const * classEntry = sChrClassesStore . LookupEntry ( class_ );
2011-02-17 19:47:08 +06:00
if ( ! classEntry )
{
data << ( uint8 ) CHAR_CREATE_FAILED ;
SendPacket ( & data );
sLog -> outError ( "Class (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?" , class_ , GetAccountId ());
return ;
}
2009-10-17 15:51:44 -07:00
2011-02-17 19:47:08 +06:00
ChrRacesEntry const * raceEntry = sChrRacesStore . LookupEntry ( race_ );
if ( ! raceEntry )
2008-10-11 14:16:25 -05:00
{
data << ( uint8 ) CHAR_CREATE_FAILED ;
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2011-02-17 19:47:08 +06:00
sLog -> outError ( "Race (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?" , race_ , GetAccountId ());
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// prevent character creating Expansion race without Expansion account
2009-12-17 10:49:15 +01:00
if ( raceEntry -> expansion > Expansion ())
2008-10-11 14:16:25 -05:00
{
data << ( uint8 ) CHAR_CREATE_EXPANSION ;
2011-04-29 20:47:02 +02:00
sLog -> outError ( "Expansion %u account:[%d] tried to Create character with expansion %u race (%u)" , Expansion (), GetAccountId (), raceEntry -> expansion , race_ );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-10-20 12:23:56 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-20 12:23:56 -05:00
// prevent character creating Expansion class without Expansion account
2009-12-17 10:49:15 +01:00
if ( classEntry -> expansion > Expansion ())
2008-10-20 12:23:56 -05:00
{
2008-12-24 09:58:26 -06:00
data << ( uint8 ) CHAR_CREATE_EXPANSION_CLASS ;
2011-04-29 20:47:02 +02:00
sLog -> outError ( "Expansion %u account:[%d] tried to Create character with expansion %u class (%u)" , Expansion (), GetAccountId (), classEntry -> expansion , class_ );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-09-08 15:11:55 +02:00
if ( AccountMgr :: IsPlayerAccount ( GetSecurity ()))
2010-09-06 23:34:16 +06:00
{
2010-12-23 23:25:44 +01:00
uint32 raceMaskDisabled = sWorld -> getIntConfig ( CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK );
2010-09-06 23:34:16 +06:00
if (( 1 << ( race_ - 1 )) & raceMaskDisabled )
{
data << uint8 ( CHAR_CREATE_DISABLED );
SendPacket ( & data );
return ;
}
2010-12-23 23:25:44 +01:00
uint32 classMaskDisabled = sWorld -> getIntConfig ( CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK );
2010-09-06 23:34:16 +06:00
if (( 1 << ( class_ - 1 )) & classMaskDisabled )
{
data << uint8 ( CHAR_CREATE_DISABLED );
SendPacket ( & data );
return ;
}
}
2008-10-11 14:16:25 -05:00
// prevent character creating with invalid name
2009-07-10 08:25:33 +08:00
if ( ! normalizePlayerName ( name ))
2008-10-11 14:16:25 -05:00
{
2009-07-10 08:25:33 +08:00
data << ( uint8 ) CHAR_NAME_NO_NAME ;
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2011-04-29 20:47:02 +02:00
sLog -> outError ( "Account:[%d] but tried to Create character with empty [name] " , GetAccountId ());
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// check name limitations
2011-04-29 20:47:02 +02:00
uint8 res = ObjectMgr :: CheckPlayerName ( name , true );
2009-07-10 08:25:33 +08:00
if ( res != CHAR_NAME_SUCCESS )
2008-10-11 14:16:25 -05:00
{
2009-07-10 08:25:33 +08:00
data << uint8 ( res );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-09-08 15:11:55 +02:00
if ( AccountMgr :: IsPlayerAccount ( GetSecurity ()) && sObjectMgr -> IsReservedName ( name ))
2008-10-11 14:16:25 -05:00
{
data << ( uint8 ) CHAR_NAME_RESERVED ;
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// speedup check for heroic class disabled case
2010-12-23 23:25:44 +01:00
uint32 heroic_free_slots = sWorld -> getIntConfig ( CONFIG_HEROIC_CHARACTERS_PER_REALM );
2011-09-08 15:11:55 +02:00
if ( heroic_free_slots == 0 && AccountMgr :: IsPlayerAccount ( GetSecurity ()) && class_ == CLASS_DEATH_KNIGHT )
2008-12-24 09:58:26 -06:00
{
data << ( uint8 ) CHAR_CREATE_UNIQUE_CLASS_LIMIT ;
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-12-24 09:58:26 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// speedup check for heroic class disabled case
2010-12-23 23:25:44 +01:00
uint32 req_level_for_heroic = sWorld -> getIntConfig ( CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER );
2011-09-08 15:11:55 +02:00
if ( AccountMgr :: IsPlayerAccount ( GetSecurity ()) && class_ == CLASS_DEATH_KNIGHT && req_level_for_heroic > sWorld -> getIntConfig ( CONFIG_MAX_PLAYER_LEVEL ))
2008-12-24 09:58:26 -06:00
{
data << ( uint8 ) CHAR_CREATE_LEVEL_REQUIREMENT ;
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-12-24 09:58:26 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
delete _charCreateCallback . GetParam (); // Delete existing if any, to make the callback chain reset to stage 0
2011-06-22 23:30:30 +02:00
_charCreateCallback . SetParam ( new CharacterCreateInfo ( name , race_ , class_ , gender , skin , face , hairStyle , hairColor , facialHair , outfitId , recv_data ));
2012-01-01 01:09:38 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHECK_NAME );
2011-06-22 14:20:42 +02:00
stmt -> setString ( 0 , name );
_charCreateCallback . SetFutureResult ( CharacterDatabase . AsyncQuery ( stmt ));
}
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
void WorldSession :: HandleCharCreateCallback ( PreparedQueryResult result , CharacterCreateInfo * createInfo )
{
/** This is a series of callbacks executed consecutively as a result from the database becomes available.
This is much more efficient than synchronous requests on packet handler, and much less DoS prone.
It also prevents data syncrhonisation errors.
2011-06-23 09:13:58 +02:00
*/
2011-12-21 10:22:03 +01:00
switch ( _charCreateCallback . GetStage ())
2008-10-11 14:16:25 -05:00
{
2011-06-22 14:20:42 +02:00
case 0 :
2008-10-11 14:16:25 -05:00
{
2011-06-22 14:20:42 +02:00
if ( result )
{
WorldPacket data ( SMSG_CHAR_CREATE , 1 );
data << uint8 ( CHAR_CREATE_NAME_IN_USE );
SendPacket ( & data );
delete createInfo ;
2011-12-21 10:22:03 +01:00
_charCreateCallback . Reset ();
2011-06-22 14:20:42 +02:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-06-23 09:13:58 +02:00
ASSERT ( _charCreateCallback . GetParam () == createInfo );
2009-10-17 15:51:44 -07:00
2011-12-31 20:14:38 +01:00
PreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_SUM_REALM_CHARACTERS );
2011-06-22 14:20:42 +02:00
stmt -> setUInt32 ( 0 , GetAccountId ());
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
_charCreateCallback . FreeResult ();
_charCreateCallback . SetFutureResult ( LoginDatabase . AsyncQuery ( stmt ));
2011-12-21 10:22:03 +01:00
_charCreateCallback . NextStage ();
2011-06-22 14:20:42 +02:00
}
break ;
case 1 :
{
uint16 acctCharCount = 0 ;
if ( result )
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2011-06-22 14:20:42 +02:00
// SELECT SUM(x) is MYSQL_TYPE_NEWDECIMAL - needs to be read as string
const char * ch = fields [ 0 ]. GetCString ();
2011-06-22 18:03:07 +02:00
if ( ch )
acctCharCount = atoi ( ch );
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
if ( acctCharCount >= sWorld -> getIntConfig ( CONFIG_CHARACTERS_PER_ACCOUNT ))
2008-10-11 14:16:25 -05:00
{
2011-06-22 14:20:42 +02:00
WorldPacket data ( SMSG_CHAR_CREATE , 1 );
data << uint8 ( CHAR_CREATE_ACCOUNT_LIMIT );
SendPacket ( & data );
delete createInfo ;
2011-12-21 10:22:03 +01:00
_charCreateCallback . Reset ();
2011-06-22 14:20:42 +02:00
return ;
}
2011-06-23 09:13:58 +02:00
ASSERT ( _charCreateCallback . GetParam () == createInfo );
2011-06-22 14:20:42 +02:00
2012-01-01 01:09:38 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_SUM_CHARS );
2011-06-22 14:20:42 +02:00
stmt -> setUInt32 ( 0 , GetAccountId ());
_charCreateCallback . FreeResult ();
_charCreateCallback . SetFutureResult ( CharacterDatabase . AsyncQuery ( stmt ));
2011-12-21 10:22:03 +01:00
_charCreateCallback . NextStage ();
2011-06-22 14:20:42 +02:00
}
break ;
case 2 :
{
if ( result )
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2011-06-22 14:20:42 +02:00
createInfo -> CharCount = fields [ 0 ]. GetUInt8 ();
if ( createInfo -> CharCount >= sWorld -> getIntConfig ( CONFIG_CHARACTERS_PER_REALM ))
2008-10-11 14:16:25 -05:00
{
2011-06-22 14:20:42 +02:00
WorldPacket data ( SMSG_CHAR_CREATE , 1 );
data << uint8 ( CHAR_CREATE_SERVER_LIMIT );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2011-06-22 14:20:42 +02:00
delete createInfo ;
2011-12-21 10:22:03 +01:00
_charCreateCallback . Reset ();
2008-10-11 14:16:25 -05:00
return ;
}
}
2009-10-17 15:51:44 -07:00
2011-09-08 15:11:55 +02:00
bool allowTwoSideAccounts = ! sWorld -> IsPvPRealm () || sWorld -> getBoolConfig ( CONFIG_ALLOW_TWO_SIDE_ACCOUNTS ) || ! AccountMgr :: IsPlayerAccount ( GetSecurity ());
2011-06-22 14:20:42 +02:00
uint32 skipCinematics = sWorld -> getIntConfig ( CONFIG_SKIP_CINEMATICS );
2011-06-23 09:13:58 +02:00
2011-06-22 14:20:42 +02:00
_charCreateCallback . FreeResult ();
if ( ! allowTwoSideAccounts || skipCinematics == 1 || createInfo -> Class == CLASS_DEATH_KNIGHT )
2008-10-11 14:16:25 -05:00
{
2012-01-01 01:09:38 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHAR_CREATE_INFO );
2011-06-22 14:20:42 +02:00
stmt -> setUInt32 ( 0 , GetAccountId ());
stmt -> setUInt32 ( 1 , ( skipCinematics == 1 || createInfo -> Class == CLASS_DEATH_KNIGHT ) ? 10 : 1 );
_charCreateCallback . SetFutureResult ( CharacterDatabase . AsyncQuery ( stmt ));
2011-12-21 10:22:03 +01:00
_charCreateCallback . NextStage ();
2011-06-22 14:20:42 +02:00
return ;
}
2011-12-21 10:22:03 +01:00
_charCreateCallback . NextStage ();
2011-06-22 14:20:42 +02:00
HandleCharCreateCallback ( PreparedQueryResult ( NULL ), createInfo ); // Will jump to case 3
}
break ;
case 3 :
{
bool haveSameRace = false ;
uint32 heroicReqLevel = sWorld -> getIntConfig ( CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER );
bool hasHeroicReqLevel = ( heroicReqLevel == 0 );
2011-09-08 15:11:55 +02:00
bool allowTwoSideAccounts = ! sWorld -> IsPvPRealm () || sWorld -> getBoolConfig ( CONFIG_ALLOW_TWO_SIDE_ACCOUNTS ) || ! AccountMgr :: IsPlayerAccount ( GetSecurity ());
2011-06-22 14:20:42 +02:00
uint32 skipCinematics = sWorld -> getIntConfig ( CONFIG_SKIP_CINEMATICS );
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
if ( result )
{
uint32 team = Player :: TeamForRace ( createInfo -> Race );
uint32 freeHeroicSlots = sWorld -> getIntConfig ( CONFIG_HEROIC_CHARACTERS_PER_REALM );
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
Field * field = result -> Fetch ();
2011-06-23 15:00:44 +02:00
uint8 accRace = field [ 1 ]. GetUInt8 ();
2009-10-17 15:51:44 -07:00
2011-09-08 15:11:55 +02:00
if ( AccountMgr :: IsPlayerAccount ( GetSecurity ()) && createInfo -> Class == CLASS_DEATH_KNIGHT )
2008-10-11 14:16:25 -05:00
{
2011-06-23 15:00:44 +02:00
uint8 accClass = field [ 2 ]. GetUInt8 ();
2011-06-22 14:20:42 +02:00
if ( accClass == CLASS_DEATH_KNIGHT )
2008-12-24 09:58:26 -06:00
{
2011-06-22 14:20:42 +02:00
if ( freeHeroicSlots > 0 )
-- freeHeroicSlots ;
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
if ( freeHeroicSlots == 0 )
2008-12-24 09:58:26 -06:00
{
2011-06-22 14:20:42 +02:00
WorldPacket data ( SMSG_CHAR_CREATE , 1 );
data << uint8 ( CHAR_CREATE_UNIQUE_CLASS_LIMIT );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2011-06-22 14:20:42 +02:00
delete createInfo ;
2011-12-21 10:22:03 +01:00
_charCreateCallback . Reset ();
2008-12-24 09:58:26 -06:00
return ;
}
}
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
if ( ! hasHeroicReqLevel )
{
2011-06-23 15:00:44 +02:00
uint8 accLevel = field [ 0 ]. GetUInt8 ();
2011-06-22 14:20:42 +02:00
if ( accLevel >= heroicReqLevel )
hasHeroicReqLevel = true ;
}
}
// need to check team only for first character
// TODO: what to if account already has characters of both races?
if ( ! allowTwoSideAccounts )
{
uint32 accTeam = 0 ;
if ( accRace > 0 )
accTeam = Player :: TeamForRace ( accRace );
if ( accTeam != team )
{
WorldPacket data ( SMSG_CHAR_CREATE , 1 );
data << uint8 ( CHAR_CREATE_PVP_TEAMS_VIOLATION );
SendPacket ( & data );
delete createInfo ;
2011-12-21 10:22:03 +01:00
_charCreateCallback . Reset ();
2011-06-22 14:20:42 +02:00
return ;
}
}
// search same race for cinematic or same class if need
// TODO: check if cinematic already shown? (already logged in?; cinematic field)
while (( skipCinematics == 1 && ! haveSameRace ) || createInfo -> Class == CLASS_DEATH_KNIGHT )
{
if ( ! result -> NextRow ())
break ;
field = result -> Fetch ();
2011-06-23 15:00:44 +02:00
accRace = field [ 1 ]. GetUInt8 ();
2011-06-22 14:20:42 +02:00
if ( ! haveSameRace )
haveSameRace = createInfo -> Race == accRace ;
2011-09-08 15:11:55 +02:00
if ( AccountMgr :: IsPlayerAccount ( GetSecurity ()) && createInfo -> Class == CLASS_DEATH_KNIGHT )
2008-12-24 09:58:26 -06:00
{
2011-06-23 15:00:44 +02:00
uint8 acc_class = field [ 2 ]. GetUInt8 ();
2011-06-22 14:20:42 +02:00
if ( acc_class == CLASS_DEATH_KNIGHT )
{
if ( freeHeroicSlots > 0 )
-- freeHeroicSlots ;
if ( freeHeroicSlots == 0 )
{
WorldPacket data ( SMSG_CHAR_CREATE , 1 );
data << uint8 ( CHAR_CREATE_UNIQUE_CLASS_LIMIT );
SendPacket ( & data );
delete createInfo ;
2011-12-21 10:22:03 +01:00
_charCreateCallback . Reset ();
2011-06-22 14:20:42 +02:00
return ;
}
}
if ( ! hasHeroicReqLevel )
{
2011-06-23 15:00:44 +02:00
uint8 acc_level = field [ 0 ]. GetUInt8 ();
2011-06-22 14:20:42 +02:00
if ( acc_level >= heroicReqLevel )
hasHeroicReqLevel = true ;
}
2008-12-24 09:58:26 -06:00
}
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2011-09-08 15:11:55 +02:00
if ( AccountMgr :: IsPlayerAccount ( GetSecurity ()) && createInfo -> Class == CLASS_DEATH_KNIGHT && ! hasHeroicReqLevel )
2011-06-22 23:02:52 +02:00
{
WorldPacket data ( SMSG_CHAR_CREATE , 1 );
data << uint8 ( CHAR_CREATE_LEVEL_REQUIREMENT );
SendPacket ( & data );
delete createInfo ;
2011-12-21 10:22:03 +01:00
_charCreateCallback . Reset ();
2011-06-22 23:02:52 +02:00
return ;
}
2011-06-22 14:20:42 +02:00
if ( createInfo -> Data . rpos () < createInfo -> Data . wpos ())
{
uint8 unk ;
createInfo -> Data >> unk ;
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "Character creation %s (account %u) has unhandled tail data: [%u]" , createInfo -> Name . c_str (), GetAccountId (), unk );
}
2009-10-17 15:51:44 -07:00
2011-09-06 10:41:10 +02:00
Player newChar ( this );
if ( ! newChar . Create ( sObjectMgr -> GenerateLowGuid ( HIGHGUID_PLAYER ), createInfo ))
2011-06-22 14:20:42 +02:00
{
// Player not create (race/class/etc problem?)
2011-09-06 10:41:10 +02:00
newChar . CleanupsBeforeDelete ();
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
WorldPacket data ( SMSG_CHAR_CREATE , 1 );
data << uint8 ( CHAR_CREATE_ERROR );
SendPacket ( & data );
delete createInfo ;
2011-12-21 10:22:03 +01:00
_charCreateCallback . Reset ();
2011-06-22 14:20:42 +02:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
if (( haveSameRace && skipCinematics == 1 ) || skipCinematics == 2 )
2011-09-06 10:41:10 +02:00
newChar . setCinematic ( 1 ); // not show intro
2009-10-17 15:51:44 -07:00
2011-09-06 10:41:10 +02:00
newChar . SetAtLoginFlag ( AT_LOGIN_FIRST ); // First login
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
// Player created, save it now
2011-11-25 15:12:57 +01:00
newChar . SaveToDB ( true );
2011-06-22 14:20:42 +02:00
createInfo -> CharCount += 1 ;
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
SQLTransaction trans = LoginDatabase . BeginTransaction ();
2010-02-14 19:13:14 -07:00
2011-12-31 20:14:38 +01:00
PreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_DEL_REALM_CHARACTERS );
2011-06-22 14:20:42 +02:00
stmt -> setUInt32 ( 0 , GetAccountId ());
stmt -> setUInt32 ( 1 , realmID );
trans -> Append ( stmt );
2009-10-17 15:51:44 -07:00
2011-12-31 20:14:38 +01:00
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_INS_REALM_CHARACTERS );
2011-06-22 14:20:42 +02:00
stmt -> setUInt32 ( 0 , createInfo -> CharCount );
stmt -> setUInt32 ( 1 , GetAccountId ());
stmt -> setUInt32 ( 2 , realmID );
trans -> Append ( stmt );
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
LoginDatabase . CommitTransaction ( trans );
2010-08-08 19:45:53 +02:00
2011-09-06 10:41:10 +02:00
newChar . CleanupsBeforeDelete ();
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
WorldPacket data ( SMSG_CHAR_CREATE , 1 );
data << uint8 ( CHAR_CREATE_SUCCESS );
SendPacket ( & data );
2010-05-15 01:26:28 +02:00
2011-06-22 14:20:42 +02:00
std :: string IP_str = GetRemoteAddress ();
2011-09-06 10:41:10 +02:00
sLog -> outDetail ( "Account: %d (IP: %s) Create Character:[%s] (GUID: %u)" , GetAccountId (), IP_str . c_str (), createInfo -> Name . c_str (), newChar . GetGUIDLow ());
sLog -> outChar ( "Account: %d (IP: %s) Create Character:[%s] (GUID: %u)" , GetAccountId (), IP_str . c_str (), createInfo -> Name . c_str (), newChar . GetGUIDLow ());
sScriptMgr -> OnPlayerCreate ( & newChar );
2011-10-08 16:24:07 -04:00
sWorld -> AddCharacterNameData ( newChar . GetGUIDLow (), std :: string ( newChar . GetName ()), newChar . getGender (), newChar . getRace (), newChar . getClass ());
2011-06-22 14:20:42 +02:00
delete createInfo ;
2011-12-21 10:22:03 +01:00
_charCreateCallback . Reset ();
2011-06-22 14:20:42 +02:00
}
break ;
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession :: HandleCharDeleteOpcode ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
uint64 guid ;
recv_data >> guid ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// can't delete loaded character
2011-07-27 12:14:27 +02:00
if ( ObjectAccessor :: FindPlayer ( guid ))
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 accountId = 0 ;
std :: string name ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// is guild leader
2011-05-04 10:08:09 +02:00
if ( sGuildMgr -> GetGuildByLeader ( guid ))
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_CHAR_DELETE , 1 );
data << ( uint8 ) CHAR_DELETE_FAILED_GUILD_LEADER ;
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// is arena team captain
2011-05-03 15:01:10 +02:00
if ( sArenaTeamMgr -> GetArenaTeamByCaptain ( guid ))
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_CHAR_DELETE , 1 );
data << ( uint8 ) CHAR_DELETE_FAILED_ARENA_CAPTAIN ;
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
QueryResult result = CharacterDatabase . PQuery ( "SELECT account, name FROM characters WHERE guid='%u'" , GUID_LOPART ( guid ));
2010-04-07 19:14:10 +02:00
if ( result )
2008-10-11 14:16:25 -05:00
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2008-10-11 14:16:25 -05:00
accountId = fields [ 0 ]. GetUInt32 ();
2010-09-24 22:16:21 +02:00
name = fields [ 1 ]. GetString ();
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// prevent deleting other players' characters using cheating tools
2010-04-07 19:14:10 +02:00
if ( accountId != GetAccountId ())
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
std :: string IP_str = GetRemoteAddress ();
2011-04-29 20:47:02 +02:00
sLog -> outDetail ( "Account: %d (IP: %s) Delete Character:[%s] (GUID: %u)" , GetAccountId (), IP_str . c_str (), name . c_str (), GUID_LOPART ( guid ));
sLog -> outChar ( "Account: %d (IP: %s) Delete Character:[%s] (GUID: %u)" , GetAccountId (), IP_str . c_str (), name . c_str (), GUID_LOPART ( guid ));
2010-12-22 21:25:23 +01:00
sScriptMgr -> OnPlayerDelete ( guid );
2011-10-10 18:03:19 -04:00
sWorld -> DeleteCharaceterNameData ( GUID_LOPART ( guid ));
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
if ( sLog -> IsOutCharDump ()) // optimize GetPlayerDump call
2008-10-11 14:16:25 -05:00
{
2010-08-02 15:14:47 +02:00
std :: string dump ;
if ( PlayerDumpWriter (). GetDump ( GUID_LOPART ( guid ), dump ))
2011-04-29 20:47:02 +02:00
sLog -> outCharDump ( dump . c_str (), GetAccountId (), GUID_LOPART ( guid ), name . c_str ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
Player :: DeleteFromDB ( guid , GetAccountId ());
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
WorldPacket data ( SMSG_CHAR_DELETE , 1 );
data << ( uint8 ) CHAR_DELETE_SUCCESS ;
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession :: HandlePlayerLoginOpcode ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( PlayerLoading () || GetPlayer () != NULL )
2008-12-19 16:05:13 -06:00
{
2011-04-29 20:47:02 +02:00
sLog -> outError ( "Player tryes to login again, AccountId = %d" , GetAccountId ());
2008-12-19 16:05:13 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_playerLoading = true ;
uint64 playerGuid = 0 ;
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sLog -> outStaticDebug ( "WORLD: Recvd Player Logon Message" );
2009-10-17 15:51:44 -07:00
2011-11-27 12:17:24 +01:00
BitStream mask = recv_data . ReadBitStream ( 8 );
2011-11-26 20:38:00 +01:00
2011-11-27 12:17:24 +01:00
ByteBuffer bytes ( 8 , true );
2011-11-26 20:38:00 +01:00
2012-01-20 14:30:30 +01:00
recv_data . ReadXorByte ( mask [ 6 ], bytes [ 5 ]);
recv_data . ReadXorByte ( mask [ 0 ], bytes [ 0 ]);
recv_data . ReadXorByte ( mask [ 4 ], bytes [ 3 ]);
recv_data . ReadXorByte ( mask [ 1 ], bytes [ 4 ]);
recv_data . ReadXorByte ( mask [ 2 ], bytes [ 7 ]);
recv_data . ReadXorByte ( mask [ 5 ], bytes [ 2 ]);
recv_data . ReadXorByte ( mask [ 7 ], bytes [ 6 ]);
recv_data . ReadXorByte ( mask [ 3 ], bytes [ 1 ]);
2011-11-26 20:38:00 +01:00
2011-11-27 12:17:24 +01:00
playerGuid = BitConverter :: ToUInt64 ( bytes );
2011-11-26 20:38:00 +01:00
2011-12-27 10:05:49 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "Character (Guid: %u) logging in" , GUID_LOPART ( playerGuid ));
2009-10-17 15:51:44 -07:00
2011-04-01 03:11:57 +02:00
if ( ! CharCanLogin ( GUID_LOPART ( playerGuid )))
{
sLog -> outError ( "Account (%u) can't login with that character (%u)." , GetAccountId (), GUID_LOPART ( playerGuid ));
KickPlayer ();
return ;
}
2008-10-11 14:16:25 -05:00
LoginQueryHolder * holder = new LoginQueryHolder ( GetAccountId (), playerGuid );
2010-04-07 19:14:10 +02:00
if ( ! holder -> Initialize ())
2008-10-11 14:16:25 -05:00
{
delete holder ; // delete all unprocessed queries
m_playerLoading = false ;
return ;
}
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
_charLoginCallback = CharacterDatabase . DelayQueryHolder (( SQLQueryHolder * ) holder );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-11-24 18:58:00 +01:00
void WorldSession :: HandleLoadScreenOpcode ( WorldPacket & recvPacket )
{
sLog -> outStaticDebug ( "WORLD: Recvd CMSG_LOAD_SCREEN" );
uint8 unkMask ; // Loading start: 0x80, loading end: 0x0
uint32 mapID ;
recvPacket >> unkMask >> mapID ;
// TODO: Do something with this packet
}
2011-12-16 15:36:03 +01:00
void WorldSession :: HandlePlayerLogin ( LoginQueryHolder * holder )
2008-10-11 14:16:25 -05:00
{
uint64 playerGuid = holder -> GetGuid ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
Player * pCurrChar = new Player ( this );
2009-02-09 08:16:34 -05:00
// for send server info and strings (config)
2008-12-31 11:06:52 +01:00
ChatHandler chH = ChatHandler ( pCurrChar );
2009-10-17 15:51:44 -07:00
2010-04-07 23:25:02 +02:00
// "GetAccountId() == db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools)
2010-04-07 19:14:10 +02:00
if ( ! pCurrChar -> LoadFromDB ( GUID_LOPART ( playerGuid ), holder ))
2008-10-11 14:16:25 -05:00
{
2012-01-08 18:37:16 +00:00
SetPlayer ( NULL );
2008-10-11 14:16:25 -05:00
KickPlayer (); // disconnect client, player no set to session and it will not deleted or saved at kick
delete pCurrChar ; // delete it manually
delete holder ; // delete all unprocessed queries
m_playerLoading = false ;
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-09 10:48:55 -05:00
pCurrChar -> GetMotionMaster () -> Initialize ();
2008-10-11 14:16:25 -05:00
pCurrChar -> SendDungeonDifficulty ( false );
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
WorldPacket data ( SMSG_LOGIN_VERIFY_WORLD , 20 );
2008-10-11 14:16:25 -05:00
data << pCurrChar -> GetMapId ();
data << pCurrChar -> GetPositionX ();
data << pCurrChar -> GetPositionY ();
data << pCurrChar -> GetPositionZ ();
data << pCurrChar -> GetOrientation ();
SendPacket ( & data );
2009-10-17 15:51:44 -07:00
2009-09-01 16:47:49 -05:00
// load player specific part before send times
2010-09-20 18:20:40 +02:00
LoadAccountData ( holder -> GetPreparedResult ( PLAYER_LOGIN_QUERY_LOADACCOUNTDATA ), PER_CHARACTER_CACHE_MASK );
2009-12-17 10:49:15 +01:00
SendAccountDataTimes ( PER_CHARACTER_CACHE_MASK );
2009-10-17 15:51:44 -07:00
2011-11-27 23:42:55 +01:00
data . Initialize ( SMSG_FEATURE_SYSTEM_STATUS , 7 ); // checked in 4.2.2
2008-10-11 14:16:25 -05:00
data << uint8 ( 2 ); // unknown value
data << uint8 ( 0 ); // enable(1)/disable(0) voice chat interface in client
2011-11-27 23:42:55 +01:00
data << uint8 ( 0 );
data << uint32 ( 0 ); // mail related
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Send MOTD
{
data . Initialize ( SMSG_MOTD , 50 ); // new in 2.0.1
data << ( uint32 ) 0 ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 linecount = 0 ;
2010-12-23 23:25:44 +01:00
std :: string str_motd = sWorld -> GetMotd ();
2008-10-11 14:16:25 -05:00
std :: string :: size_type pos , nextpos ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
pos = 0 ;
2011-04-29 20:47:02 +02:00
while (( nextpos = str_motd . find ( '@' , pos )) != std :: string :: npos )
2008-10-11 14:16:25 -05:00
{
if ( nextpos != pos )
{
2011-04-29 20:47:02 +02:00
data << str_motd . substr ( pos , nextpos - pos );
2008-10-11 14:16:25 -05:00
++ linecount ;
}
pos = nextpos + 1 ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( pos < str_motd . length ())
{
data << str_motd . substr ( pos );
++ linecount ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
data . put ( 0 , linecount );
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2010-12-23 23:25:44 +01:00
sLog -> outStaticDebug ( "WORLD: Sent motd (SMSG_MOTD)" );
2009-10-17 15:51:44 -07:00
2009-02-09 08:16:34 -05:00
// send server info
2010-12-23 23:25:44 +01:00
if ( sWorld -> getIntConfig ( CONFIG_ENABLE_SINFO_LOGIN ) == 1 )
2008-12-31 11:06:52 +01:00
chH . PSendSysMessage ( _FULLVERSION );
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sLog -> outStaticDebug ( "WORLD: Sent server info" );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
//QueryResult* result = CharacterDatabase.PQuery("SELECT guildid, rank FROM guild_member WHERE guid = '%u'", pCurrChar->GetGUIDLow());
2010-09-20 18:20:40 +02:00
if ( PreparedQueryResult resultGuild = holder -> GetPreparedResult ( PLAYER_LOGIN_QUERY_LOADGUILD ))
2008-11-30 12:47:26 -06:00
{
2010-09-24 22:16:21 +02:00
Field * fields = resultGuild -> Fetch ();
pCurrChar -> SetInGuild ( fields [ 0 ]. GetUInt32 ());
pCurrChar -> SetRank ( fields [ 1 ]. GetUInt8 ());
2008-11-30 12:47:26 -06:00
}
2010-04-07 19:14:10 +02:00
else if ( pCurrChar -> GetGuildId ()) // clear guild related fields in case wrong data about non existed membership
2008-11-30 12:47:26 -06:00
{
pCurrChar -> SetInGuild ( 0 );
pCurrChar -> SetRank ( 0 );
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( pCurrChar -> GetGuildId () != 0 )
2008-10-11 14:16:25 -05:00
{
2011-10-07 10:54:53 -05:00
if ( Guild * guild = sGuildMgr -> GetGuildById ( pCurrChar -> GetGuildId ()))
guild -> SendLoginInfo ( this );
2008-10-11 14:16:25 -05:00
else
{
// remove wrong guild data
2011-04-29 20:47:02 +02:00
sLog -> outError ( "Player %s (GUID: %u) marked as member of not existing guild (id: %u), removing guild membership for player." , pCurrChar -> GetName (), pCurrChar -> GetGUIDLow (), pCurrChar -> GetGuildId ());
2008-11-30 12:47:26 -06:00
pCurrChar -> SetInGuild ( 0 );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2009-12-17 10:49:15 +01:00
data . Initialize ( SMSG_LEARNED_DANCE_MOVES , 4 + 4 );
data << uint32 ( 0 );
data << uint32 ( 0 );
SendPacket ( & data );
2012-01-31 14:02:59 +01:00
data . Initialize ( SMSG_HOTFIX_INFO );
HotfixData const & hotfix = sObjectMgr -> GetHotfixData ();
data << uint32 ( hotfix . size ());
for ( uint32 i = 0 ; i < hotfix . size (); ++ i )
{
data << uint32 ( hotfix [ i ]. Type );
2012-01-31 15:13:38 +01:00
data << uint32 ( hotfix [ i ]. Timestamp );
2012-01-31 14:02:59 +01:00
data << uint32 ( hotfix [ i ]. Entry );
}
SendPacket ( & data );
2008-10-11 14:16:25 -05:00
pCurrChar -> SendInitialPacketsBeforeAddToMap ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//Show cinematic at the first time that player login
2010-04-07 22:59:46 +02:00
if ( ! pCurrChar -> getCinematic ())
2008-10-11 14:16:25 -05:00
{
pCurrChar -> setCinematic ( 1 );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ChrClassesEntry const * cEntry = sChrClassesStore . LookupEntry ( pCurrChar -> getClass ()))
2008-10-11 14:16:25 -05:00
{
2009-04-05 16:25:00 -05:00
if ( cEntry -> CinematicSequence )
pCurrChar -> SendCinematicStart ( cEntry -> CinematicSequence );
else if ( ChrRacesEntry const * rEntry = sChrRacesStore . LookupEntry ( pCurrChar -> getRace ()))
pCurrChar -> SendCinematicStart ( rEntry -> CinematicSequence );
2009-10-17 15:51:44 -07:00
2009-02-09 08:16:34 -05:00
// send new char string if not empty
2010-12-23 23:25:44 +01:00
if ( ! sWorld -> GetNewCharString (). empty ())
chH . PSendSysMessage ( "%s" , sWorld -> GetNewCharString (). c_str ());
2009-04-05 16:25:00 -05:00
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2012-01-14 17:37:28 +01:00
if ( Group * group = pCurrChar -> GetGroup ())
{
if ( group -> isLFGGroup ())
{
LfgDungeonSet Dungeons ;
Dungeons . insert ( sLFGMgr -> GetDungeon ( group -> GetGUID ()));
sLFGMgr -> SetSelectedDungeons ( pCurrChar -> GetGUID (), Dungeons );
sLFGMgr -> SetState ( pCurrChar -> GetGUID (), sLFGMgr -> GetState ( group -> GetGUID ()));
}
}
2011-11-11 17:50:26 -05:00
if ( ! pCurrChar -> GetMap () -> AddPlayerToMap ( pCurrChar ) || ! pCurrChar -> CheckInstanceLoginValid ())
2008-10-11 14:16:25 -05:00
{
2010-12-22 21:25:23 +01:00
AreaTrigger const * at = sObjectMgr -> GetGoBackTrigger ( pCurrChar -> GetMapId ());
2010-04-07 19:14:10 +02:00
if ( at )
2008-12-04 10:56:50 -06:00
pCurrChar -> TeleportTo ( at -> target_mapId , at -> target_X , at -> target_Y , at -> target_Z , pCurrChar -> GetOrientation ());
else
pCurrChar -> TeleportTo ( pCurrChar -> m_homebindMapId , pCurrChar -> m_homebindX , pCurrChar -> m_homebindY , pCurrChar -> m_homebindZ , pCurrChar -> GetOrientation ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sObjectAccessor -> AddObject ( pCurrChar );
2011-04-29 20:47:02 +02:00
//sLog->outDebug("Player %s added to Map.", pCurrChar->GetName());
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
pCurrChar -> SendInitialPacketsAfterAddToMap ();
2009-10-17 15:51:44 -07:00
2012-01-01 01:09:38 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_ONLINE );
2011-12-31 00:32:05 +01:00
stmt -> setUInt32 ( 0 , pCurrChar -> GetGUIDLow ());
CharacterDatabase . Execute ( stmt );
2011-12-31 20:14:38 +01:00
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_UPD_ACCOUNT_ONLINE );
2011-12-31 00:32:05 +01:00
stmt -> setUInt32 ( 0 , GetAccountId ());
LoginDatabase . Execute ( stmt );
2010-04-07 22:59:46 +02:00
pCurrChar -> SetInGameTime ( getMSTime ());
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// announce group about member online (must be after add to player list to receive announce to self)
2011-06-12 01:47:45 +02:00
if ( Group * group = pCurrChar -> GetGroup ())
2008-10-11 14:16:25 -05:00
{
//pCurrChar->groupInfo.group->SendInit(this); // useless
group -> SendUpdate ();
2010-05-21 22:45:47 +02:00
group -> ResetMaxEnchantingLevel ();
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// friend status
2010-12-22 21:25:23 +01:00
sSocialMgr -> SendFriendStatus ( pCurrChar , FRIEND_ONLINE , pCurrChar -> GetGUIDLow (), true );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Place character in world (and load zone) before some object loading
pCurrChar -> LoadCorpse ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// setting Ghost+speed if dead
if ( pCurrChar -> m_deathState != ALIVE )
{
// not blizz like, we must correctly save and load player instead...
2010-04-07 19:14:10 +02:00
if ( pCurrChar -> getRace () == RACE_NIGHTELF )
2010-02-15 18:23:39 +01:00
pCurrChar -> CastSpell ( pCurrChar , 20584 , true , 0 ); // auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form)
pCurrChar -> CastSpell ( pCurrChar , 8326 , true , 0 ); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?)
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
pCurrChar -> SetMovement ( MOVE_WATER_WALK );
}
2009-10-17 15:51:44 -07:00
2009-08-12 20:27:00 -05:00
pCurrChar -> ContinueTaxiFlight ();
2009-10-17 15:51:44 -07:00
2009-06-23 13:05:15 +02:00
// reset for all pets before pet loading
2010-04-07 19:14:10 +02:00
if ( pCurrChar -> HasAtLoginFlag ( AT_LOGIN_RESET_PET_TALENTS ))
2009-06-23 13:05:15 +02:00
Pet :: resetTalentsForAllPetsOf ( pCurrChar );
2009-10-17 15:51:44 -07:00
2009-04-11 14:47:38 -05:00
// Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned)
pCurrChar -> LoadPet ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Set FFA PvP for non GM in non-rest mode
2011-04-29 20:47:02 +02:00
if ( sWorld -> IsFFAPvPRealm () && ! pCurrChar -> isGameMaster () && ! pCurrChar -> HasFlag ( PLAYER_FLAGS , PLAYER_FLAGS_RESTING ))
2008-12-31 10:05:45 -06:00
pCurrChar -> SetByteFlag ( UNIT_FIELD_BYTES_2 , 1 , UNIT_BYTE2_FLAG_FFA_PVP );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( pCurrChar -> HasFlag ( PLAYER_FLAGS , PLAYER_FLAGS_CONTESTED_PVP ))
2008-10-11 14:16:25 -05:00
pCurrChar -> SetContestedPvP ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Apply at_login requests
2010-04-07 19:14:10 +02:00
if ( pCurrChar -> HasAtLoginFlag ( AT_LOGIN_RESET_SPELLS ))
2008-10-11 14:16:25 -05:00
{
pCurrChar -> resetSpells ();
SendNotification ( LANG_RESET_SPELLS );
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( pCurrChar -> HasAtLoginFlag ( AT_LOGIN_RESET_TALENTS ))
2008-10-11 14:16:25 -05:00
{
2012-01-29 17:40:14 +01:00
pCurrChar -> ResetTalents ( true );
2009-08-02 10:11:48 +08:00
pCurrChar -> SendTalentsInfoData ( false ); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state
2008-10-11 14:16:25 -05:00
SendNotification ( LANG_RESET_TALENTS );
}
2009-10-17 15:51:44 -07:00
2010-02-14 19:13:14 -07:00
if ( pCurrChar -> HasAtLoginFlag ( AT_LOGIN_FIRST ))
pCurrChar -> RemoveAtLoginFlag ( AT_LOGIN_FIRST );
2008-10-11 14:16:25 -05:00
// show time before shutdown if shutdown planned.
2011-12-14 13:42:57 +01:00
if ( sWorld -> IsShuttingDown ())
2011-04-29 20:47:02 +02:00
sWorld -> ShutdownMsg ( true , pCurrChar );
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
if ( sWorld -> getBoolConfig ( CONFIG_ALL_TAXI_PATHS ))
2008-10-14 11:57:03 -05:00
pCurrChar -> SetTaxiCheater ( true );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( pCurrChar -> isGameMaster ())
2008-10-11 14:16:25 -05:00
SendNotification ( LANG_GM_ON );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
std :: string IP_str = GetRemoteAddress ();
2010-12-23 23:25:44 +01:00
sLog -> outChar ( "Account: %d (IP: %s) Login Character:[%s] (GUID: %u)" ,
2011-09-29 12:43:05 +02:00
GetAccountId (), IP_str . c_str (), pCurrChar -> GetName (), pCurrChar -> GetGUIDLow ());
2009-10-17 15:51:44 -07:00
2010-12-17 13:43:24 +01:00
if ( ! pCurrChar -> IsStandState () && ! pCurrChar -> HasUnitState ( UNIT_STAT_STUNNED ))
2009-08-05 16:03:33 -05:00
pCurrChar -> SetStandState ( UNIT_STAND_STATE_STAND );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_playerLoading = false ;
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
sScriptMgr -> OnPlayerLogin ( pCurrChar );
2008-10-11 14:16:25 -05:00
delete holder ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession :: HandleSetFactionAtWar ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outStaticDebug ( "WORLD: Received CMSG_SET_FACTION_ATWAR" );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 repListID ;
uint8 flag ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recv_data >> repListID ;
recv_data >> flag ;
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
GetPlayer () -> GetReputationMgr (). SetAtWar ( repListID , flag );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//I think this function is never used :/ I dunno, but i guess this opcode not exists
2010-04-07 22:59:46 +02:00
void WorldSession :: HandleSetFactionCheat ( WorldPacket & /*recv_data*/ )
2008-10-11 14:16:25 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "WORLD SESSION: HandleSetFactionCheat, not expected call, please report." );
2009-03-26 13:53:32 -06:00
GetPlayer () -> GetReputationMgr (). SendStates ();
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession :: HandleTutorialFlag ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
2011-02-24 23:57:43 +06:00
uint32 data ;
recv_data >> data ;
2009-10-17 15:51:44 -07:00
2011-02-24 23:57:43 +06:00
uint8 index = uint8 ( data / 32 );
if ( index >= MAX_ACCOUNT_TUTORIAL_VALUES )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-02-24 23:57:43 +06:00
uint32 value = ( data % 32 );
2009-10-17 15:51:44 -07:00
2011-02-24 23:57:43 +06:00
uint32 flag = GetTutorialInt ( index );
flag |= ( 1 << value );
SetTutorialInt ( index , flag );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession :: HandleTutorialClear ( WorldPacket & /*recv_data*/ )
2008-10-11 14:16:25 -05:00
{
2011-02-24 23:57:43 +06:00
for ( uint8 i = 0 ; i < MAX_ACCOUNT_TUTORIAL_VALUES ; ++ i )
2010-04-07 22:59:46 +02:00
SetTutorialInt ( i , 0xFFFFFFFF );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession :: HandleTutorialReset ( WorldPacket & /*recv_data*/ )
2008-10-11 14:16:25 -05:00
{
2011-02-24 23:57:43 +06:00
for ( uint8 i = 0 ; i < MAX_ACCOUNT_TUTORIAL_VALUES ; ++ i )
2010-04-07 22:59:46 +02:00
SetTutorialInt ( i , 0x00000000 );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-05-31 15:56:51 -05:00
void WorldSession :: HandleSetWatchedFactionOpcode ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outStaticDebug ( "WORLD: Received CMSG_SET_WATCHED_FACTION" );
2008-10-11 14:16:25 -05:00
uint32 fact ;
recv_data >> fact ;
GetPlayer () -> SetUInt32Value ( PLAYER_FIELD_WATCHED_FACTION_INDEX , fact );
}
2009-10-17 15:51:44 -07:00
2009-05-31 15:56:51 -05:00
void WorldSession :: HandleSetFactionInactiveOpcode ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outStaticDebug ( "WORLD: Received CMSG_SET_FACTION_INACTIVE" );
2008-10-11 14:16:25 -05:00
uint32 replistid ;
uint8 inactive ;
recv_data >> replistid >> inactive ;
2009-10-17 15:51:44 -07:00
2009-03-26 13:53:32 -06:00
_player -> GetReputationMgr (). SetInactive ( replistid , inactive );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-12-10 13:42:22 +01:00
void WorldSession :: HandleShowingHelmOpcode ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outStaticDebug ( "CMSG_SHOWING_HELM for %s" , _player -> GetName ());
2011-12-10 13:42:22 +01:00
recv_data . read_skip < uint8 > (); // unknown, bool?
2008-10-11 14:16:25 -05:00
_player -> ToggleFlag ( PLAYER_FLAGS , PLAYER_FLAGS_HIDE_HELM );
}
2009-10-17 15:51:44 -07:00
2011-12-10 13:42:22 +01:00
void WorldSession :: HandleShowingCloakOpcode ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outStaticDebug ( "CMSG_SHOWING_CLOAK for %s" , _player -> GetName ());
2011-12-10 13:42:22 +01:00
recv_data . read_skip < uint8 > (); // unknown, bool?
2008-10-11 14:16:25 -05:00
_player -> ToggleFlag ( PLAYER_FLAGS , PLAYER_FLAGS_HIDE_CLOAK );
}
2009-10-17 15:51:44 -07:00
2009-05-31 15:56:51 -05:00
void WorldSession :: HandleCharRenameOpcode ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
uint64 guid ;
2011-12-18 20:55:59 +01:00
std :: string newName ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recv_data >> guid ;
2011-12-18 20:55:59 +01:00
recv_data >> newName ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// prevent character rename to invalid name
2011-12-18 20:55:59 +01:00
if ( ! normalizePlayerName ( newName ))
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_CHAR_RENAME , 1 );
2008-12-24 09:58:26 -06:00
data << uint8 ( CHAR_NAME_NO_NAME );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-12-18 20:55:59 +01:00
uint8 res = ObjectMgr :: CheckPlayerName ( newName , true );
2009-07-10 08:25:33 +08:00
if ( res != CHAR_NAME_SUCCESS )
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_CHAR_RENAME , 1 );
2009-07-10 08:25:33 +08:00
data << uint8 ( res );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// check name limitations
2011-12-18 20:55:59 +01:00
if ( AccountMgr :: IsPlayerAccount ( GetSecurity ()) && sObjectMgr -> IsReservedName ( newName ))
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_CHAR_RENAME , 1 );
2008-12-24 09:58:26 -06:00
data << uint8 ( CHAR_NAME_RESERVED );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-12-18 20:55:59 +01:00
// Ensure that the character belongs to the current account, that rename at login is enabled
2008-12-22 10:59:38 -06:00
// and that there is no character with the desired new name
2011-12-18 20:55:59 +01:00
_charRenameCallback . SetParam ( newName );
2012-01-01 01:09:38 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_FREE_NAME );
2011-12-18 20:55:59 +01:00
stmt -> setUInt32 ( 0 , GUID_LOPART ( guid ));
stmt -> setUInt32 ( 1 , GetAccountId ());
stmt -> setUInt16 ( 2 , AT_LOGIN_RENAME );
stmt -> setUInt16 ( 3 , AT_LOGIN_RENAME );
stmt -> setString ( 4 , newName );
_charRenameCallback . SetFutureResult ( CharacterDatabase . AsyncQuery ( stmt ));
2008-12-19 16:05:13 -06:00
}
2009-10-17 15:51:44 -07:00
2011-12-18 20:55:59 +01:00
void WorldSession :: HandleChangePlayerNameOpcodeCallBack ( PreparedQueryResult result , std :: string newName )
2008-12-19 16:05:13 -06:00
{
2008-12-22 10:59:38 -06:00
if ( ! result )
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_CHAR_RENAME , 1 );
2008-12-24 09:58:26 -06:00
data << uint8 ( CHAR_CREATE_ERROR );
2010-08-18 19:48:51 +02:00
SendPacket ( & data );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-12-18 20:55:59 +01:00
Field * fields = result -> Fetch ();
uint32 guidLow = fields [ 0 ]. GetUInt32 ();
std :: string oldName = fields [ 1 ]. GetString ();
2008-12-22 10:59:38 -06:00
uint64 guid = MAKE_NEW_GUID ( guidLow , 0 , HIGHGUID_PLAYER );
2009-10-17 15:51:44 -07:00
2011-12-18 20:55:59 +01:00
// Update name and at_login flag in the db
2012-01-01 01:09:38 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_NAME );
2011-12-18 20:55:59 +01:00
stmt -> setString ( 0 , newName );
stmt -> setUInt16 ( 1 , AT_LOGIN_RENAME );
stmt -> setUInt32 ( 2 , guidLow );
CharacterDatabase . Execute ( stmt );
// Removed declined name from db
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_DECLINED_NAME );
stmt -> setUInt32 ( 0 , guidLow );
CharacterDatabase . Execute ( stmt );
2009-10-17 15:51:44 -07:00
2011-12-18 20:55:59 +01:00
sLog -> outChar ( "Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s" , GetAccountId (), GetRemoteAddress (). c_str (), oldName . c_str (), guidLow , newName . c_str ());
2009-10-17 15:51:44 -07:00
2011-12-18 20:55:59 +01:00
WorldPacket data ( SMSG_CHAR_RENAME , 1 + 8 + ( newName . size () + 1 ));
2008-12-24 09:58:26 -06:00
data << uint8 ( RESPONSE_SUCCESS );
data << uint64 ( guid );
2011-12-18 20:55:59 +01:00
data << newName ;
2010-08-18 19:48:51 +02:00
SendPacket ( & data );
2011-11-16 10:31:38 +01:00
2011-12-18 20:55:59 +01:00
sWorld -> UpdateCharacterNameData ( guidLow , newName );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-05-31 15:56:51 -05:00
void WorldSession :: HandleSetPlayerDeclinedNames ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
uint64 guid ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recv_data >> guid ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// not accept declined names for unsupported languages
std :: string name ;
2010-12-22 21:25:23 +01:00
if ( ! sObjectMgr -> GetPlayerNameByGUID ( guid , name ))
2008-10-11 14:16:25 -05:00
{
2008-11-20 17:40:13 -06:00
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( 1 );
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
std :: wstring wname ;
2010-04-07 19:14:10 +02:00
if ( ! Utf8toWStr ( name , wname ))
2008-10-11 14:16:25 -05:00
{
2008-11-20 17:40:13 -06:00
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( 1 );
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! isCyrillicCharacter ( wname [ 0 ])) // name already stored as only single alphabet using
2008-10-11 14:16:25 -05:00
{
2008-11-20 17:40:13 -06:00
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( 1 );
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
std :: string name2 ;
DeclinedName declinedname ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recv_data >> name2 ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( name2 != name ) // character have different name
2008-10-11 14:16:25 -05:00
{
2008-11-20 17:40:13 -06:00
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( 1 );
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( int i = 0 ; i < MAX_DECLINED_NAME_CASES ; ++ i )
2008-10-11 14:16:25 -05:00
{
recv_data >> declinedname . name [ i ];
2010-04-07 19:14:10 +02:00
if ( ! normalizePlayerName ( declinedname . name [ i ]))
2008-10-11 14:16:25 -05:00
{
2008-11-20 17:40:13 -06:00
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( 1 );
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
}
2009-10-17 15:51:44 -07:00
2011-05-10 18:52:28 +07:00
if ( ! ObjectMgr :: CheckDeclinedNames ( wname , declinedname ))
2008-10-11 14:16:25 -05:00
{
2008-11-20 17:40:13 -06:00
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( 1 );
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( int i = 0 ; i < MAX_DECLINED_NAME_CASES ; ++ i )
2011-06-30 14:52:44 +02:00
CharacterDatabase . EscapeString ( declinedname . name [ i ]);
2009-10-17 15:51:44 -07:00
2010-08-21 03:19:25 +02:00
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
trans -> PAppend ( "DELETE FROM character_declinedname WHERE guid = '%u'" , GUID_LOPART ( guid ));
2011-04-29 20:47:02 +02:00
trans -> PAppend ( "INSERT INTO character_declinedname (guid, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u', '%s', '%s', '%s', '%s', '%s')" ,
2008-11-20 17:40:13 -06:00
GUID_LOPART ( guid ), 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 ());
2010-08-21 03:19:25 +02:00
CharacterDatabase . CommitTransaction ( trans );
2009-10-17 15:51:44 -07:00
2008-11-20 17:40:13 -06:00
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( 0 ); // OK
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession :: HandleAlterAppearance ( WorldPacket & recv_data )
2008-12-24 09:58:26 -06:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "CMSG_ALTER_APPEARANCE" );
2009-10-17 15:51:44 -07:00
2009-12-17 10:49:15 +01:00
uint32 Hair , Color , FacialHair , SkinColor ;
recv_data >> Hair >> Color >> FacialHair >> SkinColor ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
BarberShopStyleEntry const * bs_hair = sBarberShopStyleStore . LookupEntry ( Hair );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! bs_hair || bs_hair -> type != 0 || bs_hair -> race != _player -> getRace () || bs_hair -> gender != _player -> getGender ())
2008-12-24 09:58:26 -06:00
return ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
BarberShopStyleEntry const * bs_facialHair = sBarberShopStyleStore . LookupEntry ( FacialHair );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! bs_facialHair || bs_facialHair -> type != 2 || bs_facialHair -> race != _player -> getRace () || bs_facialHair -> gender != _player -> getGender ())
2008-12-24 09:58:26 -06:00
return ;
2009-10-17 15:51:44 -07:00
2009-12-17 10:49:15 +01:00
BarberShopStyleEntry const * bs_skinColor = sBarberShopStyleStore . LookupEntry ( SkinColor );
2010-04-07 22:59:46 +02:00
if ( bs_skinColor && ( bs_skinColor -> type != 3 || bs_skinColor -> race != _player -> getRace () || bs_skinColor -> gender != _player -> getGender ()))
2009-12-17 10:49:15 +01:00
return ;
uint32 Cost = _player -> GetBarberShopCost ( bs_hair -> hair_id , Color , bs_facialHair -> hair_id , bs_skinColor );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// 0 - ok
2011-04-29 20:47:02 +02:00
// 1, 3 - not enough money
2008-12-24 09:58:26 -06:00
// 2 - you have to seat on barber chair
2010-08-23 22:58:32 +06:00
if ( ! _player -> HasEnoughMoney ( Cost ))
2008-12-24 09:58:26 -06:00
{
WorldPacket data ( SMSG_BARBER_SHOP_RESULT , 4 );
data << uint32 ( 1 ); // no money
SendPacket ( & data );
return ;
}
else
{
WorldPacket data ( SMSG_BARBER_SHOP_RESULT , 4 );
data << uint32 ( 0 ); // ok
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2009-03-05 09:22:43 -06:00
_player -> ModifyMoney ( - int32 ( Cost )); // it isn't free
_player -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER , Cost );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
_player -> SetByteValue ( PLAYER_BYTES , 2 , uint8 ( bs_hair -> hair_id ));
_player -> SetByteValue ( PLAYER_BYTES , 3 , uint8 ( Color ));
_player -> SetByteValue ( PLAYER_BYTES_2 , 0 , uint8 ( bs_facialHair -> hair_id ));
2009-12-17 10:49:15 +01:00
if ( bs_skinColor )
_player -> SetByteValue ( PLAYER_BYTES , 0 , uint8 ( bs_skinColor -> hair_id ));
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
_player -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP , 1 );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
_player -> SetStandState ( 0 ); // stand up
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession :: HandleRemoveGlyph ( WorldPacket & recv_data )
2008-12-24 09:58:26 -06:00
{
uint32 slot ;
recv_data >> slot ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( slot >= MAX_GLYPH_SLOT_INDEX )
2008-12-24 09:58:26 -06:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "Client sent wrong glyph slot number in opcode CMSG_REMOVE_GLYPH %u" , slot );
2009-03-21 14:53:38 -06:00
return ;
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2012-01-29 17:40:14 +01:00
if ( uint32 glyph = _player -> GetGlyph ( _player -> GetActiveSpec (), slot ))
2009-03-21 14:54:21 -06:00
{
2011-09-15 14:08:17 +02:00
if ( GlyphPropertiesEntry const * gp = sGlyphPropertiesStore . LookupEntry ( glyph ))
2009-03-21 14:54:21 -06:00
{
_player -> RemoveAurasDueToSpell ( gp -> SpellId );
_player -> SetGlyph ( slot , 0 );
2009-06-11 00:45:59 -05:00
_player -> SendTalentsInfoData ( false );
2009-03-21 14:54:21 -06:00
}
}
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
void WorldSession :: HandleCharCustomize ( WorldPacket & recv_data )
{
uint64 guid ;
2011-12-31 00:32:05 +01:00
std :: string newName ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
recv_data >> guid ;
2011-12-31 00:32:05 +01:00
recv_data >> newName ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
uint8 gender , skin , face , hairStyle , hairColor , facialHair ;
2009-03-20 14:28:45 -06:00
recv_data >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face ;
2009-10-17 15:51:44 -07:00
2010-09-11 21:10:54 +02:00
QueryResult result = CharacterDatabase . PQuery ( "SELECT at_login FROM characters WHERE guid ='%u'" , GUID_LOPART ( guid ));
2008-12-24 09:58:26 -06:00
if ( ! result )
{
WorldPacket data ( SMSG_CHAR_CUSTOMIZE , 1 );
data << uint8 ( CHAR_CREATE_ERROR );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-12-24 09:58:26 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2011-01-19 22:46:21 +01:00
uint32 at_loginFlags = fields [ 0 ]. GetUInt16 ();
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( ! ( at_loginFlags & AT_LOGIN_CUSTOMIZE ))
{
WorldPacket data ( SMSG_CHAR_CUSTOMIZE , 1 );
data << uint8 ( CHAR_CREATE_ERROR );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-12-24 09:58:26 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// prevent character rename to invalid name
2011-12-31 00:32:05 +01:00
if ( ! normalizePlayerName ( newName ))
2008-12-24 09:58:26 -06:00
{
WorldPacket data ( SMSG_CHAR_CUSTOMIZE , 1 );
data << uint8 ( CHAR_NAME_NO_NAME );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-12-24 09:58:26 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-12-31 00:32:05 +01:00
uint8 res = ObjectMgr :: CheckPlayerName ( newName , true );
2009-07-10 08:25:33 +08:00
if ( res != CHAR_NAME_SUCCESS )
2008-12-24 09:58:26 -06:00
{
WorldPacket data ( SMSG_CHAR_CUSTOMIZE , 1 );
2009-07-10 08:25:33 +08:00
data << uint8 ( res );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-12-24 09:58:26 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// check name limitations
2011-12-31 00:32:05 +01:00
if ( AccountMgr :: IsPlayerAccount ( GetSecurity ()) && sObjectMgr -> IsReservedName ( newName ))
2008-12-24 09:58:26 -06:00
{
WorldPacket data ( SMSG_CHAR_CUSTOMIZE , 1 );
data << uint8 ( CHAR_NAME_RESERVED );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2008-12-24 09:58:26 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-02-22 17:26:03 -06:00
// character with this name already exist
2011-12-31 00:32:05 +01:00
if ( uint64 newguid = sObjectMgr -> GetPlayerGUIDByName ( newName ))
2008-12-24 09:58:26 -06:00
{
2009-07-10 08:25:33 +08:00
if ( newguid != guid )
2009-02-22 17:26:03 -06:00
{
WorldPacket data ( SMSG_CHAR_CUSTOMIZE , 1 );
data << uint8 ( CHAR_CREATE_NAME_IN_USE );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2009-02-22 17:26:03 -06:00
return ;
}
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2011-11-23 19:17:33 +01:00
if ( QueryResult oldNameResult = CharacterDatabase . PQuery ( "SELECT name FROM characters WHERE guid ='%u'" , GUID_LOPART ( guid )))
2009-08-16 16:32:11 -05:00
{
2011-11-23 19:17:33 +01:00
std :: string oldname = oldNameResult -> Fetch ()[ 0 ]. GetString ();
2009-08-16 16:32:11 -05:00
std :: string IP_str = GetRemoteAddress ();
2011-12-31 00:32:05 +01:00
sLog -> outChar ( "Account: %d (IP: %s), Character[%s] (guid:%u) Customized to: %s" , GetAccountId (), IP_str . c_str (), oldname . c_str (), GUID_LOPART ( guid ), newName . c_str ());
2009-08-16 16:32:11 -05:00
}
2008-12-24 09:58:26 -06:00
Player :: Customize ( guid , gender , skin , face , hairStyle , hairColor , facialHair );
2009-10-17 15:51:44 -07:00
2012-01-01 01:09:38 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_NAME_AT_LOGIN );
2011-12-31 00:32:05 +01:00
stmt -> setString ( 0 , newName );
stmt -> setUInt16 ( 1 , uint16 ( AT_LOGIN_CUSTOMIZE ));
stmt -> setUInt32 ( 2 , GUID_LOPART ( guid ));
CharacterDatabase . Execute ( stmt );
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_DECLINED_NAME );
stmt -> setUInt32 ( 0 , GUID_LOPART ( guid ));
CharacterDatabase . Execute ( stmt );
sWorld -> UpdateCharacterNameData ( GUID_LOPART ( guid ), newName , gender );
WorldPacket data ( SMSG_CHAR_CUSTOMIZE , 1 + 8 + ( newName . size () + 1 ) + 6 );
2008-12-24 09:58:26 -06:00
data << uint8 ( RESPONSE_SUCCESS );
data << uint64 ( guid );
2011-12-31 00:32:05 +01:00
data << newName ;
2008-12-24 09:58:26 -06:00
data << uint8 ( gender );
data << uint8 ( skin );
data << uint8 ( face );
data << uint8 ( hairStyle );
data << uint8 ( hairColor );
data << uint8 ( facialHair );
2009-02-19 22:30:30 -06:00
SendPacket ( & data );
2009-02-18 22:39:00 +01:00
}
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
void WorldSession :: HandleEquipmentSetSave ( WorldPacket & recv_data )
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "CMSG_EQUIPMENT_SET_SAVE" );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint64 setGuid ;
2010-08-08 20:32:14 +02:00
recv_data . readPackGUID ( setGuid );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint32 index ;
recv_data >> index ;
2010-04-07 19:14:10 +02:00
if ( index >= MAX_EQUIPMENT_SET_INDEX ) // client set slots amount
2009-06-11 00:45:59 -05:00
return ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
std :: string name ;
recv_data >> name ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
std :: string iconName ;
recv_data >> iconName ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
EquipmentSet eqSet ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
eqSet . Guid = setGuid ;
eqSet . Name = name ;
eqSet . IconName = iconName ;
eqSet . state = EQUIPMENT_SET_NEW ;
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( uint32 i = 0 ; i < EQUIPMENT_SLOT_END ; ++ i )
2009-06-11 00:45:59 -05:00
{
uint64 itemGuid ;
2010-08-08 20:32:14 +02:00
recv_data . readPackGUID ( itemGuid );
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
Item * item = _player -> GetItemByPos ( INVENTORY_SLOT_BAG_0 , i );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! item && itemGuid ) // cheating check 1
2009-06-11 00:45:59 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( item && item -> GetGUID () != itemGuid ) // cheating check 2
2009-06-11 00:45:59 -05:00
return ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
eqSet . Items [ i ] = GUID_LOPART ( itemGuid );
}
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
_player -> SetEquipmentSet ( index , eqSet );
}
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
void WorldSession :: HandleEquipmentSetDelete ( WorldPacket & recv_data )
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "CMSG_EQUIPMENT_SET_DELETE" );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint64 setGuid ;
2010-08-08 20:32:14 +02:00
recv_data . readPackGUID ( setGuid );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
_player -> DeleteEquipmentSet ( setGuid );
}
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
void WorldSession :: HandleEquipmentSetUse ( WorldPacket & recv_data )
{
2011-06-17 18:07:34 +02:00
if ( _player -> isInCombat ())
return ;
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "CMSG_EQUIPMENT_SET_USE" );
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( uint32 i = 0 ; i < EQUIPMENT_SLOT_END ; ++ i )
2009-06-11 00:45:59 -05:00
{
uint64 itemGuid ;
2010-08-08 20:32:14 +02:00
recv_data . readPackGUID ( itemGuid );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint8 srcbag , srcslot ;
recv_data >> srcbag >> srcslot ;
2009-10-17 15:51:44 -07:00
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_PLAYER_ITEMS , "Item " UI64FMTD ": srcbag %u, srcslot %u" , itemGuid , srcbag , srcslot );
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
Item * item = _player -> GetItemByGuid ( itemGuid );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint16 dstpos = i | ( INVENTORY_SLOT_BAG_0 << 8 );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! item )
2009-06-11 00:45:59 -05:00
{
2011-09-15 14:08:17 +02:00
Item * uItem = _player -> GetItemByPos ( INVENTORY_SLOT_BAG_0 , i );
2010-04-07 19:14:10 +02:00
if ( ! uItem )
2009-06-11 00:45:59 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
ItemPosCountVec sDest ;
2011-04-29 16:48:15 +06:00
InventoryResult msg = _player -> CanStoreItem ( NULL_BAG , NULL_SLOT , sDest , uItem , false );
2010-04-07 19:14:10 +02:00
if ( msg == EQUIP_ERR_OK )
2009-06-11 00:45:59 -05:00
{
_player -> RemoveItem ( INVENTORY_SLOT_BAG_0 , i , true );
2010-04-07 22:59:46 +02:00
_player -> StoreItem ( sDest , uItem , true );
2009-06-11 00:45:59 -05:00
}
else
_player -> SendEquipError ( msg , uItem , NULL );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( item -> GetPos () == dstpos )
2009-06-11 00:45:59 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
_player -> SwapItem ( item -> GetPos (), dstpos );
}
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
WorldPacket data ( SMSG_EQUIPMENT_SET_USE_RESULT , 1 );
data << uint8 ( 0 ); // 4 - equipment swap failed - inventory is full
SendPacket ( & data );
}
2010-09-05 13:12:24 -07:00
void WorldSession :: HandleCharFactionOrRaceChange ( WorldPacket & recv_data )
{
2010-12-15 14:08:12 +06:00
// TODO: Move queries to prepared statements
2010-09-05 13:12:24 -07:00
uint64 guid ;
std :: string newname ;
uint8 gender , skin , face , hairStyle , hairColor , facialHair , race ;
recv_data >> guid ;
recv_data >> newname ;
recv_data >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face >> race ;
2010-12-23 19:15:44 +01:00
uint32 lowGuid = GUID_LOPART ( guid );
QueryResult result = CharacterDatabase . PQuery ( "SELECT class, level, at_login FROM characters WHERE guid ='%u'" , lowGuid );
2010-09-05 13:12:24 -07:00
if ( ! result )
{
WorldPacket data ( SMSG_CHAR_FACTION_CHANGE , 1 );
data << uint8 ( CHAR_CREATE_ERROR );
2010-12-23 19:15:44 +01:00
SendPacket ( & data );
2010-09-05 13:12:24 -07:00
return ;
}
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2010-09-05 13:12:24 -07:00
uint32 playerClass = fields [ 0 ]. GetUInt32 ();
uint32 level = fields [ 1 ]. GetUInt32 ();
2011-01-19 22:46:21 +01:00
uint32 at_loginFlags = fields [ 2 ]. GetUInt16 ();
2010-09-05 13:12:24 -07:00
uint32 used_loginFlag = (( recv_data . GetOpcode () == CMSG_CHAR_RACE_CHANGE ) ? AT_LOGIN_CHANGE_RACE : AT_LOGIN_CHANGE_FACTION );
2010-12-22 21:25:23 +01:00
if ( ! sObjectMgr -> GetPlayerInfo ( race , playerClass ))
2010-09-05 13:12:24 -07:00
{
WorldPacket data ( SMSG_CHAR_FACTION_CHANGE , 1 );
data << uint8 ( CHAR_CREATE_ERROR );
2010-12-23 19:15:44 +01:00
SendPacket ( & data );
2010-09-05 13:12:24 -07:00
return ;
}
if ( ! ( at_loginFlags & used_loginFlag ))
{
WorldPacket data ( SMSG_CHAR_FACTION_CHANGE , 1 );
data << uint8 ( CHAR_CREATE_ERROR );
2010-12-23 19:15:44 +01:00
SendPacket ( & data );
2010-09-05 13:12:24 -07:00
return ;
}
2010-09-12 01:40:27 +02:00
2011-09-08 15:11:55 +02:00
if ( AccountMgr :: IsPlayerAccount ( GetSecurity ()))
2010-09-06 10:42:53 -07:00
{
2010-12-23 23:25:44 +01:00
uint32 raceMaskDisabled = sWorld -> getIntConfig ( CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK );
2010-09-06 10:42:53 -07:00
if (( 1 << ( race - 1 )) & raceMaskDisabled )
{
WorldPacket data ( SMSG_CHAR_FACTION_CHANGE , 1 );
data << uint8 ( CHAR_CREATE_ERROR );
2010-12-23 19:15:44 +01:00
SendPacket ( & data );
2010-09-06 10:42:53 -07:00
return ;
}
}
2010-09-05 13:12:24 -07:00
// prevent character rename to invalid name
if ( ! normalizePlayerName ( newname ))
{
WorldPacket data ( SMSG_CHAR_FACTION_CHANGE , 1 );
data << uint8 ( CHAR_NAME_NO_NAME );
2010-12-23 19:15:44 +01:00
SendPacket ( & data );
2010-09-05 13:12:24 -07:00
return ;
}
2011-04-29 20:47:02 +02:00
uint8 res = ObjectMgr :: CheckPlayerName ( newname , true );
2010-09-05 13:12:24 -07:00
if ( res != CHAR_NAME_SUCCESS )
{
WorldPacket data ( SMSG_CHAR_FACTION_CHANGE , 1 );
data << uint8 ( res );
2010-12-23 19:15:44 +01:00
SendPacket ( & data );
2010-09-05 13:12:24 -07:00
return ;
}
// check name limitations
2011-09-08 15:11:55 +02:00
if ( AccountMgr :: IsPlayerAccount ( GetSecurity ()) && sObjectMgr -> IsReservedName ( newname ))
2010-09-05 13:12:24 -07:00
{
WorldPacket data ( SMSG_CHAR_FACTION_CHANGE , 1 );
data << uint8 ( CHAR_NAME_RESERVED );
2010-12-23 19:15:44 +01:00
SendPacket ( & data );
2010-09-05 13:12:24 -07:00
return ;
}
// character with this name already exist
2010-12-22 21:25:23 +01:00
if ( uint64 newguid = sObjectMgr -> GetPlayerGUIDByName ( newname ))
2010-09-05 13:12:24 -07:00
{
if ( newguid != guid )
{
WorldPacket data ( SMSG_CHAR_FACTION_CHANGE , 1 );
data << uint8 ( CHAR_CREATE_NAME_IN_USE );
2010-12-23 19:15:44 +01:00
SendPacket ( & data );
2010-09-05 13:12:24 -07:00
return ;
}
}
2011-06-30 14:52:44 +02:00
CharacterDatabase . EscapeString ( newname );
2010-09-05 13:12:24 -07:00
Player :: Customize ( guid , gender , skin , face , hairStyle , hairColor , facialHair );
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
2010-12-23 19:15:44 +01:00
trans -> PAppend ( "UPDATE `characters` SET name='%s', race='%u', at_login=at_login & ~ %u WHERE guid='%u'" , newname . c_str (), race , used_loginFlag , lowGuid );
trans -> PAppend ( "DELETE FROM character_declinedname WHERE guid ='%u'" , lowGuid );
2011-11-16 10:31:38 +01:00
sWorld -> UpdateCharacterNameData ( GUID_LOPART ( guid ), newname , gender , race );
2010-09-05 13:12:24 -07:00
2010-12-23 19:15:44 +01:00
BattlegroundTeamId team = BG_TEAM_ALLIANCE ;
2010-09-05 13:12:24 -07:00
// Search each faction is targeted
2010-12-23 19:15:44 +01:00
switch ( race )
2010-09-05 13:12:24 -07:00
{
2010-12-23 19:15:44 +01:00
case RACE_ORC :
2012-01-14 19:27:14 +00:00
case RACE_GOBLIN :
2010-12-23 19:15:44 +01:00
case RACE_TAUREN :
case RACE_UNDEAD_PLAYER :
case RACE_TROLL :
case RACE_BLOODELF :
team = BG_TEAM_HORDE ;
break ;
default :
break ;
2010-09-05 13:12:24 -07:00
}
// Switch Languages
// delete all languages first
2012-01-14 19:27:14 +00:00
trans -> PAppend ( "DELETE FROM `character_skills` WHERE `skill` IN (98, 113, 759, 111, 313, 109, 115, 315, 673, 137, 791, 792) AND `guid`='%u'" , lowGuid );
2010-09-05 13:12:24 -07:00
// now add them back
if ( team == BG_TEAM_ALLIANCE )
{
2010-12-23 19:15:44 +01:00
trans -> PAppend ( "INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 98, 300, 300)" , lowGuid );
2010-09-05 13:12:24 -07:00
switch ( race )
{
case RACE_DWARF :
2010-12-23 19:15:44 +01:00
trans -> PAppend ( "INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 111, 300, 300)" , lowGuid );
2010-09-05 13:12:24 -07:00
break ;
case RACE_DRAENEI :
2010-12-23 19:15:44 +01:00
trans -> PAppend ( "INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 759, 300, 300)" , lowGuid );
2010-09-05 13:12:24 -07:00
break ;
case RACE_GNOME :
2010-12-23 19:15:44 +01:00
trans -> PAppend ( "INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 313, 300, 300)" , lowGuid );
2010-09-05 13:12:24 -07:00
break ;
case RACE_NIGHTELF :
2010-12-23 19:15:44 +01:00
trans -> PAppend ( "INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 113, 300, 300)" , lowGuid );
2010-09-05 13:12:24 -07:00
break ;
2012-01-14 19:27:14 +00:00
case RACE_WORGEN :
trans -> PAppend ( "INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 791, 300, 300)" , lowGuid );
break ;
2010-09-05 13:12:24 -07:00
}
}
else if ( team == BG_TEAM_HORDE )
{
2010-12-23 19:15:44 +01:00
trans -> PAppend ( "INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 109, 300, 300)" , lowGuid );
2010-09-05 13:12:24 -07:00
switch ( race )
{
case RACE_UNDEAD_PLAYER :
2010-12-23 19:15:44 +01:00
trans -> PAppend ( "INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 673, 300, 300)" , lowGuid );
2010-09-05 13:12:24 -07:00
break ;
case RACE_TAUREN :
2010-12-23 19:15:44 +01:00
trans -> PAppend ( "INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 115, 300, 300)" , lowGuid );
2010-09-05 13:12:24 -07:00
break ;
case RACE_TROLL :
2010-12-23 19:15:44 +01:00
trans -> PAppend ( "INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 315, 300, 300)" , lowGuid );
2010-09-05 13:12:24 -07:00
break ;
case RACE_BLOODELF :
2010-12-23 19:15:44 +01:00
trans -> PAppend ( "INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 137, 300, 300)" , lowGuid );
2010-09-05 13:12:24 -07:00
break ;
2012-01-14 19:27:14 +00:00
case RACE_GOBLIN :
trans -> PAppend ( "INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 792, 300, 300)" , lowGuid );
break ;
2010-09-05 13:12:24 -07:00
}
}
2010-12-23 19:15:44 +01:00
if ( recv_data . GetOpcode () == CMSG_CHAR_FACTION_CHANGE )
2010-09-05 13:12:24 -07:00
{
// Delete all Flypaths
2010-12-23 19:15:44 +01:00
trans -> PAppend ( "UPDATE `characters` SET taxi_path = '' WHERE guid ='%u'" , lowGuid );
2010-09-05 13:12:24 -07:00
if ( level > 7 )
{
// Update Taxi path
// this doesn't seem to be 100% blizzlike... but it can't really be helped.
std :: ostringstream taximaskstream ;
uint32 numFullTaximasks = level / 7 ;
if ( numFullTaximasks > 11 )
numFullTaximasks = 11 ;
if ( team == BG_TEAM_ALLIANCE )
{
if ( playerClass != CLASS_DEATH_KNIGHT )
{
for ( uint8 i = 0 ; i < numFullTaximasks ; ++ i )
2011-07-29 14:18:28 +02:00
taximaskstream << uint32 ( sAllianceTaxiNodesMask [ i ]) << ' ' ;
2010-09-05 13:12:24 -07:00
}
else
{
for ( uint8 i = 0 ; i < numFullTaximasks ; ++ i )
2011-07-29 14:18:28 +02:00
taximaskstream << uint32 ( sAllianceTaxiNodesMask [ i ] | sDeathKnightTaxiNodesMask [ i ]) << ' ' ;
2010-09-05 13:12:24 -07:00
}
}
else
{
if ( playerClass != CLASS_DEATH_KNIGHT )
{
for ( uint8 i = 0 ; i < numFullTaximasks ; ++ i )
2011-07-29 14:18:28 +02:00
taximaskstream << uint32 ( sHordeTaxiNodesMask [ i ]) << ' ' ;
2010-09-05 13:12:24 -07:00
}
else
{
for ( uint8 i = 0 ; i < numFullTaximasks ; ++ i )
2011-07-29 14:18:28 +02:00
taximaskstream << uint32 ( sHordeTaxiNodesMask [ i ] | sDeathKnightTaxiNodesMask [ i ]) << ' ' ;
2010-09-05 13:12:24 -07:00
}
}
uint32 numEmptyTaximasks = 11 - numFullTaximasks ;
for ( uint8 i = 0 ; i < numEmptyTaximasks ; ++ i )
taximaskstream << "0 " ;
2011-07-29 14:18:28 +02:00
taximaskstream << '0' ;
2010-09-05 13:12:24 -07:00
std :: string taximask = taximaskstream . str ();
2010-12-23 19:15:44 +01:00
trans -> PAppend ( "UPDATE `characters` SET `taximask`= '%s' WHERE `guid` = '%u'" , taximask . c_str (), lowGuid );
2010-09-05 13:12:24 -07:00
}
// Delete all current quests
2011-04-29 20:47:02 +02:00
trans -> PAppend ( "DELETE FROM `character_queststatus` WHERE guid ='%u'" , GUID_LOPART ( guid ));
2010-09-05 13:12:24 -07:00
// Delete record of the faction old completed quests
{
std :: ostringstream quests ;
2010-12-22 21:25:23 +01:00
ObjectMgr :: QuestMap const & qTemplates = sObjectMgr -> GetQuestTemplates ();
2010-09-05 13:12:24 -07:00
for ( ObjectMgr :: QuestMap :: const_iterator iter = qTemplates . begin (); iter != qTemplates . end (); ++ iter )
{
Quest * qinfo = iter -> second ;
uint32 requiredRaces = qinfo -> GetRequiredRaces ();
if ( team == BG_TEAM_ALLIANCE )
{
if ( requiredRaces & RACEMASK_ALLIANCE )
{
quests << uint32 ( qinfo -> GetQuestId ());
2011-07-29 14:18:28 +02:00
quests << ',' ;
2010-09-05 13:12:24 -07:00
}
}
else // if (team == BG_TEAM_HORDE)
{
if ( requiredRaces & RACEMASK_HORDE )
{
quests << uint32 ( qinfo -> GetQuestId ());
2011-07-29 14:18:28 +02:00
quests << ',' ;
2010-09-05 13:12:24 -07:00
}
}
}
std :: string questsStr = quests . str ();
questsStr = questsStr . substr ( 0 , questsStr . length () - 1 );
2010-12-23 19:15:44 +01:00
if ( ! questsStr . empty ())
2010-12-26 04:16:18 +01:00
trans -> PAppend ( "DELETE FROM `character_queststatus_rewarded` WHERE guid='%u' AND quest IN (%s)" , lowGuid , questsStr . c_str ());
2010-09-05 13:12:24 -07:00
}
2010-12-23 23:25:44 +01:00
if ( ! sWorld -> getBoolConfig ( CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD ))
2010-09-05 13:12:24 -07:00
{
// Reset guild
2012-01-05 00:50:33 +02:00
if ( QueryResult result = CharacterDatabase . PQuery ( "SELECT guildid FROM `guild_member` WHERE guid ='%u'" , lowGuid ))
if ( Guild * guild = sGuildMgr -> GetGuildById (( result -> Fetch ()[ 0 ]). GetUInt32 ()))
guild -> DeleteMember ( MAKE_NEW_GUID ( lowGuid , 0 , HIGHGUID_PLAYER ));
2010-09-05 13:12:24 -07:00
}
2010-12-23 23:25:44 +01:00
if ( ! sWorld -> getBoolConfig ( CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND ))
2010-09-05 13:12:24 -07:00
{
// Delete Friend List
2010-12-23 19:15:44 +01:00
trans -> PAppend ( "DELETE FROM `character_social` WHERE `guid`= '%u'" , lowGuid );
trans -> PAppend ( "DELETE FROM `character_social` WHERE `friend`= '%u'" , lowGuid );
2010-09-05 13:12:24 -07:00
}
// Leave Arena Teams
2010-12-23 19:15:44 +01:00
Player :: LeaveAllArenaTeams ( guid );
2010-09-05 13:12:24 -07:00
// Reset homebind and position
2011-04-08 17:04:51 +06:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_PLAYER_HOMEBIND );
stmt -> setUInt32 ( 0 , lowGuid );
trans -> Append ( stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_INS_PLAYER_HOMEBIND );
2011-04-08 17:04:51 +06:00
stmt -> setUInt32 ( 0 , lowGuid );
2010-12-23 19:15:44 +01:00
if ( team == BG_TEAM_ALLIANCE )
2010-09-05 13:12:24 -07:00
{
2011-04-08 17:04:51 +06:00
stmt -> setUInt16 ( 1 , 0 );
stmt -> setUInt16 ( 2 , 1519 );
stmt -> setFloat ( 3 , - 8867.68f );
stmt -> setFloat ( 4 , 673.373f );
stmt -> setFloat ( 5 , 97.9034f );
2010-12-23 19:15:44 +01:00
Player :: SavePositionInDB ( 0 , - 8867.68f , 673.373f , 97.9034f , 0.0f , 1519 , lowGuid );
2010-09-05 13:12:24 -07:00
}
else
{
2011-04-08 17:04:51 +06:00
stmt -> setUInt16 ( 1 , 1 );
stmt -> setUInt16 ( 2 , 1637 );
stmt -> setFloat ( 3 , 1633.33f );
stmt -> setFloat ( 4 , - 4439.11f );
stmt -> setFloat ( 5 , 15.7588f );
2010-12-23 19:15:44 +01:00
Player :: SavePositionInDB ( 1 , 1633.33f , - 4439.11f , 15.7588f , 0.0f , 1637 , lowGuid );
2010-09-05 13:12:24 -07:00
}
2011-04-08 17:04:51 +06:00
trans -> Append ( stmt );
2010-09-05 13:12:24 -07:00
// Achievement conversion
2010-12-22 21:25:23 +01:00
for ( std :: map < uint32 , uint32 >:: const_iterator it = sObjectMgr -> factionchange_achievements . begin (); it != sObjectMgr -> factionchange_achievements . end (); ++ it )
2010-09-05 13:12:24 -07:00
{
uint32 achiev_alliance = it -> first ;
uint32 achiev_horde = it -> second ;
2010-09-05 16:45:18 -07:00
trans -> PAppend ( "DELETE FROM `character_achievement` WHERE `achievement`=%u AND `guid`=%u" ,
2010-12-23 19:15:44 +01:00
team == BG_TEAM_ALLIANCE ? achiev_alliance : achiev_horde , lowGuid );
2010-09-05 13:12:24 -07:00
trans -> PAppend ( "UPDATE `character_achievement` SET achievement = '%u' where achievement = '%u' AND guid = '%u'" ,
2010-12-23 19:15:44 +01:00
team == BG_TEAM_ALLIANCE ? achiev_alliance : achiev_horde , team == BG_TEAM_ALLIANCE ? achiev_horde : achiev_alliance , lowGuid );
2010-09-05 13:12:24 -07:00
}
// Item conversion
2010-12-22 21:25:23 +01:00
for ( std :: map < uint32 , uint32 >:: const_iterator it = sObjectMgr -> factionchange_items . begin (); it != sObjectMgr -> factionchange_items . end (); ++ it )
2010-09-05 13:12:24 -07:00
{
uint32 item_alliance = it -> first ;
uint32 item_horde = it -> second ;
2010-12-15 14:08:12 +06:00
trans -> PAppend ( "UPDATE `item_instance` ii, `character_inventory` ci SET ii.itemEntry = '%u' WHERE ii.itemEntry = '%u' AND ci.guid = '%u' AND ci.item = ii.guid" ,
2010-09-05 13:12:24 -07:00
team == BG_TEAM_ALLIANCE ? item_alliance : item_horde , team == BG_TEAM_ALLIANCE ? item_horde : item_alliance , guid );
}
// Spell conversion
2010-12-22 21:25:23 +01:00
for ( std :: map < uint32 , uint32 >:: const_iterator it = sObjectMgr -> factionchange_spells . begin (); it != sObjectMgr -> factionchange_spells . end (); ++ it )
2010-09-05 13:12:24 -07:00
{
uint32 spell_alliance = it -> first ;
uint32 spell_horde = it -> second ;
2010-09-05 16:45:18 -07:00
trans -> PAppend ( "DELETE FROM `character_spell` WHERE `spell`=%u AND `guid`=%u" ,
2010-12-23 19:15:44 +01:00
team == BG_TEAM_ALLIANCE ? spell_alliance : spell_horde , lowGuid );
2010-09-05 13:12:24 -07:00
trans -> PAppend ( "UPDATE `character_spell` SET spell = '%u' where spell = '%u' AND guid = '%u'" ,
2010-12-23 19:15:44 +01:00
team == BG_TEAM_ALLIANCE ? spell_alliance : spell_horde , team == BG_TEAM_ALLIANCE ? spell_horde : spell_alliance , lowGuid );
2010-09-05 13:12:24 -07:00
}
// Reputation conversion
2010-12-22 21:25:23 +01:00
for ( std :: map < uint32 , uint32 >:: const_iterator it = sObjectMgr -> factionchange_reputations . begin (); it != sObjectMgr -> factionchange_reputations . end (); ++ it )
2010-09-05 13:12:24 -07:00
{
uint32 reputation_alliance = it -> first ;
uint32 reputation_horde = it -> second ;
trans -> PAppend ( "DELETE FROM character_reputation WHERE faction = '%u' AND guid = '%u'" ,
2010-12-23 19:15:44 +01:00
team == BG_TEAM_ALLIANCE ? reputation_alliance : reputation_horde , lowGuid );
2010-09-05 13:12:24 -07:00
trans -> PAppend ( "UPDATE `character_reputation` SET faction = '%u' where faction = '%u' AND guid = '%u'" ,
2010-12-23 19:15:44 +01:00
team == BG_TEAM_ALLIANCE ? reputation_alliance : reputation_horde , team == BG_TEAM_ALLIANCE ? reputation_horde : reputation_alliance , lowGuid );
2010-09-05 13:12:24 -07:00
}
}
CharacterDatabase . CommitTransaction ( trans );
std :: string IP_str = GetRemoteAddress ();
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_UNITS , "Account: %d (IP: %s), Character guid: %u Change Race/Faction to: %s" , GetAccountId (), IP_str . c_str (), lowGuid , newname . c_str ());
2010-09-05 13:12:24 -07:00
WorldPacket data ( SMSG_CHAR_FACTION_CHANGE , 1 + 8 + ( newname . size () + 1 ) + 1 + 1 + 1 + 1 + 1 + 1 + 1 );
data << uint8 ( RESPONSE_SUCCESS );
data << uint64 ( guid );
data << newname ;
data << uint8 ( gender );
data << uint8 ( skin );
data << uint8 ( face );
data << uint8 ( hairStyle );
data << uint8 ( hairColor );
data << uint8 ( facialHair );
data << uint8 ( race );
SendPacket ( & data );
}
2011-11-28 23:06:50 -03:00
void WorldSession :: HandleRandomizeCharNameOpcode ( WorldPacket & recv_data )
{
uint8 gender , race ;
recv_data >> gender ;
recv_data >> race ;
2011-11-29 18:45:22 +00:00
if ( ! Player :: IsValidRace ( race ))
2011-11-28 23:06:50 -03:00
{
2011-11-29 18:45:22 +00:00
sLog -> outError ( "Invalid race (%u) sent by accountId: %u" , race , GetAccountId ());
2011-11-28 23:06:50 -03:00
return ;
}
if ( ! Player :: IsValidGender ( gender ))
{
2011-11-29 18:45:22 +00:00
sLog -> outError ( "Invalid gender (%u) sent by accountId: %u" , gender , GetAccountId ());
2011-11-28 23:06:50 -03:00
return ;
}
WorldPacket data ( SMSG_RANDOMIZE_CHAR_NAME , 10 );
data << uint8 ( 128 ); // unk1
data << * GetRandomCharacterName ( race , gender );
SendPacket ( & data );
2011-12-10 15:21:55 +01:00
}