2010-10-07 15:35:36 +02:00
/*
2014-01-01 00:07:53 +01:00
* Copyright (C) 2008-2014 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"
2014-11-09 04:25:09 +01:00
#include "AuthenticationPackets.h"
2012-11-20 12:30:30 +01:00
#include "Battleground.h"
2014-11-09 04:25:09 +01:00
#include "BattlegroundPackets.h"
#include "BattlenetServerManager.h"
2012-11-20 12:30:30 +01:00
#include "CalendarMgr.h"
2014-10-31 14:47:56 +01:00
#include "CharacterPackets.h"
2009-06-04 21:41:07 +02:00
#include "Chat.h"
2014-11-04 00:01:09 +01:00
#include "ClientConfigPackets.h"
2012-11-20 12:30:30 +01:00
#include "Common.h"
#include "DatabaseEnv.h"
2014-11-19 21:09:30 +01:00
#include "EquipmentSetPackets.h"
2009-06-04 21:41:07 +02:00
#include "Group.h"
#include "Guild.h"
2012-09-10 12:28:40 +02:00
#include "GuildFinderMgr.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"
2014-11-23 04:25:47 +01:00
#include "MiscPackets.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"
2014-11-08 02:55:45 +01:00
#include "SystemPackets.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 ;
2014-09-14 16:14:12 +02:00
ObjectGuid m_guid ;
2008-10-11 14:16:25 -05:00
public :
2014-09-14 16:14:12 +02:00
LoginQueryHolder ( uint32 accountId , ObjectGuid guid )
2008-10-11 14:16:25 -05:00
: m_accountId ( accountId ), m_guid ( guid ) { }
2014-09-14 16:14:12 +02:00
ObjectGuid GetGuid () const { return m_guid ; }
2008-10-11 14:16:25 -05:00
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 ;
2014-10-23 21:34:03 +02:00
ObjectGuid :: LowType lowGuid = m_guid . GetCounter ();
2010-09-20 18:20:40 +02:00
2013-01-04 23:13:21 +00:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER );
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 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 );
2014-10-25 15:04:38 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 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 );
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 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
2014-03-02 00:00:39 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 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
2014-03-02 00:00:39 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_QUESTSTATUS_WEEKLY );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS , stmt );
2014-03-02 00:00:39 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_QUESTSTATUS_MONTHLY );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2012-12-04 00:02:06 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS , stmt );
2010-09-20 18:20:40 +02:00
2014-03-02 00:00:39 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_QUESTSTATUS_SEASONAL );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 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-09-05 02:55:42 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHAR_VOID_STORAGE );
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2012-12-07 09:22:43 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE , stmt );
2012-07-30 16:39:46 +01:00
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_ACTIONS );
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 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 );
2014-10-26 02:57:28 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2010-09-20 18:20:40 +02:00
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 );
2014-10-26 02:57:28 +02:00
stmt -> setUInt64 ( 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 );
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 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 );
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 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 );
2014-10-25 15:04:38 +02:00
stmt -> setUInt64 ( 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 );
2014-10-20 19:25:50 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 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-09-05 19:01:28 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHAR_CUF_PROFILES );
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2012-09-05 19:01:28 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES , stmt );
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_BGDATA );
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 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 );
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 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 );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 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
2012-09-03 22:27:18 +03:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_PLAYER_CURRENCY );
2014-10-26 02:57:28 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2012-12-07 09:22:43 +01:00
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_CURRENCY , stmt );
2012-09-03 22:27:18 +03: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
{
2014-11-15 13:03:32 +01:00
WorldPackets :: Character :: EnumCharactersResult charEnum ;
2014-10-31 14:47:56 +01:00
charEnum . Success = true ;
charEnum . IsDeletedCharacters = false ;
2009-10-17 15:51:44 -07:00
2014-11-03 19:11:14 +01:00
_legitCharacters . clear ();
2010-04-07 22:59:46 +02:00
if ( result )
2008-10-11 14:16:25 -05:00
{
do
{
2014-10-31 14:47:56 +01:00
Field * fields = result -> Fetch ();
2014-11-15 13:03:32 +01:00
WorldPackets :: Character :: EnumCharactersResult :: CharacterInfo charInfo ( fields );
2011-11-20 18:28:18 +01:00
2014-10-31 14:47:56 +01:00
TC_LOG_INFO ( "network" , "Loading char guid %s from account %u." , charInfo . Guid . ToString (). c_str (), GetAccountId ());
2011-11-20 18:28:18 +01:00
2014-10-31 14:47:56 +01:00
// Do not allow locked characters to login
if ( ! ( charInfo . Flags & ( CHARACTER_FLAG_LOCKED_FOR_TRANSFER | CHARACTER_FLAG_LOCKED_BY_BILLING )))
_legitCharacters . insert ( charInfo . Guid );
2011-11-20 18:28:18 +01:00
2014-11-12 19:16:14 +01:00
if ( ! sWorld -> HasCharacterInfo ( charInfo . Guid )) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet.
sWorld -> AddCharacterInfo ( charInfo . Guid , charInfo . Name , charInfo . Sex , charInfo . Race , charInfo . Class , charInfo . Level , false );
2013-08-18 18:13:14 +02:00
2014-10-31 14:47:56 +01:00
charEnum . Characters . emplace_back ( charInfo );
}
while ( result -> NextRow ());
2014-10-19 17:23:48 +02:00
}
2009-10-17 15:51:44 -07:00
2014-11-03 20:23:21 +01:00
SendPacket ( charEnum . Write ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-11-15 13:03:32 +01:00
void WorldSession :: HandleCharEnumOpcode ( WorldPackets :: Character :: EnumCharacters & /*enumCharacters*/ )
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 ());
2014-11-03 19:11:14 +01:00
_charEnumCallback . SetParam ( false );
_charEnumCallback . SetFutureResult ( CharacterDatabase . AsyncQuery ( stmt ));
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-11-03 19:11:14 +01:00
void WorldSession :: HandleCharUndeleteEnum ( PreparedQueryResult result )
2008-10-11 14:16:25 -05:00
{
2014-11-15 13:03:32 +01:00
WorldPackets :: Character :: EnumCharactersResult charEnum ;
2014-11-03 19:11:14 +01:00
charEnum . Success = true ;
charEnum . IsDeletedCharacters = true ;
2014-10-19 15:12:20 +02:00
2014-11-03 19:11:14 +01:00
if ( result )
{
do
{
Field * fields = result -> Fetch ();
2014-11-15 13:03:32 +01:00
WorldPackets :: Character :: EnumCharactersResult :: CharacterInfo charInfo ( fields );
2014-10-19 17:23:48 +02:00
2014-11-03 19:11:14 +01:00
TC_LOG_INFO ( "network" , "Loading undeleted char guid %s from account %u." , charInfo . Guid . ToString (). c_str (), GetAccountId ());
2009-10-17 15:51:44 -07:00
2014-11-12 19:16:14 +01:00
if ( ! sWorld -> HasCharacterInfo ( charInfo . Guid )) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet.
sWorld -> AddCharacterInfo ( charInfo . Guid , charInfo . Name , charInfo . Sex , charInfo . Race , charInfo . Class , charInfo . Level , true );
2014-11-03 19:11:14 +01:00
charEnum . Characters . emplace_back ( charInfo );
}
while ( result -> NextRow ());
}
2014-10-19 17:23:48 +02:00
2014-11-03 20:23:21 +01:00
SendPacket ( charEnum . Write ());
2014-11-03 19:11:14 +01:00
}
2014-10-19 17:23:48 +02:00
2014-11-03 19:11:14 +01:00
void WorldSession :: HandleCharUndeleteEnumOpcode ( WorldPacket & /*recvData*/ )
{
/// get all the data necessary for loading all undeleted characters (along with their pets) on the account
PreparedStatement * stmt = nullptr ;
if ( sWorld -> getBoolConfig ( CONFIG_DECLINED_NAMES_USED ))
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_UNDELETE_ENUM_DECLINED_NAME );
else
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_UNDELETE_ENUM );
2014-10-19 17:23:48 +02:00
2014-11-03 19:11:14 +01:00
stmt -> setUInt8 ( 0 , PET_SAVE_AS_CURRENT );
stmt -> setUInt32 ( 1 , GetAccountId ());
_charEnumCallback . SetParam ( true );
_charEnumCallback . SetFutureResult ( CharacterDatabase . AsyncQuery ( stmt ));
}
2014-11-15 13:03:32 +01:00
void WorldSession :: HandleCharCreateOpcode ( WorldPackets :: Character :: CreateChar & charCreate )
2014-11-03 19:11:14 +01:00
{
2013-09-27 12:46:01 +02:00
if ( ! HasPermission ( rbac :: 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
2014-11-03 19:11:14 +01:00
switch ( Player :: TeamForRace ( charCreate . CreateInfo -> Race ))
2008-10-11 14:16:25 -05:00
{
2013-02-25 15:28:41 +01:00
case ALLIANCE :
2014-07-17 15:42:57 +02:00
disabled = ( mask & ( 1 << 0 )) != 0 ;
2013-02-25 15:28:41 +01:00
break ;
case HORDE :
2014-07-17 15:42:57 +02:00
disabled = ( mask & ( 1 << 1 )) != 0 ;
2013-02-25 15:28:41 +01:00
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
{
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_DISABLED );
2008-10-11 14:16:25 -05:00
return ;
}
}
}
2009-10-17 15:51:44 -07:00
2014-11-03 19:11:14 +01:00
ChrClassesEntry const * classEntry = sChrClassesStore . LookupEntry ( charCreate . CreateInfo -> Class );
2011-02-17 19:47:08 +06:00
if ( ! classEntry )
{
2014-11-03 19:11:14 +01:00
TC_LOG_ERROR ( "network" , "Class (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?" , charCreate . CreateInfo -> Class , GetAccountId ());
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_FAILED );
2011-02-17 19:47:08 +06:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-11-03 19:11:14 +01:00
ChrRacesEntry const * raceEntry = sChrRacesStore . LookupEntry ( charCreate . CreateInfo -> Race );
2011-02-17 19:47:08 +06:00
if ( ! raceEntry )
2008-10-11 14:16:25 -05:00
{
2014-11-03 19:11:14 +01:00
TC_LOG_ERROR ( "network" , "Race (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?" , charCreate . CreateInfo -> Race , GetAccountId ());
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_FAILED );
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
2014-11-07 17:39:16 +02:00
uint8 raceExpansionRequirement = sObjectMgr -> GetRaceExpansionRequirement ( charCreate . CreateInfo -> Race );
if ( raceExpansionRequirement > Expansion ())
2008-10-11 14:16:25 -05:00
{
2014-11-07 17:39:16 +02:00
TC_LOG_ERROR ( "network" , "Expansion %u account:[%d] tried to Create character with expansion %u race (%u)" , Expansion (), GetAccountId (), raceExpansionRequirement , charCreate . CreateInfo -> Race );
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_EXPANSION );
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
2014-11-07 17:39:16 +02:00
uint8 classExpansionRequirement = sObjectMgr -> GetClassExpansionRequirement ( charCreate . CreateInfo -> Class );
if ( classExpansionRequirement > Expansion ())
2008-10-20 12:23:56 -05:00
{
2014-11-07 17:39:16 +02:00
TC_LOG_ERROR ( "network" , "Expansion %u account:[%d] tried to Create character with expansion %u class (%u)" , Expansion (), GetAccountId (), classExpansionRequirement , charCreate . CreateInfo -> Class );
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_EXPANSION_CLASS );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2013-09-27 12:46:01 +02:00
if ( ! HasPermission ( rbac :: 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 );
2014-11-03 19:11:14 +01:00
if (( 1 << ( charCreate . CreateInfo -> Race - 1 )) & raceMaskDisabled )
2010-09-06 23:34:16 +06:00
{
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_DISABLED );
2010-09-06 23:34:16 +06:00
return ;
}
2013-02-25 15:28:41 +01:00
}
2010-09-06 23:34:16 +06:00
2013-09-27 12:46:01 +02:00
if ( ! HasPermission ( rbac :: RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_CLASSMASK ))
2013-02-25 15:28:41 +01:00
{
2010-12-23 23:25:44 +01:00
uint32 classMaskDisabled = sWorld -> getIntConfig ( CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK );
2014-11-03 19:11:14 +01:00
if (( 1 << ( charCreate . CreateInfo -> Class - 1 )) & classMaskDisabled )
2010-09-06 23:34:16 +06:00
{
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_DISABLED );
2010-09-06 23:34:16 +06:00
return ;
}
}
2008-10-11 14:16:25 -05:00
// prevent character creating with invalid name
2014-11-03 19:11:14 +01:00
if ( ! normalizePlayerName ( charCreate . CreateInfo -> Name ))
2008-10-11 14:16:25 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "network" , "Account:[%d] but tried to Create character with empty [name] " , GetAccountId ());
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_NAME_NO_NAME );
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
2014-11-03 19:11:14 +01:00
ResponseCodes res = ObjectMgr :: CheckPlayerName ( charCreate . CreateInfo -> Name , true );
2009-07-10 08:25:33 +08:00
if ( res != CHAR_NAME_SUCCESS )
2008-10-11 14:16:25 -05:00
{
2014-10-19 15:12:20 +02:00
SendCharCreate ( res );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-11-03 19:11:14 +01:00
if ( ! HasPermission ( rbac :: RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME ) && sObjectMgr -> IsReservedName ( charCreate . CreateInfo -> Name ))
2008-10-11 14:16:25 -05:00
{
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_NAME_RESERVED );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-11-03 19:11:14 +01:00
if ( charCreate . CreateInfo -> Class == CLASS_DEATH_KNIGHT && ! HasPermission ( rbac :: 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
2014-11-03 19:11:14 +01:00
if ( ! sWorld -> getIntConfig ( CONFIG_HEROIC_CHARACTERS_PER_REALM ))
2013-02-25 15:28:41 +01:00
{
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_UNIQUE_CLASS_LIMIT );
2013-02-25 15:28:41 +01:00
return ;
}
2009-10-17 15:51:44 -07:00
2013-02-25 15:28:41 +01:00
// speedup check for heroic class disabled case
2014-11-03 19:11:14 +01:00
if ( sWorld -> getIntConfig ( CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER ) > sWorld -> getIntConfig ( CONFIG_MAX_PLAYER_LEVEL ))
2013-02-25 15:28:41 +01:00
{
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_LEVEL_REQUIREMENT );
2013-02-25 15:28:41 +01:00
return ;
}
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2012-01-01 01:09:38 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHECK_NAME );
2014-11-03 19:11:14 +01:00
stmt -> setString ( 0 , charCreate . CreateInfo -> Name );
2014-10-19 15:12:20 +02:00
2014-11-03 19:11:14 +01:00
_charCreateCallback . SetParam ( charCreate . CreateInfo );
2011-06-22 14:20:42 +02:00
_charCreateCallback . SetFutureResult ( CharacterDatabase . AsyncQuery ( stmt ));
}
2009-10-17 15:51:44 -07:00
2014-11-03 19:11:14 +01:00
void WorldSession :: HandleCharCreateCallback ( PreparedQueryResult result , WorldPackets :: Character :: CharacterCreateInfo * createInfo )
2011-06-22 14:20:42 +02:00
{
/** 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.
2014-11-03 19:11:14 +01:00
It also prevents data synchronisation 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 )
{
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_NAME_IN_USE );
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
2014-11-03 19:11:14 +01:00
ASSERT ( _charCreateCallback . GetParam (). get () == 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 ();
2014-10-19 15:12:20 +02:00
break ;
2011-06-22 14:20:42 +02:00
}
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
{
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_ACCOUNT_LIMIT );
2011-12-21 10:22:03 +01:00
_charCreateCallback . Reset ();
2011-06-22 14:20:42 +02:00
return ;
}
2014-11-03 19:11:14 +01:00
ASSERT ( _charCreateCallback . GetParam (). get () == createInfo );
2011-06-22 14:20:42 +02:00
2012-01-01 01:09:38 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_SUM_CHARS );
2011-06-22 14:20:42 +02:00
stmt -> setUInt32 ( 0 , GetAccountId ());
_charCreateCallback . FreeResult ();
_charCreateCallback . SetFutureResult ( CharacterDatabase . AsyncQuery ( stmt ));
2011-12-21 10:22:03 +01:00
_charCreateCallback . NextStage ();
2014-10-19 15:12:20 +02:00
break ;
2011-06-22 14:20:42 +02:00
}
case 2 :
{
if ( result )
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2012-05-30 08:01:02 +02: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
{
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_SERVER_LIMIT );
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-09-27 12:46:01 +02:00
bool allowTwoSideAccounts = ! sWorld -> IsPvPRealm () || HasPermission ( rbac :: 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
2014-10-19 15:12:20 +02:00
break ;
2011-06-22 14:20:42 +02:00
}
case 3 :
{
bool haveSameRace = false ;
uint32 heroicReqLevel = sWorld -> getIntConfig ( CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER );
bool hasHeroicReqLevel = ( heroicReqLevel == 0 );
2013-09-27 12:46:01 +02:00
bool allowTwoSideAccounts = ! sWorld -> IsPvPRealm () || HasPermission ( rbac :: RBAC_PERM_TWO_SIDE_CHARACTER_CREATION );
2011-06-22 14:20:42 +02:00
uint32 skipCinematics = sWorld -> getIntConfig ( CONFIG_SKIP_CINEMATICS );
2013-09-27 12:46:01 +02:00
bool checkHeroicReqs = createInfo -> Class == CLASS_DEATH_KNIGHT && ! HasPermission ( rbac :: 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
{
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_UNIQUE_CLASS_LIMIT );
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 )
{
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_PVP_TEAMS_VIOLATION );
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 )
{
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_UNIQUE_CLASS_LIMIT );
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
{
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_LEVEL_REQUIREMENT );
2011-12-21 10:22:03 +01:00
_charCreateCallback . Reset ();
2011-06-22 23:02:52 +02:00
return ;
}
2011-09-06 10:41:10 +02:00
Player newChar ( this );
2012-02-16 16:27:38 -05:00
newChar . GetMotionMaster () -> Initialize ();
2014-10-27 12:03:35 +01:00
if ( ! newChar . Create ( sObjectMgr -> GetGenerator < HighGuid :: Player > () -> Generate (), 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
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_ERROR );
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-05-30 08:01:02 +02:00
PreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_DEL_REALM_CHARACTERS_BY_REALM );
2011-06-22 14:20:42 +02:00
stmt -> setUInt32 ( 0 , GetAccountId ());
2014-10-17 22:48:06 +02:00
stmt -> setUInt32 ( 1 , realmHandle . Index );
2011-06-22 14:20:42 +02:00
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 ());
2014-10-17 22:48:06 +02:00
stmt -> setUInt32 ( 2 , realmHandle . Index );
2011-06-22 14:20:42 +02:00
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
2014-10-19 15:12:20 +02:00
SendCharCreate ( CHAR_CREATE_SUCCESS );
2010-05-15 01:26:28 +02:00
2014-10-22 17:33:55 +02:00
TC_LOG_INFO ( "entities.player.character" , "Account: %u (IP: %s) Create Character: %s %s" , GetAccountId (), GetRemoteAddress (). c_str (), createInfo -> Name . c_str (), newChar . GetGUID (). ToString (). c_str ());
2011-09-06 10:41:10 +02:00
sScriptMgr -> OnPlayerCreate ( & newChar );
2014-11-12 19:16:14 +01:00
sWorld -> AddCharacterInfo ( newChar . GetGUID (), newChar . GetName (), newChar . getGender (), newChar . getRace (), newChar . getClass (), newChar . getLevel (), false );
2011-06-22 14:20:42 +02:00
2012-05-30 08:01:02 +02:00
newChar . CleanupsBeforeDelete ();
2011-12-21 10:22:03 +01:00
_charCreateCallback . Reset ();
2014-10-19 15:12:20 +02:00
break ;
2011-06-22 14:20:42 +02:00
}
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-11-15 13:03:32 +01:00
void WorldSession :: HandleCharDeleteOpcode ( WorldPackets :: Character :: DeleteChar & charDelete )
2008-10-11 14:16:25 -05:00
{
2014-05-02 03:44:21 +02:00
// Initiating
uint32 initAccountId = GetAccountId ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// can't delete loaded character
2014-11-03 19:11:14 +01:00
if ( ObjectAccessor :: FindPlayer ( charDelete . Guid ))
2014-05-02 03:44:21 +02:00
{
2014-11-03 19:11:14 +01:00
sScriptMgr -> OnPlayerFailedDelete ( charDelete . Guid , initAccountId );
2008-10-11 14:16:25 -05:00
return ;
2014-05-02 03:44:21 +02:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// is guild leader
2014-11-03 19:11:14 +01:00
if ( sGuildMgr -> GetGuildByLeader ( charDelete . Guid ))
2008-10-11 14:16:25 -05:00
{
2014-11-03 19:11:14 +01:00
sScriptMgr -> OnPlayerFailedDelete ( charDelete . Guid , initAccountId );
2014-10-19 15:12:20 +02:00
SendCharDelete ( CHAR_DELETE_FAILED_GUILD_LEADER );
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
2014-11-03 19:11:14 +01:00
if ( sArenaTeamMgr -> GetArenaTeamByCaptain ( charDelete . Guid ))
2008-10-11 14:16:25 -05:00
{
2014-11-03 19:11:14 +01:00
sScriptMgr -> OnPlayerFailedDelete ( charDelete . Guid , initAccountId );
2014-10-19 15:12:20 +02:00
SendCharDelete ( CHAR_DELETE_FAILED_ARENA_CAPTAIN );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-11-03 19:11:14 +01:00
uint32 accountId = 0 ;
uint8 level = 0 ;
std :: string name ;
2012-11-30 13:59:01 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_DATA_BY_GUID );
2014-11-03 19:11:14 +01:00
stmt -> setUInt64 ( 0 , charDelete . Guid . GetCounter ());
2012-05-30 08:01:02 +02:00
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
2014-05-02 03:44:21 +02:00
if ( accountId != initAccountId )
{
2014-11-03 19:11:14 +01:00
sScriptMgr -> OnPlayerFailedDelete ( charDelete . Guid , initAccountId );
2008-10-11 14:16:25 -05:00
return ;
2014-05-02 03:44:21 +02:00
}
2009-10-17 15:51:44 -07:00
2014-11-03 19:11:14 +01:00
TC_LOG_INFO ( "entities.player.character" , "Account: %u, IP: %s deleted character: %s, %s, Level: %u" , accountId , GetRemoteAddress (). c_str (), name . c_str (), charDelete . Guid . ToString (). c_str (), level );
2014-06-26 22:50:06 +02:00
2014-05-02 03:44:21 +02:00
// To prevent hook failure, place hook before removing reference from DB
2014-11-03 19:11:14 +01:00
sScriptMgr -> OnPlayerDelete ( charDelete . Guid , initAccountId ); // To prevent race conditioning, but as it also makes sense, we hand the accountId over for successful delete.
2014-05-02 03:44:21 +02:00
// Shouldn't interfere with character deletion though
2009-10-17 15:51:44 -07:00
2013-11-08 10:50:51 +01:00
if ( sLog -> ShouldLog ( "entities.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 ;
2014-11-03 19:11:14 +01:00
if ( PlayerDumpWriter (). GetDump ( charDelete . Guid . GetCounter (), dump ))
sLog -> outCharDump ( dump . c_str (), accountId , charDelete . Guid . GetCounter (), name . c_str ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-11-03 19:11:14 +01:00
sGuildFinderMgr -> RemoveAllMembershipRequestsFromPlayer ( charDelete . Guid );
sCalendarMgr -> RemoveAllPlayerEventsAndInvites ( charDelete . Guid );
Player :: DeleteFromDB ( charDelete . Guid , accountId );
2009-10-17 15:51:44 -07:00
2014-10-19 15:12:20 +02:00
SendCharDelete ( CHAR_DELETE_SUCCESS );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-11-03 18:30:23 +01:00
void WorldSession :: HandlePlayerLoginOpcode ( WorldPackets :: Character :: PlayerLogin & playerLogin )
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
{
2013-11-08 11:12:17 +01:00
TC_LOG_ERROR ( "network" , "Player tries to login again, AccountId = %d" , GetAccountId ());
2014-06-02 17:03:31 +02:00
KickPlayer ();
2008-12-19 16:05:13 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-10-31 14:47:56 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: Recvd Player Logon Message" );
2014-11-09 00:37:33 +01:00
m_playerLoading = playerLogin . Guid ;
2009-10-17 15:51:44 -07:00
2014-10-31 14:47:56 +01:00
TC_LOG_DEBUG ( "network" , "Character %s logging in" , playerLogin . Guid . ToString (). c_str ());
if ( ! IsLegitCharacterForAccount ( playerLogin . Guid ))
2011-04-01 03:11:57 +02:00
{
2014-10-31 14:47:56 +01:00
TC_LOG_ERROR ( "network" , "Account (%u) can't login with that character (%s)." , GetAccountId (), playerLogin . Guid . ToString (). c_str ());
2011-04-01 03:11:57 +02:00
KickPlayer ();
return ;
}
2014-11-09 00:37:33 +01:00
boost :: system :: error_code ignored_error ;
boost :: asio :: ip :: tcp :: endpoint instanceAddress = realm . GetAddressForClient ( boost :: asio :: ip :: address :: from_string ( GetRemoteAddress (), ignored_error ));
instanceAddress . port ( sWorld -> getIntConfig ( CONFIG_PORT_INSTANCE ));
WorldPackets :: Auth :: ConnectTo connectTo ;
connectTo . Key = MAKE_PAIR64 ( GetAccountId (), CONNECTION_TYPE_INSTANCE );
connectTo . Serial = 1 ;
connectTo . Payload . Where = instanceAddress ;
connectTo . Con = CONNECTION_TYPE_INSTANCE ;
SendPacket ( connectTo . Write ());
}
void WorldSession :: HandleContinuePlayerLogin ()
{
if ( ! PlayerLoading () || GetPlayer ())
{
KickPlayer ();
return ;
}
LoginQueryHolder * holder = new LoginQueryHolder ( GetAccountId (), m_playerLoading );
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
2014-11-09 00:37:33 +01:00
m_playerLoading . Clear ();
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-09-14 16:14:12 +02:00
_charLoginCallback = CharacterDatabase . DelayQueryHolder ( holder );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-11-10 05:30:39 +00:00
void WorldSession :: HandleLoadScreenOpcode ( WorldPackets :: Character :: LoadingScreenNotify & /*loadingScreenNotify*/ )
2011-11-24 18:58:00 +01:00
{
// TODO: Do something with this packet
}
2011-12-16 15:36:03 +01:00
void WorldSession :: HandlePlayerLogin ( LoginQueryHolder * holder )
2008-10-11 14:16:25 -05:00
{
2014-09-14 16:14:12 +02:00
ObjectGuid 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)
2014-09-14 16:14:12 +02:00
if ( ! pCurrChar -> LoadFromDB ( 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
2014-11-09 00:37:33 +01:00
m_playerLoading . Clear ();
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-11-23 04:25:47 +01:00
SendTutorialsData ();
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
2014-11-03 20:25:21 +01:00
WorldPackets :: Character :: LoginVerifyWorld loginVerifyWorld ;
loginVerifyWorld . MapID = pCurrChar -> GetMapId ();
loginVerifyWorld . Pos = pCurrChar -> GetPosition ();
SendPacket ( loginVerifyWorld . Write ());
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 );
2014-11-04 00:01:09 +01:00
WorldPackets :: ClientConfig :: AccountDataTimes accountDataTimes ;
accountDataTimes . PlayerGuid = playerGuid ;
accountDataTimes . ServerTime = uint32 ( sWorld -> GetGameTime ());
for ( uint32 i = 0 ; i < NUM_ACCOUNT_DATA_TYPES ; ++ i )
accountDataTimes . AccountTimes [ i ] = uint32 ( GetAccountData ( AccountDataType ( i )) -> Time );
SendPacket ( accountDataTimes . Write ());
2009-10-17 15:51:44 -07:00
2014-11-14 02:00:34 +01:00
/// Send FeatureSystemStatus
2012-08-01 21:58:28 +02:00
{
2014-11-14 02:00:34 +01:00
WorldPackets :: System :: FeatureSystemStatus features ;
2014-11-19 21:09:30 +01:00
/// START OF DUMMY VALUES
features . ComplaintStatus = 2 ;
features . ScrollOfResurrectionRequestsRemaining = 1 ;
features . ScrollOfResurrectionMaxRequestsPerDay = 1 ;
features . CfgRealmID = 2 ;
features . CfgRealmRecID = 0 ;
features . VoiceEnabled = true ;
/// END OF DUMMY VALUES
2014-11-14 02:00:34 +01:00
features . CharUndeleteEnabled = sWorld -> getBoolConfig ( CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED );
features . BpayStoreEnabled = sWorld -> getBoolConfig ( CONFIG_FEATURE_SYSTEM_BPAY_STORE_ENABLED );
2012-07-11 23:28:40 +02:00
2014-11-14 02:00:34 +01:00
SendPacket ( features . Write ());
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Send MOTD
{
2014-11-08 02:55:45 +01:00
WorldPackets :: System :: MOTD motd ;
motd . Text = & sWorld -> GetMotd ();
SendPacket ( motd . Write ());
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: Sent motd (SMSG_MOTD)" );
2014-11-08 02:55:45 +01:00
}
2009-10-17 15:51:44 -07:00
2014-11-09 04:25:09 +01:00
SendSetTimeZoneInformation ();
// Send PVPSeason
{
WorldPackets :: Battleground :: PVPSeason season ;
season . PreviousSeason = sWorld -> getIntConfig ( CONFIG_ARENA_SEASON_ID ) - sWorld -> getBoolConfig ( CONFIG_ARENA_SEASON_IN_PROGRESS );
if ( sWorld -> getBoolConfig ( CONFIG_ARENA_SEASON_IN_PROGRESS ))
season . CurrentSeason = sWorld -> getIntConfig ( CONFIG_ARENA_SEASON_ID );
SendPacket ( season . Write ());
TC_LOG_DEBUG ( "network" , "WORLD: Sent PVPSeason" );
}
2014-11-08 02:55:45 +01: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
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "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 ();
2014-10-25 15:04:38 +02:00
pCurrChar -> SetInGuild ( fields [ 0 ]. GetUInt64 ());
2010-09-24 22:16:21 +02:00
pCurrChar -> SetRank ( fields [ 1 ]. GetUInt8 ());
2012-07-19 16:07:37 +02:00
if ( Guild * guild = sGuildMgr -> GetGuildById ( pCurrChar -> GetGuildId ()))
2012-09-07 14:39:19 +02:00
pCurrChar -> SetGuildLevel ( guild -> GetLevel ());
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
{
2014-10-26 02:57:28 +02:00
pCurrChar -> SetInGuild ( UI64LIT ( 0 ));
2008-11-30 12:47:26 -06:00
pCurrChar -> SetRank ( 0 );
2012-09-07 14:39:19 +02:00
pCurrChar -> SetGuildLevel ( 0 );
2008-11-30 12:47:26 -06:00
}
2009-10-17 15:51:44 -07:00
2014-11-14 02:00:34 +01:00
WorldPacket data ( SMSG_LEARNED_DANCE_MOVES , 4 + 4 );
2012-07-11 23:28:40 +02:00
data << uint64 ( 0 );
2009-12-17 10:49:15 +01:00
SendPacket ( & data );
2012-01-31 14:02:59 +01:00
data . Initialize ( SMSG_HOTFIX_INFO );
HotfixData const & hotfix = sObjectMgr -> GetHotfixData ();
2012-07-11 23:28:40 +02:00
data . WriteBits ( hotfix . size (), 22 );
2012-07-12 21:20:34 +02:00
data . FlushBits ();
2012-01-31 14:02:59 +01:00
for ( uint32 i = 0 ; i < hotfix . size (); ++ i )
{
data << uint32 ( hotfix [ i ]. Type );
2012-01-31 15:13:38 +01:00
data << uint32 ( hotfix [ i ]. Timestamp );
2012-01-31 14:02:59 +01:00
data << uint32 ( hotfix [ i ]. Entry );
}
SendPacket ( & data );
2008-10-11 14:16:25 -05:00
pCurrChar -> SendInitialPacketsBeforeAddToMap ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//Show cinematic at the first time that player login
2010-04-07 22:59:46 +02:00
if ( ! pCurrChar -> getCinematic ())
2008-10-11 14:16:25 -05:00
{
pCurrChar -> setCinematic ( 1 );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ChrClassesEntry const * cEntry = sChrClassesStore . LookupEntry ( pCurrChar -> getClass ()))
2008-10-11 14:16:25 -05:00
{
2014-11-07 17:39:16 +02:00
if ( cEntry -> CinematicSequenceID )
pCurrChar -> SendCinematicStart ( cEntry -> CinematicSequenceID );
2009-04-05 16:25:00 -05:00
else if ( ChrRacesEntry const * rEntry = sChrRacesStore . LookupEntry ( pCurrChar -> getRace ()))
2014-11-07 17:39:16 +02:00
pCurrChar -> SendCinematicStart ( rEntry -> CinematicSequenceID );
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
{
2013-05-26 02:25:58 +03:00
AreaTriggerStruct 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 );
2013-05-13 15:07:36 +02:00
//TC_LOG_DEBUG("Player %s added to Map.", pCurrChar->GetName().c_str());
2009-10-17 15:51:44 -07:00
2014-10-26 02:57:28 +02:00
if ( pCurrChar -> GetGuildId ())
2012-07-19 16:07:37 +02:00
{
if ( Guild * guild = sGuildMgr -> GetGuildById ( pCurrChar -> GetGuildId ()))
guild -> SendLoginInfo ( this );
else
{
// remove wrong guild data
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "misc" , "Player %s (%s) marked as member of not existing guild (id: " UI64FMTD "), removing guild membership for player." , pCurrChar -> GetName (). c_str (), pCurrChar -> GetGUID (). ToString (). c_str (), pCurrChar -> GetGuildId ());
pCurrChar -> SetInGuild ( UI64LIT ( 0 ));
2012-07-19 16:07:37 +02: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 );
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 0 , pCurrChar -> GetGUID (). GetCounter ());
2011-12-31 00:32:05 +01:00
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
2014-10-22 12:52:12 +02:00
sSocialMgr -> SendFriendStatus ( pCurrChar , FRIEND_ONLINE , pCurrChar -> GetGUID (), 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...
2013-08-10 13:44:08 +02:00
if ( pCurrChar -> getRace () == RACE_NIGHTELF && ! pCurrChar -> HasAura ( 20584 ))
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)
2013-08-10 13:44:08 +02:00
if ( ! pCurrChar -> HasAura ( 8326 ))
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
2013-06-18 21:04:31 +02:00
pCurrChar -> SetWaterWalking ( true );
2008-10-11 14:16:25 -05:00
}
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
2013-06-11 21:25:12 -02:30
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
{
2014-07-12 17:28:35 +02:00
pCurrChar -> ResetSpells ();
2008-10-11 14:16:25 -05:00
SendNotification ( LANG_RESET_SPELLS );
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( pCurrChar -> HasAtLoginFlag ( AT_LOGIN_RESET_TALENTS ))
2008-10-11 14:16:25 -05:00
{
2012-01-29 17:40:14 +01:00
pCurrChar -> ResetTalents ( true );
2014-11-12 03:58:17 +02:00
pCurrChar -> SendTalentsInfoData (); // 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
2014-06-21 15:40:58 +03:00
bool firstLogin = pCurrChar -> HasAtLoginFlag ( AT_LOGIN_FIRST );
if ( firstLogin )
2013-05-10 20:39:15 +02:00
{
2010-02-14 19:13:14 -07:00
pCurrChar -> RemoveAtLoginFlag ( AT_LOGIN_FIRST );
2014-07-09 20:34:39 +02:00
PlayerInfo const * info = sObjectMgr -> GetPlayerInfo ( pCurrChar -> getRace (), pCurrChar -> getClass ());
for ( uint32 spellId : info -> castSpells )
pCurrChar -> CastSpell ( pCurrChar , spellId , true );
2013-05-10 20:39:15 +02:00
}
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
2013-06-11 21:25:12 -02:30
if ( pCurrChar -> IsGameMaster ())
2008-10-11 14:16:25 -05:00
SendNotification ( LANG_GM_ON );
2009-10-17 15:51:44 -07:00
2014-10-22 17:33:55 +02:00
TC_LOG_INFO ( "entities.player.character" , "Account: %u (IP: %s) Login Character: [%s] (%s) Level: %d" ,
2014-10-31 14:47:56 +01:00
GetAccountId (), GetRemoteAddress (). c_str (), pCurrChar -> GetName (). c_str (), pCurrChar -> GetGUID (). ToString (). c_str (), pCurrChar -> getLevel ());
2009-10-17 15:51:44 -07:00
2012-02-03 19:12:41 +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
2014-11-09 00:37:33 +01:00
m_playerLoading . Clear ();
2009-10-17 15:51:44 -07:00
2014-02-05 09:34:12 +01:00
// Handle Login-Achievements (should be handled after loading)
_player -> UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN , 1 );
2014-06-21 15:40:58 +03:00
sScriptMgr -> OnPlayerLogin ( pCurrChar , firstLogin );
2014-10-17 22:48:06 +02:00
sBattlenetServer . SendChangeToonOnlineState ( GetBattlenetAccountId (), GetAccountId (), _player -> GetGUID (), _player -> GetName (), true );
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
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "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-08-05 19:40:30 -05:00
recvData >> repListID ;
recvData >> flag ;
2009-10-17 15:51:44 -07:00
2014-07-17 15:42:57 +02:00
GetPlayer () -> GetReputationMgr (). SetAtWar ( repListID , flag != 0 );
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
2014-10-19 15:12:20 +02:00
void WorldSession :: HandleSetFactionCheat ( WorldPacket & /*recvData*/ )
2008-10-11 14:16:25 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "network" , "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
2014-11-23 04:25:47 +01:00
void WorldSession :: HandleTutorialFlag ( WorldPackets :: Misc :: TutorialSetFlag & packet )
2008-10-11 14:16:25 -05:00
{
2014-11-23 04:25:47 +01:00
switch ( packet . Action )
{
case TUTORIAL_ACTION_UPDATE :
{
uint8 index = uint8 ( packet . TutorialBit >> 5 );
if ( index >= MAX_ACCOUNT_TUTORIAL_VALUES )
{
TC_LOG_ERROR ( "network" , "CMSG_TUTORIAL_FLAG received bad TutorialBit %u." , packet . TutorialBit );
return ;
}
uint32 flag = GetTutorialInt ( index );
flag |= ( 1 << ( packet . TutorialBit & 0x1F ));
SetTutorialInt ( index , flag );
break ;
}
case TUTORIAL_ACTION_CLEAR :
for ( uint8 i = 0 ; i < MAX_ACCOUNT_TUTORIAL_VALUES ; ++ i )
SetTutorialInt ( i , 0xFFFFFFFF );
break ;
case TUTORIAL_ACTION_RESET :
for ( uint8 i = 0 ; i < MAX_ACCOUNT_TUTORIAL_VALUES ; ++ i )
SetTutorialInt ( i , 0x00000000 );
break ;
default :
TC_LOG_ERROR ( "network" , "CMSG_TUTORIAL_FLAG received unknown TutorialAction %u." , packet . Action );
return ;
}
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
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: Received CMSG_SET_WATCHED_FACTION" );
2008-10-11 14:16:25 -05:00
uint32 fact ;
2012-08-05 19:40:30 -05: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
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: Received CMSG_SET_FACTION_INACTIVE" );
2008-10-11 14:16:25 -05:00
uint32 replistid ;
uint8 inactive ;
2012-08-05 19:40:30 -05:00
recvData >> replistid >> inactive ;
2009-10-17 15:51:44 -07:00
2014-07-17 15:42:57 +02:00
_player -> GetReputationMgr (). SetInactive ( replistid , inactive != 0 );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2012-08-05 19:40:30 -05:00
void WorldSession :: HandleShowingHelmOpcode ( WorldPacket & recvData )
2008-10-11 14:16:25 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "CMSG_SHOWING_HELM for %s" , _player -> GetName (). c_str ());
2012-08-05 19:40:30 -05: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-08-05 19:40:30 -05:00
void WorldSession :: HandleShowingCloakOpcode ( WorldPacket & recvData )
2008-10-11 14:16:25 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "CMSG_SHOWING_CLOAK for %s" , _player -> GetName (). c_str ());
2012-08-05 19:40:30 -05: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
2014-11-12 16:36:05 +01:00
void WorldSession :: HandleCharRenameOpcode ( WorldPackets :: Character :: CharacterRenameRequest & request )
2008-10-11 14:16:25 -05:00
{
2014-11-12 16:36:05 +01:00
if ( ! IsLegitCharacterForAccount ( request . RenameInfo -> Guid ))
{
TC_LOG_ERROR ( "network" , "Account %u, IP: %s tried to rename character %s, but it does not belong to their account!" ,
GetAccountId (), GetRemoteAddress (). c_str (), request . RenameInfo -> Guid . ToString (). c_str ());
KickPlayer ();
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// prevent character rename to invalid name
2014-11-12 16:36:05 +01:00
if ( ! normalizePlayerName ( request . RenameInfo -> NewName ))
2008-10-11 14:16:25 -05:00
{
2014-11-12 16:36:05 +01:00
SendCharRename ( CHAR_NAME_NO_NAME , request . RenameInfo . get ());
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-11-12 16:36:05 +01:00
ResponseCodes res = ObjectMgr :: CheckPlayerName ( request . RenameInfo -> NewName , true );
2009-07-10 08:25:33 +08:00
if ( res != CHAR_NAME_SUCCESS )
2008-10-11 14:16:25 -05:00
{
2014-11-12 16:36:05 +01:00
SendCharRename ( res , request . RenameInfo . get ());
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
2014-11-12 16:36:05 +01:00
if ( ! HasPermission ( rbac :: RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME ) && sObjectMgr -> IsReservedName ( request . RenameInfo -> NewName ))
2008-10-11 14:16:25 -05:00
{
2014-11-12 16:36:05 +01:00
SendCharRename ( CHAR_NAME_RESERVED , request . RenameInfo . get ());
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-11-12 16:36:05 +01:00
// Ensure that there is no character with the desired new name
2012-01-01 01:09:38 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_FREE_NAME );
2014-11-12 16:36:05 +01:00
stmt -> setUInt64 ( 0 , request . RenameInfo -> Guid . GetCounter ());
stmt -> setString ( 1 , request . RenameInfo -> NewName );
2011-12-18 20:55:59 +01:00
2014-11-12 16:36:05 +01:00
_charRenameCallback . SetParam ( request . RenameInfo );
2011-12-18 20:55:59 +01:00
_charRenameCallback . SetFutureResult ( CharacterDatabase . AsyncQuery ( stmt ));
2008-12-19 16:05:13 -06:00
}
2009-10-17 15:51:44 -07:00
2014-11-12 16:36:05 +01:00
void WorldSession :: HandleCharRenameCallBack ( PreparedQueryResult result , WorldPackets :: Character :: CharacterRenameInfo * renameInfo )
2008-12-19 16:05:13 -06:00
{
2014-11-12 16:36:05 +01:00
ASSERT ( _charRenameCallback . GetParam (). get () == renameInfo );
2008-12-22 10:59:38 -06:00
if ( ! result )
2008-10-11 14:16:25 -05:00
{
2014-11-12 16:36:05 +01:00
SendCharRename ( CHAR_CREATE_ERROR , renameInfo );
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 ();
2014-10-23 21:34:03 +02:00
std :: string oldName = fields [ 0 ]. GetString ();
2014-11-12 16:36:05 +01:00
uint16 atLoginFlags = fields [ 1 ]. GetUInt16 ();
2011-12-18 20:55:59 +01:00
2014-11-12 16:36:05 +01:00
if ( ! ( atLoginFlags & AT_LOGIN_RENAME ))
{
SendCharRename ( CHAR_CREATE_ERROR , renameInfo );
return ;
}
2011-12-18 20:55:59 +01:00
2014-11-12 16:36:05 +01:00
atLoginFlags &= ~ AT_LOGIN_RENAME ;
2011-12-18 20:55:59 +01:00
2014-11-12 16:36:05 +01:00
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
ObjectGuid :: LowType lowGuid = renameInfo -> Guid . GetCounter ();
// Update name and at_login flag in the db
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_NAME_AT_LOGIN );
stmt -> setString ( 0 , renameInfo -> NewName );
stmt -> setUInt16 ( 1 , atLoginFlags );
stmt -> setUInt64 ( 2 , lowGuid );
trans -> Append ( stmt );
2011-12-18 20:55:59 +01:00
// Removed declined name from db
2014-11-12 16:36:05 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_DECLINED_NAME );
stmt -> setUInt64 ( 0 , lowGuid );
2011-12-18 20:55:59 +01:00
2014-11-12 16:36:05 +01:00
trans -> Append ( stmt );
2011-12-18 20:55:59 +01:00
2014-11-12 16:36:05 +01:00
CharacterDatabase . CommitTransaction ( trans );
2009-10-17 15:51:44 -07:00
2014-11-12 16:36:05 +01:00
TC_LOG_INFO ( "entities.player.character" , "Account: %u (IP: %s) Character:[%s] (%s) Changed name to: %s" ,
GetAccountId (), GetRemoteAddress (). c_str (), oldName . c_str (), renameInfo -> Guid . ToString (). c_str (), renameInfo -> NewName . c_str ());
2009-10-17 15:51:44 -07:00
2014-11-12 16:36:05 +01:00
SendCharRename ( RESPONSE_SUCCESS , renameInfo );
2011-11-16 10:31:38 +01:00
2014-11-12 19:16:14 +01:00
sWorld -> UpdateCharacterInfo ( renameInfo -> Guid , renameInfo -> NewName );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2012-08-05 19:40:30 -05:00
void WorldSession :: HandleSetPlayerDeclinedNames ( WorldPacket & recvData )
2008-10-11 14:16:25 -05:00
{
2014-09-14 16:14:12 +02:00
ObjectGuid guid ;
2009-10-17 15:51:44 -07:00
2012-08-05 19:40:30 -05: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 ;
2014-11-12 19:16:14 +01:00
if ( ! ObjectMgr :: GetPlayerNameByGUID ( guid , name ))
2008-10-11 14:16:25 -05:00
{
2014-10-19 15:12:20 +02:00
SendSetPlayerDeclinedNamesResult ( DECLINED_NAMES_RESULT_ERROR , 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
std :: wstring wname ;
2010-04-07 19:14:10 +02:00
if ( ! Utf8toWStr ( name , wname ))
2008-10-11 14:16:25 -05:00
{
2014-10-19 15:12:20 +02:00
SendSetPlayerDeclinedNamesResult ( DECLINED_NAMES_RESULT_ERROR , guid );
2008-10-11 14:16:25 -05:00
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
{
2014-10-19 15:12:20 +02:00
SendSetPlayerDeclinedNamesResult ( DECLINED_NAMES_RESULT_ERROR , 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
std :: string name2 ;
DeclinedName declinedname ;
2009-10-17 15:51:44 -07:00
2012-08-05 19:40:30 -05: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
{
2014-10-19 15:12:20 +02:00
SendSetPlayerDeclinedNamesResult ( DECLINED_NAMES_RESULT_ERROR , guid );
2008-10-11 14:16:25 -05:00
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-08-05 19:40:30 -05: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
{
2014-10-19 15:12:20 +02:00
SendSetPlayerDeclinedNamesResult ( DECLINED_NAMES_RESULT_ERROR , guid );
2008-10-11 14:16:25 -05:00
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
{
2014-10-19 15:12:20 +02:00
SendSetPlayerDeclinedNamesResult ( DECLINED_NAMES_RESULT_ERROR , guid );
2008-10-11 14:16:25 -05:00
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-05-30 08:01:02 +02:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_DECLINED_NAME );
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 0 , guid . GetCounter ());
2012-05-30 08:01:02 +02:00
trans -> Append ( stmt );
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_INS_CHAR_DECLINED_NAME );
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 0 , guid . GetCounter ());
2012-05-30 08:01:02 +02:00
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
2014-10-19 15:12:20 +02:00
SendSetPlayerDeclinedNamesResult ( DECLINED_NAMES_RESULT_SUCCESS , guid );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2012-08-09 18:46:59 -05:00
void WorldSession :: HandleAlterAppearance ( WorldPacket & recvData )
2008-12-24 09:58:26 -06:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "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-08-05 19:40:30 -05: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
2014-11-06 01:53:04 +02:00
if ( ! bs_hair || bs_hair -> Type != 0 || bs_hair -> Race != _player -> getRace () || bs_hair -> Sex != _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
2014-11-06 01:53:04 +02:00
if ( ! bs_facialHair || bs_facialHair -> Type != 2 || bs_facialHair -> Race != _player -> getRace () || bs_facialHair -> Sex != _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 );
2014-11-06 01:53:04 +02:00
if ( bs_skinColor && ( bs_skinColor -> Type != 3 || bs_skinColor -> Race != _player -> getRace () || bs_skinColor -> Sex != _player -> getGender ()))
2009-12-17 10:49:15 +01:00
return ;
2012-09-09 03:05:45 +01:00
GameObject * go = _player -> FindNearestGameObjectOfType ( GAMEOBJECT_TYPE_BARBER_CHAIR , 5.0f );
2012-09-08 23:16:14 +01:00
if ( ! go )
{
2014-10-19 15:12:20 +02:00
SendBarberShopResult ( BARBER_SHOP_RESULT_NOT_ON_CHAIR );
2012-09-08 23:16:14 +01:00
return ;
}
if ( _player -> getStandState () != UNIT_STAND_STATE_SIT_LOW_CHAIR + go -> GetGOInfo () -> barberChair . chairheight )
{
2014-10-19 15:12:20 +02:00
SendBarberShopResult ( BARBER_SHOP_RESULT_NOT_ON_CHAIR );
2012-09-08 23:16:14 +01:00
return ;
}
2014-11-06 01:53:04 +02:00
uint32 cost = _player -> GetBarberShopCost ( bs_hair -> Data , Color , bs_facialHair -> Data , 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
2012-08-08 19:00:14 -05:00
// 2 - you have to sit on barber chair
2012-07-24 15:27:42 +01:00
if ( ! _player -> HasEnoughMoney (( uint64 ) cost ))
2008-12-24 09:58:26 -06:00
{
2014-10-19 15:12:20 +02:00
SendBarberShopResult ( BARBER_SHOP_RESULT_NO_MONEY );
2008-12-24 09:58:26 -06:00
return ;
}
2014-10-19 15:12:20 +02:00
SendBarberShopResult ( BARBER_SHOP_RESULT_SUCCESS );
2009-10-17 15:51:44 -07:00
2012-07-24 15:27:42 +01:00
_player -> ModifyMoney ( - int64 ( cost )); // it isn't free
_player -> UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER , cost );
2009-10-17 15:51:44 -07:00
2014-11-06 01:53:04 +02:00
_player -> SetByteValue ( PLAYER_BYTES , 2 , uint8 ( bs_hair -> Data ));
2008-12-24 09:58:26 -06:00
_player -> SetByteValue ( PLAYER_BYTES , 3 , uint8 ( Color ));
2014-11-06 01:53:04 +02:00
_player -> SetByteValue ( PLAYER_BYTES_2 , 0 , uint8 ( bs_facialHair -> Data ));
2009-12-17 10:49:15 +01:00
if ( bs_skinColor )
2014-11-06 01:53:04 +02:00
_player -> SetByteValue ( PLAYER_BYTES , 0 , uint8 ( bs_skinColor -> Data ));
2009-10-17 15:51:44 -07:00
2012-07-09 11:08:33 +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-08-05 19:40:30 -05: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
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "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
2014-11-12 03:58:17 +02:00
if ( uint32 glyph = _player -> GetGlyph ( _player -> GetActiveTalentGroup (), 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
{
2014-11-08 20:21:17 +02:00
_player -> RemoveAurasDueToSpell ( gp -> SpellID );
2009-03-21 14:54:21 -06:00
_player -> SetGlyph ( slot , 0 );
2014-11-12 03:58:17 +02:00
_player -> SendTalentsInfoData ();
2009-03-21 14:54:21 -06:00
}
}
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2014-11-12 16:36:05 +01:00
void WorldSession :: HandleCharCustomizeOpcode ( WorldPackets :: Character :: CharCustomize & packet )
2008-12-24 09:58:26 -06:00
{
2014-11-12 16:36:05 +01:00
if ( ! IsLegitCharacterForAccount ( packet . CustomizeInfo -> CharGUID ))
2013-02-14 16:07:36 +01:00
{
2014-09-14 16:14:12 +02:00
TC_LOG_ERROR ( "network" , "Account %u, IP: %s tried to customise %s, but it does not belong to their account!" ,
2014-11-12 16:36:05 +01:00
GetAccountId (), GetRemoteAddress (). c_str (), packet . CustomizeInfo -> CharGUID . ToString (). c_str ());
2013-02-14 16:07:36 +01:00
KickPlayer ();
2013-02-14 16:12:58 +01:00
return ;
2013-02-14 16:07:36 +01:00
}
2014-11-12 16:36:05 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHAR_CUSTOMIZE_INFO );
stmt -> setUInt64 ( 0 , packet . CustomizeInfo -> CharGUID . GetCounter ());
2009-10-17 15:51:44 -07:00
2014-11-12 16:36:05 +01:00
_charCustomizeCallback . SetParam ( packet . CustomizeInfo );
_charCustomizeCallback . SetFutureResult ( CharacterDatabase . AsyncQuery ( stmt ));
}
void WorldSession :: HandleCharCustomizeCallback ( PreparedQueryResult result , WorldPackets :: Character :: CharCustomizeInfo * customizeInfo )
{
ASSERT ( _charCustomizeCallback . GetParam (). get () == customizeInfo );
2012-05-30 08:01:02 +02:00
2008-12-24 09:58:26 -06:00
if ( ! result )
{
2014-10-19 15:12:20 +02:00
SendCharCustomize ( CHAR_CREATE_ERROR , customizeInfo );
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 ();
2009-10-17 15:51:44 -07:00
2014-11-12 16:36:05 +01:00
std :: string oldName = fields [ 0 ]. GetString ();
uint16 atLoginFlags = fields [ 1 ]. GetUInt16 ();
uint32 playerBytes2 = fields [ 2 ]. GetUInt32 ();
if ( ! ( atLoginFlags & AT_LOGIN_CUSTOMIZE ))
2008-12-24 09:58:26 -06:00
{
2014-10-19 15:12:20 +02:00
SendCharCustomize ( CHAR_CREATE_ERROR , customizeInfo );
2008-12-24 09:58:26 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-11-12 16:36:05 +01:00
atLoginFlags &= ~ AT_LOGIN_CUSTOMIZE ;
2008-12-24 09:58:26 -06:00
// prevent character rename to invalid name
2014-11-12 16:36:05 +01:00
if ( ! normalizePlayerName ( customizeInfo -> CharName ))
2008-12-24 09:58:26 -06:00
{
2014-10-19 15:12:20 +02:00
SendCharCustomize ( CHAR_NAME_NO_NAME , customizeInfo );
2008-12-24 09:58:26 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-11-12 16:36:05 +01:00
ResponseCodes res = ObjectMgr :: CheckPlayerName ( customizeInfo -> CharName , true );
2009-07-10 08:25:33 +08:00
if ( res != CHAR_NAME_SUCCESS )
2008-12-24 09:58:26 -06:00
{
2014-10-19 15:12:20 +02:00
SendCharCustomize ( res , customizeInfo );
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
2014-11-12 16:36:05 +01:00
if ( ! HasPermission ( rbac :: RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME ) && sObjectMgr -> IsReservedName ( customizeInfo -> CharName ))
2008-12-24 09:58:26 -06:00
{
2014-10-19 15:12:20 +02:00
SendCharCustomize ( CHAR_NAME_RESERVED , customizeInfo );
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
2014-11-12 16:36:05 +01:00
/// @todo: make async
2014-11-12 19:16:14 +01:00
ObjectGuid newGuid = ObjectMgr :: GetPlayerGUIDByName ( customizeInfo -> CharName );
2014-10-21 20:27:00 +02:00
if ( ! newGuid . IsEmpty ())
2008-12-24 09:58:26 -06:00
{
2014-11-12 16:36:05 +01:00
if ( newGuid != customizeInfo -> CharGUID )
2009-02-22 17:26:03 -06:00
{
2014-10-19 15:12:20 +02:00
SendCharCustomize ( CHAR_CREATE_NAME_IN_USE , customizeInfo );
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
2014-11-12 16:36:05 +01:00
PreparedStatement * stmt = nullptr ;
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
ObjectGuid :: LowType lowGuid = customizeInfo -> CharGUID . GetCounter ();
2012-05-30 08:01:02 +02:00
2014-11-12 16:36:05 +01:00
/// Customize
2009-08-16 16:32:11 -05:00
{
2014-11-12 16:36:05 +01:00
playerBytes2 &= ~ 0xFF ;
playerBytes2 |= customizeInfo -> FacialHairStyleID ;
2012-05-30 08:01:02 +02:00
2014-11-12 16:36:05 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_GENDER_PLAYERBYTES );
2009-10-17 15:51:44 -07:00
2014-11-12 16:36:05 +01:00
stmt -> setUInt8 ( 0 , customizeInfo -> SexID );
stmt -> setUInt32 ( 1 , customizeInfo -> SkinID | ( uint32 ( customizeInfo -> FaceID ) << 8 ) | ( uint32 ( customizeInfo -> HairStyleID ) << 16 ) | ( uint32 ( customizeInfo -> HairColorID ) << 24 ));
stmt -> setUInt32 ( 2 , playerBytes2 );
stmt -> setUInt64 ( 3 , lowGuid );
2011-12-31 00:32:05 +01:00
2014-11-12 16:36:05 +01:00
trans -> Append ( stmt );
}
2011-12-31 00:32:05 +01:00
2014-11-12 16:36:05 +01:00
/// Name Change and update atLogin flags
{
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_NAME_AT_LOGIN );
stmt -> setString ( 0 , customizeInfo -> CharName );
stmt -> setUInt16 ( 1 , atLoginFlags );
stmt -> setUInt64 ( 2 , lowGuid );
2011-12-31 00:32:05 +01:00
2014-11-12 16:36:05 +01:00
trans -> Append ( stmt );
2011-12-31 00:32:05 +01:00
2014-11-12 16:36:05 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_DECLINED_NAME );
stmt -> setUInt64 ( 0 , lowGuid );
trans -> Append ( stmt );
}
2011-12-31 00:32:05 +01:00
2014-10-19 15:12:20 +02:00
CharacterDatabase . CommitTransaction ( trans );
2011-12-31 00:32:05 +01:00
2014-11-12 19:16:14 +01:00
sWorld -> UpdateCharacterInfo ( customizeInfo -> CharGUID , customizeInfo -> CharName , customizeInfo -> SexID );
2014-10-19 15:12:20 +02:00
SendCharCustomize ( RESPONSE_SUCCESS , customizeInfo );
2014-11-12 16:36:05 +01:00
TC_LOG_INFO ( "entities.player.character" , "Account: %u (IP: %s), Character[%s] (%s) Customized to: %s" ,
GetAccountId (), GetRemoteAddress (). c_str (), oldName . c_str (), customizeInfo -> CharGUID . ToString (). c_str (), customizeInfo -> CharName . c_str ());
2009-02-18 22:39:00 +01:00
}
2009-10-17 15:51:44 -07:00
2014-11-19 21:09:30 +01:00
void WorldSession :: HandleEquipmentSetSave ( WorldPackets :: EquipmentSet :: SaveEquipmentSet & packet )
2009-06-11 00:45:59 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "CMSG_EQUIPMENT_SET_SAVE" );
2009-10-17 15:51:44 -07:00
2014-11-19 21:09:30 +01:00
if ( packet . Set . SetID >= 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
2014-11-19 21:09:30 +01:00
for ( uint8 i = 0 ; i < EQUIPMENT_SLOT_END ; ++ i )
2009-06-11 00:45:59 -05:00
{
2014-11-19 21:09:30 +01:00
if ( ! ( packet . Set . IgnoreMask & ( 1 << i )))
2012-07-13 15:16:37 +02:00
{
2014-11-19 21:09:30 +01:00
ObjectGuid const & itemGuid = packet . Set . Pieces [ i ];
2009-10-17 15:51:44 -07:00
2014-11-19 21:09:30 +01:00
Item * item = _player -> GetItemByPos ( INVENTORY_SLOT_BAG_0 , i );
2009-10-17 15:51:44 -07:00
2014-11-19 21:09:30 +01:00
/// cheating check 1 (item equipped but sent empty guid)
if ( ! item && ! itemGuid . IsEmpty ())
return ;
2009-10-17 15:51:44 -07:00
2014-11-19 21:09:30 +01:00
/// cheating check 2 (sent guid does not match equipped item)
if ( item && item -> GetGUID () != itemGuid )
return ;
}
else
packet . Set . Pieces [ i ]. Clear ();
2009-06-11 00:45:59 -05:00
}
2009-10-17 15:51:44 -07:00
2014-11-19 21:09:30 +01:00
packet . Set . IgnoreMask &= 0x7FFFF ; /// clear invalid bits (i > EQUIPMENT_SLOT_END)
_player -> SetEquipmentSet ( std :: move ( packet . Set ));
2009-06-11 00:45:59 -05:00
}
2009-10-17 15:51:44 -07:00
2014-10-19 15:12:20 +02:00
void WorldSession :: HandleEquipmentSetDelete ( WorldPacket & recvData )
2009-06-11 00:45:59 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "CMSG_EQUIPMENT_SET_DELETE" );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint64 setGuid ;
2014-10-23 17:01:26 +02:00
recvData . ReadPackedUInt64 ( 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-08-08 19:00:14 -05:00
void WorldSession :: HandleEquipmentSetUse ( WorldPacket & recvData )
2009-06-11 00:45:59 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "CMSG_EQUIPMENT_SET_USE" );
2009-10-17 15:51:44 -07:00
2014-10-25 17:11:35 +02:00
ObjectGuid ignoredItemGuid ;
ignoredItemGuid . SetRawValue ( 0 , 1 );
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
{
2014-09-14 16:14:12 +02:00
ObjectGuid itemGuid ;
recvData >> itemGuid . ReadAsPacked ();
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint8 srcbag , srcslot ;
2012-08-05 19:40:30 -05:00
recvData >> srcbag >> srcslot ;
2009-10-17 15:51:44 -07:00
2014-09-14 16:14:12 +02:00
TC_LOG_DEBUG ( "entities.player.items" , "%s: srcbag %u, srcslot %u" , itemGuid . ToString (). c_str (), 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
2014-10-25 17:11:35 +02:00
if ( itemGuid == ignoredItemGuid )
2012-07-13 15:16:37 +02:00
continue ;
2014-01-18 12:58:01 +01:00
// Only equip weapons in combat
if ( _player -> IsInCombat () && i != EQUIPMENT_SLOT_MAINHAND && i != EQUIPMENT_SLOT_OFFHAND && i != EQUIPMENT_SLOT_RANGED )
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
2014-11-12 16:36:05 +01:00
void WorldSession :: HandleCharRaceOrFactionChangeOpcode ( WorldPackets :: Character :: CharRaceOrFactionChange & packet )
2010-09-05 13:12:24 -07:00
{
2014-11-12 16:36:05 +01:00
if ( ! IsLegitCharacterForAccount ( packet . RaceOrFactionChangeInfo -> Guid ))
2013-02-14 16:07:36 +01:00
{
2014-09-14 16:14:12 +02:00
TC_LOG_ERROR ( "network" , "Account %u, IP: %s tried to factionchange character %s, but it does not belong to their account!" ,
2014-11-12 16:36:05 +01:00
GetAccountId (), GetRemoteAddress (). c_str (), packet . RaceOrFactionChangeInfo -> Guid . ToString (). c_str ());
2013-02-14 16:07:36 +01:00
KickPlayer ();
2013-02-14 16:12:58 +01:00
return ;
2013-02-14 16:07:36 +01:00
}
2014-11-12 16:36:05 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS );
stmt -> setUInt64 ( 0 , packet . RaceOrFactionChangeInfo -> Guid . GetCounter ());
_charFactionChangeCallback . SetParam ( packet . RaceOrFactionChangeInfo );
_charFactionChangeCallback . SetFutureResult ( CharacterDatabase . AsyncQuery ( stmt ));
}
2010-09-05 13:12:24 -07:00
2014-11-12 16:36:05 +01:00
void WorldSession :: HandleCharRaceOrFactionChangeCallback ( PreparedQueryResult result , WorldPackets :: Character :: CharRaceOrFactionChangeInfo * factionChangeInfo )
{
ASSERT ( _charFactionChangeCallback . GetParam (). get () == factionChangeInfo );
if ( ! result )
{
SendCharFactionChange ( CHAR_CREATE_ERROR , factionChangeInfo );
return ;
}
2012-05-30 08:01:02 +02:00
2012-10-07 13:55:04 +01:00
// get the players old (at this moment current) race
2014-11-12 19:16:14 +01:00
CharacterInfo const * characterInfo = sWorld -> GetCharacterInfo ( factionChangeInfo -> Guid );
if ( ! characterInfo )
2013-02-14 15:43:26 +01:00
{
2014-10-19 15:12:20 +02:00
SendCharFactionChange ( CHAR_CREATE_ERROR , factionChangeInfo );
2013-02-14 15:43:26 +01:00
return ;
}
2014-11-12 19:16:14 +01:00
uint8 oldRace = characterInfo -> Race ;
uint8 playerClass = characterInfo -> Class ;
uint8 level = characterInfo -> Level ;
2012-05-30 08:01:02 +02:00
2014-11-12 16:36:05 +01:00
if ( ! sObjectMgr -> GetPlayerInfo ( factionChangeInfo -> RaceID , playerClass ))
2010-09-05 13:12:24 -07:00
{
2014-10-19 15:12:20 +02:00
SendCharFactionChange ( CHAR_CREATE_ERROR , factionChangeInfo );
2010-09-05 13:12:24 -07:00
return ;
}
2014-11-12 16:36:05 +01:00
Field * fields = result -> Fetch ();
uint16 atLoginFlags = fields [ 0 ]. GetUInt16 ();
2014-10-19 15:12:20 +02:00
std :: string knownTitlesStr = fields [ 1 ]. GetString ();
2014-11-12 16:36:05 +01:00
uint32 playerBytes = fields [ 2 ]. GetUInt32 ();
uint32 playerBytes2 = fields [ 3 ]. GetUInt32 ();
2010-09-05 13:12:24 -07:00
2014-11-12 16:36:05 +01:00
uint16 usedLoginFlag = ( factionChangeInfo -> FactionChange ? AT_LOGIN_CHANGE_FACTION : AT_LOGIN_CHANGE_RACE );
if ( ! ( atLoginFlags & usedLoginFlag ))
2010-09-05 13:12:24 -07:00
{
2014-10-19 15:12:20 +02:00
SendCharFactionChange ( CHAR_CREATE_ERROR , factionChangeInfo );
2010-09-05 13:12:24 -07:00
return ;
}
2014-11-12 16:36:05 +01:00
TeamId newTeamId = Player :: TeamIdForRace ( factionChangeInfo -> RaceID );
if ( newTeamId == TEAM_NEUTRAL )
2010-09-05 13:12:24 -07:00
{
2014-11-12 16:36:05 +01:00
SendCharFactionChange ( CHAR_CREATE_RESTRICTED_RACECLASS , factionChangeInfo );
return ;
}
if ( factionChangeInfo -> FactionChange == ( Player :: TeamIdForRace ( oldRace ) != newTeamId ))
{
SendCharFactionChange ( factionChangeInfo -> FactionChange ? CHAR_CREATE_CHARACTER_SWAP_FACTION : CHAR_CREATE_CHARACTER_RACE_ONLY , factionChangeInfo );
2010-09-05 13:12:24 -07:00
return ;
}
2010-09-12 01:40:27 +02:00
2013-09-27 12:46:01 +02:00
if ( ! HasPermission ( rbac :: 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 );
2014-11-12 16:36:05 +01:00
if (( 1 << ( factionChangeInfo -> RaceID - 1 )) & raceMaskDisabled )
2010-09-06 10:42:53 -07:00
{
2014-10-19 15:12:20 +02:00
SendCharFactionChange ( CHAR_CREATE_ERROR , factionChangeInfo );
2010-09-06 10:42:53 -07:00
return ;
}
}
2010-09-05 13:12:24 -07:00
// prevent character rename to invalid name
2014-11-12 16:36:05 +01:00
if ( ! normalizePlayerName ( factionChangeInfo -> Name ))
2010-09-05 13:12:24 -07:00
{
2014-10-19 15:12:20 +02:00
SendCharFactionChange ( CHAR_NAME_NO_NAME , factionChangeInfo );
2010-09-05 13:12:24 -07:00
return ;
}
2014-11-12 16:36:05 +01:00
ResponseCodes res = ObjectMgr :: CheckPlayerName ( factionChangeInfo -> Name , true );
2010-09-05 13:12:24 -07:00
if ( res != CHAR_NAME_SUCCESS )
{
2014-10-19 15:12:20 +02:00
SendCharFactionChange ( res , factionChangeInfo );
2010-09-05 13:12:24 -07:00
return ;
}
// check name limitations
2014-11-12 16:36:05 +01:00
if ( ! HasPermission ( rbac :: RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME ) && sObjectMgr -> IsReservedName ( factionChangeInfo -> Name ))
2010-09-05 13:12:24 -07:00
{
2014-10-19 15:12:20 +02:00
SendCharFactionChange ( CHAR_NAME_RESERVED , factionChangeInfo );
2010-09-05 13:12:24 -07:00
return ;
}
// character with this name already exist
2014-11-12 19:16:14 +01:00
ObjectGuid newGuid = ObjectMgr :: GetPlayerGUIDByName ( factionChangeInfo -> Name );
2014-10-21 20:27:00 +02:00
if ( ! newGuid . IsEmpty ())
2010-09-05 13:12:24 -07:00
{
2014-11-12 16:36:05 +01:00
if ( newGuid != factionChangeInfo -> Guid )
2010-09-05 13:12:24 -07:00
{
2014-10-19 15:12:20 +02:00
SendCharFactionChange ( CHAR_CREATE_NAME_IN_USE , factionChangeInfo );
2010-09-05 13:12:24 -07:00
return ;
}
}
2014-11-12 16:36:05 +01:00
if ( sArenaTeamMgr -> GetArenaTeamByCaptain ( factionChangeInfo -> Guid ))
{
SendCharFactionChange ( CHAR_CREATE_CHARACTER_ARENA_LEADER , factionChangeInfo );
return ;
}
/// All checks are fine, deal with race change now
ObjectGuid :: LowType lowGuid = factionChangeInfo -> Guid . GetCounter ();
2014-04-20 14:58:24 +02:00
// resurrect the character in case he's dead
2014-11-12 16:36:05 +01:00
sObjectAccessor -> ConvertCorpseForPlayer ( factionChangeInfo -> Guid );
2014-04-20 14:58:24 +02:00
2014-11-12 16:36:05 +01:00
PreparedStatement * stmt = nullptr ;
2010-09-05 13:12:24 -07:00
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
2012-05-30 08:01:02 +02:00
2014-11-12 16:36:05 +01:00
/// Name Change and update atLogin flags
{
CharacterDatabase . EscapeString ( factionChangeInfo -> Name );
2014-10-19 15:12:20 +02:00
2014-11-12 16:36:05 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_NAME_AT_LOGIN );
stmt -> setString ( 0 , factionChangeInfo -> Name );
stmt -> setUInt16 ( 1 , uint16 ( atLoginFlags & ~ usedLoginFlag ));
stmt -> setUInt64 ( 2 , lowGuid );
2012-05-30 08:01:02 +02:00
2014-11-12 16:36:05 +01:00
trans -> Append ( stmt );
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_DECLINED_NAME );
stmt -> setUInt64 ( 0 , lowGuid );
2012-05-30 08:01:02 +02:00
2014-11-12 16:36:05 +01:00
trans -> Append ( stmt );
}
2010-09-05 13:12:24 -07:00
2014-11-12 16:36:05 +01:00
/// Customize
2010-09-05 13:12:24 -07:00
{
2014-11-12 16:36:05 +01:00
if ( factionChangeInfo -> SkinID . HasValue )
{
playerBytes &= ~ uint32 ( 0xFF );
2014-11-20 01:17:45 +01:00
playerBytes |= factionChangeInfo -> SkinID . Value ;
2014-11-12 16:36:05 +01:00
}
else
factionChangeInfo -> SkinID . Set ( uint8 ( playerBytes & 0xFF ));
2012-05-30 08:01:02 +02:00
2014-11-12 16:36:05 +01:00
if ( factionChangeInfo -> FaceID . HasValue )
2010-09-05 13:12:24 -07:00
{
2014-11-12 16:36:05 +01:00
playerBytes &= ~ ( uint32 ( 0xFF ) << 8 );
2014-11-20 01:17:45 +01:00
playerBytes |= uint32 ( factionChangeInfo -> FaceID . Value ) << 8 ;
2010-09-05 13:12:24 -07:00
}
2014-11-12 16:36:05 +01:00
else
factionChangeInfo -> FaceID . Set ( uint8 (( playerBytes2 >> 8 ) & 0xFF ));
2012-05-30 08:01:02 +02:00
2014-11-12 16:36:05 +01:00
if ( factionChangeInfo -> HairStyleID . HasValue )
{
playerBytes &= ~ ( uint32 ( 0xFF ) << 16 );
2014-11-20 01:17:45 +01:00
playerBytes |= uint32 ( factionChangeInfo -> HairStyleID . Value ) << 16 ;
2014-11-12 16:36:05 +01:00
}
else
factionChangeInfo -> HairStyleID . Set ( uint8 (( playerBytes2 >> 16 ) & 0xFF ));
if ( factionChangeInfo -> HairColorID . HasValue )
{
playerBytes &= ~ ( uint32 ( 0xFF ) << 24 );
2014-11-20 01:17:45 +01:00
playerBytes |= uint32 ( factionChangeInfo -> HairColorID . Value ) << 24 ;
2014-11-12 16:36:05 +01:00
}
else
factionChangeInfo -> HairColorID . Set ( uint8 (( playerBytes2 >> 24 ) & 0xFF ));
if ( factionChangeInfo -> FacialHairStyleID . HasValue )
{
playerBytes2 &= ~ 0xFF ;
2014-11-20 01:17:45 +01:00
playerBytes2 |= factionChangeInfo -> FacialHairStyleID . Value ;
2014-11-12 16:36:05 +01:00
}
else
factionChangeInfo -> FacialHairStyleID . Set ( uint8 ( playerBytes2 & 0xFF ));
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_GENDER_PLAYERBYTES );
stmt -> setUInt8 ( 0 , factionChangeInfo -> SexID );
stmt -> setUInt32 ( 1 , playerBytes );
stmt -> setUInt32 ( 2 , playerBytes2 );
stmt -> setUInt64 ( 3 , lowGuid );
trans -> Append ( stmt );
}
/// Race Change
{
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_RACE );
stmt -> setUInt8 ( 0 , factionChangeInfo -> RaceID );
stmt -> setUInt64 ( 1 , lowGuid );
trans -> Append ( stmt );
}
2014-11-12 19:16:14 +01:00
sWorld -> UpdateCharacterInfo ( factionChangeInfo -> Guid , factionChangeInfo -> Name , factionChangeInfo -> SexID , factionChangeInfo -> RaceID );
2014-11-12 16:36:05 +01:00
if ( oldRace != factionChangeInfo -> RaceID )
{
2012-10-29 12:28:12 +01:00
// Switch Languages
// delete all languages first
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_SKILL_LANGUAGES );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2012-05-30 08:01:02 +02:00
trans -> Append ( stmt );
2010-09-05 13:12:24 -07:00
2012-10-29 12:28:12 +01:00
// Now add them back
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_INS_CHAR_SKILL_LANGUAGE );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2012-10-29 12:28:12 +01:00
// Faction specific languages
2014-11-12 16:36:05 +01:00
if ( newTeamId == TEAM_HORDE )
2012-10-29 12:28:12 +01:00
stmt -> setUInt16 ( 1 , 109 );
else
stmt -> setUInt16 ( 1 , 98 );
2012-05-30 08:01:02 +02:00
trans -> Append ( stmt );
2010-09-05 13:12:24 -07:00
2012-10-29 12:28:12 +01:00
// Race specific languages
2014-11-12 16:36:05 +01:00
if ( factionChangeInfo -> RaceID != RACE_ORC && factionChangeInfo -> RaceID != 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 );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2012-10-29 12:28:12 +01:00
2014-11-12 16:36:05 +01:00
switch ( factionChangeInfo -> RaceID )
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 ;
2012-11-02 00:18:44 +01:00
case RACE_WORGEN :
stmt -> setUInt16 ( 1 , 791 );
break ;
2012-10-29 12:28:12 +01:00
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 ;
2012-11-02 00:18:44 +01:00
case RACE_GOBLIN :
stmt -> setUInt16 ( 1 , 792 );
break ;
2010-09-05 13:12:24 -07:00
}
2012-05-30 08:01:02 +02:00
trans -> Append ( stmt );
2010-09-05 13:12:24 -07:00
}
2014-11-12 16:36:05 +01:00
/// Team Conversation
if ( factionChangeInfo -> FactionChange )
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 );
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2012-10-29 12:28:12 +01:00
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 ;
2014-11-12 16:36:05 +01:00
if ( newTeamId == 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
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 ] | 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' ;
2010-09-05 13:12:24 -07:00
2012-12-19 12:55:51 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_TAXIMASK );
2014-11-12 16:36:05 +01:00
stmt -> setString ( 0 , taximaskstream . str ());
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 1 , lowGuid );
2012-10-29 12:28:12 +01:00
trans -> Append ( stmt );
}
2010-09-05 13:12:24 -07:00
2014-11-12 16:36:05 +01:00
/// @todo: make this part asynch
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 );
2014-10-25 15:04:38 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2010-09-05 13:12:24 -07:00
2014-11-12 16:36:05 +01:00
if ( PreparedQueryResult result = CharacterDatabase . Query ( stmt ))
if ( Guild * guild = sGuildMgr -> GetGuildById ( result -> Fetch ()[ 0 ]. GetUInt64 ()))
guild -> DeleteMember ( factionChangeInfo -> Guid , false , false , true );
2014-01-17 08:17:09 +01:00
2014-11-12 16:36:05 +01:00
Player :: LeaveAllArenaTeams ( factionChangeInfo -> Guid );
2012-10-29 12:28:12 +01:00
}
2010-09-05 13:12:24 -07:00
2013-09-27 12:46:01 +02:00
if ( ! HasPermission ( rbac :: 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 );
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2012-10-29 12:28:12 +01:00
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 );
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2012-10-29 12:28:12 +01:00
trans -> Append ( stmt );
}
2012-05-30 08:01:02 +02:00
2012-10-29 12:28:12 +01:00
// Reset homebind and position
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_PLAYER_HOMEBIND );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2012-05-30 08:01:02 +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 );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2014-10-19 15:12:20 +02:00
WorldLocation loc ;
uint16 zoneId = 0 ;
2014-11-12 16:36:05 +01:00
if ( newTeamId == TEAM_ALLIANCE )
2012-10-29 12:28:12 +01:00
{
2014-10-19 15:12:20 +02:00
loc . WorldRelocate ( 0 , - 8867.68f , 673.373f , 97.9034f , 0.0f );
zoneId = 1519 ;
2012-10-29 12:28:12 +01:00
}
else
{
2014-10-19 15:12:20 +02:00
loc . WorldRelocate ( 1 , 1633.33f , - 4439.11f , 15.7588f , 0.0f );
zoneId = 1637 ;
2012-10-29 12:28:12 +01:00
}
2014-10-19 15:12:20 +02:00
stmt -> setUInt16 ( 1 , loc . GetMapId ());
stmt -> setUInt16 ( 2 , zoneId );
stmt -> setFloat ( 3 , loc . GetPositionX ());
stmt -> setFloat ( 4 , loc . GetPositionY ());
stmt -> setFloat ( 5 , loc . GetPositionZ ());
2012-05-30 08:01:02 +02:00
trans -> Append ( stmt );
2010-09-05 13:12:24 -07:00
2014-11-12 16:36:05 +01:00
Player :: SavePositionInDB ( loc , zoneId , factionChangeInfo -> Guid , trans );
2014-10-19 15:12:20 +02: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-05-30 08:01:02 +02:00
2012-12-19 12:55:51 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT );
2014-11-12 16:36:05 +01:00
stmt -> setUInt16 ( 0 , uint16 ( newTeamId == TEAM_ALLIANCE ? achiev_alliance : achiev_horde ));
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 1 , lowGuid );
2012-10-29 12:28:12 +01:00
trans -> Append ( stmt );
2012-05-30 08:01:02 +02:00
2012-10-29 12:28:12 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_ACHIEVEMENT );
2014-11-12 16:36:05 +01:00
stmt -> setUInt16 ( 0 , uint16 ( newTeamId == TEAM_ALLIANCE ? achiev_alliance : achiev_horde ));
stmt -> setUInt16 ( 1 , uint16 ( newTeamId == TEAM_ALLIANCE ? achiev_horde : achiev_alliance ));
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 2 , lowGuid );
2012-10-29 12:28:12 +01:00
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 );
2014-11-12 16:36:05 +01:00
stmt -> setUInt32 ( 0 , ( newTeamId == TEAM_ALLIANCE ? item_alliance : item_horde ));
stmt -> setUInt32 ( 1 , ( newTeamId == TEAM_ALLIANCE ? item_horde : item_alliance ));
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 2 , lowGuid );
2012-10-29 12:28:12 +01:00
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 );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2013-03-04 14:15:52 +01:00
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 );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2014-11-12 16:36:05 +01:00
stmt -> setUInt32 ( 1 , ( newTeamId == TEAM_ALLIANCE ? quest_alliance : quest_horde ));
2013-03-04 14:15:52 +01:00
trans -> Append ( stmt );
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_FACTION_CHANGE );
2014-11-12 16:36:05 +01:00
stmt -> setUInt32 ( 0 , ( newTeamId == TEAM_ALLIANCE ? quest_alliance : quest_horde ));
stmt -> setUInt32 ( 1 , ( newTeamId == TEAM_ALLIANCE ? quest_horde : quest_alliance ));
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 2 , lowGuid );
2013-03-04 14:15:52 +01:00
trans -> Append ( stmt );
}
// Mark all rewarded quests as "active" (will count for completed quests achievements)
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2013-03-04 14:15:52 +01:00
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 ;
2014-11-12 16:36:05 +01:00
uint32 newRaceMask = ( newTeamId == TEAM_ALLIANCE ) ? RACEMASK_ALLIANCE : RACEMASK_HORDE ;
if ( quest -> GetRequiredRaces () && ! ( quest -> GetRequiredRaces () & newRaceMask ))
2013-03-04 14:15:52 +01:00
{
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2013-03-04 14:15:52 +01:00
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-05-30 08:01:02 +02:00
2012-12-19 12:55:51 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_SPELL_BY_SPELL );
2014-11-12 16:36:05 +01:00
stmt -> setUInt32 ( 0 , ( newTeamId == TEAM_ALLIANCE ? spell_alliance : spell_horde ));
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 1 , lowGuid );
2012-10-29 12:28:12 +01:00
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 );
2014-11-12 16:36:05 +01:00
stmt -> setUInt32 ( 0 , ( newTeamId == TEAM_ALLIANCE ? spell_alliance : spell_horde ));
stmt -> setUInt32 ( 1 , ( newTeamId == TEAM_ALLIANCE ? spell_horde : spell_alliance ));
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 2 , lowGuid );
2012-10-29 12:28:12 +01:00
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 ;
2014-11-12 16:36:05 +01:00
uint32 newReputation = ( newTeamId == TEAM_ALLIANCE ) ? reputation_alliance : reputation_horde ;
uint32 oldReputation = ( newTeamId == TEAM_ALLIANCE ) ? reputation_horde : reputation_alliance ;
2012-10-29 12:28:12 +01:00
// 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 );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 1 , lowGuid );
2012-10-07 13:55:04 +01:00
2014-10-19 15:12:20 +02:00
if ( PreparedQueryResult result = CharacterDatabase . Query ( stmt ))
2012-10-29 12:28:12 +01:00
{
2014-10-19 15:12:20 +02:00
Field * fields = result -> Fetch ();
int32 oldDBRep = fields [ 0 ]. GetInt32 ();
FactionEntry const * factionEntry = sFactionStore . LookupEntry ( oldReputation );
2012-05-30 08:01:02 +02:00
2014-10-19 15:12:20 +02:00
// old base reputation
int32 oldBaseRep = sObjectMgr -> GetBaseReputationOf ( factionEntry , oldRace , playerClass );
2012-09-27 22:38:19 +01:00
2014-10-19 15:12:20 +02:00
// new base reputation
2014-11-12 16:36:05 +01:00
int32 newBaseRep = sObjectMgr -> GetBaseReputationOf ( sFactionStore . LookupEntry ( newReputation ), factionChangeInfo -> RaceID , playerClass );
2012-09-27 22:38:19 +01:00
2014-10-19 15:12:20 +02:00
// final reputation shouldnt change
int32 FinalRep = oldDBRep + oldBaseRep ;
int32 newDBRep = FinalRep - newBaseRep ;
2012-09-27 22:38:19 +01:00
2014-10-19 15:12:20 +02:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_CHAR_REP_BY_FACTION );
stmt -> setUInt32 ( 0 , newReputation );
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 1 , lowGuid );
2014-10-19 15:12:20 +02:00
trans -> Append ( stmt );
2012-10-29 12:28:12 +01:00
2014-10-19 15:12:20 +02:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_REP_FACTION_CHANGE );
stmt -> setUInt16 ( 0 , uint16 ( newReputation ));
stmt -> setInt32 ( 1 , newDBRep );
stmt -> setUInt16 ( 2 , uint16 ( oldReputation ));
2014-10-23 23:04:16 +02:00
stmt -> setUInt64 ( 3 , lowGuid );
2014-10-19 15:12:20 +02:00
trans -> Append ( stmt );
}
2012-10-29 12:28:12 +01:00
}
// Title conversion
2014-10-19 15:12:20 +02:00
if ( ! knownTitlesStr . empty ())
2012-09-27 22:38:19 +01:00
{
2014-11-12 16:36:05 +01:00
uint32 const ktcount = KNOWN_TITLES_SIZE * 2 ;
2012-10-29 12:28:12 +01:00
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 )
2014-10-19 15:12:20 +02:00
{
SendCharFactionChange ( CHAR_CREATE_ERROR , factionChangeInfo );
2012-10-29 12:28:12 +01:00
return ;
2014-10-19 15:12:20 +02:00
}
2012-10-29 12:28:12 +01:00
for ( uint32 index = 0 ; index < ktcount ; ++ index )
2014-11-26 02:03:30 +00:00
knownTitles [ index ] = atoul ( tokens [ index ]);
2012-10-29 12:28:12 +01:00
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
2014-11-12 16:36:05 +01:00
if ( newTeamId == TEAM_ALLIANCE )
2012-09-27 22:38:19 +01:00
{
2014-11-07 14:32:47 +02:00
uint32 maskID = htitleInfo -> MaskID ;
uint32 index = maskID / 32 ;
uint32 old_flag = 1 << ( maskID % 32 );
uint32 new_flag = 1 << ( atitleInfo -> MaskID % 32 );
2012-10-29 12:28:12 +01:00
if ( knownTitles [ index ] & old_flag )
{
knownTitles [ index ] &= ~ old_flag ;
// use index of the new title
2014-11-07 14:32:47 +02:00
knownTitles [ atitleInfo -> MaskID / 32 ] |= new_flag ;
2012-10-29 12:28:12 +01:00
}
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
{
2014-11-07 14:32:47 +02:00
uint32 maskID = atitleInfo -> MaskID ;
uint32 index = maskID / 32 ;
uint32 old_flag = 1 << ( maskID % 32 );
uint32 new_flag = 1 << ( htitleInfo -> MaskID % 32 );
2012-10-29 12:28:12 +01:00
if ( knownTitles [ index ] & old_flag )
{
knownTitles [ index ] &= ~ old_flag ;
// use index of the new title
2014-11-07 14:32:47 +02:00
knownTitles [ htitleInfo -> MaskID / 32 ] |= new_flag ;
2012-10-29 12:28:12 +01:00
}
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 );
2014-11-12 16:36:05 +01:00
stmt -> setString ( 0 , ss . str ());
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 1 , lowGuid );
2012-10-29 12:28:12 +01:00
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 );
2014-10-24 19:56:17 +02:00
stmt -> setUInt64 ( 0 , lowGuid );
2012-10-29 12:28:12 +01:00
trans -> Append ( stmt );
}
2012-09-27 22:38:19 +01:00
}
}
2010-09-05 13:12:24 -07:00
}
CharacterDatabase . CommitTransaction ( trans );
2014-11-12 16:36:05 +01:00
TC_LOG_DEBUG ( "entities.player" , "%s (IP: %s) changed race from %u to %u" , GetPlayerInfo (). c_str (), GetRemoteAddress (). c_str (), oldRace , factionChangeInfo -> RaceID );
2014-10-19 15:12:20 +02:00
SendCharFactionChange ( RESPONSE_SUCCESS , factionChangeInfo );
2010-09-05 13:12:24 -07:00
}
2011-11-28 23:06:50 -03:00
2014-11-08 02:55:45 +01:00
void WorldSession :: HandleRandomizeCharNameOpcode ( WorldPackets :: Character :: GenerateRandomCharacterName & packet )
2011-11-28 23:06:50 -03:00
{
2014-11-08 02:55:45 +01:00
if ( ! Player :: IsValidRace ( packet . Race ))
2011-11-28 23:06:50 -03:00
{
2014-11-08 02:55:45 +01:00
TC_LOG_ERROR ( "misc" , "Invalid race (%u) sent by accountId: %u" , packet . Race , GetAccountId ());
2011-11-28 23:06:50 -03:00
return ;
}
2014-11-08 02:55:45 +01:00
if ( ! Player :: IsValidGender ( packet . Sex ))
2011-11-28 23:06:50 -03:00
{
2014-11-08 02:55:45 +01:00
TC_LOG_ERROR ( "misc" , "Invalid gender (%u) sent by accountId: %u" , packet . Sex , GetAccountId ());
2011-11-28 23:06:50 -03:00
return ;
}
2014-11-08 02:55:45 +01:00
WorldPackets :: Character :: GenerateRandomCharacterNameResult result ;
result . Success = true ;
result . Name = GetRandomCharacterName ( packet . Race , packet . Sex );
SendPacket ( result . Write ());
2011-12-10 15:21:55 +01:00
}
2012-08-22 23:18:06 +02:00
2014-11-06 02:59:59 +01:00
void WorldSession :: HandleReorderCharacters ( WorldPackets :: Character :: ReorderCharacters & reorderChars )
2012-08-22 23:18:06 +02:00
{
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
2014-11-06 02:59:59 +01:00
for ( WorldPackets :: Character :: ReorderCharacters :: ReorderInfo const & reorderInfo : reorderChars . Entries )
{
2012-08-23 01:54:06 +02:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_CHAR_LIST_SLOT );
2014-11-06 02:59:59 +01:00
stmt -> setUInt8 ( 0 , reorderInfo . NewPosition );
stmt -> setUInt64 ( 1 , reorderInfo . PlayerGUID . GetCounter ());
stmt -> setUInt32 ( 2 , GetAccountId ());
2012-08-23 01:54:06 +02:00
trans -> Append ( stmt );
2012-08-22 23:18:06 +02:00
}
2012-08-23 01:54:06 +02:00
2012-08-22 23:18:06 +02:00
CharacterDatabase . CommitTransaction ( trans );
}
2012-09-18 01:30:00 +02:00
void WorldSession :: HandleOpeningCinematic ( WorldPacket & /*recvData*/ )
{
// Only players that has not yet gained any experience can use this
if ( _player -> GetUInt32Value ( PLAYER_XP ))
return ;
if ( ChrClassesEntry const * classEntry = sChrClassesStore . LookupEntry ( _player -> getClass ()))
{
2014-11-07 17:39:16 +02:00
if ( classEntry -> CinematicSequenceID )
_player -> SendCinematicStart ( classEntry -> CinematicSequenceID );
2012-09-18 01:30:00 +02:00
else if ( ChrRacesEntry const * raceEntry = sChrRacesStore . LookupEntry ( _player -> getRace ()))
2014-11-07 17:39:16 +02:00
_player -> SendCinematicStart ( raceEntry -> CinematicSequenceID );
2012-09-18 01:30:00 +02:00
}
}
2014-10-19 15:12:20 +02:00
2014-11-03 19:11:14 +01:00
void WorldSession :: HandleUndeleteCooldownStatusQuery ( WorldPacket & /*recvData*/ )
{
/// empty result to force wait
PreparedQueryResultPromise result ;
result . set_value ( PreparedQueryResult ( nullptr ));
_undeleteCooldownStatusCallback . SetFutureResult ( result . get_future ());
}
void WorldSession :: HandleUndeleteCooldownStatusCallback ( PreparedQueryResult result )
{
switch ( _undeleteCooldownStatusCallback . GetStage ())
{
case 0 :
{
PreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_LAST_CHAR_UNDELETE );
stmt -> setUInt32 ( 0 , GetBattlenetAccountId ());
_undeleteCooldownStatusCallback . FreeResult ();
_undeleteCooldownStatusCallback . SetFutureResult ( LoginDatabase . AsyncQuery ( stmt ));
_undeleteCooldownStatusCallback . NextStage ();
break ;
}
case 1 :
{
uint32 cooldown = 0 ;
uint32 maxCooldown = sWorld -> getIntConfig ( CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN );
if ( result )
{
uint32 lastUndelete = result -> Fetch ()[ 0 ]. GetUInt32 ();
if ( lastUndelete )
cooldown = uint32 ( std :: max < int32 > ( 0 , int32 ( lastUndelete ) + maxCooldown - time ( nullptr )));
}
SendUndeleteCooldownStatusResponse ( cooldown , maxCooldown );
_undeleteCooldownStatusCallback . Reset ();
break ;
}
}
}
void WorldSession :: HandleCharUndeleteOpcode ( WorldPackets :: Character :: UndeleteCharacter & undeleteInfo )
{
if ( ! sWorld -> getBoolConfig ( CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED ))
{
SendUndeleteCharacterResponse ( CHARACTER_UNDELETE_RESULT_ERROR_DISABLED , undeleteInfo . UndeleteInfo . get ());
return ;
}
PreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_LAST_CHAR_UNDELETE );
stmt -> setUInt32 ( 0 , GetBattlenetAccountId ());
_charUndeleteCallback . SetParam ( undeleteInfo . UndeleteInfo );
_charUndeleteCallback . SetFutureResult ( LoginDatabase . AsyncQuery ( stmt ));
_charUndeleteCallback . NextStage ();
}
void WorldSession :: HandleCharUndeleteCallback ( PreparedQueryResult result , WorldPackets :: Character :: CharacterUndeleteInfo * undeleteInfo )
{
/** 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.
* It also prevents data synchronisation errors.
*/
ASSERT ( _charUndeleteCallback . GetParam (). get () == undeleteInfo );
switch ( _charUndeleteCallback . GetStage ())
{
case 1 :
{
if ( result )
{
uint32 lastUndelete = result -> Fetch ()[ 0 ]. GetUInt32 ();
uint32 maxCooldown = sWorld -> getIntConfig ( CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN );
if ( lastUndelete && ( lastUndelete + maxCooldown > time ( nullptr )))
{
SendUndeleteCharacterResponse ( CHARACTER_UNDELETE_RESULT_ERROR_COOLDOWN , undeleteInfo );
_charUndeleteCallback . Reset ();
return ;
}
}
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHAR_DEL_INFO_BY_GUID );
stmt -> setUInt64 ( 0 , undeleteInfo -> CharacterGuid . GetCounter ());
_charUndeleteCallback . FreeResult ();
_charUndeleteCallback . SetFutureResult ( CharacterDatabase . AsyncQuery ( stmt ));
_charUndeleteCallback . NextStage ();
break ;
}
case 2 :
{
if ( ! result )
{
SendUndeleteCharacterResponse ( CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE , undeleteInfo );
_charUndeleteCallback . Reset ();
return ;
}
Field * fields = result -> Fetch ();
undeleteInfo -> Name = fields [ 1 ]. GetString ();
uint32 account = fields [ 2 ]. GetUInt32 ();
if ( account != GetAccountId ())
{
SendUndeleteCharacterResponse ( CHARACTER_UNDELETE_RESULT_ERROR_UNKNOWN , undeleteInfo );
_charUndeleteCallback . Reset ();
return ;
}
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHECK_NAME );
stmt -> setString ( 0 , undeleteInfo -> Name );
_charUndeleteCallback . FreeResult ();
_charUndeleteCallback . SetFutureResult ( CharacterDatabase . AsyncQuery ( stmt ));
_charUndeleteCallback . NextStage ();
break ;
}
case 3 :
{
if ( result )
{
SendUndeleteCharacterResponse ( CHARACTER_UNDELETE_RESULT_ERROR_NAME_TAKEN_BY_THIS_ACCOUNT , undeleteInfo );
_charUndeleteCallback . Reset ();
return ;
}
/// @todo: add more safety checks
/// * max char count per account
/// * max heroic char count
/// * team violation
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_SUM_CHARS );
stmt -> setUInt32 ( 0 , GetAccountId ());
_charUndeleteCallback . FreeResult ();
_charUndeleteCallback . SetFutureResult ( CharacterDatabase . AsyncQuery ( stmt ));
_charUndeleteCallback . NextStage ();
break ;
}
case 4 :
{
if ( result )
{
Field * fields = result -> Fetch ();
if ( fields [ 0 ]. GetUInt64 () >= sWorld -> getIntConfig ( CONFIG_CHARACTERS_PER_REALM )) // SQL's COUNT() returns uint64 but it will always be less than uint8.Max
{
SendUndeleteCharacterResponse ( CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE , undeleteInfo );
_charUndeleteCallback . Reset ();
return ;
}
}
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_RESTORE_DELETE_INFO );
stmt -> setString ( 0 , undeleteInfo -> Name );
stmt -> setUInt32 ( 1 , GetAccountId ());
stmt -> setUInt64 ( 2 , undeleteInfo -> CharacterGuid . GetCounter ());
CharacterDatabase . Execute ( stmt );
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_UPD_LAST_CHAR_UNDELETE );
stmt -> setUInt32 ( 0 , GetBattlenetAccountId ());
LoginDatabase . Execute ( stmt );
2014-11-12 19:16:14 +01:00
sWorld -> UpdateCharacterInfoDeleted ( undeleteInfo -> CharacterGuid , false , & undeleteInfo -> Name );
2014-11-03 19:11:14 +01:00
SendUndeleteCharacterResponse ( CHARACTER_UNDELETE_RESULT_OK , undeleteInfo );
_charUndeleteCallback . Reset ();
break ;
}
}
}
2014-10-19 15:12:20 +02:00
void WorldSession :: SendCharCreate ( ResponseCodes result )
{
2014-11-03 19:11:14 +01:00
WorldPackets :: Character :: CharacterCreateResponse response ;
response . Code = result ;
2014-11-03 20:23:21 +01:00
SendPacket ( response . Write ());
2014-10-19 15:12:20 +02:00
}
void WorldSession :: SendCharDelete ( ResponseCodes result )
{
2014-11-03 19:11:14 +01:00
WorldPackets :: Character :: CharacterDeleteResponse response ;
response . Code = result ;
2014-11-03 20:23:21 +01:00
SendPacket ( response . Write ());
2014-10-19 15:12:20 +02:00
}
2014-11-12 16:36:05 +01:00
void WorldSession :: SendCharRename ( ResponseCodes result , WorldPackets :: Character :: CharacterRenameInfo const * renameInfo )
2014-10-19 15:12:20 +02:00
{
2014-11-12 16:36:05 +01:00
WorldPackets :: Character :: CharacterRenameResult packet ;
packet . Result = result ;
packet . Name = renameInfo -> NewName ;
2014-10-19 15:12:20 +02:00
if ( result == RESPONSE_SUCCESS )
2014-11-12 16:36:05 +01:00
packet . Guid . Set ( renameInfo -> Guid );
SendPacket ( packet . Write ());
2014-10-19 15:12:20 +02:00
}
2014-11-12 16:36:05 +01:00
void WorldSession :: SendCharCustomize ( ResponseCodes result , WorldPackets :: Character :: CharCustomizeInfo const * customizeInfo )
2014-10-19 15:12:20 +02:00
{
2014-11-12 16:36:05 +01:00
/// @todo: fix 6.x implementation
( void ) customizeInfo ;
/*
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1 + 8 + customizeInfo.NewName.size() + 1 + 6);
2014-10-19 15:12:20 +02:00
data << uint8(result);
if (result == RESPONSE_SUCCESS)
{
data << customizeInfo.Guid;
2014-11-12 16:36:05 +01:00
data << customizeInfo.NewName;
2014-10-19 15:12:20 +02:00
data << uint8(customizeInfo.Gender);
data << uint8(customizeInfo.Skin);
data << uint8(customizeInfo.Face);
data << uint8(customizeInfo.HairStyle);
data << uint8(customizeInfo.HairColor);
data << uint8(customizeInfo.FacialHair);
}
SendPacket(&data);
2014-11-12 16:36:05 +01:00
*/
2014-10-19 15:12:20 +02:00
}
2014-11-12 16:36:05 +01:00
void WorldSession :: SendCharFactionChange ( ResponseCodes result , WorldPackets :: Character :: CharRaceOrFactionChangeInfo const * factionChangeInfo )
2014-10-19 15:12:20 +02:00
{
2014-11-12 16:36:05 +01:00
WorldPackets :: Character :: CharFactionChangeResult packet ;
packet . Result = result ;
packet . Guid = factionChangeInfo -> Guid ;
2014-10-19 15:12:20 +02:00
if ( result == RESPONSE_SUCCESS )
{
2014-11-12 16:36:05 +01:00
packet . Display . HasValue = true ;
2014-11-20 01:17:45 +01:00
packet . Display . Value . Name = factionChangeInfo -> Name ;
packet . Display . Value . SexID = factionChangeInfo -> SexID ;
packet . Display . Value . SkinID = factionChangeInfo -> SkinID . Value ;
packet . Display . Value . HairColorID = factionChangeInfo -> HairColorID . Value ;
packet . Display . Value . HairStyleID = factionChangeInfo -> HairStyleID . Value ;
packet . Display . Value . FacialHairStyleID = factionChangeInfo -> FacialHairStyleID . Value ;
packet . Display . Value . FaceID = factionChangeInfo -> FaceID . Value ;
packet . Display . Value . RaceID = factionChangeInfo -> RaceID ;
2014-10-19 15:12:20 +02:00
}
2014-11-12 16:36:05 +01:00
SendPacket ( packet . Write ());
2014-10-19 15:12:20 +02:00
}
void WorldSession :: SendSetPlayerDeclinedNamesResult ( DeclinedNameResult result , ObjectGuid guid )
{
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( result );
if ( result == DECLINED_NAMES_RESULT_SUCCESS )
data << guid ;
SendPacket ( & data );
}
void WorldSession :: SendBarberShopResult ( BarberShopResult result )
{
WorldPacket data ( SMSG_BARBER_SHOP_RESULT , 4 );
data << uint32 ( result );
SendPacket ( & data );
}
2014-11-03 19:11:14 +01:00
void WorldSession :: SendUndeleteCooldownStatusResponse ( uint32 currentCooldown , uint32 maxCooldown )
{
WorldPackets :: Character :: UndeleteCooldownStatusResponse response ;
response . OnCooldown = ( currentCooldown > 0 );
response . MaxCooldown = maxCooldown ;
response . CurrentCooldown = currentCooldown ;
2014-11-03 20:23:21 +01:00
SendPacket ( response . Write ());
2014-11-03 19:11:14 +01:00
}
void WorldSession :: SendUndeleteCharacterResponse ( CharacterUndeleteResult result , WorldPackets :: Character :: CharacterUndeleteInfo const * undeleteInfo )
{
WorldPackets :: Character :: UndeleteCharacterResponse response ;
response . UndeleteInfo = undeleteInfo ;
response . Result = result ;
2014-11-03 20:23:21 +01:00
SendPacket ( response . Write ());
2014-11-03 19:11:14 +01:00
}