2010-10-07 15:35:36 +02:00
/*
2019-01-01 10:13:49 +01:00
* Copyright (C) 2008-2019 TrinityCore <https://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
2017-05-18 23:52:58 +02:00
#include "WorldSession.h"
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"
2018-07-31 23:31:44 +02:00
#include "ArtifactPackets.h"
2014-11-09 04:25:09 +01:00
#include "AuthenticationPackets.h"
2012-11-20 12:30:30 +01:00
#include "Battleground.h"
2017-05-18 23:52:58 +02:00
#include "BattlegroundPackets.h"
2015-09-09 14:52:32 +02:00
#include "BattlePetPackets.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"
2017-06-04 01:00:45 +02:00
#include "DB2Stores.h"
2014-11-19 21:09:30 +01:00
#include "EquipmentSetPackets.h"
2017-06-04 01:00:45 +02:00
#include "GameObject.h"
2017-05-18 23:52:58 +02:00
#include "GitRevision.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"
2017-06-04 01:00:45 +02:00
#include "Item.h"
2009-06-04 21:41:07 +02:00
#include "Language.h"
#include "Log.h"
2017-06-04 01:00:45 +02:00
#include "Map.h"
2017-05-18 23:52:58 +02:00
#include "Metric.h"
2014-11-23 04:25:47 +01:00
#include "MiscPackets.h"
2017-06-04 01:00:45 +02:00
#include "MotionMaster.h"
2012-11-20 12:30:30 +01:00
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Pet.h"
#include "Player.h"
2017-05-18 23:52:58 +02:00
#include "PlayerDump.h"
2017-05-12 18:49:51 +02:00
#include "QueryHolder.h"
2014-12-26 01:38:40 +01:00
#include "QueryPackets.h"
2017-05-18 23:52:58 +02:00
#include "Realm.h"
2012-11-20 12:30:30 +01:00
#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"
2014-11-08 02:55:45 +01:00
#include "SystemPackets.h"
2008-10-11 14:16:25 -05:00
#include "Util.h"
2012-11-20 12:30:30 +01:00
#include "World.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
2015-01-16 23:32:41 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_AURA_EFFECTS );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_AURA_EFFECTS , stmt );
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-12-28 22:55:53 +02:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES , stmt );
2017-08-20 17:24:41 +02:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_CRITERIA );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA , stmt );
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA_PROGRESS , stmt );
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
2016-08-15 00:03:38 +02:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_ITEM_INSTANCE_ARTIFACT );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS , stmt );
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
2015-02-17 01:01:44 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_SPELL_CHARGES );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_SPELL_CHARGES , stmt );
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
2016-06-18 23:03:16 +02:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_TRANSMOG_OUTFITS );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS , stmt );
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
2016-08-25 19:12:00 +02:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_GLYPHS );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_GLYPHS , stmt );
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
2018-03-04 22:32:08 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_PVP_TALENTS );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_PVP_TALENTS , stmt );
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
2015-09-28 17:20:27 +02:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CORPSE_LOCATION );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION , stmt );
2015-05-08 00:03:15 +02:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_GARRISON );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_GARRISON , stmt );
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_GARRISON_BLUEPRINTS );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_GARRISON_BLUEPRINTS , stmt );
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_GARRISON_BUILDINGS );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS , stmt );
2015-05-22 00:17:48 +02:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWERS , stmt );
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_GARRISON_FOLLOWER_ABILITIES );
stmt -> setUInt64 ( 0 , lowGuid );
res &= SetPreparedQuery ( PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES , stmt );
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
{
2016-07-23 18:39:56 +02:00
uint8 demonHunterCount = 0 ; // We use this counter to allow multiple demon hunter creations when allowed in config
bool canAlwaysCreateDemonHunter = HasPermission ( rbac :: RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_DEMON_HUNTER );
2016-07-25 08:57:10 +02:00
if ( sWorld -> getIntConfig ( CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_DEMON_HUNTER ) == 0 ) // char level = 0 means this check is disabled, so always true
canAlwaysCreateDemonHunter = true ;
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 ;
2016-01-05 23:29:36 +01:00
charEnum . DisabledClassesMask = sWorld -> getIntConfig ( CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK );
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
{
2018-02-10 01:24:00 +01:00
charEnum . Characters . emplace_back ( result -> Fetch ());
WorldPackets :: Character :: EnumCharactersResult :: CharacterInfo & charInfo = charEnum . Characters . back ();
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
2016-01-24 15:56:10 +01:00
if ( ! Player :: ValidateAppearance ( charInfo . Race , charInfo . Class , charInfo . Sex , charInfo . HairStyle , charInfo . HairColor , charInfo . Face , charInfo . FacialHair , charInfo . Skin , charInfo . CustomDisplay ))
2015-04-05 00:30:02 +02:00
{
TC_LOG_ERROR ( "entities.player.loading" , "Player %s has wrong Appearance values (Hair/Skin/Color), forcing recustomize" , charInfo . Guid . ToString (). c_str ());
2016-08-14 00:29:37 +02:00
// Make sure customization always works properly - send all zeroes instead
charInfo . Skin = 0 , charInfo . Face = 0 , charInfo . HairStyle = 0 , charInfo . HairColor = 0 , charInfo . FacialHair = 0 ;
2015-04-05 00:30:02 +02:00
if ( ! ( charInfo . CustomizationFlag == CHAR_CUSTOMIZE_FLAG_CUSTOMIZE ))
{
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_ADD_AT_LOGIN_FLAG );
stmt -> setUInt16 ( 0 , uint16 ( AT_LOGIN_CUSTOMIZE ));
stmt -> setUInt64 ( 1 , charInfo . Guid . GetCounter ());
CharacterDatabase . Execute ( stmt );
charInfo . CustomizationFlag = CHAR_CUSTOMIZE_FLAG_CUSTOMIZE ;
}
}
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.
2015-10-05 15:06:27 +02:00
sWorld -> AddCharacterInfo ( charInfo . Guid , GetAccountId (), charInfo . Name , charInfo . Sex , charInfo . Race , charInfo . Class , charInfo . Level , false );
2013-08-18 18:13:14 +02:00
2016-06-12 14:03:48 +02:00
if ( charInfo . Class == CLASS_DEMON_HUNTER )
2016-07-23 18:39:56 +02:00
demonHunterCount ++ ;
if ( demonHunterCount >= sWorld -> getIntConfig ( CONFIG_DEMON_HUNTERS_PER_REALM ) && ! canAlwaysCreateDemonHunter )
2016-06-12 14:03:48 +02:00
charEnum . HasDemonHunterOnRealm = true ;
2016-07-23 18:39:56 +02:00
else
charEnum . HasDemonHunterOnRealm = false ;
2018-02-10 01:24:00 +01:00
charEnum . MaxCharacterLevel = std :: max < int32 > ( charEnum . MaxCharacterLevel , charInfo . Level );
2014-10-31 14:47:56 +01:00
}
while ( result -> NextRow ());
2014-10-19 17:23:48 +02:00
}
2009-10-17 15:51:44 -07:00
2018-10-04 18:50:21 +02:00
charEnum . IsTestDemonHunterCreationAllowed = canAlwaysCreateDemonHunter ;
2018-02-10 01:24:00 +01:00
charEnum . IsDemonHunterCreationAllowed = GetAccountExpansion () >= EXPANSION_LEGION || canAlwaysCreateDemonHunter ;
charEnum . IsAlliedRacesCreationAllowed = GetAccountExpansion () >= EXPANSION_BATTLE_FOR_AZEROTH ;
for ( std :: pair < uint8 const , RaceUnlockRequirement > const & requirement : sObjectMgr -> GetRaceUnlockRequirements ())
{
WorldPackets :: Character :: EnumCharactersResult :: RaceUnlock raceUnlock ;
raceUnlock . RaceID = requirement . first ;
raceUnlock . HasExpansion = GetAccountExpansion () >= requirement . second . Expansion ;
charEnum . RaceUnlockData . push_back ( raceUnlock );
}
2016-07-23 18:39:56 +02: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 ());
2017-01-13 21:38:03 +01:00
_queryProcessor . AddQuery ( CharacterDatabase . AsyncQuery ( stmt ). WithPreparedCallback ( std :: bind ( & WorldSession :: HandleCharEnum , this , std :: placeholders :: _1 )));
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 ;
2016-01-05 23:29:36 +01:00
charEnum . DisabledClassesMask = sWorld -> getIntConfig ( CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK );
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.
2015-10-05 15:06:27 +02:00
sWorld -> AddCharacterInfo ( charInfo . Guid , GetAccountId (), charInfo . Name , charInfo . Sex , charInfo . Race , charInfo . Class , charInfo . Level , true );
2014-11-12 19:16:14 +01:00
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
2015-01-26 12:59:18 +01:00
void WorldSession :: HandleCharUndeleteEnumOpcode ( WorldPackets :: Character :: EnumCharacters & /*enumCharacters*/ )
2014-11-03 19:11:14 +01:00
{
/// 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 ());
2017-01-13 21:38:03 +01:00
_queryProcessor . AddQuery ( CharacterDatabase . AsyncQuery ( stmt ). WithPreparedCallback ( std :: bind ( & WorldSession :: HandleCharUndeleteEnum , this , std :: placeholders :: _1 )));
2014-11-03 19:11:14 +01:00
}
2015-04-01 01:44:10 +02:00
void WorldSession :: HandleCharCreateOpcode ( WorldPackets :: Character :: CreateCharacter & 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
2015-04-18 01:44:37 +02:00
switch ( Player :: TeamIdForRace ( charCreate . CreateInfo -> Race ))
2008-10-11 14:16:25 -05:00
{
2015-04-18 01:44:37 +02:00
case TEAM_ALLIANCE :
2014-07-17 15:42:57 +02:00
disabled = ( mask & ( 1 << 0 )) != 0 ;
2013-02-25 15:28:41 +01:00
break ;
2015-04-18 01:44:37 +02:00
case TEAM_HORDE :
2014-07-17 15:42:57 +02:00
disabled = ( mask & ( 1 << 1 )) != 0 ;
2013-02-25 15:28:41 +01:00
break ;
2015-04-18 01:44:37 +02:00
case TEAM_NEUTRAL :
disabled = ( mask & ( 1 << 2 )) != 0 ;
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
2018-02-10 01:24:00 +01:00
RaceUnlockRequirement const * raceExpansionRequirement = sObjectMgr -> GetRaceUnlockRequirement ( charCreate . CreateInfo -> Race );
if ( ! raceExpansionRequirement )
2008-10-11 14:16:25 -05:00
{
2018-02-10 01:24:00 +01:00
TC_LOG_ERROR ( "entities.player.cheat" , "Account %u tried to create character with unavailable race %u" , GetAccountId (), charCreate . CreateInfo -> Race );
SendCharCreate ( CHAR_CREATE_FAILED );
return ;
}
if ( raceExpansionRequirement -> Expansion > GetAccountExpansion ())
{
TC_LOG_ERROR ( "entities.player.cheat" , "Expansion %u account:[%d] tried to Create character with expansion %u race (%u)" ,
GetAccountExpansion (), GetAccountId (), raceExpansionRequirement -> Expansion , 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
2018-02-10 01:24:00 +01:00
//if (raceExpansionRequirement->AchievementId && !)
//{
// TC_LOG_ERROR("entities.player.cheat", "Expansion %u account:[%d] tried to Create character without achievement %u race (%u)",
// GetAccountExpansion(), GetAccountId(), raceExpansionRequirement->AchievementId, charCreate.CreateInfo->Race);
// SendCharCreate(CHAR_CREATE_ALLIED_RACE_ACHIEVEMENT);
// return;
//}
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 );
2018-02-10 01:24:00 +01:00
if ( classExpansionRequirement > GetAccountExpansion ())
2008-10-20 12:23:56 -05:00
{
2018-02-10 01:24:00 +01:00
TC_LOG_ERROR ( "entities.player.cheat" , "Expansion %u account:[%d] tried to Create character with expansion %u class (%u)" ,
GetAccountExpansion (), 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
{
2018-09-26 21:34:56 +02:00
uint64 raceMaskDisabled = sWorld -> GetUInt64Config ( CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK );
if (( UI64LIT ( 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
{
2016-08-11 09:10:20 +02:00
TC_LOG_ERROR ( "entities.player.cheat" , "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
2015-08-30 00:17:08 +02:00
ResponseCodes res = ObjectMgr :: CheckPlayerName ( charCreate . CreateInfo -> Name , GetSessionDbcLocale (), 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
2017-01-13 21:38:03 +01:00
std :: shared_ptr < WorldPackets :: Character :: CharacterCreateInfo > createInfo = charCreate . CreateInfo ;
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
2017-01-13 21:38:03 +01:00
_queryProcessor . AddQuery ( CharacterDatabase . AsyncQuery ( stmt )
. WithChainingPreparedCallback ([ this ]( QueryCallback & queryCallback , PreparedQueryResult result )
2008-10-11 14:16:25 -05:00
{
2017-01-13 21:38:03 +01:00
if ( result )
2008-10-11 14:16:25 -05:00
{
2017-01-13 21:38:03 +01:00
SendCharCreate ( CHAR_CREATE_NAME_IN_USE );
return ;
}
2009-10-17 15:51:44 -07:00
2017-01-13 21:38:03 +01:00
PreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_SUM_REALM_CHARACTERS );
stmt -> setUInt32 ( 0 , GetAccountId ());
queryCallback . SetNextQuery ( LoginDatabase . AsyncQuery ( stmt ));
})
. WithChainingPreparedCallback ([ this ]( QueryCallback & queryCallback , PreparedQueryResult result )
{
uint64 acctCharCount = 0 ;
if ( result )
{
Field * fields = result -> Fetch ();
acctCharCount = uint64 ( fields [ 0 ]. GetDouble ());
}
2009-10-17 15:51:44 -07:00
2017-01-13 21:38:03 +01:00
if ( acctCharCount >= sWorld -> getIntConfig ( CONFIG_CHARACTERS_PER_ACCOUNT ))
{
SendCharCreate ( CHAR_CREATE_ACCOUNT_LIMIT );
return ;
2011-06-22 14:20:42 +02:00
}
2017-01-13 21:38:03 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_SUM_CHARS );
stmt -> setUInt32 ( 0 , GetAccountId ());
2017-01-16 15:09:14 +01:00
queryCallback . SetNextQuery ( CharacterDatabase . AsyncQuery ( stmt ));
2017-01-13 21:38:03 +01:00
})
. WithChainingPreparedCallback ([ this , createInfo ]( QueryCallback & queryCallback , PreparedQueryResult result )
{
if ( result )
2011-06-22 14:20:42 +02:00
{
2017-01-13 21:38:03 +01:00
Field * fields = result -> Fetch ();
createInfo -> CharCount = uint8 ( fields [ 0 ]. GetUInt64 ()); // SQL's COUNT() returns uint64 but it will always be less than uint8.Max
2009-10-17 15:51:44 -07:00
2017-01-13 21:38:03 +01:00
if ( createInfo -> CharCount >= sWorld -> getIntConfig ( CONFIG_CHARACTERS_PER_REALM ))
2008-10-11 14:16:25 -05:00
{
2017-01-13 21:38:03 +01:00
SendCharCreate ( CHAR_CREATE_SERVER_LIMIT );
2011-06-22 14:20:42 +02:00
return ;
}
}
2017-01-13 21:38:03 +01:00
bool allowTwoSideAccounts = ! sWorld -> IsPvPRealm () || HasPermission ( rbac :: RBAC_PERM_TWO_SIDE_CHARACTER_CREATION );
uint32 skipCinematics = sWorld -> getIntConfig ( CONFIG_SKIP_CINEMATICS );
2011-06-22 14:20:42 +02:00
2017-01-13 21:38:03 +01:00
std :: function < void ( PreparedQueryResult ) > finalizeCharacterCreation = [ this , createInfo ]( PreparedQueryResult result )
2011-06-22 14:20:42 +02:00
{
bool haveSameRace = false ;
2016-07-23 18:39:56 +02:00
uint32 demonHunterReqLevel = sWorld -> getIntConfig ( CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_DEMON_HUNTER );
bool hasDemonHunterReqLevel = ( demonHunterReqLevel == 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 );
2016-07-23 18:39:56 +02:00
bool checkDemonHunterReqs = createInfo -> Class == CLASS_DEMON_HUNTER && ! HasPermission ( rbac :: RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_DEMON_HUNTER );
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
if ( result )
{
uint32 team = Player :: TeamForRace ( createInfo -> Race );
2016-07-23 18:39:56 +02:00
uint32 freeDemonHunterSlots = sWorld -> getIntConfig ( CONFIG_DEMON_HUNTERS_PER_REALM );
2009-10-17 15:51:44 -07:00
2011-06-22 14:20:42 +02:00
Field * field = result -> Fetch ();
2017-01-13 21:38:03 +01:00
uint8 accRace = field [ 1 ]. GetUInt8 ();
2009-10-17 15:51:44 -07:00
2016-07-23 18:39:56 +02:00
if ( checkDemonHunterReqs )
{
uint8 accClass = field [ 2 ]. GetUInt8 ();
if ( accClass == CLASS_DEMON_HUNTER )
{
if ( freeDemonHunterSlots > 0 )
-- freeDemonHunterSlots ;
if ( freeDemonHunterSlots == 0 )
{
SendCharCreate ( CHAR_CREATE_FAILED );
return ;
}
}
if ( ! hasDemonHunterReqLevel )
{
uint8 accLevel = field [ 0 ]. GetUInt8 ();
if ( accLevel >= demonHunterReqLevel )
hasDemonHunterReqLevel = true ;
}
}
2011-06-22 14:20:42 +02:00
// 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-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)
2017-12-10 12:39:33 +01:00
while (( skipCinematics == 1 && ! haveSameRace ) || createInfo -> Class == CLASS_DEMON_HUNTER )
2011-06-22 14:20:42 +02:00
{
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 ;
2016-07-23 18:39:56 +02:00
if ( checkDemonHunterReqs )
{
uint8 accClass = field [ 2 ]. GetUInt8 ();
if ( accClass == CLASS_DEMON_HUNTER )
{
if ( freeDemonHunterSlots > 0 )
-- freeDemonHunterSlots ;
if ( freeDemonHunterSlots == 0 )
{
SendCharCreate ( CHAR_CREATE_FAILED );
return ;
}
}
if ( ! hasDemonHunterReqLevel )
{
uint8 accLevel = field [ 0 ]. GetUInt8 ();
if ( accLevel >= demonHunterReqLevel )
hasDemonHunterReqLevel = true ;
}
}
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2016-07-23 18:39:56 +02:00
if ( checkDemonHunterReqs && ! hasDemonHunterReqLevel )
{
2018-02-10 01:24:00 +01:00
SendCharCreate ( CHAR_CREATE_LEVEL_REQUIREMENT_DEMON_HUNTER );
2016-07-23 18:39:56 +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 ();
2017-01-13 21:38:03 +01:00
if ( ! newChar . Create ( sObjectMgr -> GetGenerator < HighGuid :: Player > (). Generate (), createInfo . get ()))
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-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
2017-01-13 21:38:03 +01: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 ());
2015-10-06 00:30:47 +02:00
stmt -> setUInt32 ( 1 , realm . Id . Realm );
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 ());
2015-10-06 00:30:47 +02:00
stmt -> setUInt32 ( 2 , realm . Id . Realm );
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
2018-10-04 18:50:21 +02:00
SendCharCreate ( CHAR_CREATE_SUCCESS , newChar . GetGUID ());
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 );
2019-06-03 20:40:34 +02:00
sWorld -> AddCharacterInfo ( newChar . GetGUID (), GetAccountId (), newChar . GetName (), newChar . m_playerData -> NativeSex , 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 ();
2017-01-13 21:38:03 +01:00
};
2017-12-10 12:39:33 +01:00
if ( allowTwoSideAccounts && ! skipCinematics && createInfo -> Class != CLASS_DEMON_HUNTER )
2017-01-13 21:38:03 +01:00
{
finalizeCharacterCreation ( PreparedQueryResult ( nullptr ));
return ;
2011-06-22 14:20:42 +02:00
}
2017-01-13 21:38:03 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHAR_CREATE_INFO );
stmt -> setUInt32 ( 0 , GetAccountId ());
2017-12-10 12:39:33 +01:00
stmt -> setUInt32 ( 1 , ( skipCinematics == 1 || createInfo -> Class == CLASS_DEMON_HUNTER ) ? 12 : 1 );
2017-01-13 21:38:03 +01:00
queryCallback . WithPreparedCallback ( std :: move ( finalizeCharacterCreation )). SetNextQuery ( CharacterDatabase . AsyncQuery ( stmt ));
}));
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2015-04-01 01:44:10 +02:00
void WorldSession :: HandleCharDeleteOpcode ( WorldPackets :: Character :: CharDelete & 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
2016-07-16 20:51:32 -03:00
CharacterInfo const * characterInfo = sWorld -> GetCharacterInfo ( charDelete . Guid );
if ( ! characterInfo )
2008-10-11 14:16:25 -05:00
{
2016-07-16 20:51:32 -03:00
sScriptMgr -> OnPlayerFailedDelete ( charDelete . Guid , initAccountId );
return ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2016-07-16 20:51:32 -03:00
uint32 accountId = characterInfo -> AccountId ;
std :: string name = characterInfo -> Name ;
uint8 level = characterInfo -> Level ;
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-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 ;
}
2015-02-23 22:35:26 +01:00
SendConnectToInstance ( WorldPackets :: Auth :: ConnectToSerial :: WorldAttempt1 );
2014-11-09 00:37:33 +01:00
}
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
2015-04-19 15:30:24 +02:00
SendPacket ( WorldPackets :: Auth :: ResumeComms ( CONNECTION_TYPE_INSTANCE ). Write ());
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
2015-02-23 22:35:26 +01:00
void WorldSession :: AbortLogin ( WorldPackets :: Character :: LoginFailureReason reason )
{
if ( ! PlayerLoading () || GetPlayer ())
{
KickPlayer ();
return ;
}
m_playerLoading . Clear ();
SendPacket ( WorldPackets :: Character :: CharacterLoginFailed ( reason ). Write ());
}
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
2019-06-03 20:40:34 +02:00
pCurrChar -> SetVirtualPlayerRealm ( GetVirtualRealmAddress ());
2017-04-27 00:03:18 +02:00
2014-11-23 04:25:47 +01:00
SendTutorialsData ();
2009-05-09 10:48:55 -05:00
pCurrChar -> GetMotionMaster () -> Initialize ();
2015-01-10 01:35:47 +01:00
pCurrChar -> SendDungeonDifficulty ();
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
2015-02-03 18:11:38 +01:00
SendFeatureSystemStatus ();
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 ());
}
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 ());
}
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 )
2015-08-16 23:27:25 +02:00
chH . PSendSysMessage ( GitRevision :: GetFullVersion ());
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 ());
2018-04-22 14:53:01 +02:00
pCurrChar -> SetGuildRank ( 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 ));
2018-04-22 14:53:01 +02:00
pCurrChar -> SetGuildRank ( 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
2015-09-09 14:52:32 +02:00
// TODO: Move this to BattlePetMgr::SendJournalLock() just to have all packets in one file
WorldPackets :: BattlePet :: BattlePetJournalLockAcquired lock ;
SendPacket ( lock . Write ());
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
{
2016-08-28 19:49:35 +02:00
if ( pCurrChar -> getClass () == CLASS_DEMON_HUNTER ) /// @todo: find a more generic solution
pCurrChar -> SendMovieStart ( 469 );
else if ( cEntry -> CinematicSequenceID )
2014-11-07 17:39:16 +02:00
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
2015-10-15 23:29:19 +02:00
if ( ! pCurrChar -> GetMap () -> AddPlayerToMap ( pCurrChar ))
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
2015-09-28 17:20:27 +02:00
ObjectAccessor :: 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
2015-09-28 17:20:27 +02:00
pCurrChar -> LoadCorpse ( holder -> GetPreparedResult ( PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION ));
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 ))
2016-04-29 11:49:07 -04:00
{
// Delete all of the player's pet spells
PreparedStatement * stmtSpells = CharacterDatabase . GetPreparedStatement ( CHAR_DEL_ALL_PET_SPELLS_BY_OWNER );
stmtSpells -> setUInt64 ( 0 , pCurrChar -> GetGUID (). GetCounter ());
CharacterDatabase . Execute ( stmtSpells );
// Then reset all of the player's pet specualizations
2016-05-26 23:13:31 +02:00
PreparedStatement * stmtSpec = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_PET_SPECS_BY_OWNER );
2016-04-29 11:49:07 -04:00
stmtSpec -> setUInt64 ( 0 , pCurrChar -> GetGUID (). GetCounter ());
CharacterDatabase . Execute ( stmtSpec );
}
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
2019-06-03 20:40:34 +02:00
if ( sWorld -> IsFFAPvPRealm () && ! pCurrChar -> IsGameMaster () && ! pCurrChar -> HasPlayerFlag ( PLAYER_FLAGS_RESTING ))
pCurrChar -> AddPvpFlag ( UNIT_BYTE2_FLAG_FFA_PVP );
2009-10-17 15:51:44 -07:00
2019-06-03 20:40:34 +02:00
if ( pCurrChar -> HasPlayerFlag ( 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 );
2015-03-30 20:16:27 +02:00
pCurrChar -> ResetTalentSpecialization ();
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)
2016-05-07 01:16:29 +02:00
_player -> UpdateCriteria ( CRITERIA_TYPE_ON_LOGIN , 1 );
2014-02-05 09:34:12 +01:00
2014-06-21 15:40:58 +03:00
sScriptMgr -> OnPlayerLogin ( pCurrChar , firstLogin );
2016-06-04 11:26:57 +01:00
TC_METRIC_EVENT ( "player_events" , "Login" , pCurrChar -> GetName ());
2008-10-11 14:16:25 -05:00
delete holder ;
}
2009-10-17 15:51:44 -07:00
2015-02-03 18:11:38 +01:00
void WorldSession :: SendFeatureSystemStatus ()
{
WorldPackets :: System :: FeatureSystemStatus features ;
/// START OF DUMMY VALUES
features . ComplaintStatus = 2 ;
features . ScrollOfResurrectionRequestsRemaining = 1 ;
features . ScrollOfResurrectionMaxRequestsPerDay = 1 ;
2016-01-06 23:47:28 +01:00
features . TwitterPostThrottleLimit = 60 ;
features . TwitterPostThrottleCooldown = 20 ;
2015-02-03 18:11:38 +01:00
features . CfgRealmID = 2 ;
features . CfgRealmRecID = 0 ;
2015-04-10 22:28:16 +02:00
features . TokenPollTimeSeconds = 300 ;
features . TokenRedeemIndex = 0 ;
2015-02-03 18:11:38 +01:00
features . VoiceEnabled = false ;
features . BrowserEnabled = false ; // Has to be false, otherwise client will crash if "Customer Support" is opened
2015-02-05 20:52:51 +01:00
2015-04-27 17:01:30 +02:00
features . EuropaTicketSystemStatus = boost :: in_place ();
2015-04-26 23:45:52 +02:00
features . EuropaTicketSystemStatus -> ThrottleState . MaxTries = 10 ;
features . EuropaTicketSystemStatus -> ThrottleState . PerMilliseconds = 60000 ;
features . EuropaTicketSystemStatus -> ThrottleState . TryCount = 1 ;
features . EuropaTicketSystemStatus -> ThrottleState . LastResetTimeBeforeNow = 111111 ;
2015-02-08 01:07:00 +01:00
features . ComplaintStatus = 0 ;
features . TutorialsEnabled = true ;
2015-07-06 01:52:21 +02:00
features . NPETutorialsEnabled = true ;
2015-02-03 18:11:38 +01:00
/// END OF DUMMY VALUES
2015-04-26 23:45:52 +02:00
features . EuropaTicketSystemStatus -> TicketsEnabled = sWorld -> getBoolConfig ( CONFIG_SUPPORT_TICKETS_ENABLED );
features . EuropaTicketSystemStatus -> BugsEnabled = sWorld -> getBoolConfig ( CONFIG_SUPPORT_BUGS_ENABLED );
features . EuropaTicketSystemStatus -> ComplaintsEnabled = sWorld -> getBoolConfig ( CONFIG_SUPPORT_COMPLAINTS_ENABLED );
features . EuropaTicketSystemStatus -> SuggestionsEnabled = sWorld -> getBoolConfig ( CONFIG_SUPPORT_SUGGESTIONS_ENABLED );
2015-02-08 01:07:00 +01:00
2015-02-03 18:11:38 +01:00
features . CharUndeleteEnabled = sWorld -> getBoolConfig ( CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED );
features . BpayStoreEnabled = sWorld -> getBoolConfig ( CONFIG_FEATURE_SYSTEM_BPAY_STORE_ENABLED );
SendPacket ( features . Write ());
}
2015-04-22 23:26:31 +02:00
void WorldSession :: HandleSetFactionAtWar ( WorldPackets :: Character :: SetFactionAtWar & packet )
2008-10-11 14:16:25 -05:00
{
2015-04-22 23:26:31 +02:00
GetPlayer () -> GetReputationMgr (). SetAtWar ( packet . FactionIndex , true );
}
2009-10-17 15:51:44 -07:00
2015-04-22 23:26:31 +02:00
void WorldSession :: HandleSetFactionNotAtWar ( WorldPackets :: Character :: SetFactionNotAtWar & packet )
{
GetPlayer () -> GetReputationMgr (). SetAtWar ( packet . FactionIndex , false );
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
2015-04-22 23:26:31 +02:00
void WorldSession :: HandleSetWatchedFactionOpcode ( WorldPackets :: Character :: SetWatchedFaction & packet )
2008-10-11 14:16:25 -05:00
{
2019-06-03 20:40:34 +02:00
GetPlayer () -> SetWatchedFactionIndex ( packet . FactionIndex );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2015-04-22 23:26:31 +02:00
void WorldSession :: HandleSetFactionInactiveOpcode ( WorldPackets :: Character :: SetFactionInactive & packet )
2008-10-11 14:16:25 -05:00
{
2015-04-22 23:26:31 +02:00
_player -> GetReputationMgr (). SetInactive ( packet . Index , packet . State );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2015-04-09 00:05:31 +02:00
void WorldSession :: HandleRequestForcedReactionsOpcode ( WorldPackets :: Reputation :: RequestForcedReactions & /*requestForcedReactions*/ )
{
_player -> GetReputationMgr (). SendForceReactions ();
}
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
2015-08-30 00:17:08 +02:00
ResponseCodes res = ObjectMgr :: CheckPlayerName ( request . RenameInfo -> NewName , GetSessionDbcLocale (), 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
2017-01-13 21:38:03 +01:00
_queryProcessor . AddQuery ( CharacterDatabase . AsyncQuery ( stmt )
. WithPreparedCallback ( std :: bind ( & WorldSession :: HandleCharRenameCallBack , this , request . RenameInfo , std :: placeholders :: _1 )));
2008-12-19 16:05:13 -06:00
}
2009-10-17 15:51:44 -07:00
2017-01-13 21:38:03 +01:00
void WorldSession :: HandleCharRenameCallBack ( std :: shared_ptr < WorldPackets :: Character :: CharacterRenameInfo > renameInfo , PreparedQueryResult result )
2008-12-19 16:05:13 -06:00
{
2008-12-22 10:59:38 -06:00
if ( ! result )
2008-10-11 14:16:25 -05:00
{
2017-01-13 21:38:03 +01:00
SendCharRename ( CHAR_CREATE_ERROR , renameInfo . get ());
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 ))
{
2017-01-13 21:38:03 +01:00
SendCharRename ( CHAR_CREATE_ERROR , renameInfo . get ());
2014-11-12 16:36:05 +01:00
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
2017-01-13 21:38:03 +01:00
SendCharRename ( RESPONSE_SUCCESS , renameInfo . get ());
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
2016-02-02 23:19:37 +01:00
void WorldSession :: HandleSetPlayerDeclinedNames ( WorldPackets :: Character :: SetPlayerDeclinedNames & packet )
2008-10-11 14:16:25 -05:00
{
// not accept declined names for unsupported languages
std :: string name ;
2016-02-02 23:19:37 +01:00
if ( ! ObjectMgr :: GetPlayerNameByGUID ( packet . Player , name ))
2008-10-11 14:16:25 -05:00
{
2016-02-02 23:19:37 +01:00
SendSetPlayerDeclinedNamesResult ( DECLINED_NAMES_RESULT_ERROR , packet . Player );
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
{
2016-02-02 23:19:37 +01:00
SendSetPlayerDeclinedNamesResult ( DECLINED_NAMES_RESULT_ERROR , packet . Player );
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
{
2016-02-02 23:19:37 +01:00
SendSetPlayerDeclinedNamesResult ( DECLINED_NAMES_RESULT_ERROR , packet . Player );
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
{
2016-02-02 23:19:37 +01:00
if ( ! normalizePlayerName ( packet . DeclinedNames . name [ i ]))
2008-10-11 14:16:25 -05:00
{
2016-02-02 23:19:37 +01:00
SendSetPlayerDeclinedNamesResult ( DECLINED_NAMES_RESULT_ERROR , packet . Player );
2008-10-11 14:16:25 -05:00
return ;
}
}
2009-10-17 15:51:44 -07:00
2016-02-02 23:19:37 +01:00
if ( ! ObjectMgr :: CheckDeclinedNames ( wname , packet . DeclinedNames ))
2008-10-11 14:16:25 -05:00
{
2016-02-02 23:19:37 +01:00
SendSetPlayerDeclinedNamesResult ( DECLINED_NAMES_RESULT_ERROR , packet . Player );
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 )
2016-02-02 23:19:37 +01:00
CharacterDatabase . EscapeString ( packet . DeclinedNames . 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 );
2016-02-02 23:19:37 +01:00
stmt -> setUInt64 ( 0 , packet . Player . GetCounter ());
2012-05-30 08:01:02 +02:00
trans -> Append ( stmt );
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_INS_CHAR_DECLINED_NAME );
2016-02-02 23:19:37 +01:00
stmt -> setUInt64 ( 0 , packet . Player . GetCounter ());
2012-05-30 08:01:02 +02:00
2016-02-02 23:19:37 +01:00
for ( uint8 i = 0 ; i < MAX_DECLINED_NAME_CASES ; i ++ )
stmt -> setString ( i + 1 , packet . DeclinedNames . name [ i ]);
2012-05-30 08:01:02 +02:00
trans -> Append ( stmt );
2010-08-21 03:19:25 +02:00
CharacterDatabase . CommitTransaction ( trans );
2009-10-17 15:51:44 -07:00
2016-02-02 23:19:37 +01:00
SendSetPlayerDeclinedNamesResult ( DECLINED_NAMES_RESULT_SUCCESS , packet . Player );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2015-03-28 18:12:26 +01:00
void WorldSession :: HandleAlterAppearance ( WorldPackets :: Character :: AlterApperance & packet )
2008-12-24 09:58:26 -06:00
{
2015-03-28 18:12:26 +01:00
BarberShopStyleEntry const * bs_hair = sBarberShopStyleStore . LookupEntry ( packet . NewHairStyle );
2019-06-03 20:40:34 +02:00
if ( ! bs_hair || bs_hair -> Type != 0 || bs_hair -> Race != _player -> getRace () || bs_hair -> Sex != _player -> m_playerData -> NativeSex )
2008-12-24 09:58:26 -06:00
return ;
2009-10-17 15:51:44 -07:00
2015-03-28 18:12:26 +01:00
BarberShopStyleEntry const * bs_facialHair = sBarberShopStyleStore . LookupEntry ( packet . NewFacialHair );
2019-06-03 20:40:34 +02:00
if ( ! bs_facialHair || bs_facialHair -> Type != 2 || bs_facialHair -> Race != _player -> getRace () || bs_facialHair -> Sex != _player -> m_playerData -> NativeSex )
2008-12-24 09:58:26 -06:00
return ;
2009-10-17 15:51:44 -07:00
2015-03-28 18:12:26 +01:00
BarberShopStyleEntry const * bs_skinColor = sBarberShopStyleStore . LookupEntry ( packet . NewSkinColor );
2019-06-03 20:40:34 +02:00
if ( bs_skinColor && ( bs_skinColor -> Type != 3 || bs_skinColor -> Race != _player -> getRace () || bs_skinColor -> Sex != _player -> m_playerData -> NativeSex ))
2009-12-17 10:49:15 +01:00
return ;
2015-04-21 00:24:26 +02:00
BarberShopStyleEntry const * bs_face = sBarberShopStyleStore . LookupEntry ( packet . NewFace );
2019-06-03 20:40:34 +02:00
if ( bs_face && ( bs_face -> Type != 4 || bs_face -> Race != _player -> getRace () || bs_face -> Sex != _player -> m_playerData -> NativeSex ))
2015-04-21 00:24:26 +02:00
return ;
2016-05-30 23:51:39 +02:00
std :: array < BarberShopStyleEntry const * , PLAYER_CUSTOM_DISPLAY_SIZE > customDisplayEntries ;
std :: array < uint8 , PLAYER_CUSTOM_DISPLAY_SIZE > customDisplay ;
for ( std :: size_t i = 0 ; i < PLAYER_CUSTOM_DISPLAY_SIZE ; ++ i )
{
BarberShopStyleEntry const * bs_customDisplay = sBarberShopStyleStore . LookupEntry ( packet . NewCustomDisplay [ i ]);
2019-06-03 20:40:34 +02:00
if ( bs_customDisplay && ( bs_customDisplay -> Type != 5 + i || bs_customDisplay -> Race != _player -> getRace () || bs_customDisplay -> Sex != _player -> m_playerData -> NativeSex ))
2016-05-30 23:51:39 +02:00
return ;
customDisplayEntries [ i ] = bs_customDisplay ;
2016-08-27 19:58:17 +02:00
customDisplay [ i ] = bs_customDisplay ? bs_customDisplay -> Data : 0 ;
2016-05-30 23:51:39 +02:00
}
2019-06-03 20:40:34 +02:00
if ( ! Player :: ValidateAppearance ( _player -> getRace (), _player -> getClass (), _player -> m_playerData -> NativeSex ,
2015-04-21 00:24:26 +02:00
bs_hair -> Data ,
packet . NewHairColor ,
2019-06-03 20:40:34 +02:00
bs_face ? bs_face -> Data : _player -> m_playerData -> FaceID ,
2015-04-21 00:24:26 +02:00
bs_facialHair -> Data ,
2019-06-03 20:40:34 +02:00
bs_skinColor ? bs_skinColor -> Data : _player -> m_playerData -> SkinID ,
2016-05-30 23:51:39 +02:00
customDisplay ))
2015-04-05 00:30:02 +02: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 )
{
2017-05-21 23:18:43 +02:00
SendPacket ( WorldPackets :: Character :: BarberShopResult ( WorldPackets :: Character :: BarberShopResult :: ResultEnum :: NotOnChair ). Write ());
2012-09-08 23:16:14 +01:00
return ;
}
2015-03-22 13:47:55 +01:00
if ( _player -> GetStandState () != UnitStandStateType ( UNIT_STAND_STATE_SIT_LOW_CHAIR + go -> GetGOInfo () -> barberChair . chairheight ))
2012-09-08 23:16:14 +01:00
{
2017-05-21 23:18:43 +02:00
SendPacket ( WorldPackets :: Character :: BarberShopResult ( WorldPackets :: Character :: BarberShopResult :: ResultEnum :: NotOnChair ). Write ());
2012-09-08 23:16:14 +01:00
return ;
}
2016-05-30 23:51:39 +02:00
uint32 cost = _player -> GetBarberShopCost ( bs_hair , packet . NewHairColor , bs_facialHair , bs_skinColor , bs_face , customDisplayEntries );
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
{
2017-05-21 23:18:43 +02:00
SendPacket ( WorldPackets :: Character :: BarberShopResult ( WorldPackets :: Character :: BarberShopResult :: ResultEnum :: NoMoney ). Write ());
2008-12-24 09:58:26 -06:00
return ;
}
2014-10-19 15:12:20 +02:00
2017-05-21 23:18:43 +02:00
SendPacket ( WorldPackets :: Character :: BarberShopResult ( WorldPackets :: Character :: BarberShopResult :: ResultEnum :: Success ). Write ());
2009-10-17 15:51:44 -07:00
2012-07-24 15:27:42 +01:00
_player -> ModifyMoney ( - int64 ( cost )); // it isn't free
2016-05-07 01:16:29 +02:00
_player -> UpdateCriteria ( CRITERIA_TYPE_GOLD_SPENT_AT_BARBER , cost );
2009-10-17 15:51:44 -07:00
2019-06-03 20:40:34 +02:00
_player -> SetHairStyleId ( bs_hair -> Data );
_player -> SetHairColorId ( packet . NewHairColor );
_player -> SetFacialHairStyleId ( bs_facialHair -> Data );
2009-12-17 10:49:15 +01:00
if ( bs_skinColor )
2019-06-03 20:40:34 +02:00
_player -> SetSkinId ( bs_skinColor -> Data );
2015-04-21 00:24:26 +02:00
if ( bs_face )
2019-06-03 20:40:34 +02:00
_player -> SetFaceId ( bs_face -> Data );
2009-10-17 15:51:44 -07:00
2016-08-27 19:58:17 +02:00
for ( uint32 i = 0 ; i < PLAYER_CUSTOM_DISPLAY_SIZE ; ++ i )
2019-06-03 20:40:34 +02:00
_player -> SetCustomDisplayOption ( i , customDisplay [ i ]);
2016-08-27 19:58:17 +02:00
2016-05-07 01:16:29 +02:00
_player -> UpdateCriteria ( CRITERIA_TYPE_VISIT_BARBER_SHOP , 1 );
2009-10-17 15:51:44 -07:00
2015-01-28 19:29:31 +00:00
_player -> SetStandState ( UNIT_STAND_STATE_STAND );
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
{
2016-08-11 09:10:20 +02:00
TC_LOG_ERROR ( "entities.player.cheat" , "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
2017-01-13 21:38:03 +01:00
_queryProcessor . AddQuery ( CharacterDatabase . AsyncQuery ( stmt )
. WithPreparedCallback ( std :: bind ( & WorldSession :: HandleCharCustomizeCallback , this , packet . CustomizeInfo , std :: placeholders :: _1 )));
2014-11-12 16:36:05 +01:00
}
2017-01-13 21:38:03 +01:00
void WorldSession :: HandleCharCustomizeCallback ( std :: shared_ptr < WorldPackets :: Character :: CharCustomizeInfo > customizeInfo , PreparedQueryResult result )
2014-11-12 16:36:05 +01:00
{
2008-12-24 09:58:26 -06:00
if ( ! result )
{
2017-01-13 21:38:03 +01:00
SendCharCustomize ( CHAR_CREATE_ERROR , customizeInfo . get ());
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 ();
2015-04-05 00:30:02 +02:00
uint8 plrRace = fields [ 1 ]. GetUInt8 ();
uint8 plrClass = fields [ 2 ]. GetUInt8 ();
uint8 plrGender = fields [ 3 ]. GetUInt8 ();
uint16 atLoginFlags = fields [ 4 ]. GetUInt16 ();
2016-01-24 15:56:10 +01:00
if ( ! Player :: ValidateAppearance ( plrRace , plrClass , plrGender , customizeInfo -> HairStyleID , customizeInfo -> HairColorID , customizeInfo -> FaceID ,
2016-05-30 23:51:39 +02:00
customizeInfo -> FacialHairStyleID , customizeInfo -> SkinID , customizeInfo -> CustomDisplay ))
2015-04-05 00:30:02 +02:00
{
2017-01-13 21:38:03 +01:00
SendCharCustomize ( CHAR_CREATE_ERROR , customizeInfo . get ());
2015-04-05 00:30:02 +02:00
return ;
}
2014-11-12 16:36:05 +01:00
if ( ! ( atLoginFlags & AT_LOGIN_CUSTOMIZE ))
2008-12-24 09:58:26 -06:00
{
2017-01-13 21:38:03 +01:00
SendCharCustomize ( CHAR_CREATE_ERROR , customizeInfo . get ());
2008-12-24 09:58:26 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2016-06-19 10:23:27 +04:30
// prevent character rename
if ( sWorld -> getBoolConfig ( CONFIG_PREVENT_RENAME_CUSTOMIZATION ) && ( customizeInfo -> CharName != oldName ))
{
SendCharCustomize ( CHAR_NAME_FAILURE , customizeInfo . get ());
return ;
}
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
{
2017-01-13 21:38:03 +01:00
SendCharCustomize ( CHAR_NAME_NO_NAME , customizeInfo . get ());
2008-12-24 09:58:26 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2015-08-30 00:17:08 +02:00
ResponseCodes res = ObjectMgr :: CheckPlayerName ( customizeInfo -> CharName , GetSessionDbcLocale (), true );
2009-07-10 08:25:33 +08:00
if ( res != CHAR_NAME_SUCCESS )
2008-12-24 09:58:26 -06:00
{
2017-01-13 21:38:03 +01:00
SendCharCustomize ( res , customizeInfo . get ());
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
{
2017-01-13 21:38:03 +01:00
SendCharCustomize ( CHAR_NAME_RESERVED , customizeInfo . get ());
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
{
2017-01-13 21:38:03 +01:00
SendCharCustomize ( CHAR_CREATE_NAME_IN_USE , customizeInfo . get ());
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
{
2016-01-05 00:03:18 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_GENDER_AND_APPEARANCE );
2009-10-17 15:51:44 -07:00
2014-11-12 16:36:05 +01:00
stmt -> setUInt8 ( 0 , customizeInfo -> SexID );
2016-01-05 00:03:18 +01:00
stmt -> setUInt8 ( 1 , customizeInfo -> SkinID );
stmt -> setUInt8 ( 2 , customizeInfo -> FaceID );
stmt -> setUInt8 ( 3 , customizeInfo -> HairStyleID );
stmt -> setUInt8 ( 4 , customizeInfo -> HairColorID );
stmt -> setUInt8 ( 5 , customizeInfo -> FacialHairStyleID );
2016-01-05 23:29:36 +01:00
stmt -> setUInt8 ( 6 , customizeInfo -> CustomDisplay [ 0 ]);
stmt -> setUInt8 ( 7 , customizeInfo -> CustomDisplay [ 1 ]);
stmt -> setUInt8 ( 8 , customizeInfo -> CustomDisplay [ 2 ]);
stmt -> setUInt64 ( 9 , 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
2017-01-13 21:38:03 +01:00
SendCharCustomize ( RESPONSE_SUCCESS , customizeInfo . get ());
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
2015-07-21 00:33:36 +02:00
void WorldSession :: HandleEquipmentSetSave ( WorldPackets :: EquipmentSet :: SaveEquipmentSet & saveEquipmentSet )
2009-06-11 00:45:59 -05:00
{
2015-07-21 00:33:36 +02:00
if ( saveEquipmentSet . 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
2016-06-18 23:03:16 +02:00
if ( saveEquipmentSet . Set . Type > EquipmentSetInfo :: TRANSMOG )
return ;
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
{
2015-07-21 00:33:36 +02:00
if ( ! ( saveEquipmentSet . Set . IgnoreMask & ( 1 << i )))
2012-07-13 15:16:37 +02:00
{
2016-06-18 23:03:16 +02:00
if ( saveEquipmentSet . Set . Type == EquipmentSetInfo :: EQUIPMENT )
{
saveEquipmentSet . Set . Appearances [ i ] = 0 ;
2009-10-17 15:51:44 -07:00
2016-06-18 23:03:16 +02:00
ObjectGuid const & itemGuid = saveEquipmentSet . Set . Pieces [ i ];
2018-04-11 21:07:39 +02:00
if ( ! itemGuid . IsEmpty ())
{
Item * item = _player -> GetItemByPos ( INVENTORY_SLOT_BAG_0 , i );
2009-10-17 15:51:44 -07:00
2018-04-11 21:07:39 +02:00
/// cheating check 1 (item equipped but sent empty guid)
if ( ! item )
return ;
2016-06-18 23:03:16 +02:00
2018-04-11 21:07:39 +02:00
/// cheating check 2 (sent guid does not match equipped item)
if ( item -> GetGUID () != itemGuid )
return ;
}
else
saveEquipmentSet . Set . IgnoreMask |= 1 << i ;
2016-06-18 23:03:16 +02:00
}
else
{
saveEquipmentSet . Set . Pieces [ i ]. Clear ();
2016-07-05 22:07:35 +02:00
if ( saveEquipmentSet . Set . Appearances [ i ])
{
if ( ! sItemModifiedAppearanceStore . LookupEntry ( saveEquipmentSet . Set . Appearances [ i ]))
return ;
2016-06-18 23:03:16 +02:00
2016-07-05 22:07:35 +02:00
bool hasAppearance , isTemporary ;
std :: tie ( hasAppearance , isTemporary ) = GetCollectionMgr () -> HasItemAppearance ( saveEquipmentSet . Set . Appearances [ i ]);
if ( ! hasAppearance )
return ;
}
2018-04-11 21:07:39 +02:00
else
saveEquipmentSet . Set . IgnoreMask |= 1 << i ;
2016-06-18 23:03:16 +02:00
}
2014-11-19 21:09:30 +01:00
}
else
2016-06-18 23:03:16 +02:00
{
2015-07-21 00:33:36 +02:00
saveEquipmentSet . Set . Pieces [ i ]. Clear ();
2016-06-18 23:03:16 +02:00
saveEquipmentSet . Set . Appearances [ i ] = 0 ;
}
2009-06-11 00:45:59 -05:00
}
2009-10-17 15:51:44 -07:00
2015-07-21 00:33:36 +02:00
saveEquipmentSet . Set . IgnoreMask &= 0x7FFFF ; /// clear invalid bits (i > EQUIPMENT_SLOT_END)
2016-06-18 23:03:16 +02:00
if ( saveEquipmentSet . Set . Type == EquipmentSetInfo :: EQUIPMENT )
{
saveEquipmentSet . Set . Enchants [ 0 ] = 0 ;
saveEquipmentSet . Set . Enchants [ 1 ] = 0 ;
}
2016-07-05 22:07:35 +02:00
else
{
auto validateIllusion = [ this ]( uint32 enchantId ) -> bool
{
SpellItemEnchantmentEntry const * illusion = sSpellItemEnchantmentStore . LookupEntry ( enchantId );
if ( ! illusion )
return false ;
if ( ! illusion -> ItemVisual || ! ( illusion -> Flags & ENCHANTMENT_COLLECTABLE ))
return false ;
2018-03-12 18:20:26 +01:00
if ( PlayerConditionEntry const * condition = sPlayerConditionStore . LookupEntry ( illusion -> TransmogPlayerConditionID ))
2016-07-05 22:07:35 +02:00
if ( ! sConditionMgr -> IsPlayerMeetingCondition ( _player , condition ))
return false ;
if ( illusion -> ScalingClassRestricted > 0 && uint8 ( illusion -> ScalingClassRestricted ) != _player -> getClass ())
return false ;
return true ;
};
if ( saveEquipmentSet . Set . Enchants [ 0 ] && ! validateIllusion ( saveEquipmentSet . Set . Enchants [ 0 ]))
return ;
if ( saveEquipmentSet . Set . Enchants [ 1 ] && ! validateIllusion ( saveEquipmentSet . Set . Enchants [ 1 ]))
return ;
}
2014-11-19 21:09:30 +01:00
2016-06-18 23:03:16 +02:00
_player -> SetEquipmentSet ( saveEquipmentSet . Set );
2009-06-11 00:45:59 -05:00
}
2009-10-17 15:51:44 -07:00
2015-07-21 00:33:36 +02:00
void WorldSession :: HandleDeleteEquipmentSet ( WorldPackets :: EquipmentSet :: DeleteEquipmentSet & deleteEquipmentSet )
2009-06-11 00:45:59 -05:00
{
2015-07-21 00:33:36 +02:00
_player -> DeleteEquipmentSet ( deleteEquipmentSet . ID );
2009-06-11 00:45:59 -05:00
}
2009-10-17 15:51:44 -07:00
2015-07-21 00:33:36 +02:00
void WorldSession :: HandleUseEquipmentSet ( WorldPackets :: EquipmentSet :: UseEquipmentSet & useEquipmentSet )
2009-06-11 00:45:59 -05:00
{
2014-10-25 17:11:35 +02:00
ObjectGuid ignoredItemGuid ;
2018-04-11 21:07:39 +02:00
ignoredItemGuid . SetRawValue ( 0x0C00040000000000 , 0xFFFFFFFFFFFFFFFF );
2009-10-17 15:51:44 -07:00
2015-04-12 03:55:32 +02:00
for ( uint8 i = 0 ; i < EQUIPMENT_SLOT_END ; ++ i )
{
2015-07-21 00:33:36 +02:00
TC_LOG_DEBUG ( "entities.player.items" , "%s: ContainerSlot: %u, Slot: %u" , useEquipmentSet . Items [ i ]. Item . ToString (). c_str (), useEquipmentSet . Items [ i ]. ContainerSlot , useEquipmentSet . Items [ i ]. Slot );
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
2015-07-21 00:33:36 +02:00
if ( useEquipmentSet . Items [ i ]. Item == ignoredItemGuid )
2012-07-13 15:16:37 +02:00
continue ;
2014-01-18 12:58:01 +01:00
// Only equip weapons in combat
2015-09-27 00:05:33 +02:00
if ( _player -> IsInCombat () && i != EQUIPMENT_SLOT_MAINHAND && i != EQUIPMENT_SLOT_OFFHAND )
2014-01-18 12:58:01 +01:00
continue ;
2015-07-21 00:33:36 +02:00
Item * item = _player -> GetItemByGuid ( useEquipmentSet . Items [ i ]. Item );
2009-10-17 15:51:44 -07:00
2015-04-12 03:55:32 +02: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
2015-04-12 03:55:32 +02:00
ItemPosCountVec itemPosCountVec ;
InventoryResult inventoryResult = _player -> CanStoreItem ( NULL_BAG , NULL_SLOT , itemPosCountVec , uItem , false );
if ( inventoryResult == EQUIP_ERR_OK )
2009-06-11 00:45:59 -05:00
{
_player -> RemoveItem ( INVENTORY_SLOT_BAG_0 , i , true );
2015-04-12 03:55:32 +02:00
_player -> StoreItem ( itemPosCountVec , uItem , true );
2009-06-11 00:45:59 -05:00
}
else
2015-04-12 03:55:32 +02:00
_player -> SendEquipError ( inventoryResult , uItem , NULL );
2009-06-11 00:45:59 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2015-04-12 03:55:32 +02:00
if ( item -> GetPos () == dstPos )
2009-06-11 00:45:59 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2015-04-12 03:55:32 +02:00
_player -> SwapItem ( item -> GetPos (), dstPos );
2009-06-11 00:45:59 -05:00
}
2009-10-17 15:51:44 -07:00
2015-04-12 03:55:32 +02:00
WorldPackets :: EquipmentSet :: UseEquipmentSetResult result ;
2017-04-15 12:32:36 +02:00
result . GUID = useEquipmentSet . GUID ;
2015-04-12 03:55:32 +02:00
result . Reason = 0 ; // 4 - equipment swap failed - inventory is full
SendPacket ( result . Write ());
2009-06-11 00:45:59 -05:00
}
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
{
2016-08-11 09:10:20 +02:00
TC_LOG_ERROR ( "entities.player.cheat" , "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 ());
2017-01-13 21:38:03 +01:00
_queryProcessor . AddQuery ( CharacterDatabase . AsyncQuery ( stmt )
. WithPreparedCallback ( std :: bind ( & WorldSession :: HandleCharRaceOrFactionChangeCallback , this , packet . RaceOrFactionChangeInfo , std :: placeholders :: _1 )));
2014-11-12 16:36:05 +01:00
}
2010-09-05 13:12:24 -07:00
2017-01-13 21:38:03 +01:00
void WorldSession :: HandleCharRaceOrFactionChangeCallback ( std :: shared_ptr < WorldPackets :: Character :: CharRaceOrFactionChangeInfo > factionChangeInfo , PreparedQueryResult result )
2014-11-12 16:36:05 +01:00
{
if ( ! result )
{
2017-01-13 21:38:03 +01:00
SendCharFactionChange ( CHAR_CREATE_ERROR , factionChangeInfo . get ());
2014-11-12 16:36:05 +01:00
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
{
2017-01-13 21:38:03 +01:00
SendCharFactionChange ( CHAR_CREATE_ERROR , factionChangeInfo . get ());
2013-02-14 15:43:26 +01:00
return ;
}
2016-06-19 10:23:27 +04:30
std :: string oldName = characterInfo -> Name ;
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
{
2017-01-13 21:38:03 +01:00
SendCharFactionChange ( CHAR_CREATE_ERROR , factionChangeInfo . get ());
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 ();
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
{
2017-01-13 21:38:03 +01:00
SendCharFactionChange ( CHAR_CREATE_ERROR , factionChangeInfo . get ());
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
{
2017-01-13 21:38:03 +01:00
SendCharFactionChange ( CHAR_CREATE_RESTRICTED_RACECLASS , factionChangeInfo . get ());
2014-11-12 16:36:05 +01:00
return ;
}
2015-04-17 19:27:51 +02:00
if ( factionChangeInfo -> FactionChange == ( Player :: TeamIdForRace ( oldRace ) == newTeamId ))
2014-11-12 16:36:05 +01:00
{
2017-01-13 21:38:03 +01:00
SendCharFactionChange ( factionChangeInfo -> FactionChange ? CHAR_CREATE_CHARACTER_SWAP_FACTION : CHAR_CREATE_CHARACTER_RACE_ONLY , factionChangeInfo . get ());
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
{
2018-09-26 21:34:56 +02:00
uint64 raceMaskDisabled = sWorld -> GetUInt64Config ( CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK );
if (( UI64LIT ( 1 ) << ( factionChangeInfo -> RaceID - 1 )) & raceMaskDisabled )
2010-09-06 10:42:53 -07:00
{
2017-01-13 21:38:03 +01:00
SendCharFactionChange ( CHAR_CREATE_ERROR , factionChangeInfo . get ());
2010-09-06 10:42:53 -07:00
return ;
}
}
2010-09-05 13:12:24 -07:00
2016-06-19 10:23:27 +04:30
// prevent character rename
if ( sWorld -> getBoolConfig ( CONFIG_PREVENT_RENAME_CUSTOMIZATION ) && ( factionChangeInfo -> Name != oldName ))
{
SendCharFactionChange ( CHAR_NAME_FAILURE , factionChangeInfo . get ());
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
{
2017-01-13 21:38:03 +01:00
SendCharFactionChange ( CHAR_NAME_NO_NAME , factionChangeInfo . get ());
2010-09-05 13:12:24 -07:00
return ;
}
2015-08-30 00:17:08 +02:00
ResponseCodes res = ObjectMgr :: CheckPlayerName ( factionChangeInfo -> Name , GetSessionDbcLocale (), true );
2010-09-05 13:12:24 -07:00
if ( res != CHAR_NAME_SUCCESS )
{
2017-01-13 21:38:03 +01:00
SendCharFactionChange ( res , factionChangeInfo . get ());
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
{
2017-01-13 21:38:03 +01:00
SendCharFactionChange ( CHAR_NAME_RESERVED , factionChangeInfo . get ());
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
{
2017-01-13 21:38:03 +01:00
SendCharFactionChange ( CHAR_CREATE_NAME_IN_USE , factionChangeInfo . get ());
2010-09-05 13:12:24 -07:00
return ;
}
}
2014-11-12 16:36:05 +01:00
if ( sArenaTeamMgr -> GetArenaTeamByCaptain ( factionChangeInfo -> Guid ))
{
2017-01-13 21:38:03 +01:00
SendCharFactionChange ( CHAR_CREATE_CHARACTER_ARENA_LEADER , factionChangeInfo . get ());
2014-11-12 16:36:05 +01:00
return ;
}
2015-09-28 17:20:27 +02:00
// All checks are fine, deal with race change now
2014-11-12 16:36:05 +01:00
ObjectGuid :: LowType lowGuid = factionChangeInfo -> Guid . GetCounter ();
PreparedStatement * stmt = nullptr ;
2010-09-05 13:12:24 -07:00
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
2012-05-30 08:01:02 +02:00
2015-09-28 17:20:27 +02:00
// resurrect the character in case he's dead
Player :: OfflineResurrect ( factionChangeInfo -> Guid , trans );
// Name Change and update atLogin flags
2014-11-12 16:36:05 +01:00
{
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 );
2015-09-28 17:20:27 +02:00
stmt -> setUInt16 ( 1 , uint16 (( atLoginFlags | AT_LOGIN_RESURRECT ) & ~ usedLoginFlag ));
2014-11-12 16:36:05 +01:00
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
2015-09-28 17:20:27 +02:00
// Customize
2010-09-05 13:12:24 -07:00
{
2016-01-05 00:03:18 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_GENDER_AND_APPEARANCE );
2014-11-12 16:36:05 +01:00
stmt -> setUInt8 ( 0 , factionChangeInfo -> SexID );
2016-01-05 23:29:36 +01:00
stmt -> setUInt8 ( 1 , factionChangeInfo -> SkinID );
stmt -> setUInt8 ( 2 , factionChangeInfo -> FaceID );
stmt -> setUInt8 ( 3 , factionChangeInfo -> HairStyleID );
stmt -> setUInt8 ( 4 , factionChangeInfo -> HairColorID );
stmt -> setUInt8 ( 5 , factionChangeInfo -> FacialHairStyleID );
stmt -> setUInt8 ( 6 , factionChangeInfo -> CustomDisplay [ 0 ]);
stmt -> setUInt8 ( 7 , factionChangeInfo -> CustomDisplay [ 1 ]);
stmt -> setUInt8 ( 8 , factionChangeInfo -> CustomDisplay [ 2 ]);
stmt -> setUInt64 ( 9 , lowGuid );
2014-11-12 16:36:05 +01:00
trans -> Append ( stmt );
}
2015-09-28 17:20:27 +02:00
// Race Change
2014-11-12 16:36:05 +01:00
{
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
2018-09-08 16:49:33 +02:00
if ( factionChangeInfo -> RaceID != RACE_ORC && factionChangeInfo -> RaceID != RACE_HUMAN && factionChangeInfo -> RaceID != RACE_MAGHAR_ORC )
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 :
2018-09-08 16:49:33 +02:00
case RACE_DARK_IRON_DWARF :
2012-10-29 12:28:12 +01:00
stmt -> setUInt16 ( 1 , 111 );
break ;
case RACE_DRAENEI :
2018-08-03 11:01:55 +03:00
case RACE_LIGHTFORGED_DRAENEI :
2012-10-29 12:28:12 +01:00
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 :
2018-08-03 11:01:55 +03:00
case RACE_HIGHMOUNTAIN_TAUREN :
2012-10-29 12:28:12 +01:00
stmt -> setUInt16 ( 1 , 115 );
break ;
case RACE_TROLL :
stmt -> setUInt16 ( 1 , 315 );
break ;
case RACE_BLOODELF :
2018-08-03 11:01:55 +03:00
case RACE_VOID_ELF :
2012-10-29 12:28:12 +01:00
stmt -> setUInt16 ( 1 , 137 );
break ;
2012-11-02 00:18:44 +01:00
case RACE_GOBLIN :
stmt -> setUInt16 ( 1 , 792 );
break ;
2018-08-03 11:01:55 +03:00
case RACE_NIGHTBORNE :
stmt -> setUInt16 ( 1 , 2464 );
break ;
default :
TC_LOG_ERROR ( "entities.player" , "Could not find language data for race (%u)." , factionChangeInfo -> RaceID );
SendCharFactionChange ( CHAR_CREATE_ERROR , factionChangeInfo . get ());
return ;
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
}
2015-09-28 17:20:27 +02:00
// Team Conversion
2014-11-12 16:36:05 +01:00
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 ;
2015-09-19 16:44:33 +02:00
TaxiMask const & factionMask = newTeamId == TEAM_HORDE ? sHordeTaxiNodesMask : sAllianceTaxiNodesMask ;
2018-02-18 16:32:03 +01:00
for ( std :: size_t i = 0 ; i < TaxiMaskSize ; ++ i )
2010-09-05 13:12:24 -07:00
{
2015-09-19 16:44:33 +02:00
// i = (315 - 1) / 8 = 39
// m = 1 << ((315 - 1) % 8) = 4
uint8 deathKnightExtraNode = playerClass != CLASS_DEATH_KNIGHT || i != 39 ? 0 : 4 ;
taximaskstream << uint32 ( factionMask [ i ] | deathKnightExtraNode ) << ' ' ;
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
2015-09-28 17:20:27 +02:00
/// @todo: make this part async
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
2015-07-21 00:33:36 +02:00
if ( PreparedQueryResult memberResult = CharacterDatabase . Query ( stmt ))
if ( Guild * guild = sGuildMgr -> GetGuildById ( memberResult -> Fetch ()[ 0 ]. GetUInt64 ()))
2016-11-19 23:28:52 -03:00
guild -> DeleteMember ( trans , 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 );
2016-05-07 01:16:29 +02:00
stmt -> setUInt32 ( 0 , uint16 ( newTeamId == TEAM_ALLIANCE ? achiev_alliance : achiev_horde ));
stmt -> setUInt32 ( 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 ;
2018-02-10 01:24:00 +01:00
uint64 newRaceMask = ( newTeamId == TEAM_ALLIANCE ) ? RACEMASK_ALLIANCE : RACEMASK_HORDE ;
if ( quest -> GetAllowableRaces () != uint64 ( - 1 ) && ! ( quest -> GetAllowableRaces () & 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
2015-07-21 00:33:36 +02:00
if ( PreparedQueryResult reputationResult = CharacterDatabase . Query ( stmt ))
2012-10-29 12:28:12 +01:00
{
2015-07-21 00:33:36 +02:00
fields = reputationResult -> Fetch ();
2014-10-19 15:12:20 +02:00
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
{
2019-06-03 20:40:34 +02:00
std :: vector < uint32 > knownTitles ;
Tokenizer tokens ( knownTitlesStr , ' ' );
2012-09-27 22:38:19 +01:00
2019-06-03 20:40:34 +02:00
for ( uint32 index = 0 ; index < tokens . size (); ++ index )
knownTitles . push_back ( 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 ;
2016-06-06 09:16:59 +02:00
CharTitlesEntry const * atitleInfo = sCharTitlesStore . AssertEntry ( title_alliance );
CharTitlesEntry const * htitleInfo = sCharTitlesStore . AssertEntry ( title_horde );
2012-10-29 12:28:12 +01:00
// 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 ;
2019-06-03 20:40:34 +02:00
if ( index >= knownTitles . size ())
continue ;
2014-11-07 14:32:47 +02:00
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 ;
2019-06-03 20:40:34 +02:00
if ( index >= knownTitles . size ())
continue ;
2014-11-07 14:32:47 +02:00
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 ;
2019-06-03 20:40:34 +02:00
for ( uint32 index = 0 ; index < knownTitles . size (); ++ index )
2012-10-29 12:28:12 +01:00
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
2017-01-13 21:38:03 +01:00
SendCharFactionChange ( RESPONSE_SUCCESS , factionChangeInfo . get ());
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 ;
2018-03-12 18:20:26 +01:00
result . Name = sDB2Manager . GetNameGenEntry ( packet . Race , packet . Sex );
2014-11-08 02:55:45 +01:00
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
2015-08-01 18:42:07 +02:00
void WorldSession :: HandleOpeningCinematic ( WorldPackets :: Misc :: OpeningCinematic & /*packet*/ )
2012-09-18 01:30:00 +02:00
{
// Only players that has not yet gained any experience can use this
2019-06-03 20:40:34 +02:00
if ( * _player -> m_activePlayerData -> XP )
2012-09-18 01:30:00 +02:00
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
2015-04-01 01:44:10 +02:00
void WorldSession :: HandleGetUndeleteCooldownStatus ( WorldPackets :: Character :: GetUndeleteCharacterCooldownStatus & /*getCooldown*/ )
2014-11-03 19:11:14 +01:00
{
2017-01-13 21:38:03 +01:00
PreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_LAST_CHAR_UNDELETE );
stmt -> setUInt32 ( 0 , GetBattlenetAccountId ());
_queryProcessor . AddQuery ( LoginDatabase . AsyncQuery ( stmt ). WithPreparedCallback ( std :: bind ( & WorldSession :: HandleUndeleteCooldownStatusCallback , this , std :: placeholders :: _1 )));
2014-11-03 19:11:14 +01:00
}
void WorldSession :: HandleUndeleteCooldownStatusCallback ( PreparedQueryResult result )
{
2017-01-13 21:38:03 +01:00
uint32 cooldown = 0 ;
uint32 maxCooldown = sWorld -> getIntConfig ( CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN );
if ( result )
2014-11-03 19:11:14 +01:00
{
2017-01-13 21:38:03 +01:00
uint32 lastUndelete = result -> Fetch ()[ 0 ]. GetUInt32 ();
uint32 now = uint32 ( time ( nullptr ));
if ( lastUndelete + maxCooldown > now )
cooldown = std :: max < uint32 > ( 0 , lastUndelete + maxCooldown - now );
2014-11-03 19:11:14 +01:00
}
2017-01-13 21:38:03 +01:00
SendUndeleteCooldownStatusResponse ( cooldown , maxCooldown );
2014-11-03 19:11:14 +01:00
}
2017-01-13 21:38:03 +01:00
void WorldSession :: HandleCharUndeleteOpcode ( WorldPackets :: Character :: UndeleteCharacter & undeleteCharacter )
2014-11-03 19:11:14 +01:00
{
if ( ! sWorld -> getBoolConfig ( CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED ))
{
2017-01-13 21:38:03 +01:00
SendUndeleteCharacterResponse ( CHARACTER_UNDELETE_RESULT_ERROR_DISABLED , undeleteCharacter . UndeleteInfo . get ());
2014-11-03 19:11:14 +01:00
return ;
}
PreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_LAST_CHAR_UNDELETE );
stmt -> setUInt32 ( 0 , GetBattlenetAccountId ());
2017-01-13 21:38:03 +01:00
std :: shared_ptr < WorldPackets :: Character :: CharacterUndeleteInfo > undeleteInfo = undeleteCharacter . UndeleteInfo ;
_queryProcessor . AddQuery ( LoginDatabase . AsyncQuery ( stmt )
. WithChainingPreparedCallback ([ this , undeleteInfo ]( QueryCallback & queryCallback , PreparedQueryResult result )
2014-11-03 19:11:14 +01:00
{
2017-01-13 21:38:03 +01:00
if ( result )
2014-11-03 19:11:14 +01:00
{
2017-01-13 21:38:03 +01:00
uint32 lastUndelete = result -> Fetch ()[ 0 ]. GetUInt32 ();
uint32 maxCooldown = sWorld -> getIntConfig ( CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN );
if ( lastUndelete && ( lastUndelete + maxCooldown > time ( nullptr )))
2014-11-03 19:11:14 +01:00
{
2017-01-13 21:38:03 +01:00
SendUndeleteCharacterResponse ( CHARACTER_UNDELETE_RESULT_ERROR_COOLDOWN , undeleteInfo . get ());
2014-11-03 19:11:14 +01:00
return ;
}
2017-01-13 21:38:03 +01:00
}
2014-11-03 19:11:14 +01:00
2017-01-13 21:38:03 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHAR_DEL_INFO_BY_GUID );
stmt -> setUInt64 ( 0 , undeleteInfo -> CharacterGuid . GetCounter ());
queryCallback . SetNextQuery ( CharacterDatabase . AsyncQuery ( stmt ));
})
. WithChainingPreparedCallback ([ this , undeleteInfo ]( QueryCallback & queryCallback , PreparedQueryResult result )
{
if ( ! result )
{
SendUndeleteCharacterResponse ( CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE , undeleteInfo . get ());
return ;
}
2014-11-03 19:11:14 +01:00
2017-01-13 21:38:03 +01:00
Field * fields = result -> Fetch ();
undeleteInfo -> Name = fields [ 1 ]. GetString ();
uint32 account = fields [ 2 ]. GetUInt32 ();
2014-11-03 19:11:14 +01:00
2017-01-13 21:38:03 +01:00
if ( account != GetAccountId ())
2014-11-03 19:11:14 +01:00
{
2017-01-13 21:38:03 +01:00
SendUndeleteCharacterResponse ( CHARACTER_UNDELETE_RESULT_ERROR_UNKNOWN , undeleteInfo . get ());
return ;
}
2014-11-03 19:11:14 +01:00
2017-01-13 21:38:03 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHECK_NAME );
stmt -> setString ( 0 , undeleteInfo -> Name );
queryCallback . SetNextQuery ( CharacterDatabase . AsyncQuery ( stmt ));
})
. WithChainingPreparedCallback ([ this , undeleteInfo ]( QueryCallback & queryCallback , PreparedQueryResult result )
{
if ( result )
{
SendUndeleteCharacterResponse ( CHARACTER_UNDELETE_RESULT_ERROR_NAME_TAKEN_BY_THIS_ACCOUNT , undeleteInfo . get ());
return ;
}
2014-11-03 19:11:14 +01:00
2017-01-13 21:38:03 +01:00
/// @todo: add more safety checks
/// * max char count per account
2017-03-17 19:00:33 +01:00
/// * max death knight count
2017-03-17 19:08:38 +01:00
/// * max demon hunter count
2017-01-13 21:38:03 +01:00
/// * team violation
2014-11-03 19:11:14 +01:00
2017-01-13 21:38:03 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_SUM_CHARS );
stmt -> setUInt32 ( 0 , GetAccountId ());
queryCallback . SetNextQuery ( CharacterDatabase . AsyncQuery ( stmt ));
})
. WithPreparedCallback ([ this , undeleteInfo ]( PreparedQueryResult result )
{
if ( result )
2014-11-03 19:11:14 +01:00
{
2017-01-13 21:38:03 +01:00
Field * fields = result -> Fetch ();
2014-11-03 19:11:14 +01:00
2017-01-13 21:38:03 +01:00
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 . get ());
return ;
2014-11-03 19:11:14 +01:00
}
2017-01-13 21:38:03 +01:00
}
2014-11-03 19:11:14 +01:00
2017-01-13 21:38:03 +01:00
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 );
2014-11-03 19:11:14 +01:00
2017-01-13 21:38:03 +01:00
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_UPD_LAST_CHAR_UNDELETE );
stmt -> setUInt32 ( 0 , GetBattlenetAccountId ());
LoginDatabase . Execute ( stmt );
2014-11-03 19:11:14 +01:00
2017-01-13 21:38:03 +01:00
sWorld -> UpdateCharacterInfoDeleted ( undeleteInfo -> CharacterGuid , false , & undeleteInfo -> Name );
2014-11-03 19:11:14 +01:00
2017-01-13 21:38:03 +01:00
SendUndeleteCharacterResponse ( CHARACTER_UNDELETE_RESULT_OK , undeleteInfo . get ());
}));
2014-11-03 19:11:14 +01:00
}
2018-10-04 18:50:21 +02:00
void WorldSession :: SendCharCreate ( ResponseCodes result , ObjectGuid const & guid /*= ObjectGuid::Empty*/ )
2014-10-19 15:12:20 +02:00
{
2015-04-01 01:44:10 +02:00
WorldPackets :: Character :: CreateChar response ;
2014-11-03 19:11:14 +01:00
response . Code = result ;
2018-10-04 18:50:21 +02:00
response . Guid = guid ;
2014-11-03 19:11:14 +01:00
2014-11-03 20:23:21 +01:00
SendPacket ( response . Write ());
2014-10-19 15:12:20 +02:00
}
void WorldSession :: SendCharDelete ( ResponseCodes result )
{
2015-04-01 01:44:10 +02:00
WorldPackets :: Character :: DeleteChar response ;
2014-11-03 19:11:14 +01:00
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 )
2015-04-26 23:45:52 +02:00
packet . Guid = renameInfo -> Guid ;
2014-11-12 16:36:05 +01:00
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
{
if ( result == RESPONSE_SUCCESS )
{
2015-05-28 18:46:45 +02:00
WorldPackets :: Character :: CharCustomizeResponse response ( customizeInfo );
SendPacket ( response . Write ());
}
else
{
WorldPackets :: Character :: CharCustomizeFailed failed ;
failed . Result = uint8 ( result );
failed . CharGUID = customizeInfo -> CharGUID ;
SendPacket ( failed . Write ());
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 )
{
2015-04-27 17:01:30 +02:00
packet . Display = boost :: in_place ();
2015-04-26 23:45:52 +02:00
packet . Display -> Name = factionChangeInfo -> Name ;
packet . Display -> SexID = factionChangeInfo -> SexID ;
2016-01-05 23:29:36 +01:00
packet . Display -> SkinID = factionChangeInfo -> SkinID ;
packet . Display -> HairColorID = factionChangeInfo -> HairColorID ;
packet . Display -> HairStyleID = factionChangeInfo -> HairStyleID ;
packet . Display -> FacialHairStyleID = factionChangeInfo -> FacialHairStyleID ;
packet . Display -> FaceID = factionChangeInfo -> FaceID ;
2015-04-26 23:45:52 +02:00
packet . Display -> RaceID = factionChangeInfo -> RaceID ;
2016-01-05 23:29:36 +01:00
packet . Display -> CustomDisplay = factionChangeInfo -> CustomDisplay ;
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 )
{
2016-02-07 21:02:35 +01:00
WorldPackets :: Character :: SetPlayerDeclinedNamesResult packet ;
packet . ResultCode = result ;
packet . Player = guid ;
SendPacket ( packet . Write ());
2014-10-19 15:12:20 +02:00
}
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
}