2010-10-07 15:35:36 +02:00
/*
2012-12-31 23:15:50 +01:00
* Copyright (C) 2008-2013 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
2012-11-20 12:30:30 +01:00
#include "AccountMgr.h"
2009-06-04 21:41:07 +02:00
#include "ArenaTeam.h"
2012-11-20 12:30:30 +01:00
#include "ArenaTeamMgr.h"
#include "Battleground.h"
#include "CalendarMgr.h"
2009-06-04 21:41:07 +02:00
#include "Chat.h"
2012-11-20 12:30:30 +01:00
#include "Common.h"
#include "DatabaseEnv.h"
2009-06-04 21:41:07 +02:00
#include "Group.h"
#include "Guild.h"
2012-11-20 12:30:30 +01:00
#include "GuildMgr.h"
2009-06-04 21:41:07 +02:00
#include "Language.h"
2012-11-20 12:30:30 +01:00
#include "LFGMgr.h"
2009-06-04 21:41:07 +02:00
#include "Log.h"
2012-11-20 12:30:30 +01:00
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
2009-06-04 21:41:07 +02:00
#include "Opcodes.h"
2012-11-20 12:30:30 +01:00
#include "Pet.h"
2008-10-11 14:16:25 -05:00
#include "PlayerDump.h"
2012-11-20 12:30:30 +01:00
#include "Player.h"
#include "ReputationMgr.h"
#include "ScriptMgr.h"
2009-06-04 21:41:07 +02:00
#include "SharedDefines.h"
2008-10-11 14:16:25 -05:00
#include "SocialMgr.h"
2012-11-20 12:30:30 +01:00
#include "SystemConfig.h"
2009-06-04 21:41:07 +02:00
#include "UpdateMask.h"
2008-10-11 14:16:25 -05:00
#include "Util.h"
2012-11-20 12:30:30 +01:00
#include "World.h"
#include "WorldPacket.h"
#include "WorldSession.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 );
2013-01-04 23:13:21 +00:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_FROM , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_GROUP , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_BOUND_INSTANCES , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_AURAS , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_SPELLS , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS , stmt );
2010-09-20 18:20:40 +02:00
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-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS , stmt );
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_MONTHLYQUESTSTATUS );
stmt -> setUInt32 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS , stmt );
2012-01-03 08:37:21 -05:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_SEASONALQUESTSTATUS );
stmt -> setUInt32 ( 0 , lowGuid );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS , 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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_REPUTATION , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_INVENTORY , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_ACTIONS , stmt );
2010-09-20 18:20:40 +02:00
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 )));
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_HOME_BIND , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS , 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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES , stmt );
2010-09-20 18:20:40 +02:00
}
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_GUILD , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_ARENA_INFO , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_BG_DATA , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_GLYPHS , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_TALENTS , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_SKILLS , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG , stmt );
2010-09-20 18:20:40 +02:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_BANNED , 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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW , stmt );
2010-12-26 04:16:18 +01:00
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 );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES , stmt );
2012-02-18 16:52:08 +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
{
WorldPacket data ( SMSG_CHAR_ENUM , 100 ); // we guess size
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint8 num = 0 ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
data << num ;
2009-10-17 15:51:44 -07:00
2013-02-14 16:07:36 +01:00
_legitCharacters . clear ();
2010-04-07 22:59:46 +02:00
if ( result )
2008-10-11 14:16:25 -05:00
{
do
{
2008-11-05 09:22:56 -06:00
uint32 guidlow = ( * result )[ 0 ]. GetUInt32 ();
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_NETWORKIO , "Loading char guid %u from account %u." , guidlow , GetAccountId ());
2010-04-07 19:14:10 +02:00
if ( Player :: BuildEnumData ( result , & data ))
2011-04-01 03:11:57 +02:00
{
2013-02-14 16:07:36 +01:00
_legitCharacters . insert ( guidlow );
2013-02-14 15:43:26 +01:00
if ( ! sWorld -> HasCharacterNameData ( guidlow )) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet.
sWorld -> AddCharacterNameData ( guidlow , ( * result )[ 1 ]. GetString (), ( * result )[ 4 ]. GetUInt8 (), ( * result )[ 2 ]. GetUInt8 (), ( * result )[ 3 ]. GetUInt8 (), ( * result )[ 7 ]. GetUInt8 ());
2008-10-11 14:16:25 -05:00
++ num ;
2011-04-01 03:11:57 +02:00
}
2008-10-11 14:16:25 -05:00
}
2010-04-07 22:59:46 +02:00
while ( result -> NextRow ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
data . put < uint8 > ( 0 , num );
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
2012-11-02 22:23:14 +01:00
void WorldSession :: HandleCharEnumOpcode ( WorldPacket & /*recvData*/ )
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
2012-11-27 13:02:04 +01:00
void WorldSession :: HandleCharCreateOpcode ( WorldPacket & recvData )
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
2012-11-02 22:23:14 +01:00
recvData >> name ;
2009-10-17 15:51:44 -07:00
2012-11-02 22:23:14 +01:00
recvData >> race_ ;
recvData >> 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 ;
2012-11-02 22:23:14 +01:00
recvData >> gender >> skin >> face ;
recvData >> hairStyle >> hairColor >> facialHair >> outfitId ;
2011-04-29 16:48:15 +06:00
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
2013-02-25 15:28:41 +01:00
if ( ! HasPermission ( RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_TEAMMASK ))
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
{
2013-02-25 15:28:41 +01: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
{
2013-02-25 15:28:41 +01: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 )
{
2013-02-25 15:28:41 +01:00
data << uint8 ( CHAR_CREATE_FAILED );
2011-02-17 19:47:08 +06:00
SendPacket ( & data );
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "Class (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?" , class_ , GetAccountId ());
2011-02-17 19:47:08 +06:00
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
{
2013-02-25 15:28:41 +01:00
data << uint8 ( CHAR_CREATE_FAILED );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "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
{
2013-02-25 15:28:41 +01:00
data << uint8 ( CHAR_CREATE_EXPANSION );
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "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
{
2013-02-25 15:28:41 +01:00
data << uint8 ( CHAR_CREATE_EXPANSION_CLASS );
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "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
2013-02-25 15:28:41 +01:00
if ( ! HasPermission ( RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RACEMASK ))
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 ;
}
2013-02-25 15:28:41 +01:00
}
2010-09-06 23:34:16 +06:00
2013-02-25 15:28:41 +01:00
if ( ! HasPermission ( RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_CLASSMASK ))
{
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
{
2013-02-25 15:28:41 +01:00
data << uint8 ( CHAR_NAME_NO_NAME );
2010-04-07 22:59:46 +02:00
SendPacket ( & data );
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "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
2013-02-25 15:28:41 +01:00
if ( ! HasPermission ( RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME ) && sObjectMgr -> IsReservedName ( name ))
2008-10-11 14:16:25 -05:00
{
2013-02-25 15:28:41 +01: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
2013-02-25 15:28:41 +01:00
if ( class_ == CLASS_DEATH_KNIGHT && ! HasPermission ( RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_HEROIC_CHARACTER ))
2008-12-24 09:58:26 -06:00
{
2013-02-25 15:28:41 +01:00
// speedup check for heroic class disabled case
uint32 heroic_free_slots = sWorld -> getIntConfig ( CONFIG_HEROIC_CHARACTERS_PER_REALM );
if ( heroic_free_slots == 0 )
{
data << uint8 ( CHAR_CREATE_UNIQUE_CLASS_LIMIT );
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2013-02-25 15:28:41 +01:00
// speedup check for heroic class disabled case
uint32 req_level_for_heroic = sWorld -> getIntConfig ( CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER );
if ( req_level_for_heroic > sWorld -> getIntConfig ( CONFIG_MAX_PLAYER_LEVEL ))
{
data << uint8 ( CHAR_CREATE_LEVEL_REQUIREMENT );
SendPacket ( & data );
return ;
}
2008-12-24 09:58:26 -06:00
}
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
2012-11-02 22:23:14 +01:00
_charCreateCallback . SetParam ( new CharacterCreateInfo ( name , race_ , class_ , gender , skin , face , hairStyle , hairColor , facialHair , outfitId , recvData ));
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 );
2012-03-29 16:41:42 +02:00
stmt -> setUInt32 ( 0 , GetAccountId ());
2011-06-22 14:20:42 +02:00
_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 ();
2012-04-02 00:22:02 +01:00
createInfo -> CharCount = uint8 ( fields [ 0 ]. GetUInt64 ()); // SQL's COUNT() returns uint64 but it will always be less than uint8.Max
2011-06-22 14:20:42 +02:00
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
2013-03-08 13:15:25 +01:00
bool allowTwoSideAccounts = ! sWorld -> IsPvPRealm () || HasPermission ( RBAC_PERM_TWO_SIDE_CHARACTER_CREATION );
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 );
2013-03-08 13:15:25 +01:00
bool allowTwoSideAccounts = ! sWorld -> IsPvPRealm () || HasPermission ( RBAC_PERM_TWO_SIDE_CHARACTER_CREATION );
2011-06-22 14:20:42 +02:00
uint32 skipCinematics = sWorld -> getIntConfig ( CONFIG_SKIP_CINEMATICS );
2013-02-25 15:28:41 +01:00
bool checkHeroicReqs = createInfo -> Class == CLASS_DEATH_KNIGHT && ! HasPermission ( RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_HEROIC_CHARACTER );
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
2013-02-25 15:28:41 +01:00
if ( checkHeroicReqs )
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
2013-03-08 21:41:30 +01:00
/// @todo what to if account already has characters of both races?
2011-06-22 14:20:42 +02:00
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
2013-03-08 21:41:30 +01:00
/// @todo check if cinematic already shown? (already logged in?; cinematic field)
2011-06-22 14:20:42 +02:00
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 ;
2013-02-25 15:28:41 +01:00
if ( checkHeroicReqs )
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
2013-02-25 15:28:41 +01:00
if ( checkHeroicReqs && ! 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 );
2012-02-16 16:27:38 -05:00
newChar . GetMotionMaster () -> Initialize ();
2011-09-06 10:41:10 +02:00
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
2012-03-25 16:22:24 +02:00
PreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_DEL_REALM_CHARACTERS_BY_REALM );
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-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 ();
2012-08-06 12:10:33 +02:00
sLog -> outInfo ( LOG_FILTER_CHARACTER , "Account: %d (IP: %s) Create Character:[%s] (GUID: %u)" , GetAccountId (), IP_str . c_str (), createInfo -> Name . c_str (), newChar . GetGUIDLow ());
2011-09-06 10:41:10 +02:00
sScriptMgr -> OnPlayerCreate ( & newChar );
2012-10-24 13:29:34 +02:00
sWorld -> AddCharacterNameData ( newChar . GetGUIDLow (), newChar . GetName (), newChar . getGender (), newChar . getRace (), newChar . getClass (), newChar . getLevel ());
2011-06-22 14:20:42 +02:00
2012-04-03 00:02:58 +02:00
newChar . CleanupsBeforeDelete ();
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
2012-11-27 13:02:04 +01:00
void WorldSession :: HandleCharDeleteOpcode ( WorldPacket & recvData )
2008-10-11 14:16:25 -05:00
{
uint64 guid ;
2012-11-02 22:23:14 +01:00
recvData >> 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 ;
2012-11-30 13:59:01 +01:00
uint8 level = 0 ;
2008-10-11 14:16:25 -05:00
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 );
2012-08-06 08:49:31 +02:00
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 );
2012-08-06 08:49:31 +02:00
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
2012-11-30 13:59:01 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_DATA_BY_GUID );
2012-03-24 01:25:08 +01:00
stmt -> setUInt32 ( 0 , GUID_LOPART ( guid ));
2012-08-06 08:49:31 +02:00
if ( PreparedQueryResult result = CharacterDatabase . Query ( stmt ))
2008-10-11 14:16:25 -05:00
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2012-11-30 13:59:01 +01:00
accountId = fields [ 0 ]. GetUInt32 ();
name = fields [ 1 ]. GetString ();
level = fields [ 2 ]. GetUInt8 ();
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 ();
2012-11-30 13:59:01 +01:00
sLog -> outInfo ( LOG_FILTER_CHARACTER , "Account: %d, IP: %s deleted character: %s, GUID: %u, Level: %u" , accountId , IP_str . c_str (), name . c_str (), GUID_LOPART ( guid ), level );
2010-12-22 21:25:23 +01:00
sScriptMgr -> OnPlayerDelete ( guid );
2013-02-16 18:53:44 +01:00
sWorld -> DeleteCharacterNameData ( GUID_LOPART ( guid ));
2009-10-17 15:51:44 -07:00
2012-08-15 19:58:02 +02:00
if ( sLog -> ShouldLog ( LOG_FILTER_PLAYER_DUMP , LOG_LEVEL_INFO )) // 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 ))
2012-11-30 13:59:01 +01:00
sLog -> outCharDump ( dump . c_str (), accountId , GUID_LOPART ( guid ), name . c_str ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2012-11-18 22:42:28 +00:00
sCalendarMgr -> RemoveAllPlayerEventsAndInvites ( guid );
2012-11-30 13:59:01 +01:00
Player :: DeleteFromDB ( guid , accountId );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
WorldPacket data ( SMSG_CHAR_DELETE , 1 );
2012-08-06 08:49:31 +02:00
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
2012-11-27 13:02:04 +01:00
void WorldSession :: HandlePlayerLoginOpcode ( WorldPacket & recvData )
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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "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
2012-08-03 14:20:18 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: Recvd Player Logon Message" );
2009-10-17 15:51:44 -07:00
2012-11-02 22:23:14 +01:00
recvData >> playerGuid ;
2009-10-17 15:51:44 -07:00
2013-02-14 16:07:36 +01:00
if ( ! IsLegitCharacterForAccount ( GUID_LOPART ( playerGuid )))
2011-04-01 03:11:57 +02:00
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "Account (%u) can't login with that character (%u)." , GetAccountId (), GUID_LOPART ( playerGuid ));
2011-04-01 03:11:57 +02:00
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-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)
2012-11-17 05:18:37 +01:00
ChatHandler chH = ChatHandler ( pCurrChar -> GetSession ());
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
2012-12-04 00:02:06 +01:00
LoadAccountData ( holder -> GetPreparedResult ( PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA ), 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
2008-10-11 14:16:25 -05:00
data . Initialize ( SMSG_FEATURE_SYSTEM_STATUS , 2 ); // added in 2.2.0
data << uint8 ( 2 ); // unknown value
data << uint8 ( 0 ); // enable(1)/disable(0) voice chat interface in client
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 );
2012-08-03 14:20:18 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "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
2012-08-03 14:20:18 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "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());
2012-12-04 00:02:06 +01:00
if ( PreparedQueryResult resultGuild = holder -> GetPreparedResult ( PLAYER_LOGIN_QUERY_LOAD_GUILD ))
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
2012-10-24 13:29:34 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "Player %s (GUID: %u) marked as member of not existing guild (id: %u), removing guild membership for player." , pCurrChar -> GetName (). c_str (), 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 );
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
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 );
2012-10-24 13:29:34 +02:00
//sLog->outDebug("Player %s added to Map.", pCurrChar->GetName().c_str());
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
{
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 ();
2012-08-06 12:10:33 +02:00
sLog -> outInfo ( LOG_FILTER_CHARACTER , "Account: %d (IP: %s) Login Character:[%s] (GUID: %u) Level: %d" ,
2012-10-24 13:29:34 +02:00
GetAccountId (), IP_str . c_str (), pCurrChar -> GetName (). c_str (), pCurrChar -> GetGUIDLow (), pCurrChar -> getLevel ());
2009-10-17 15:51:44 -07:00
2012-02-03 19:02:17 +02:00
if ( ! pCurrChar -> IsStandState () && ! pCurrChar -> HasUnitState ( UNIT_STATE_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
2012-11-27 13:02:04 +01:00
void WorldSession :: HandleSetFactionAtWar ( WorldPacket & recvData )
2008-10-11 14:16:25 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "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
2012-11-02 22:23:14 +01:00
recvData >> repListID ;
recvData >> 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
2012-11-02 22:23:14 +01:00
void WorldSession :: HandleSetFactionCheat ( WorldPacket & /*recvData*/ )
2008-10-11 14:16:25 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "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
2012-11-27 13:02:04 +01:00
void WorldSession :: HandleTutorialFlag ( WorldPacket & recvData )
2008-10-11 14:16:25 -05:00
{
2011-02-24 23:57:43 +06:00
uint32 data ;
2012-11-02 22:23:14 +01:00
recvData >> 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
2012-11-02 22:23:14 +01:00
void WorldSession :: HandleTutorialClear ( WorldPacket & /*recvData*/ )
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
2012-11-02 22:23:14 +01:00
void WorldSession :: HandleTutorialReset ( WorldPacket & /*recvData*/ )
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
2012-11-27 13:02:04 +01:00
void WorldSession :: HandleSetWatchedFactionOpcode ( WorldPacket & recvData )
2008-10-11 14:16:25 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: Received CMSG_SET_WATCHED_FACTION" );
2008-10-11 14:16:25 -05:00
uint32 fact ;
2012-11-02 22:23:14 +01:00
recvData >> fact ;
2008-10-11 14:16:25 -05:00
GetPlayer () -> SetUInt32Value ( PLAYER_FIELD_WATCHED_FACTION_INDEX , fact );
}
2009-10-17 15:51:44 -07:00
2012-11-27 13:02:04 +01:00
void WorldSession :: HandleSetFactionInactiveOpcode ( WorldPacket & recvData )
2008-10-11 14:16:25 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: Received CMSG_SET_FACTION_INACTIVE" );
2008-10-11 14:16:25 -05:00
uint32 replistid ;
uint8 inactive ;
2012-11-02 22:23:14 +01:00
recvData >> 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
2012-11-02 22:23:14 +01:00
void WorldSession :: HandleShowingHelmOpcode ( WorldPacket & recvData )
2008-10-11 14:16:25 -05:00
{
2012-10-24 13:29:34 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "CMSG_SHOWING_HELM for %s" , _player -> GetName (). c_str ());
2012-11-02 22:23:14 +01:00
recvData . 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
2012-11-02 22:23:14 +01:00
void WorldSession :: HandleShowingCloakOpcode ( WorldPacket & recvData )
2008-10-11 14:16:25 -05:00
{
2012-10-24 13:29:34 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "CMSG_SHOWING_CLOAK for %s" , _player -> GetName (). c_str ());
2012-11-02 22:23:14 +01:00
recvData . 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
2012-11-02 22:23:14 +01:00
void WorldSession :: HandleCharRenameOpcode ( WorldPacket & recvData )
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
2012-11-02 22:23:14 +01:00
recvData >> guid ;
recvData >> 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
{
2012-03-28 04:02:02 +02:00
WorldPacket data ( SMSG_CHAR_RENAME , 1 + 8 + ( newName . size () + 1 ));
2009-07-10 08:25:33 +08:00
data << uint8 ( res );
2012-03-28 04:02:02 +02:00
data << uint64 ( guid );
data << newName ;
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
2013-02-25 15:28:41 +01:00
if ( ! HasPermission ( RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME ) && 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
2012-10-24 15:34:23 +02:00
void WorldSession :: HandleChangePlayerNameOpcodeCallBack ( PreparedQueryResult result , std :: string const & 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
2012-08-06 12:10:33 +02:00
sLog -> outInfo ( LOG_FILTER_CHARACTER , "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
2012-11-02 22:23:14 +01:00
void WorldSession :: HandleSetPlayerDeclinedNames ( WorldPacket & recvData )
2008-10-11 14:16:25 -05:00
{
uint64 guid ;
2009-10-17 15:51:44 -07:00
2012-11-02 22:23:14 +01:00
recvData >> 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
2012-11-02 22:23:14 +01:00
recvData >> 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
{
2012-11-02 22:23:14 +01:00
recvData >> 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 ();
2012-03-25 20:19:48 +02:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_DECLINED_NAME );
stmt -> setUInt32 ( 0 , GUID_LOPART ( guid ));
trans -> Append ( stmt );
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_INS_CHAR_DECLINED_NAME );
stmt -> setUInt32 ( 0 , GUID_LOPART ( guid ));
for ( uint8 i = 0 ; i < 5 ; i ++ )
stmt -> setString ( i + 1 , declinedname . name [ i ]);
trans -> Append ( stmt );
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
2012-11-27 13:02:04 +01:00
void WorldSession :: HandleAlterAppearance ( WorldPacket & recvData )
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 ;
2012-11-02 22:23:14 +01:00
recvData >> 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 ;
2012-09-08 23:16:14 +01:00
GameObject * go = _player -> FindNearestGameObjectOfType ( GAMEOBJECT_TYPE_BARBER_CHAIR , 5.0f );
if ( ! go )
{
WorldPacket data ( SMSG_BARBER_SHOP_RESULT , 4 );
2012-09-09 00:10:23 +01:00
data << uint32 ( 2 );
2012-09-08 23:16:14 +01:00
SendPacket ( & data );
return ;
}
if ( _player -> getStandState () != UNIT_STAND_STATE_SIT_LOW_CHAIR + go -> GetGOInfo () -> barberChair . chairheight )
{
WorldPacket data ( SMSG_BARBER_SHOP_RESULT , 4 );
2012-09-09 00:10:23 +01:00
data << uint32 ( 2 );
2012-09-08 23:16:14 +01:00
SendPacket ( & data );
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
2012-09-08 23:16:14 +01: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
2012-09-08 23:16:14 +01:00
_player -> ModifyMoney ( - int32 ( cost )); // it isn't free
2012-09-18 14:29:53 +02:00
_player -> 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
2012-09-18 14:29:53 +02:00
_player -> 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
2012-11-27 13:02:04 +01:00
void WorldSession :: HandleRemoveGlyph ( WorldPacket & recvData )
2008-12-24 09:58:26 -06:00
{
uint32 slot ;
2012-11-02 22:23:14 +01:00
recvData >> 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
2010-04-07 19:14:10 +02:00
if ( uint32 glyph = _player -> GetGlyph ( 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
2012-11-02 22:23:14 +01:00
void WorldSession :: HandleCharCustomize ( WorldPacket & recvData )
2008-12-24 09:58:26 -06:00
{
uint64 guid ;
2011-12-31 00:32:05 +01:00
std :: string newName ;
2009-10-17 15:51:44 -07:00
2012-11-02 22:23:14 +01:00
recvData >> guid ;
2013-02-14 16:07:36 +01:00
if ( ! IsLegitCharacterForAccount ( GUID_LOPART ( guid )))
{
sLog -> outError ( LOG_FILTER_NETWORKIO , "Account %u, IP: %s tried to customise character %u, but it does not belong to their account!" ,
GetAccountId (), GetRemoteAddress (). c_str (), GUID_LOPART ( guid ));
recvData . rfinish ();
KickPlayer ();
2013-02-14 16:12:58 +01:00
return ;
2013-02-14 16:07:36 +01:00
}
2012-11-02 22:23:14 +01:00
recvData >> newName ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
uint8 gender , skin , face , hairStyle , hairColor , facialHair ;
2012-11-02 22:23:14 +01:00
recvData >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face ;
2009-10-17 15:51:44 -07:00
2012-03-24 01:25:08 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_AT_LOGIN );
stmt -> setUInt32 ( 0 , GUID_LOPART ( guid ));
2013-02-14 16:07:36 +01:00
// TODO: Make async with callback
2012-03-24 01:25:08 +01:00
PreparedQueryResult result = CharacterDatabase . Query ( stmt );
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
2013-02-25 15:28:41 +01:00
if ( ! HasPermission ( RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME ) && 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
2012-03-24 01:25:08 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_NAME );
stmt -> setUInt32 ( 0 , GUID_LOPART ( guid ));
result = CharacterDatabase . Query ( stmt );
if ( result )
2009-08-16 16:32:11 -05:00
{
2012-03-24 01:25:08 +01:00
std :: string oldname = result -> Fetch ()[ 0 ]. GetString ();
2012-08-06 12:10:33 +02:00
sLog -> outInfo ( LOG_FILTER_CHARACTER , "Account: %d (IP: %s), Character[%s] (guid:%u) Customized to: %s" , GetAccountId (), GetRemoteAddress (). c_str (), oldname . c_str (), GUID_LOPART ( guid ), newName . c_str ());
2009-08-16 16:32:11 -05:00
}
2012-03-28 04:02:02 +02: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-03-24 01:25:08 +01:00
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
2012-11-02 22:23:14 +01:00
void WorldSession :: HandleEquipmentSetSave ( WorldPacket & recvData )
2009-06-11 00:45:59 -05:00
{
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 ;
2012-11-02 22:23:14 +01:00
recvData . readPackGUID ( setGuid );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint32 index ;
2012-11-02 22:23:14 +01:00
recvData >> 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 ;
2012-11-02 22:23:14 +01:00
recvData >> name ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
std :: string iconName ;
2012-11-02 22:23:14 +01:00
recvData >> 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 ;
2012-11-02 22:23:14 +01:00
recvData . readPackGUID ( itemGuid );
2009-10-17 15:51:44 -07:00
2012-07-13 15:16:37 +02:00
// equipment manager sends "1" (as raw GUID) for slots set to "ignore" (don't touch slot at equip set)
if ( itemGuid == 1 )
{
// ignored slots saved as bit mask because we have no free special values for Items[i]
eqSet . IgnoreMask |= 1 << i ;
continue ;
}
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
2012-11-02 22:23:14 +01:00
void WorldSession :: HandleEquipmentSetDelete ( WorldPacket & recvData )
2009-06-11 00:45:59 -05:00
{
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 ;
2012-11-02 22:23:14 +01:00
recvData . 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
2012-11-02 22:23:14 +01:00
void WorldSession :: HandleEquipmentSetUse ( WorldPacket & recvData )
2009-06-11 00:45:59 -05:00
{
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 ;
2012-11-02 22:23:14 +01:00
recvData . readPackGUID ( itemGuid );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint8 srcbag , srcslot ;
2012-11-02 22:23:14 +01:00
recvData >> 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
2012-07-13 15:16:37 +02:00
// check if item slot is set to "ignored" (raw value == 1), must not be unequipped then
if ( itemGuid == 1 )
continue ;
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
2012-11-02 22:23:14 +01:00
void WorldSession :: HandleCharFactionOrRaceChange ( WorldPacket & recvData )
2010-09-05 13:12:24 -07:00
{
uint64 guid ;
std :: string newname ;
uint8 gender , skin , face , hairStyle , hairColor , facialHair , race ;
2012-11-02 22:23:14 +01:00
recvData >> guid ;
2013-02-14 16:07:36 +01:00
if ( ! IsLegitCharacterForAccount ( GUID_LOPART ( guid )))
{
sLog -> outError ( LOG_FILTER_NETWORKIO , "Account %u, IP: %s tried to factionchange character %u, but it does not belong to their account!" ,
GetAccountId (), GetRemoteAddress (). c_str (), GUID_LOPART ( guid ));
recvData . rfinish ();
KickPlayer ();
2013-02-14 16:12:58 +01:00
return ;
2013-02-14 16:07:36 +01:00
}
2012-11-02 22:23:14 +01:00
recvData >> newname ;
recvData >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face >> race ;
2010-09-05 13:12:24 -07:00
2010-12-23 19:15:44 +01:00
uint32 lowGuid = GUID_LOPART ( guid );
2012-03-24 01:25:08 +01:00
2012-10-07 13:55:04 +01:00
// get the players old (at this moment current) race
2012-10-08 17:21:09 +01:00
CharacterNameData const * nameData = sWorld -> GetCharacterNameData ( lowGuid );
2013-02-14 15:43:26 +01:00
if ( ! nameData )
{
WorldPacket data ( SMSG_CHAR_FACTION_CHANGE , 1 );
data << uint8 ( CHAR_CREATE_ERROR );
SendPacket ( & data );
return ;
}
2012-10-08 17:21:09 +01:00
uint8 oldRace = nameData -> m_race ;
uint8 playerClass = nameData -> m_class ;
uint8 level = nameData -> m_level ;
2012-03-24 01:25:08 +01:00
2012-10-08 17:29:02 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHAR_AT_LOGIN_TITLES );
2012-03-24 01:25:08 +01:00
stmt -> setUInt32 ( 0 , lowGuid );
2012-10-08 17:21:09 +01:00
PreparedQueryResult result = CharacterDatabase . Query ( stmt );
2012-03-24 01:25:08 +01:00
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 ;
}
2012-10-08 17:21:09 +01:00
Field * fields = result -> Fetch ();
2012-10-08 17:29:02 +01:00
uint32 at_loginFlags = fields [ 0 ]. GetUInt16 ();
char const * knownTitlesStr = fields [ 1 ]. GetCString ();
2012-11-02 22:23:14 +01:00
uint32 used_loginFlag = (( recvData . GetOpcode () == CMSG_CHAR_RACE_CHANGE ) ? AT_LOGIN_CHANGE_RACE : AT_LOGIN_CHANGE_FACTION );
2010-09-05 13:12:24 -07:00
2010-12-22 21:25:23 +01:00
if ( ! sObjectMgr -> GetPlayerInfo ( race , playerClass ))
2012-10-29 13:58:48 +01:00
{
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
2013-02-25 15:28:41 +01:00
if ( ! HasPermission ( RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RACEMASK ))
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
2013-02-25 15:28:41 +01:00
if ( ! HasPermission ( RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME ) && sObjectMgr -> IsReservedName ( newname ))
2010-09-05 13:12:24 -07:00
{
WorldPacket data ( SMSG_CHAR_FACTION_CHANGE , 1 );
data << uint8 ( CHAR_NAME_RESERVED );
2012-03-29 14:43:34 +08: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 ();
2012-03-25 20:19:48 +02:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_FACTION_OR_RACE );
stmt -> setString ( 0 , newname );
stmt -> setUInt8 ( 1 , race );
stmt -> setUInt16 ( 2 , used_loginFlag );
stmt -> setUInt32 ( 3 , lowGuid );
trans -> Append ( stmt );
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_DECLINED_NAME );
stmt -> setUInt32 ( 0 , lowGuid );
trans -> Append ( stmt );
2011-11-16 10:31:38 +01:00
sWorld -> UpdateCharacterNameData ( GUID_LOPART ( guid ), newname , gender , race );
2010-09-05 13:12:24 -07:00
2012-10-29 12:28:12 +01:00
if ( oldRace != race )
2010-09-05 13:12:24 -07:00
{
2012-10-29 12:28:12 +01:00
TeamId team = TEAM_ALLIANCE ;
2012-03-25 20:19:48 +02:00
2012-10-29 12:28:12 +01:00
// Search each faction is targeted
2012-03-29 11:30:37 +02:00
switch ( race )
{
2012-10-29 12:28:12 +01:00
case RACE_ORC :
2012-03-29 11:30:37 +02:00
case RACE_TAUREN :
2012-10-29 12:28:12 +01:00
case RACE_UNDEAD_PLAYER :
2012-03-29 11:30:37 +02:00
case RACE_TROLL :
case RACE_BLOODELF :
2012-10-29 12:28:12 +01:00
team = TEAM_HORDE ;
break ;
default :
2012-03-29 11:30:37 +02:00
break ;
}
2012-10-29 12:28:12 +01:00
// Switch Languages
// delete all languages first
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_SKILL_LANGUAGES );
stmt -> setUInt32 ( 0 , lowGuid );
2012-03-29 11:30:37 +02:00
trans -> Append ( stmt );
2012-03-25 20:19:48 +02:00
2012-10-29 12:28:12 +01:00
// Now add them back
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_INS_CHAR_SKILL_LANGUAGE );
2012-03-25 20:19:48 +02:00
stmt -> setUInt32 ( 0 , lowGuid );
2012-10-29 12:28:12 +01:00
// Faction specific languages
if ( team == TEAM_HORDE )
stmt -> setUInt16 ( 1 , 109 );
else
stmt -> setUInt16 ( 1 , 98 );
2012-03-25 20:19:48 +02:00
trans -> Append ( stmt );
2010-09-05 13:12:24 -07:00
2012-10-29 12:28:12 +01:00
// Race specific languages
if ( race != RACE_ORC && race != RACE_HUMAN )
2010-09-05 13:12:24 -07:00
{
2012-10-29 12:28:12 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_INS_CHAR_SKILL_LANGUAGE );
stmt -> setUInt32 ( 0 , lowGuid );
switch ( race )
2010-09-05 13:12:24 -07:00
{
2012-10-29 12:28:12 +01:00
case RACE_DWARF :
stmt -> setUInt16 ( 1 , 111 );
break ;
case RACE_DRAENEI :
stmt -> setUInt16 ( 1 , 759 );
break ;
case RACE_GNOME :
stmt -> setUInt16 ( 1 , 313 );
break ;
case RACE_NIGHTELF :
stmt -> setUInt16 ( 1 , 113 );
break ;
case RACE_UNDEAD_PLAYER :
stmt -> setUInt16 ( 1 , 673 );
break ;
case RACE_TAUREN :
stmt -> setUInt16 ( 1 , 115 );
break ;
case RACE_TROLL :
stmt -> setUInt16 ( 1 , 315 );
break ;
case RACE_BLOODELF :
stmt -> setUInt16 ( 1 , 137 );
break ;
2010-09-05 13:12:24 -07:00
}
2012-03-25 20:19:48 +02:00
trans -> Append ( stmt );
2010-09-05 13:12:24 -07:00
}
2012-11-02 22:23:14 +01:00
if ( recvData . GetOpcode () == CMSG_CHAR_FACTION_CHANGE )
2010-09-05 13:12:24 -07:00
{
2012-10-29 12:28:12 +01:00
// Delete all Flypaths
2012-12-19 12:55:51 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_TAXI_PATH );
2012-10-29 12:28:12 +01:00
stmt -> setUInt32 ( 0 , lowGuid );
trans -> Append ( stmt );
if ( level > 7 )
2010-09-05 13:12:24 -07:00
{
2012-10-29 12:28:12 +01:00
// 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 ;
2012-10-04 10:57:32 +02:00
if ( team == TEAM_ALLIANCE )
2010-09-05 13:12:24 -07:00
{
2012-10-29 12:28:12 +01:00
if ( playerClass != CLASS_DEATH_KNIGHT )
2010-09-05 13:12:24 -07:00
{
2012-10-29 12:28:12 +01:00
for ( uint8 i = 0 ; i < numFullTaximasks ; ++ i )
taximaskstream << uint32 ( sAllianceTaxiNodesMask [ i ]) << ' ' ;
}
else
{
for ( uint8 i = 0 ; i < numFullTaximasks ; ++ i )
taximaskstream << uint32 ( sAllianceTaxiNodesMask [ i ] | sDeathKnightTaxiNodesMask [ i ]) << ' ' ;
2010-09-05 13:12:24 -07:00
}
}
2012-10-29 12:28:12 +01:00
else
2010-09-05 13:12:24 -07:00
{
2012-10-29 12:28:12 +01:00
if ( playerClass != CLASS_DEATH_KNIGHT )
2010-09-05 13:12:24 -07:00
{
2012-10-29 12:28:12 +01:00
for ( uint8 i = 0 ; i < numFullTaximasks ; ++ i )
taximaskstream << uint32 ( sHordeTaxiNodesMask [ i ]) << ' ' ;
}
else
{
for ( uint8 i = 0 ; i < numFullTaximasks ; ++ i )
taximaskstream << uint32 ( sHordeTaxiNodesMask [ i ] | sDeathKnightTaxiNodesMask [ i ]) << ' ' ;
2010-09-05 13:12:24 -07:00
}
}
2012-10-29 12:28:12 +01:00
uint32 numEmptyTaximasks = 11 - numFullTaximasks ;
for ( uint8 i = 0 ; i < numEmptyTaximasks ; ++ i )
taximaskstream << "0 " ;
taximaskstream << '0' ;
std :: string taximask = taximaskstream . str ();
2010-09-05 13:12:24 -07:00
2012-12-19 12:55:51 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_TAXIMASK );
2012-10-29 12:28:12 +01:00
stmt -> setString ( 0 , taximask );
stmt -> setUInt32 ( 1 , lowGuid );
trans -> Append ( stmt );
}
2010-09-05 13:12:24 -07:00
2012-10-29 12:28:12 +01:00
if ( ! sWorld -> getBoolConfig ( CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD ))
{
// Reset guild
2012-12-19 12:55:51 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_GUILD_MEMBER );
2012-03-25 20:19:48 +02:00
2012-10-29 12:28:12 +01:00
stmt -> setUInt32 ( 0 , lowGuid );
2010-09-05 13:12:24 -07:00
2012-10-29 12:28:12 +01:00
PreparedQueryResult result = CharacterDatabase . Query ( stmt );
if ( result )
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
2013-03-08 13:15:25 +01:00
if ( ! HasPermission ( RBAC_PERM_TWO_SIDE_ADD_FRIEND ))
2012-10-29 12:28:12 +01:00
{
// Delete Friend List
2012-12-19 12:55:51 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_SOCIAL_BY_GUID );
2012-10-29 12:28:12 +01:00
stmt -> setUInt32 ( 0 , lowGuid );
trans -> Append ( stmt );
2011-04-08 17:04:51 +06:00
2012-10-29 12:28:12 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_SOCIAL_BY_FRIEND );
stmt -> setUInt32 ( 0 , lowGuid );
trans -> Append ( stmt );
2010-09-05 13:12:24 -07:00
2012-10-29 12:28:12 +01:00
}
2012-03-25 20:19:48 +02:00
2012-10-29 12:28:12 +01:00
// Leave Arena Teams
Player :: LeaveAllArenaTeams ( guid );
2012-03-25 20:19:48 +02:00
2012-10-29 12:28:12 +01:00
// Reset homebind and position
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_PLAYER_HOMEBIND );
stmt -> setUInt32 ( 0 , lowGuid );
2012-03-25 20:19:48 +02:00
trans -> Append ( stmt );
2010-09-05 13:12:24 -07:00
2012-10-29 12:28:12 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_INS_PLAYER_HOMEBIND );
stmt -> setUInt32 ( 0 , lowGuid );
if ( team == TEAM_ALLIANCE )
{
stmt -> setUInt16 ( 1 , 0 );
stmt -> setUInt16 ( 2 , 1519 );
stmt -> setFloat ( 3 , - 8867.68f );
stmt -> setFloat ( 4 , 673.373f );
stmt -> setFloat ( 5 , 97.9034f );
Player :: SavePositionInDB ( 0 , - 8867.68f , 673.373f , 97.9034f , 0.0f , 1519 , lowGuid );
}
else
{
stmt -> setUInt16 ( 1 , 1 );
stmt -> setUInt16 ( 2 , 1637 );
stmt -> setFloat ( 3 , 1633.33f );
stmt -> setFloat ( 4 , - 4439.11f );
stmt -> setFloat ( 5 , 15.7588f );
Player :: SavePositionInDB ( 1 , 1633.33f , - 4439.11f , 15.7588f , 0.0f , 1637 , lowGuid );
}
2012-03-25 20:19:48 +02:00
trans -> Append ( stmt );
2010-09-05 13:12:24 -07:00
2012-10-29 12:28:12 +01:00
// Achievement conversion
2013-03-04 14:15:52 +01:00
for ( std :: map < uint32 , uint32 >:: const_iterator it = sObjectMgr -> FactionChangeAchievements . begin (); it != sObjectMgr -> FactionChangeAchievements . end (); ++ it )
2012-10-29 12:28:12 +01:00
{
uint32 achiev_alliance = it -> first ;
uint32 achiev_horde = it -> second ;
2012-03-25 20:19:48 +02:00
2012-12-19 12:55:51 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT );
2012-10-29 12:28:12 +01:00
stmt -> setUInt16 ( 0 , uint16 ( team == TEAM_ALLIANCE ? achiev_alliance : achiev_horde ));
stmt -> setUInt32 ( 1 , lowGuid );
trans -> Append ( stmt );
2012-03-25 20:19:48 +02:00
2012-10-29 12:28:12 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_ACHIEVEMENT );
stmt -> setUInt16 ( 0 , uint16 ( team == TEAM_ALLIANCE ? achiev_alliance : achiev_horde ));
stmt -> setUInt16 ( 1 , uint16 ( team == TEAM_ALLIANCE ? achiev_horde : achiev_alliance ));
stmt -> setUInt32 ( 2 , lowGuid );
trans -> Append ( stmt );
}
2010-09-05 13:12:24 -07:00
2012-10-29 12:28:12 +01:00
// Item conversion
2013-03-04 14:15:52 +01:00
for ( std :: map < uint32 , uint32 >:: const_iterator it = sObjectMgr -> FactionChangeItems . begin (); it != sObjectMgr -> FactionChangeItems . end (); ++ it )
2012-10-07 13:55:04 +01:00
{
2012-10-29 12:28:12 +01:00
uint32 item_alliance = it -> first ;
uint32 item_horde = it -> second ;
2012-12-19 12:55:51 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_INVENTORY_FACTION_CHANGE );
2012-10-29 12:28:12 +01:00
stmt -> setUInt32 ( 0 , ( team == TEAM_ALLIANCE ? item_alliance : item_horde ));
stmt -> setUInt32 ( 1 , ( team == TEAM_ALLIANCE ? item_horde : item_alliance ));
stmt -> setUInt32 ( 2 , guid );
trans -> Append ( stmt );
2012-10-07 13:55:04 +01:00
}
2013-03-04 14:15:52 +01:00
// Delete all current quests
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_QUESTSTATUS );
stmt -> setUInt32 ( 0 , GUID_LOPART ( guid ));
trans -> Append ( stmt );
// Quest conversion
for ( std :: map < uint32 , uint32 >:: const_iterator it = sObjectMgr -> FactionChangeQuests . begin (); it != sObjectMgr -> FactionChangeQuests . end (); ++ it )
{
uint32 quest_alliance = it -> first ;
uint32 quest_horde = it -> second ;
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST );
stmt -> setUInt32 ( 0 , lowGuid );
stmt -> setUInt32 ( 1 , ( team == TEAM_ALLIANCE ? quest_alliance : quest_horde ));
trans -> Append ( stmt );
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_FACTION_CHANGE );
stmt -> setUInt32 ( 0 , ( team == TEAM_ALLIANCE ? quest_alliance : quest_horde ));
stmt -> setUInt32 ( 1 , ( team == TEAM_ALLIANCE ? quest_horde : quest_alliance ));
stmt -> setUInt32 ( 2 , lowGuid );
trans -> Append ( stmt );
}
// Mark all rewarded quests as "active" (will count for completed quests achievements)
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE );
stmt -> setUInt32 ( 0 , lowGuid );
trans -> Append ( stmt );
// Disable all old-faction specific quests
{
ObjectMgr :: QuestMap const & questTemplates = sObjectMgr -> GetQuestTemplates ();
for ( ObjectMgr :: QuestMap :: const_iterator iter = questTemplates . begin (); iter != questTemplates . end (); ++ iter )
{
Quest const * quest = iter -> second ;
uint32 newRaceMask = ( team == TEAM_ALLIANCE ) ? RACEMASK_ALLIANCE : RACEMASK_HORDE ;
if ( ! ( quest -> GetRequiredRaces () & newRaceMask ))
{
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST );
stmt -> setUInt32 ( 0 , lowGuid );
stmt -> setUInt32 ( 1 , quest -> GetQuestId ());
trans -> Append ( stmt );
}
}
}
2012-10-29 12:28:12 +01:00
// Spell conversion
2013-03-04 14:15:52 +01:00
for ( std :: map < uint32 , uint32 >:: const_iterator it = sObjectMgr -> FactionChangeSpells . begin (); it != sObjectMgr -> FactionChangeSpells . end (); ++ it )
2012-10-29 12:28:12 +01:00
{
uint32 spell_alliance = it -> first ;
uint32 spell_horde = it -> second ;
2012-10-07 13:55:04 +01:00
2012-12-19 12:55:51 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_SPELL_BY_SPELL );
2012-10-29 12:28:12 +01:00
stmt -> setUInt32 ( 0 , ( team == TEAM_ALLIANCE ? spell_alliance : spell_horde ));
stmt -> setUInt32 ( 1 , lowGuid );
trans -> Append ( stmt );
2012-10-07 13:55:04 +01:00
2012-10-29 12:28:12 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_SPELL_FACTION_CHANGE );
stmt -> setUInt32 ( 0 , ( team == TEAM_ALLIANCE ? spell_alliance : spell_horde ));
stmt -> setUInt32 ( 1 , ( team == TEAM_ALLIANCE ? spell_horde : spell_alliance ));
stmt -> setUInt32 ( 2 , lowGuid );
trans -> Append ( stmt );
}
2012-10-07 13:55:04 +01:00
2012-10-29 12:28:12 +01:00
// Reputation conversion
2013-03-04 14:15:52 +01:00
for ( std :: map < uint32 , uint32 >:: const_iterator it = sObjectMgr -> FactionChangeReputation . begin (); it != sObjectMgr -> FactionChangeReputation . end (); ++ it )
2012-10-29 12:28:12 +01:00
{
uint32 reputation_alliance = it -> first ;
uint32 reputation_horde = it -> second ;
uint32 newReputation = ( team == TEAM_ALLIANCE ) ? reputation_alliance : reputation_horde ;
uint32 oldReputation = ( team == TEAM_ALLIANCE ) ? reputation_horde : reputation_alliance ;
// select old standing set in db
2012-12-19 12:55:51 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHAR_REP_BY_FACTION );
2012-10-29 12:28:12 +01:00
stmt -> setUInt32 ( 0 , oldReputation );
stmt -> setUInt32 ( 1 , lowGuid );
PreparedQueryResult result = CharacterDatabase . Query ( stmt );
2012-10-07 13:55:04 +01:00
2012-10-29 12:28:12 +01:00
if ( ! result )
{
WorldPacket data ( SMSG_CHAR_FACTION_CHANGE , 1 );
data << uint8 ( CHAR_CREATE_ERROR );
SendPacket ( & data );
return ;
}
2012-03-25 20:19:48 +02:00
2012-10-29 12:28:12 +01:00
Field * fields = result -> Fetch ();
int32 oldDBRep = fields [ 0 ]. GetInt32 ();
FactionEntry const * factionEntry = sFactionStore . LookupEntry ( oldReputation );
2012-09-27 22:38:19 +01:00
2012-10-29 12:28:12 +01:00
// old base reputation
2013-03-04 14:15:52 +01:00
int32 oldBaseRep = sObjectMgr -> GetBaseReputationOf ( factionEntry , oldRace , playerClass );
2012-09-27 22:38:19 +01:00
2012-10-29 12:28:12 +01:00
// new base reputation
2013-03-04 14:15:52 +01:00
int32 newBaseRep = sObjectMgr -> GetBaseReputationOf ( sFactionStore . LookupEntry ( newReputation ), race , playerClass );
2012-09-27 22:38:19 +01:00
2012-10-29 12:28:12 +01:00
// final reputation shouldnt change
int32 FinalRep = oldDBRep + oldBaseRep ;
int32 newDBRep = FinalRep - newBaseRep ;
2012-09-27 22:38:19 +01:00
2012-10-29 12:28:12 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_REP_BY_FACTION );
stmt -> setUInt32 ( 0 , newReputation );
stmt -> setUInt32 ( 1 , lowGuid );
trans -> Append ( stmt );
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_REP_FACTION_CHANGE );
stmt -> setUInt16 ( 0 , uint16 ( newReputation ));
stmt -> setInt32 ( 1 , newDBRep );
stmt -> setUInt16 ( 2 , uint16 ( oldReputation ));
stmt -> setUInt32 ( 3 , lowGuid );
trans -> Append ( stmt );
}
// Title conversion
if ( knownTitlesStr )
2012-09-27 22:38:19 +01:00
{
2012-10-29 12:28:12 +01:00
const uint32 ktcount = KNOWN_TITLES_SIZE * 2 ;
uint32 knownTitles [ ktcount ];
Tokenizer tokens ( knownTitlesStr , ' ' , ktcount );
2012-09-27 22:38:19 +01:00
2012-10-29 12:28:12 +01:00
if ( tokens . size () != ktcount )
return ;
for ( uint32 index = 0 ; index < ktcount ; ++ index )
knownTitles [ index ] = atol ( tokens [ index ]);
2013-03-04 14:15:52 +01:00
for ( std :: map < uint32 , uint32 >:: const_iterator it = sObjectMgr -> FactionChangeTitles . begin (); it != sObjectMgr -> FactionChangeTitles . end (); ++ it )
2012-09-27 22:38:19 +01:00
{
2012-10-29 12:28:12 +01:00
uint32 title_alliance = it -> first ;
uint32 title_horde = it -> second ;
CharTitlesEntry const * atitleInfo = sCharTitlesStore . LookupEntry ( title_alliance );
CharTitlesEntry const * htitleInfo = sCharTitlesStore . LookupEntry ( title_horde );
// new team
if ( team == TEAM_ALLIANCE )
2012-09-27 22:38:19 +01:00
{
2012-10-29 12:28:12 +01:00
uint32 bitIndex = htitleInfo -> bit_index ;
uint32 index = bitIndex / 32 ;
uint32 old_flag = 1 << ( bitIndex % 32 );
uint32 new_flag = 1 << ( atitleInfo -> bit_index % 32 );
if ( knownTitles [ index ] & old_flag )
{
knownTitles [ index ] &= ~ old_flag ;
// use index of the new title
knownTitles [ atitleInfo -> bit_index / 32 ] |= new_flag ;
}
2012-09-27 22:38:19 +01:00
}
2012-10-29 12:28:12 +01:00
else
2012-09-27 22:38:19 +01:00
{
2012-10-29 12:28:12 +01:00
uint32 bitIndex = atitleInfo -> bit_index ;
uint32 index = bitIndex / 32 ;
uint32 old_flag = 1 << ( bitIndex % 32 );
uint32 new_flag = 1 << ( htitleInfo -> bit_index % 32 );
if ( knownTitles [ index ] & old_flag )
{
knownTitles [ index ] &= ~ old_flag ;
// use index of the new title
knownTitles [ htitleInfo -> bit_index / 32 ] |= new_flag ;
}
2012-09-27 22:38:19 +01:00
}
2012-10-29 12:28:12 +01:00
std :: ostringstream ss ;
for ( uint32 index = 0 ; index < ktcount ; ++ index )
ss << knownTitles [ index ] << ' ' ;
2012-09-27 22:38:19 +01:00
2012-12-19 12:55:51 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_TITLES_FACTION_CHANGE );
2012-10-29 12:28:12 +01:00
stmt -> setString ( 0 , ss . str (). c_str ());
stmt -> setUInt32 ( 1 , lowGuid );
trans -> Append ( stmt );
2012-09-27 22:38:19 +01:00
2012-10-29 12:28:12 +01:00
// unset any currently chosen title
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_RES_CHAR_TITLES_FACTION_CHANGE );
stmt -> setUInt32 ( 0 , lowGuid );
trans -> Append ( stmt );
}
2012-09-27 22:38:19 +01:00
}
}
2010-09-05 13:12:24 -07:00
}
CharacterDatabase . CommitTransaction ( trans );
std :: string IP_str = GetRemoteAddress ();
2012-10-29 12:28:12 +01:00
sLog -> outDebug ( LOG_FILTER_PLAYER , "%s (IP: %s) changed race from %u to %u" , GetPlayerInfo (). c_str (), IP_str . c_str (), oldRace , race );
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 );
}