2008-10-11 14:16:25 -05:00
/*
2009-02-04 12:42:26 +01:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2009-02-04 12:04:12 +01:00
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
2008-10-11 14:16:25 -05:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
2008-11-20 17:40:13 -06:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-11 14:16:25 -05:00
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
2008-11-20 17:40:13 -06:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-11 14:16:25 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
#include "Common.h"
2009-06-04 21:41:07 +02:00
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "SystemConfig.h"
#include "World.h"
2008-10-11 14:16:25 -05:00
#include "WorldPacket.h"
#include "WorldSession.h"
#include "Auth/md5.h"
2009-06-04 21:41:07 +02:00
#include "Database/DatabaseEnv.h"
2008-10-11 14:16:25 -05:00
#include "Database/DatabaseImpl.h"
2009-10-17 15:51:44 -07:00
2009-06-04 21:41:07 +02:00
#include "ArenaTeam.h"
#include "Chat.h"
#include "Group.h"
#include "Guild.h"
#include "Language.h"
#include "Log.h"
#include "Opcodes.h"
#include "Player.h"
2008-10-11 14:16:25 -05:00
#include "PlayerDump.h"
2009-06-04 21:41:07 +02:00
#include "SharedDefines.h"
2008-10-11 14:16:25 -05:00
#include "SocialMgr.h"
2009-06-04 21:41:07 +02:00
#include "UpdateMask.h"
2008-10-11 14:16:25 -05:00
#include "Util.h"
2009-09-13 00:01:35 -07:00
#include "ScriptCalls.h"
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
class LoginQueryHolder : public SqlQueryHolder
{
private :
uint32 m_accountId ;
uint64 m_guid ;
public :
LoginQueryHolder ( uint32 accountId , uint64 guid )
: m_accountId ( accountId ), m_guid ( guid ) { }
uint64 GetGuid () const { return m_guid ; }
uint32 GetAccountId () const { return m_accountId ; }
bool Initialize ();
};
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool LoginQueryHolder :: Initialize ()
{
SetSize ( MAX_PLAYER_LOGIN_QUERY );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool res = true ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// NOTE: all fields in `characters` must be read to prevent lost character data at next save in case wrong DB structure.
// !!! NOTE: including unused `zone`,`online`
2009-08-14 17:24:52 -07:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADFROM , "SELECT guid, account, data, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points, instance_id, speccount, activespec FROM characters WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
2008-10-11 14:16:25 -05:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADGROUP , "SELECT leaderGuid FROM group_member WHERE memberGuid ='%u'" , GUID_LOPART ( m_guid ));
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES , "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
2009-04-06 13:31:14 +02:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADAURAS , "SELECT caster_guid,spell,effect_mask,stackcount,amount0, amount1, amount2 ,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
2009-01-09 16:06:17 -06:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADSPELLS , "SELECT spell,active,disabled FROM character_spell WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
2008-10-11 14:16:25 -05:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADQUESTSTATUS , "SELECT quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4 FROM character_queststatus WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS , "SELECT quest,time FROM character_queststatus_daily WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADREPUTATION , "SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADINVENTORY , "SELECT data,bag,slot,item,item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag,slot" , GUID_LOPART ( m_guid ));
2009-08-14 17:24:52 -07:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADACTIONS , "SELECT a.button,a.action,a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activespec AND a.guid = '%u' ORDER BY button" , GUID_LOPART ( m_guid ));
2009-05-31 16:15:12 -05:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADMAILCOUNT , "SELECT COUNT(id) FROM mail WHERE receiver = '%u' AND (checked & 1)=0 AND deliver_time <= '" UI64FMTD "'" , GUID_LOPART ( m_guid ),( uint64 ) time ( NULL ));
2008-10-11 14:16:25 -05:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADMAILDATE , "SELECT MIN(deliver_time) FROM mail WHERE receiver = '%u' AND (checked & 1)=0" , GUID_LOPART ( m_guid ));
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADSOCIALLIST , "SELECT friend,flags,note FROM character_social WHERE guid = '%u' LIMIT 255" , GUID_LOPART ( m_guid ));
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADHOMEBIND , "SELECT map,zone,position_x,position_y,position_z FROM character_homebind WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS , "SELECT spell,item,time FROM character_spell_cooldown WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
if ( sWorld . getConfig ( CONFIG_DECLINED_NAMES_USED ))
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES , "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
// in other case still be dummy query
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADGUILD , "SELECT guildid,rank FROM guild_member WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
2009-01-22 22:44:27 -06:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADARENAINFO , "SELECT arenateamid, played_week, played_season, personal_rating FROM arena_team_member WHERE guid='%u'" , GUID_LOPART ( m_guid ));
2008-12-24 09:58:26 -06:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS , "SELECT achievement, date FROM character_achievement WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS , "SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
2009-06-11 00:45:59 -05:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS , "SELECT setguid, setindex, name, iconname, item0, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE guid = '%u' ORDER BY setindex" , GUID_LOPART ( m_guid ));
2009-08-12 20:27:00 -05:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADBGDATA , "SELECT instance_id, team, join_x, join_y, join_z, join_o, join_map, taxi_start, taxi_end, mount_spell FROM character_battleground_data WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
2009-08-14 17:24:52 -07:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADGLYPHS , "SELECT spec, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6 FROM character_glyphs WHERE guid='%u'" , GUID_LOPART ( m_guid ));
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADTALENTS , "SELECT spell, spec FROM character_talent WHERE guid='%u'" , GUID_LOPART ( m_guid ));
2009-09-01 16:47:49 -05:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADACCOUNTDATA , "SELECT type, time, data FROM character_account_data WHERE guid='%u'" , GUID_LOPART ( m_guid ));
2009-12-14 20:47:43 +01:00
res &= SetPQuery ( PLAYER_LOGIN_QUERY_LOADSKILLS , "SELECT skill, value, max FROM character_skills WHERE guid = '%u'" , GUID_LOPART ( m_guid ));
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return res ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// don't call WorldSession directly
// it may get deleted before the query callbacks get executed
// instead pass an account id to this handler
class CharacterHandler
{
public :
void HandleCharEnumCallback ( QueryResult * result , uint32 account )
{
WorldSession * session = sWorld . FindSession ( account );
if ( ! session )
{
delete result ;
return ;
}
session -> HandleCharEnum ( result );
}
void HandlePlayerLoginCallback ( QueryResult * /*dummy*/ , SqlQueryHolder * holder )
{
if ( ! holder ) return ;
WorldSession * session = sWorld . FindSession ((( LoginQueryHolder * ) holder ) -> GetAccountId ());
if ( ! session )
{
delete holder ;
return ;
}
session -> HandlePlayerLogin (( LoginQueryHolder * ) holder );
}
} chrHandler ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleCharEnum ( QueryResult * result )
{
WorldPacket data ( SMSG_CHAR_ENUM , 100 ); // we guess size
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint8 num = 0 ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
data << num ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( result )
{
do
{
2008-11-05 09:22:56 -06:00
uint32 guidlow = ( * result )[ 0 ]. GetUInt32 ();
sLog . outDetail ( "Loading char guid %u from account %u." , guidlow , GetAccountId ());
2009-06-27 17:39:51 -05:00
if ( Player :: BuildEnumData ( result , & data ))
2008-10-11 14:16:25 -05:00
++ num ;
}
while ( result -> NextRow () );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
delete result ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
data . put < uint8 > ( 0 , num );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleCharEnumOpcode ( WorldPacket & /*recv_data*/ )
{
/// get all the data necessary for loading all characters (along with their pets) on the account
CharacterDatabase . AsyncPQuery ( & chrHandler , & CharacterHandler :: HandleCharEnumCallback , GetAccountId (),
! sWorld . getConfig ( CONFIG_DECLINED_NAMES_USED ) ?
// ------- Query Without Declined Names --------
2009-06-27 17:39:51 -05:00
// 0 1 2 3 4 5 6 7
"SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, "
// 8 9 10 11 12 13 14
"characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, "
// 15 16 17 18 19
"characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data "
2009-04-10 18:18:44 -05:00
"FROM characters LEFT JOIN character_pet ON characters.guid=character_pet.owner AND character_pet.slot='%u' "
2008-11-30 12:47:26 -06:00
"LEFT JOIN guild_member ON characters.guid = guild_member.guid "
2008-10-11 14:16:25 -05:00
"WHERE characters.account = '%u' ORDER BY characters.guid"
:
// --------- Query With Declined Names ---------
2009-06-27 17:39:51 -05:00
// 0 1 2 3 4 5 6 7
"SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, "
// 8 9 10 11 12 13 14
"characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, "
// 15 16 17 18 19 20
"characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data, character_declinedname.genitive "
2009-04-10 18:18:44 -05:00
"FROM characters LEFT JOIN character_pet ON characters.guid = character_pet.owner AND character_pet.slot='%u' "
2008-10-11 14:16:25 -05:00
"LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid "
2008-11-30 12:47:26 -06:00
"LEFT JOIN guild_member ON characters.guid = guild_member.guid "
2008-10-11 14:16:25 -05:00
"WHERE characters.account = '%u' ORDER BY characters.guid" ,
2009-04-10 18:18:44 -05:00
PET_SAVE_AS_CURRENT , GetAccountId ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleCharCreateOpcode ( WorldPacket & recv_data )
{
std :: string name ;
uint8 race_ , class_ ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recv_data >> name ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recv_data >> race_ ;
recv_data >> class_ ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
WorldPacket data ( SMSG_CHAR_CREATE , 1 ); // returned with diff.values in all cases
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( GetSecurity () == SEC_PLAYER )
{
if ( uint32 mask = sWorld . getConfig ( CONFIG_CHARACTERS_CREATING_DISABLED ))
{
bool disabled = false ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 team = Player :: TeamForRace ( race_ );
switch ( team )
{
case ALLIANCE : disabled = mask & ( 1 << 0 ); break ;
case HORDE : disabled = mask & ( 1 << 1 ); break ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( disabled )
{
data << ( uint8 ) CHAR_CREATE_DISABLED ;
SendPacket ( & data );
return ;
}
}
}
2009-10-17 15:51:44 -07:00
2008-10-20 12:23:56 -05:00
ChrClassesEntry const * classEntry = sChrClassesStore . LookupEntry ( class_ );
ChrRacesEntry const * raceEntry = sChrRacesStore . LookupEntry ( race_ );
2009-10-17 15:51:44 -07:00
2008-10-20 12:23:56 -05:00
if ( ! classEntry || ! raceEntry )
2008-10-11 14:16:25 -05:00
{
data << ( uint8 ) CHAR_CREATE_FAILED ;
SendPacket ( & data );
sLog . outError ( "Class: %u or Race %u not found in DBC (Wrong DBC files?) or Cheater?" , class_ , race_ );
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
2008-10-20 12:23:56 -05:00
if ( raceEntry -> addon > Expansion ())
2008-10-11 14:16:25 -05:00
{
data << ( uint8 ) CHAR_CREATE_EXPANSION ;
2008-12-24 09:58:26 -06:00
sLog . outError ( "Expansion %u account:[%d] tried to Create character with expansion %u race (%u)" , Expansion (), GetAccountId (), raceEntry -> addon , race_ );
2008-10-20 12:23:56 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-20 12:23:56 -05:00
// prevent character creating Expansion class without Expansion account
2008-12-24 09:58:26 -06:00
if ( classEntry -> addon > Expansion ())
2008-10-20 12:23:56 -05:00
{
2008-12-24 09:58:26 -06:00
data << ( uint8 ) CHAR_CREATE_EXPANSION_CLASS ;
sLog . outError ( "Expansion %u account:[%d] tried to Create character with expansion %u class (%u)" , Expansion (), GetAccountId (), classEntry -> addon , class_ );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// prevent character creating with invalid name
2009-07-10 08:25:33 +08:00
if ( ! normalizePlayerName ( name ))
2008-10-11 14:16:25 -05:00
{
2009-07-10 08:25:33 +08:00
data << ( uint8 ) CHAR_NAME_NO_NAME ;
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
sLog . outError ( "Account:[%d] but tried to Create character with empty [name] " , GetAccountId ());
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// check name limitations
2009-07-10 08:25:33 +08:00
uint8 res = ObjectMgr :: CheckPlayerName ( name , true );
if ( res != CHAR_NAME_SUCCESS )
2008-10-11 14:16:25 -05:00
{
2009-07-10 08:25:33 +08:00
data << uint8 ( res );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2009-07-10 08:25:33 +08:00
if ( GetSecurity () == SEC_PLAYER && objmgr . IsReservedName ( name ))
2008-10-11 14:16:25 -05:00
{
data << ( uint8 ) CHAR_NAME_RESERVED ;
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2009-07-10 08:25:33 +08:00
if ( objmgr . GetPlayerGUIDByName ( name ))
2008-10-11 14:16:25 -05:00
{
data << ( uint8 ) CHAR_CREATE_NAME_IN_USE ;
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2009-07-31 11:29:28 +08:00
QueryResult * resultacct = loginDatabase . PQuery ( "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'" , GetAccountId ());
2009-07-10 08:25:33 +08:00
if ( resultacct )
2008-10-11 14:16:25 -05:00
{
Field * fields = resultacct -> Fetch ();
uint32 acctcharcount = fields [ 0 ]. GetUInt32 ();
delete resultacct ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( acctcharcount >= sWorld . getConfig ( CONFIG_CHARACTERS_PER_ACCOUNT ))
{
data << ( uint8 ) CHAR_CREATE_ACCOUNT_LIMIT ;
SendPacket ( & data );
return ;
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
QueryResult * result = CharacterDatabase . PQuery ( "SELECT COUNT(guid) FROM characters WHERE account = '%d'" , GetAccountId ());
uint8 charcount = 0 ;
if ( result )
{
Field * fields = result -> Fetch ();
charcount = fields [ 0 ]. GetUInt8 ();
delete result ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( charcount >= sWorld . getConfig ( CONFIG_CHARACTERS_PER_REALM ))
{
data << ( uint8 ) CHAR_CREATE_SERVER_LIMIT ;
SendPacket ( & data );
return ;
}
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// speedup check for heroic class disabled case
uint32 heroic_free_slots = sWorld . getConfig ( CONFIG_HEROIC_CHARACTERS_PER_REALM );
if ( heroic_free_slots == 0 && GetSecurity () == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT )
{
data << ( uint8 ) CHAR_CREATE_UNIQUE_CLASS_LIMIT ;
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// speedup check for heroic class disabled case
uint32 req_level_for_heroic = sWorld . getConfig ( CONFIG_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING );
if ( GetSecurity () == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && req_level_for_heroic > sWorld . getConfig ( CONFIG_MAX_PLAYER_LEVEL ))
{
data << ( uint8 ) CHAR_CREATE_LEVEL_REQUIREMENT ;
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool AllowTwoSideAccounts = ! sWorld . IsPvPRealm () || sWorld . getConfig ( CONFIG_ALLOW_TWO_SIDE_ACCOUNTS ) || GetSecurity () > SEC_PLAYER ;
uint32 skipCinematics = sWorld . getConfig ( CONFIG_SKIP_CINEMATICS );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool have_same_race = false ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// if 0 then allowed creating without any characters
bool have_req_level_for_heroic = ( req_level_for_heroic == 0 );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( ! AllowTwoSideAccounts || skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT )
2008-10-11 14:16:25 -05:00
{
2009-06-27 17:39:51 -05:00
QueryResult * result2 = CharacterDatabase . PQuery ( "SELECT level,race,class FROM characters WHERE account = '%u' %s" ,
2008-12-24 09:58:26 -06:00
GetAccountId (), ( skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT ) ? "" : "LIMIT 1" );
2008-10-11 14:16:25 -05:00
if ( result2 )
{
uint32 team_ = Player :: TeamForRace ( race_ );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
Field * field = result2 -> Fetch ();
2008-12-24 09:58:26 -06:00
uint8 acc_race = field [ 1 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( GetSecurity () == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT )
{
uint8 acc_class = field [ 2 ]. GetUInt32 ();
if ( acc_class == CLASS_DEATH_KNIGHT )
{
if ( heroic_free_slots > 0 )
-- heroic_free_slots ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( heroic_free_slots == 0 )
{
data << ( uint8 ) CHAR_CREATE_UNIQUE_CLASS_LIMIT ;
SendPacket ( & data );
return ;
}
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( ! have_req_level_for_heroic )
{
2009-06-27 17:39:51 -05:00
uint32 acc_level = field [ 0 ]. GetUInt32 ();
2008-12-24 09:58:26 -06:00
if ( acc_level >= req_level_for_heroic )
have_req_level_for_heroic = true ;
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// need to check team only for first character
// TODO: what to if account already has characters of both races?
if ( ! AllowTwoSideAccounts )
{
2008-12-24 09:58:26 -06:00
uint32 acc_team = 0 ;
if ( acc_race > 0 )
acc_team = Player :: TeamForRace ( acc_race );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( acc_team != team_ )
2008-10-11 14:16:25 -05:00
{
data << ( uint8 ) CHAR_CREATE_PVP_TEAMS_VIOLATION ;
SendPacket ( & data );
delete result2 ;
return ;
}
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// search same race for cinematic or same class if need
// TODO: check if cinematic already shown? (already logged in?; cinematic field)
while (( skipCinematics == 1 && ! have_same_race ) || class_ == CLASS_DEATH_KNIGHT )
2008-10-11 14:16:25 -05:00
{
2008-12-24 09:58:26 -06:00
if ( ! result2 -> NextRow ())
break ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
field = result2 -> Fetch ();
acc_race = field [ 1 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( ! have_same_race )
have_same_race = race_ == acc_race ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( GetSecurity () == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT )
2008-10-11 14:16:25 -05:00
{
2008-12-24 09:58:26 -06:00
uint8 acc_class = field [ 2 ]. GetUInt32 ();
if ( acc_class == CLASS_DEATH_KNIGHT )
{
if ( heroic_free_slots > 0 )
-- heroic_free_slots ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( heroic_free_slots == 0 )
{
data << ( uint8 ) CHAR_CREATE_UNIQUE_CLASS_LIMIT ;
SendPacket ( & data );
return ;
}
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( ! have_req_level_for_heroic )
{
2009-06-27 17:39:51 -05:00
uint32 acc_level = field [ 0 ]. GetUInt32 ();
2008-12-24 09:58:26 -06:00
if ( acc_level >= req_level_for_heroic )
have_req_level_for_heroic = true ;
}
2008-10-11 14:16:25 -05:00
}
}
delete result2 ;
}
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( GetSecurity () == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && ! have_req_level_for_heroic )
{
data << ( uint8 ) CHAR_CREATE_LEVEL_REQUIREMENT ;
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// extract other data required for player creating
uint8 gender , skin , face , hairStyle , hairColor , facialHair , outfitId ;
2009-08-24 02:41:01 +02:00
recv_data >> gender ;
recv_data >> skin ;
recv_data >> face ;
recv_data >> hairStyle ;
recv_data >> hairColor ;
recv_data >> facialHair ;
recv_data >> outfitId ;
2009-10-17 16:20:24 -07:00
2009-08-24 02:41:01 +02:00
if ( recv_data . rpos () < recv_data . wpos ())
{
uint8 unk ;
recv_data >> unk ;
sLog . outDebug ( "Character creation %s (account %u) has unhandled tail data: [%u]" , name . c_str (), GetAccountId (), unk );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
Player * pNewChar = new Player ( this );
if ( ! pNewChar -> Create ( objmgr . GenerateLowGuid ( HIGHGUID_PLAYER ), name , race_ , class_ , gender , skin , face , hairStyle , hairColor , facialHair , outfitId ))
{
// Player not create (race/class problem?)
delete pNewChar ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
data << ( uint8 ) CHAR_CREATE_ERROR ;
SendPacket ( & data );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-02-24 11:14:28 -06:00
if (( have_same_race && skipCinematics == 1 ) || skipCinematics == 2 )
2008-10-11 14:16:25 -05:00
pNewChar -> setCinematic ( 1 ); // not show intro
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Player created, save it now
pNewChar -> SaveToDB ();
charcount += 1 ;
2009-10-17 15:51:44 -07:00
2009-07-31 11:29:28 +08:00
loginDatabase . PExecute ( "DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'" , GetAccountId (), realmID );
loginDatabase . PExecute ( "INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)" , charcount , GetAccountId (), realmID );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
delete pNewChar ; // created only to call SaveToDB()
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
data << ( uint8 ) CHAR_CREATE_SUCCESS ;
SendPacket ( & data );
2009-10-17 15:51:44 -07:00
2008-11-02 16:53:46 -06:00
std :: string IP_str = GetRemoteAddress ();
2009-01-15 22:01:47 -05:00
sLog . outDetail ( "Account: %d (IP: %s) Create Character:[%s]" , GetAccountId (), IP_str . c_str (), name . c_str ());
2008-10-11 14:16:25 -05:00
sLog . outChar ( "Account: %d (IP: %s) Create Character:[%s]" , GetAccountId (), IP_str . c_str (), name . c_str ());
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleCharDeleteOpcode ( WorldPacket & recv_data )
{
uint64 guid ;
recv_data >> guid ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// can't delete loaded character
if ( objmgr . GetPlayer ( guid ))
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 accountId = 0 ;
std :: string name ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// is guild leader
if ( objmgr . GetGuildByLeader ( guid ))
{
WorldPacket data ( SMSG_CHAR_DELETE , 1 );
data << ( uint8 ) CHAR_DELETE_FAILED_GUILD_LEADER ;
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// is arena team captain
2008-12-19 16:05:13 -06:00
if ( objmgr . GetArenaTeamByCaptain ( guid ))
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_CHAR_DELETE , 1 );
data << ( uint8 ) CHAR_DELETE_FAILED_ARENA_CAPTAIN ;
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
QueryResult * result = CharacterDatabase . PQuery ( "SELECT account,name FROM characters WHERE guid='%u'" , GUID_LOPART ( guid ));
if ( result )
{
Field * fields = result -> Fetch ();
accountId = fields [ 0 ]. GetUInt32 ();
name = fields [ 1 ]. GetCppString ();
delete result ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// prevent deleting other players' characters using cheating tools
if ( accountId != GetAccountId ())
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
std :: string IP_str = GetRemoteAddress ();
2009-03-25 16:07:19 -06:00
sLog . outDetail ( "Account: %d (IP: %s) Delete Character:[%s] (guid: %u)" , GetAccountId (), IP_str . c_str (), name . c_str (), GUID_LOPART ( guid ));
2008-10-11 14:16:25 -05:00
sLog . outChar ( "Account: %d (IP: %s) Delete Character:[%s] (guid: %u)" , GetAccountId (), IP_str . c_str (), name . c_str (), GUID_LOPART ( guid ));
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( sLog . IsOutCharDump ()) // optimize GetPlayerDump call
{
std :: string dump = PlayerDumpWriter (). GetDump ( GUID_LOPART ( guid ));
sLog . outCharDump ( dump . c_str (), GetAccountId (), GUID_LOPART ( guid ), name . c_str ());
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
Player :: DeleteFromDB ( guid , GetAccountId ());
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
WorldPacket data ( SMSG_CHAR_DELETE , 1 );
data << ( uint8 ) CHAR_DELETE_SUCCESS ;
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandlePlayerLoginOpcode ( WorldPacket & recv_data )
{
2008-12-19 16:05:13 -06:00
if ( PlayerLoading () || GetPlayer () != NULL )
{
sLog . outError ( "Player tryes to login again, AccountId = %d" , GetAccountId ());
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_playerLoading = true ;
uint64 playerGuid = 0 ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
DEBUG_LOG ( "WORLD: Recvd Player Logon Message" );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recv_data >> playerGuid ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
LoginQueryHolder * holder = new LoginQueryHolder ( GetAccountId (), playerGuid );
if ( ! holder -> Initialize ())
{
delete holder ; // delete all unprocessed queries
m_playerLoading = false ;
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
CharacterDatabase . DelayQueryHolder ( & chrHandler , & CharacterHandler :: HandlePlayerLoginCallback , holder );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandlePlayerLogin ( LoginQueryHolder * holder )
{
uint64 playerGuid = holder -> GetGuid ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
Player * pCurrChar = new Player ( this );
2009-02-09 08:16:34 -05:00
// for send server info and strings (config)
2008-12-31 11:06:52 +01:00
ChatHandler chH = ChatHandler ( pCurrChar );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// "GetAccountId()==db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools)
if ( ! pCurrChar -> LoadFromDB ( GUID_LOPART ( playerGuid ), holder ))
{
KickPlayer (); // disconnect client, player no set to session and it will not deleted or saved at kick
delete pCurrChar ; // delete it manually
delete holder ; // delete all unprocessed queries
m_playerLoading = false ;
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-09 10:48:55 -05:00
pCurrChar -> GetMotionMaster () -> Initialize ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SetPlayer ( pCurrChar );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
pCurrChar -> SendDungeonDifficulty ( false );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
WorldPacket data ( SMSG_LOGIN_VERIFY_WORLD , 20 );
data << pCurrChar -> GetMapId ();
data << pCurrChar -> GetPositionX ();
data << pCurrChar -> GetPositionY ();
data << pCurrChar -> GetPositionZ ();
data << pCurrChar -> GetOrientation ();
SendPacket ( & data );
2009-10-17 15:51:44 -07:00
2009-09-01 16:47:49 -05:00
// load player specific part before send times
LoadAccountData ( holder -> GetResult ( PLAYER_LOGIN_QUERY_LOADACCOUNTDATA ), PER_CHARACTER_CACHE_MASK );
SendAccountDataTimes ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
data . Initialize ( SMSG_FEATURE_SYSTEM_STATUS , 2 ); // added in 2.2.0
data << uint8 ( 2 ); // unknown value
data << uint8 ( 0 ); // enable(1)/disable(0) voice chat interface in client
SendPacket ( & data );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Send MOTD
{
data . Initialize ( SMSG_MOTD , 50 ); // new in 2.0.1
data << ( uint32 ) 0 ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 linecount = 0 ;
std :: string str_motd = sWorld . GetMotd ();
std :: string :: size_type pos , nextpos ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
pos = 0 ;
while ( ( nextpos = str_motd . find ( '@' , pos )) != std :: string :: npos )
{
if ( nextpos != pos )
{
data << str_motd . substr ( pos , nextpos - pos );
++ linecount ;
}
pos = nextpos + 1 ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( pos < str_motd . length ())
{
data << str_motd . substr ( pos );
++ linecount ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
data . put ( 0 , linecount );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
DEBUG_LOG ( "WORLD: Sent motd (SMSG_MOTD)" );
2009-10-17 15:51:44 -07:00
2009-02-09 08:16:34 -05:00
// send server info
2008-12-31 11:06:52 +01:00
if ( sWorld . getConfig ( CONFIG_ENABLE_SINFO_LOGIN ) == 1 )
chH . PSendSysMessage ( _FULLVERSION );
2009-10-17 15:51:44 -07:00
2008-12-31 11:06:52 +01:00
DEBUG_LOG ( "WORLD: Sent server info" );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-03-21 14:53:38 -06:00
data . Initialize ( SMSG_LEARNED_DANCE_MOVES , 4 + 4 );
data << uint32 ( 0 );
data << uint32 ( 0 );
SendPacket ( & data );
2009-10-17 15:51:44 -07:00
2008-11-30 12:47:26 -06:00
//QueryResult *result = CharacterDatabase.PQuery("SELECT guildid,rank FROM guild_member WHERE guid = '%u'",pCurrChar->GetGUIDLow());
QueryResult * resultGuild = holder -> GetResult ( PLAYER_LOGIN_QUERY_LOADGUILD );
2009-10-17 15:51:44 -07:00
2008-11-30 12:47:26 -06:00
if ( resultGuild )
{
Field * fields = resultGuild -> Fetch ();
pCurrChar -> SetInGuild ( fields [ 0 ]. GetUInt32 ());
pCurrChar -> SetRank ( fields [ 1 ]. GetUInt32 ());
delete resultGuild ;
}
else if ( pCurrChar -> GetGuildId ()) // clear guild related fields in case wrong data about non existed membership
{
pCurrChar -> SetInGuild ( 0 );
pCurrChar -> SetRank ( 0 );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( pCurrChar -> GetGuildId () != 0 )
{
Guild * guild = objmgr . GetGuildById ( pCurrChar -> GetGuildId ());
if ( guild )
{
data . Initialize ( SMSG_GUILD_EVENT , ( 2 + guild -> GetMOTD (). size () + 1 ));
data << ( uint8 ) GE_MOTD ;
data << ( uint8 ) 1 ;
data << guild -> GetMOTD ();
SendPacket ( & data );
DEBUG_LOG ( "WORLD: Sent guild-motd (SMSG_GUILD_EVENT)" );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
data . Initialize ( SMSG_GUILD_EVENT , ( 5 + 10 )); // we guess size
data << ( uint8 ) GE_SIGNED_ON ;
data << ( uint8 ) 1 ;
data << pCurrChar -> GetName ();
data << pCurrChar -> GetGUID ();
guild -> BroadcastPacket ( & data );
DEBUG_LOG ( "WORLD: Sent guild-signed-on (SMSG_GUILD_EVENT)" );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Increment online members of the guild
guild -> IncOnlineMemberCount ();
}
else
{
// remove wrong guild data
sLog . outError ( "Player %s (GUID: %u) marked as member not existed guild (id: %u), removing guild membership for player." , pCurrChar -> GetName (), pCurrChar -> GetGUIDLow (), pCurrChar -> GetGuildId ());
2008-11-30 12:47:26 -06:00
pCurrChar -> SetInGuild ( 0 );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( ! pCurrChar -> isAlive ())
pCurrChar -> SendCorpseReclaimDelay ( true );
2009-10-17 15:51:44 -07:00
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
if ( ! pCurrChar -> getCinematic () )
{
pCurrChar -> setCinematic ( 1 );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( ChrClassesEntry const * cEntry = sChrClassesStore . LookupEntry ( pCurrChar -> getClass ()))
2008-10-11 14:16:25 -05:00
{
2009-04-05 16:25:00 -05:00
if ( cEntry -> CinematicSequence )
pCurrChar -> SendCinematicStart ( cEntry -> CinematicSequence );
else if ( ChrRacesEntry const * rEntry = sChrRacesStore . LookupEntry ( pCurrChar -> getRace ()))
pCurrChar -> SendCinematicStart ( rEntry -> CinematicSequence );
2009-10-17 15:51:44 -07:00
2009-02-09 08:16:34 -05:00
// send new char string if not empty
2008-12-31 11:06:52 +01:00
if ( ! sWorld . GetNewCharString (). empty ())
chH . PSendSysMessage ( 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
2008-12-04 10:56:50 -06:00
if ( ! pCurrChar -> GetMap () -> Add ( pCurrChar ))
2008-10-11 14:16:25 -05:00
{
2008-12-04 10:56:50 -06:00
AreaTrigger const * at = objmgr . GetGoBackTrigger ( pCurrChar -> GetMapId ());
if ( at )
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
2008-10-11 14:16:25 -05:00
ObjectAccessor :: Instance (). AddObject ( pCurrChar );
//sLog.outDebug("Player %s added to Map.",pCurrChar->GetName());
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
pCurrChar -> SendInitialPacketsAfterAddToMap ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
CharacterDatabase . PExecute ( "UPDATE characters SET online = 1 WHERE guid = '%u'" , pCurrChar -> GetGUIDLow ());
2009-07-31 11:29:28 +08:00
loginDatabase . PExecute ( "UPDATE account SET online = 1 WHERE id = '%u'" , GetAccountId ());
2008-10-11 14:16:25 -05: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)
if ( Group * group = pCurrChar -> GetGroup ())
{
//pCurrChar->groupInfo.group->SendInit(this); // useless
group -> SendUpdate ();
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// friend status
2008-11-05 20:10:19 -06:00
sSocialMgr . SendFriendStatus ( pCurrChar , FRIEND_ONLINE , pCurrChar -> GetGUIDLow (), true );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Place character in world (and load zone) before some object loading
pCurrChar -> LoadCorpse ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// setting Ghost+speed if dead
if ( pCurrChar -> m_deathState != ALIVE )
{
// not blizz like, we must correctly save and load player instead...
if ( pCurrChar -> getRace () == RACE_NIGHTELF )
2009-08-12 18:51:19 +02:00
pCurrChar -> CastSpell ( pCurrChar , SPELL_ID_NE_GHOST , true , 0 ); // auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form)
pCurrChar -> CastSpell ( pCurrChar , SPELL_ID_GHOST , true , 0 ); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?)
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
pCurrChar -> SetMovement ( MOVE_WATER_WALK );
}
2009-10-17 15:51:44 -07:00
2009-08-12 20:27:00 -05:00
pCurrChar -> ContinueTaxiFlight ();
2009-10-17 15:51:44 -07:00
2009-06-23 13:05:15 +02:00
// reset for all pets before pet loading
if ( pCurrChar -> HasAtLoginFlag ( AT_LOGIN_RESET_PET_TALENTS ))
Pet :: resetTalentsForAllPetsOf ( pCurrChar );
2009-10-17 15:51:44 -07:00
2009-04-11 14:47:38 -05:00
// Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned)
pCurrChar -> LoadPet ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Set FFA PvP for non GM in non-rest mode
if ( sWorld . IsFFAPvPRealm () && ! pCurrChar -> isGameMaster () && ! pCurrChar -> HasFlag ( PLAYER_FLAGS , PLAYER_FLAGS_RESTING ) )
2008-12-31 10:05:45 -06:00
pCurrChar -> SetByteFlag ( UNIT_FIELD_BYTES_2 , 1 , UNIT_BYTE2_FLAG_FFA_PVP );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( pCurrChar -> HasFlag ( PLAYER_FLAGS , PLAYER_FLAGS_CONTESTED_PVP ))
pCurrChar -> SetContestedPvP ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Apply at_login requests
if ( pCurrChar -> HasAtLoginFlag ( AT_LOGIN_RESET_SPELLS ))
{
pCurrChar -> resetSpells ();
SendNotification ( LANG_RESET_SPELLS );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( pCurrChar -> HasAtLoginFlag ( AT_LOGIN_RESET_TALENTS ))
{
pCurrChar -> resetTalents ( true );
2009-08-02 10:11:48 +08:00
pCurrChar -> SendTalentsInfoData ( false ); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state
2008-10-11 14:16:25 -05:00
SendNotification ( LANG_RESET_TALENTS );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// show time before shutdown if shutdown planned.
if ( sWorld . IsShutdowning ())
sWorld . ShutdownMsg ( true , pCurrChar );
2009-10-17 15:51:44 -07:00
2008-12-05 23:39:03 -06:00
if ( sWorld . getConfig ( CONFIG_ALL_TAXI_PATHS ))
2008-10-14 11:57:03 -05:00
pCurrChar -> SetTaxiCheater ( true );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( pCurrChar -> isGameMaster ())
SendNotification ( LANG_GM_ON );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
std :: string IP_str = GetRemoteAddress ();
2008-11-14 17:03:03 -06:00
sLog . outChar ( "Account: %d (IP: %s) Login Character:[%s] (guid:%u)" ,
GetAccountId (), IP_str . c_str (), pCurrChar -> GetName () , pCurrChar -> GetGUIDLow ());
2009-10-17 15:51:44 -07:00
2009-08-05 16:03:33 -05:00
if ( ! pCurrChar -> IsStandState () && ! pCurrChar -> hasUnitState ( UNIT_STAT_STUNNED ))
pCurrChar -> SetStandState ( UNIT_STAND_STATE_STAND );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_playerLoading = false ;
2009-10-17 15:51:44 -07:00
2009-09-13 00:01:35 -07:00
//Hook for OnLogin Event
Script -> OnLogin ( pCurrChar );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
delete holder ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleSetFactionAtWar ( WorldPacket & recv_data )
{
DEBUG_LOG ( "WORLD: Received CMSG_SET_FACTION_ATWAR" );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 repListID ;
uint8 flag ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recv_data >> repListID ;
recv_data >> flag ;
2009-10-17 15:51:44 -07:00
2009-03-26 13:53:32 -06:00
GetPlayer () -> GetReputationMgr (). SetAtWar ( repListID , flag );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//I think this function is never used :/ I dunno, but i guess this opcode not exists
void WorldSession :: HandleSetFactionCheat ( WorldPacket & /*recv_data*/ )
{
2009-03-25 16:04:08 -06:00
sLog . outError ( "WORLD SESSION: HandleSetFactionCheat, not expected call, please report." );
2008-10-11 14:16:25 -05:00
/*
uint32 FactionID;
uint32 Standing;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recv_data >> FactionID;
recv_data >> Standing;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
std::list<struct Factions>::iterator itr;
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for (itr = GetPlayer()->factions.begin(); itr != GetPlayer()->factions.end(); ++itr)
2008-10-11 14:16:25 -05:00
{
if(itr->ReputationListID == FactionID)
{
itr->Standing += Standing;
itr->Flags = (itr->Flags | 1);
break;
}
}
*/
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
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleMeetingStoneInfo ( WorldPacket & /*recv_data*/ )
{
DEBUG_LOG ( "WORLD: Received CMSG_MEETING_STONE_INFO" );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
SendLfgUpdate ( 0 , 0 , 0 );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleTutorialFlag ( WorldPacket & recv_data )
{
uint32 iFlag ;
recv_data >> iFlag ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 wInt = ( iFlag / 32 );
if ( wInt >= 8 )
{
//sLog.outError("CHEATER? Account:[%d] Guid[%u] tried to send wrong CMSG_TUTORIAL_FLAG", GetAccountId(),GetGUID());
return ;
}
uint32 rInt = ( iFlag % 32 );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint32 tutflag = GetTutorialInt ( wInt );
2008-10-11 14:16:25 -05:00
tutflag |= ( 1 << rInt );
2009-06-11 00:45:59 -05:00
SetTutorialInt ( wInt , tutflag );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//sLog.outDebug("Received Tutorial Flag Set {%u}.", iFlag);
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleTutorialClear ( WorldPacket & /*recv_data*/ )
{
2009-04-29 00:26:07 -05:00
for ( int i = 0 ; i < 8 ; ++ i )
2009-06-11 00:45:59 -05:00
SetTutorialInt ( i , 0xFFFFFFFF );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: HandleTutorialReset ( WorldPacket & /*recv_data*/ )
{
2009-04-29 00:26:07 -05:00
for ( int i = 0 ; i < 8 ; ++ i )
2009-06-11 00:45:59 -05:00
SetTutorialInt ( i , 0x00000000 );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-05-31 15:56:51 -05:00
void WorldSession :: HandleSetWatchedFactionOpcode ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
DEBUG_LOG ( "WORLD: Received CMSG_SET_WATCHED_FACTION" );
uint32 fact ;
recv_data >> fact ;
GetPlayer () -> SetUInt32Value ( PLAYER_FIELD_WATCHED_FACTION_INDEX , fact );
}
2009-10-17 15:51:44 -07:00
2009-05-31 15:56:51 -05:00
void WorldSession :: HandleSetFactionInactiveOpcode ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
DEBUG_LOG ( "WORLD: Received CMSG_SET_FACTION_INACTIVE" );
uint32 replistid ;
uint8 inactive ;
recv_data >> replistid >> inactive ;
2009-10-17 15:51:44 -07:00
2009-03-26 13:53:32 -06:00
_player -> GetReputationMgr (). SetInactive ( replistid , inactive );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-05-31 15:56:51 -05:00
void WorldSession :: HandleShowingHelmOpcode ( WorldPacket & /*recv_data*/ )
2008-10-11 14:16:25 -05:00
{
2009-05-31 15:56:51 -05:00
DEBUG_LOG ( "CMSG_SHOWING_HELM for %s" , _player -> GetName ());
2008-10-11 14:16:25 -05:00
_player -> ToggleFlag ( PLAYER_FLAGS , PLAYER_FLAGS_HIDE_HELM );
}
2009-10-17 15:51:44 -07:00
2009-05-31 15:56:51 -05:00
void WorldSession :: HandleShowingCloakOpcode ( WorldPacket & /*recv_data*/ )
2008-10-11 14:16:25 -05:00
{
2009-05-31 15:56:51 -05:00
DEBUG_LOG ( "CMSG_SHOWING_CLOAK for %s" , _player -> GetName ());
2008-10-11 14:16:25 -05:00
_player -> ToggleFlag ( PLAYER_FLAGS , PLAYER_FLAGS_HIDE_CLOAK );
}
2009-10-17 15:51:44 -07:00
2009-05-31 15:56:51 -05:00
void WorldSession :: HandleCharRenameOpcode ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
uint64 guid ;
std :: string newname ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recv_data >> guid ;
recv_data >> newname ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// prevent character rename to invalid name
2009-07-10 08:25:33 +08:00
if ( ! normalizePlayerName ( newname ))
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_CHAR_RENAME , 1 );
2008-12-24 09:58:26 -06:00
data << uint8 ( CHAR_NAME_NO_NAME );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2009-07-10 08:25:33 +08:00
uint8 res = ObjectMgr :: CheckPlayerName ( newname , true );
if ( res != CHAR_NAME_SUCCESS )
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_CHAR_RENAME , 1 );
2009-07-10 08:25:33 +08:00
data << uint8 ( res );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// check name limitations
2009-07-10 08:25:33 +08:00
if ( GetSecurity () == SEC_PLAYER && objmgr . IsReservedName ( newname ))
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_CHAR_RENAME , 1 );
2008-12-24 09:58:26 -06:00
data << uint8 ( CHAR_NAME_RESERVED );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-12-22 10:59:38 -06:00
std :: string escaped_newname = newname ;
CharacterDatabase . escape_string ( escaped_newname );
2009-10-17 15:51:44 -07:00
2008-12-22 10:59:38 -06:00
// make sure that the character belongs to the current account, that rename at login is enabled
// and that there is no character with the desired new name
CharacterDatabase . AsyncPQuery ( & WorldSession :: HandleChangePlayerNameOpcodeCallBack ,
GetAccountId (), newname ,
"SELECT guid, name FROM characters WHERE guid = %d AND account = %d AND (at_login & %d) = %d AND NOT EXISTS (SELECT NULL FROM characters WHERE name = '%s')" ,
GUID_LOPART ( guid ), GetAccountId (), AT_LOGIN_RENAME , AT_LOGIN_RENAME , escaped_newname . c_str ()
);
2008-12-19 16:05:13 -06:00
}
2009-10-17 15:51:44 -07:00
2008-12-19 16:05:13 -06:00
void WorldSession :: HandleChangePlayerNameOpcodeCallBack ( QueryResult * result , uint32 accountId , std :: string newname )
{
WorldSession * session = sWorld . FindSession ( accountId );
if ( ! session )
2008-10-11 14:16:25 -05:00
{
2008-12-22 10:59:38 -06:00
if ( result ) delete result ;
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-12-22 10:59:38 -06:00
if ( ! result )
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_CHAR_RENAME , 1 );
2008-12-24 09:58:26 -06:00
data << uint8 ( CHAR_CREATE_ERROR );
2008-12-19 16:05:13 -06:00
session -> SendPacket ( & data );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-12-22 10:59:38 -06:00
uint32 guidLow = result -> Fetch ()[ 0 ]. GetUInt32 ();
uint64 guid = MAKE_NEW_GUID ( guidLow , 0 , HIGHGUID_PLAYER );
std :: string oldname = result -> Fetch ()[ 1 ]. GetCppString ();
2009-10-17 15:51:44 -07:00
2008-12-22 10:59:38 -06:00
delete result ;
2009-10-17 15:51:44 -07:00
2008-12-22 10:59:38 -06:00
CharacterDatabase . PExecute ( "UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'" , newname . c_str (), uint32 ( AT_LOGIN_RENAME ), guidLow );
2008-12-19 16:05:13 -06:00
CharacterDatabase . PExecute ( "DELETE FROM character_declinedname WHERE guid ='%u'" , guidLow );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
sLog . outChar ( "Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s" , session -> GetAccountId (), session -> GetRemoteAddress (). c_str (), oldname . c_str (), guidLow , newname . c_str ());
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
WorldPacket data ( SMSG_CHAR_RENAME , 1 + 8 + ( newname . size () + 1 ));
data << uint8 ( RESPONSE_SUCCESS );
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
data << newname ;
2008-12-19 16:05:13 -06:00
session -> SendPacket ( & data );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-05-31 15:56:51 -05:00
void WorldSession :: HandleSetPlayerDeclinedNames ( WorldPacket & recv_data )
2008-10-11 14:16:25 -05:00
{
uint64 guid ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recv_data >> guid ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// not accept declined names for unsupported languages
std :: string name ;
2008-11-20 17:40:13 -06:00
if ( ! objmgr . GetPlayerNameByGUID ( guid , name ))
2008-10-11 14:16:25 -05:00
{
2008-11-20 17:40:13 -06:00
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( 1 );
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
std :: wstring wname ;
2008-11-20 17:40:13 -06:00
if ( ! Utf8toWStr ( name , wname ))
2008-10-11 14:16:25 -05:00
{
2008-11-20 17:40:13 -06:00
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( 1 );
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( ! isCyrillicCharacter ( wname [ 0 ])) // name already stored as only single alphabet using
{
2008-11-20 17:40:13 -06:00
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( 1 );
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
std :: string name2 ;
DeclinedName declinedname ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
recv_data >> name2 ;
2009-10-17 15:51:44 -07:00
2008-11-20 17:40:13 -06:00
if ( name2 != name ) // character have different name
2008-10-11 14:16:25 -05:00
{
2008-11-20 17:40:13 -06:00
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( 1 );
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( int i = 0 ; i < MAX_DECLINED_NAME_CASES ; ++ i )
2008-10-11 14:16:25 -05:00
{
recv_data >> declinedname . name [ i ];
if ( ! normalizePlayerName ( declinedname . name [ i ]))
{
2008-11-20 17:40:13 -06:00
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( 1 );
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
}
2009-10-17 15:51:44 -07:00
2008-11-20 17:40:13 -06:00
if ( ! ObjectMgr :: CheckDeclinedNames ( GetMainPartOfName ( wname , 0 ), declinedname ))
2008-10-11 14:16:25 -05:00
{
2008-11-20 17:40:13 -06:00
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( 1 );
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( int i = 0 ; i < MAX_DECLINED_NAME_CASES ; ++ i )
2008-10-11 14:16:25 -05:00
CharacterDatabase . escape_string ( declinedname . name [ i ]);
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
CharacterDatabase . BeginTransaction ();
CharacterDatabase . PExecute ( "DELETE FROM character_declinedname WHERE guid = '%u'" , GUID_LOPART ( guid ));
CharacterDatabase . PExecute ( "INSERT INTO character_declinedname (guid, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u','%s','%s','%s','%s','%s')" ,
2008-11-20 17:40:13 -06:00
GUID_LOPART ( guid ), declinedname . name [ 0 ]. c_str (), declinedname . name [ 1 ]. c_str (), declinedname . name [ 2 ]. c_str (), declinedname . name [ 3 ]. c_str (), declinedname . name [ 4 ]. c_str ());
2008-10-11 14:16:25 -05:00
CharacterDatabase . CommitTransaction ();
2009-10-17 15:51:44 -07:00
2008-11-20 17:40:13 -06:00
WorldPacket data ( SMSG_SET_PLAYER_DECLINED_NAMES_RESULT , 4 + 8 );
data << uint32 ( 0 ); // OK
data << uint64 ( guid );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
void WorldSession :: HandleAlterAppearance ( WorldPacket & recv_data )
{
sLog . outDebug ( "CMSG_ALTER_APPEARANCE" );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
uint32 Hair , Color , FacialHair ;
recv_data >> Hair >> Color >> FacialHair ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
BarberShopStyleEntry const * bs_hair = sBarberShopStyleStore . LookupEntry ( Hair );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( ! bs_hair || bs_hair -> type != 0 || bs_hair -> race != _player -> getRace () || bs_hair -> gender != _player -> getGender ())
return ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
BarberShopStyleEntry const * bs_facialHair = sBarberShopStyleStore . LookupEntry ( FacialHair );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( ! bs_facialHair || bs_facialHair -> type != 2 || bs_facialHair -> race != _player -> getRace () || bs_facialHair -> gender != _player -> getGender ())
return ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
uint32 Cost = _player -> GetBarberShopCost ( bs_hair -> hair_id , Color , bs_facialHair -> hair_id );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// 0 - ok
// 1,3 - not enough money
// 2 - you have to seat on barber chair
if ( _player -> GetMoney () < Cost )
{
WorldPacket data ( SMSG_BARBER_SHOP_RESULT , 4 );
data << uint32 ( 1 ); // no money
SendPacket ( & data );
return ;
}
else
{
WorldPacket data ( SMSG_BARBER_SHOP_RESULT , 4 );
data << uint32 ( 0 ); // ok
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2009-03-05 09:22:43 -06:00
_player -> ModifyMoney ( - int32 ( Cost )); // it isn't free
_player -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER , Cost );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
_player -> SetByteValue ( PLAYER_BYTES , 2 , uint8 ( bs_hair -> hair_id ));
_player -> SetByteValue ( PLAYER_BYTES , 3 , uint8 ( Color ));
_player -> SetByteValue ( PLAYER_BYTES_2 , 0 , uint8 ( bs_facialHair -> hair_id ));
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
_player -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP , 1 );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
_player -> SetStandState ( 0 ); // stand up
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
void WorldSession :: HandleRemoveGlyph ( WorldPacket & recv_data )
{
uint32 slot ;
recv_data >> slot ;
2009-10-17 15:51:44 -07:00
2009-03-21 14:54:21 -06:00
if ( slot >= MAX_GLYPH_SLOT_INDEX )
2008-12-24 09:58:26 -06:00
{
2009-03-21 14:54:21 -06:00
sLog . outDebug ( "Client sent wrong glyph slot number in opcode CMSG_REMOVE_GLYPH %u" , slot );
2009-03-21 14:53:38 -06:00
return ;
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2009-03-21 14:54:21 -06:00
if ( uint32 glyph = _player -> GetGlyph ( slot ))
{
if ( GlyphPropertiesEntry const * gp = sGlyphPropertiesStore . LookupEntry ( glyph ))
{
_player -> RemoveAurasDueToSpell ( gp -> SpellId );
_player -> SetGlyph ( slot , 0 );
2009-06-11 00:45:59 -05:00
_player -> SendTalentsInfoData ( false );
2009-03-21 14:54:21 -06:00
}
}
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
void WorldSession :: HandleCharCustomize ( WorldPacket & recv_data )
{
uint64 guid ;
std :: string newname ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
recv_data >> guid ;
recv_data >> newname ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
uint8 gender , skin , face , hairStyle , hairColor , facialHair ;
2009-03-20 14:28:45 -06:00
recv_data >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
QueryResult * result = CharacterDatabase . PQuery ( "SELECT at_login FROM characters WHERE guid ='%u'" , GUID_LOPART ( guid ));
if ( ! result )
{
WorldPacket data ( SMSG_CHAR_CUSTOMIZE , 1 );
data << uint8 ( CHAR_CREATE_ERROR );
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
Field * fields = result -> Fetch ();
uint32 at_loginFlags = fields [ 0 ]. GetUInt32 ();
delete result ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
if ( ! ( at_loginFlags & AT_LOGIN_CUSTOMIZE ))
{
WorldPacket data ( SMSG_CHAR_CUSTOMIZE , 1 );
data << uint8 ( CHAR_CREATE_ERROR );
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// prevent character rename to invalid name
2009-07-10 08:25:33 +08:00
if ( ! normalizePlayerName ( newname ))
2008-12-24 09:58:26 -06:00
{
WorldPacket data ( SMSG_CHAR_CUSTOMIZE , 1 );
data << uint8 ( CHAR_NAME_NO_NAME );
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2009-07-10 08:25:33 +08:00
uint8 res = ObjectMgr :: CheckPlayerName ( newname , true );
if ( res != CHAR_NAME_SUCCESS )
2008-12-24 09:58:26 -06:00
{
WorldPacket data ( SMSG_CHAR_CUSTOMIZE , 1 );
2009-07-10 08:25:33 +08:00
data << uint8 ( res );
2008-12-24 09:58:26 -06:00
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// check name limitations
2009-07-10 08:25:33 +08:00
if ( GetSecurity () == SEC_PLAYER && objmgr . IsReservedName ( newname ))
2008-12-24 09:58:26 -06:00
{
WorldPacket data ( SMSG_CHAR_CUSTOMIZE , 1 );
data << uint8 ( CHAR_NAME_RESERVED );
SendPacket ( & data );
return ;
}
2009-10-17 15:51:44 -07:00
2009-02-22 17:26:03 -06:00
// character with this name already exist
2009-07-10 08:25:33 +08:00
if ( uint64 newguid = objmgr . GetPlayerGUIDByName ( newname ))
2008-12-24 09:58:26 -06:00
{
2009-07-10 08:25:33 +08:00
if ( newguid != guid )
2009-02-22 17:26:03 -06:00
{
WorldPacket data ( SMSG_CHAR_CUSTOMIZE , 1 );
data << uint8 ( CHAR_CREATE_NAME_IN_USE );
SendPacket ( & data );
return ;
}
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
CharacterDatabase . escape_string ( newname );
2009-08-16 16:32:11 -05:00
if ( QueryResult * result = CharacterDatabase . PQuery ( "SELECT name FROM characters WHERE guid ='%u'" , GUID_LOPART ( guid )))
{
std :: string oldname = result -> Fetch ()[ 0 ]. GetCppString ();
std :: string IP_str = GetRemoteAddress ();
sLog . outChar ( "Account: %d (IP: %s), Character[%s] (guid:%u) Customized to: %s" , GetAccountId (), IP_str . c_str (), oldname . c_str (), GUID_LOPART ( guid ), newname . c_str ());
}
2008-12-24 09:58:26 -06:00
Player :: Customize ( guid , gender , skin , face , hairStyle , hairColor , facialHair );
CharacterDatabase . PExecute ( "UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'" , newname . c_str (), uint32 ( AT_LOGIN_CUSTOMIZE ), GUID_LOPART ( guid ));
CharacterDatabase . PExecute ( "DELETE FROM character_declinedname WHERE guid ='%u'" , GUID_LOPART ( guid ));
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
WorldPacket data ( SMSG_CHAR_CUSTOMIZE , 1 + 8 + ( newname . size () + 1 ) + 6 );
data << uint8 ( RESPONSE_SUCCESS );
data << uint64 ( guid );
data << newname ;
data << uint8 ( gender );
data << uint8 ( skin );
data << uint8 ( face );
data << uint8 ( hairStyle );
data << uint8 ( hairColor );
data << uint8 ( facialHair );
2009-02-19 22:30:30 -06:00
SendPacket ( & data );
2009-02-18 22:39:00 +01:00
}
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
void WorldSession :: HandleEquipmentSetSave ( WorldPacket & recv_data )
{
sLog . outDebug ( "CMSG_EQUIPMENT_SET_SAVE" );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint64 setGuid ;
if ( ! recv_data . readPackGUID ( setGuid ))
return ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint32 index ;
recv_data >> index ;
if ( index >= MAX_EQUIPMENT_SET_INDEX ) // client set slots amount
return ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
std :: string name ;
recv_data >> name ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
std :: string iconName ;
recv_data >> iconName ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
EquipmentSet eqSet ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
eqSet . Guid = setGuid ;
eqSet . Name = name ;
eqSet . IconName = iconName ;
eqSet . state = EQUIPMENT_SET_NEW ;
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( uint32 i = 0 ; i < EQUIPMENT_SLOT_END ; ++ i )
2009-06-11 00:45:59 -05:00
{
uint64 itemGuid ;
if ( ! recv_data . readPackGUID ( itemGuid ))
return ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
Item * item = _player -> GetItemByPos ( INVENTORY_SLOT_BAG_0 , i );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
if ( ! item && itemGuid ) // cheating check 1
return ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
if ( item && item -> GetGUID () != itemGuid ) // cheating check 2
return ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
eqSet . Items [ i ] = GUID_LOPART ( itemGuid );
}
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
_player -> SetEquipmentSet ( index , eqSet );
}
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
void WorldSession :: HandleEquipmentSetDelete ( WorldPacket & recv_data )
{
sLog . outDebug ( "CMSG_EQUIPMENT_SET_DELETE" );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint64 setGuid ;
if ( ! recv_data . readPackGUID ( setGuid ))
return ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
_player -> DeleteEquipmentSet ( setGuid );
}
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
void WorldSession :: HandleEquipmentSetUse ( WorldPacket & recv_data )
{
sLog . outDebug ( "CMSG_EQUIPMENT_SET_USE" );
recv_data . hexlike ();
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( uint32 i = 0 ; i < EQUIPMENT_SLOT_END ; ++ i )
2009-06-11 00:45:59 -05:00
{
uint64 itemGuid ;
if ( ! recv_data . readPackGUID ( itemGuid ))
return ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint8 srcbag , srcslot ;
recv_data >> srcbag >> srcslot ;
2009-10-17 15:51:44 -07:00
2009-09-18 14:10:37 -07:00
sLog . outDebug ( "Item " UI64FMTD ": srcbag %u, srcslot %u" , itemGuid , srcbag , srcslot );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
Item * item = _player -> GetItemByGuid ( itemGuid );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
uint16 dstpos = i | ( INVENTORY_SLOT_BAG_0 << 8 );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
if ( ! item )
{
Item * uItem = _player -> GetItemByPos ( INVENTORY_SLOT_BAG_0 , i );
if ( ! uItem )
continue ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
ItemPosCountVec sDest ;
uint8 msg = _player -> CanStoreItem ( NULL_BAG , NULL_SLOT , sDest , uItem , false );
if ( msg == EQUIP_ERR_OK )
{
_player -> RemoveItem ( INVENTORY_SLOT_BAG_0 , i , true );
_player -> StoreItem ( sDest , uItem , true );
}
else
_player -> SendEquipError ( msg , uItem , NULL );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
if ( item -> GetPos () == dstpos )
continue ;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
_player -> SwapItem ( item -> GetPos (), dstpos );
}
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
WorldPacket data ( SMSG_EQUIPMENT_SET_USE_RESULT , 1 );
data << uint8 ( 0 ); // 4 - equipment swap failed - inventory is full
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2009-09-23 20:19:21 -07:00
void WorldSession :: HandleOnPVPKill ( Player * killed )
{
Script -> OnPVPKill ( GetPlayer (), killed );
}
2009-10-17 15:51:44 -07:00
2009-09-23 20:19:21 -07:00
bool WorldSession :: HandleOnPlayerChat ( const char * text )
{
return Script -> OnPlayerChat ( GetPlayer (), text );
}
2009-10-17 15:51:44 -07:00
2009-09-23 20:19:21 -07:00
uint32 WorldSession :: HandleOnGetXP ( uint32 amount )
{
return Script -> OnGetXP ( GetPlayer (), amount );
}
2009-10-17 15:51:44 -07:00
2009-09-23 20:19:21 -07:00
int32 WorldSession :: HandleOnGetMoney ( int32 amount )
{
return Script -> OnGetMoney ( GetPlayer (), amount );
}
2009-10-17 15:51:44 -07:00
2009-09-23 20:19:21 -07:00
void WorldSession :: HandleOnAreaChange ( AreaTableEntry const * pArea )
{
Script -> OnAreaChange ( GetPlayer (), pArea );
}
2009-10-17 15:51:44 -07:00
2009-09-23 20:19:21 -07:00
bool WorldSession :: HandleOnItemClick ( Item * pItem )
{
return Script -> OnItemClick ( GetPlayer (), pItem );
}
2009-10-17 15:51:44 -07:00
2009-09-23 20:19:21 -07:00
bool WorldSession :: HandleOnItemOpen ( Item * pItem )
{
return Script -> OnItemOpen ( GetPlayer (), pItem );
}
2009-10-17 15:51:44 -07:00
2009-09-23 20:19:21 -07:00
bool WorldSession :: HandleOnGoClick ( GameObject * pGameObject )
{
return Script -> OnGoClick ( GetPlayer (), pGameObject );
}
2009-10-17 15:51:44 -07:00
2009-09-23 20:19:21 -07:00
void WorldSession :: HandleOnCreatureKill ( Creature * pCreature )
{
Script -> OnCreatureKill ( GetPlayer (), pCreature );
}