ArcEmu: Core Development: Character Customize - ArcEmu

Jump to content

Toggle shoutbox Lastest Announcements

dfighter  : (07 December 2014 - 12:06 PM) Arcemu is in hibernation mode, please read http://arcemu.org/fo...showtopic=26903
dfighter  : (01 January 2013 - 05:56 PM) Arcemu wishes you all a happy new year!
Hasbro  : (12 September 2012 - 10:01 AM) Please excuse our outage from the web! Our web host had a major malfunction!
dfighter  : (01 September 2012 - 04:05 PM) Since the spam bots just don't want to stop, I've enabled admin verification when registering.
dfighter  : (23 January 2012 - 09:56 PM) Please note that from now on you will need to confirm your email on the wiki in order to edit it!
Hasbro  : (31 December 2011 - 12:50 PM) Happy New Years all!
Navid  : (26 December 2011 - 04:09 AM) Merry Christmas !!!!!! Happy holidays all :)
WAmadeus  : (24 December 2011 - 03:54 PM) Merry Christmas to all!
dfighter  : (24 December 2011 - 11:05 AM) The Arcemu team wishes y'all a Merry Christmukkah!
Hasbro  : (05 October 2011 - 12:53 PM) Looking for web designers for upcoming web related project. If you're interested in designing user interfaces contact me
dfighter  : (02 September 2011 - 03:47 PM) So who here wants vehicles in Arcemu? :P http://arcemu.org/fo...showtopic=25440
Hasbro  : (14 August 2011 - 03:25 PM) Join us on irc, grab an irc client and connect to irc.freenode.net join channel #arcemu /server irc.freenode.net:6667 /join #arcemu
jackpoz  : (03 August 2011 - 05:33 AM) to all Lua Engine (old one) users: please check http://arcemu.org/fo...showtopic=25274
Hasbro  : (20 May 2011 - 05:27 PM) Looking for people experienced with CMake configuration and setup! Contact me asap
Hasbro  : (15 May 2011 - 05:03 PM) ArcEmu is recruiting C++ programmers, contact Hasbro if interested.
paroxysm  : (03 May 2011 - 06:26 PM) Updated luabridge gossip example to describe the whole gossip creation process rather than just how to create menu. Gossip tutorial
paroxysm  : (23 April 2011 - 11:35 AM) Lua writers can refer to the Luabridge Tutorials section in the Wiki to learn how to write gossip code correctly.
Hasbro  : (20 April 2011 - 05:22 PM) Thank you for your continuous contribution of bug reports, we are working on them.
Hasbro  : (17 April 2011 - 03:20 AM) Please consider donating to support our bills. Donations can be sent using PayPal to donations@arcemu.org - Thank you for your support.
paroxysm  : (10 April 2011 - 12:43 AM) Refer to the Luabridge Tutorials section in the Wiki to learn the new syntax of luabridge.
Resize Shouts Area

Read:

When submitting patches - READ: http://arcemu.org/fo...?showtopic=2355 -
Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Core Development: Character Customize This patch adds the ability customize character looks

#1 User is offline   Wil 

  • Advanced Member
  • Group: Super Moderator
  • Posts: 224
  • Joined: 31-January 09
  • Gender:Male
  • Server OS:Windows

Posted 18 November 2011 - 11:38 PM

THIS IS VERSION 2 WITH CHANGES SUGGESTED BY JACKPOZ

Detailed Explanation:
This patch adds the ability for a GM to flag a character or through a website flag a character for Customization. On the characters next login they will be given a chance to customize their characters name and looks. The command for customization is ".character customize <char name>", This patch renames the forced_rename field to login_flags. Characters must be logged out when setting this flag from a website.

Login Flags:
LOGIN_NO_FLAG = 0
LOGIN_FORCED_RENAME = 1
LOGIN_CUSTOMIZE_FACTION = 2
LOGIN_CUSTOMIZE_RACE = 4
LOGIN_CUSTOMIZE_LOOKS = 8


Tested:
I have tested this via the in-game command, setting the flag directly within the database. All is working as intended.

MYSQL QUERY:

ALTER TABLE `characters` CHANGE `forced_rename_pending` `login_flags` int(10) unsigned NOT NULL DEFAULT '0';


Patch:

   src/arcemu-world/CharacterHandler.cpp |   95 ++++++++++++++++++++++++++++++---
 src/arcemu-world/Chat.cpp         	|	1 +
 src/arcemu-world/Chat.h           	|	3 +
 src/arcemu-world/Level3.cpp       	|   34 +++++++++++-
 src/arcemu-world/ObjectMgr.cpp    	|	4 +-
 src/arcemu-world/Opcodes.cpp      	|	3 +
 src/arcemu-world/Opcodes.h        	|	5 ++-
 src/arcemu-world/Player.cpp       	|   66 +++++++++++++++++++++--
 src/arcemu-world/Player.h         	|   54 ++++++++++++++++++-
 src/arcemu-world/WorldSession.cpp 	|	4 ++
 src/arcemu-world/WorldSession.h   	|	3 +
 11 files changed, 254 insertions(+), 18 deletions(-)

diff --git a/src/arcemu-world/CharacterHandler.cpp b/src/arcemu-world/CharacterHandler.cpp
index 5c61735..fa09c6d 100644
--- a/src/arcemu-world/CharacterHandler.cpp
+++ b/src/arcemu-world/CharacterHandler.cpp
@@ -67,6 +67,68 @@ LoginErrorCode VerifyName(const char* name, size_t nlen)
 	return E_CHAR_NAME_SUCCESS;
 }
 
+void WorldSession::HandleCharCustomizeLooksOpcode(WorldPacket& recv_data)
+{
+	uint64 guid;
+	std::string newname;
+
+	recv_data >> guid;
+	recv_data >> newname;
+
+	uint8 gender, skin, face, hairStyle, hairColor, facialHair, race, faction;
+	recv_data >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face >> race >> faction;
+
+	LoginErrorCode res = VerifyName( newname.c_str(), newname.length() );
+	if( res != E_CHAR_NAME_SUCCESS )
+	{
+    	WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
+    	data << uint8(CHAR_NAME_NO_NAME);
+    	SendPacket( &data );
+    	return;
+	}
+
+	QueryResult * result2 = CharacterDatabase.Query("SELECT COUNT(*) FROM `banned_names` WHERE name = '%s'", CharacterDatabase.EscapeString(newname).c_str());
+	if(result2)
+	{
+		if(result2->Fetch()[0].GetUInt32() > 0)
+    	{
+			WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
+        	data << uint8( E_CHAR_NAME_PROFANE );
+        	SendPacket(&data);
+    	}
+    	delete result2;
+	}
+
+	PlayerInfo* info = objmgr.GetPlayerInfoByName( newname.c_str() );
+	if( info != NULL && info->guid != guid )
+	{
+    	WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
+    	data << uint8(CHAR_CREATE_NAME_IN_USE);
+    	SendPacket(&data);
+    	return;
+	}
+
+	CharacterDatabase.EscapeString(newname).c_str();
+	CapitalizeString(newname);
+	
+	CharacterDatabase.WaitExecute("UPDATE `characters` set name = '%s' WHERE guid = '%u'", newname.c_str(), (uint32)guid);
+	CharacterDatabase.WaitExecute("UPDATE `characters` SET login_flags = %u WHERE guid = '%u'", (uint32)LOGIN_NO_FLAG, (uint32)guid);
+	
+	Player::CharChange_Looks(guid, gender, skin, face, hairStyle, hairColor, facialHair);	
+
+	WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1+8+(newname.size()+1)+6);
+	data << uint8(E_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);
+	SendPacket(&data);
+}
+
 bool ChatHandler::HandleRenameAllCharacter(const char* args, WorldSession* m_session)
 {
 	uint32 uCount = 0;
@@ -86,11 +148,11 @@ bool ChatHandler::HandleRenameAllCharacter(const char* args, WorldSession* m_ses
 				Player* pPlayer = objmgr.GetPlayer(uGuid);
 				if(pPlayer != NULL)
 				{
-					pPlayer->rename_pending = true;
+					pPlayer->login_flags = LOGIN_FORCED_RENAME;
 					pPlayer->GetSession()->SystemMessage("Your character has had a force rename set, you will be prompted to rename your character at next login in conformance with server rules.");
 				}
 
-				CharacterDatabase.WaitExecute("UPDATE characters SET forced_rename_pending = 1 WHERE guid = %u", uGuid);
+				CharacterDatabase.WaitExecute("UPDATE characters SET login_flags = %u WHERE guid = %u", (uint32)LOGIN_FORCED_RENAME, uGuid);
 				++uCount;
 			}
 
@@ -205,11 +267,28 @@ void WorldSession::CharacterEnumProc(QueryResult* result)
 				char_flags |= 0x00000400;	//Helm not displayed
 			if(flags & PLAYER_FLAG_NOCLOAK)
 				char_flags |= 0x00000800;	//Cloak not displayed
-			if(fields[16].GetUInt32() != 0)
+			if(fields[16].GetUInt32() == 1)
 				char_flags |= 0x00004000;	//Character has to be renamed before logging in
 
 			data << uint32(char_flags);
-			data << uint32(0);				//Character recustomization flags
+			
+
+			switch(fields[16].GetUInt32())
+			{
+				case LOGIN_CUSTOMIZE_LOOKS:
+					data << uint32(CHAR_CUSTOMIZE_FLAG_CUSTOMIZE);  //Character recustomization flag
+					break;
+				case LOGIN_CUSTOMIZE_RACE:
+					data << uint32(CHAR_CUSTOMIZE_FLAG_RACE);	//Character recustomization + race flag
+					break;
+				case LOGIN_CUSTOMIZE_FACTION:
+					data << uint32(CHAR_CUSTOMIZE_FLAG_FACTION); //Character recustomization + race + faction flag
+					break;
+				default:
+					data << uint32(CHAR_CUSTOMIZE_FLAG_NONE);	//Character recustomization no flag set
+				}
+
+			
 			data << uint8(0);				//Unknown 3.2.0
 
 			if(Class == WARLOCK || Class == HUNTER)
@@ -292,7 +371,7 @@ void WorldSession::CharacterEnumProc(QueryResult* result)
 void WorldSession::HandleCharEnumOpcode(WorldPacket & recv_data)
 {
 	AsyncQuery* q = new AsyncQuery(new SQLClassCallbackP1<World, uint32>(World::getSingletonPtr(), &World::CharacterEnumProc, GetAccountId()));
-	q->AddQuery("SELECT guid, level, race, class, gender, bytes, bytes2, name, positionX, positionY, positionZ, mapId, zoneId, banned, restState, deathstate, forced_rename_pending, player_flags, guild_data.guildid FROM characters LEFT JOIN guild_data ON characters.guid = guild_data.playerid WHERE acct=%u ORDER BY guid LIMIT 10", GetAccountId());
+	q->AddQuery("SELECT guid, level, race, class, gender, bytes, bytes2, name, positionX, positionY, positionZ, mapId, zoneId, banned, restState, deathstate, login_flags, player_flags, guild_data.guildid FROM characters LEFT JOIN guild_data ON characters.guid = guild_data.playerid WHERE acct=%u ORDER BY guid LIMIT 10", GetAccountId());
 	CharacterDatabase.QueueAsyncQuery(q);
 }
 
@@ -579,7 +658,7 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket & recv_data)
 	PlayerInfo* pi = objmgr.GetPlayerInfo((uint32)guid);
 	if(pi == 0) return;
 
-	QueryResult* result = CharacterDatabase.Query("SELECT forced_rename_pending FROM characters WHERE guid = %u AND acct = %u",
+	QueryResult* result = CharacterDatabase.Query("SELECT login_flags FROM characters WHERE guid = %u AND acct = %u",
 	                  	(uint32)guid, _accountId);
 	if(result == 0)
 	{
@@ -631,7 +710,7 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket & recv_data)
 	free(pi->name);
 	pi->name = strdup(name.c_str());
 	CharacterDatabase.WaitExecute("UPDATE characters SET name = '%s' WHERE guid = %u", name.c_str(), (uint32)guid);
-	CharacterDatabase.WaitExecute("UPDATE characters SET forced_rename_pending = 0 WHERE guid = %u", (uint32)guid);
+	CharacterDatabase.WaitExecute("UPDATE characters SET login_flags = %u WHERE guid = %u", (uint32)LOGIN_NO_FLAG, (uint32)guid);
 
 	data << uint8(E_RESPONSE_SUCCESS) << guid << name;
 	SendPacket(&data);
@@ -655,7 +734,7 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPacket & recv_data)
 	}
 
 	AsyncQuery* q = new AsyncQuery(new SQLClassCallbackP0<WorldSession>(this, &WorldSession::LoadPlayerFromDBProc));
-	q->AddQuery("SELECT guid,class FROM characters WHERE guid = %u AND forced_rename_pending = 0", playerGuid); // 0
+	q->AddQuery("SELECT guid,class FROM characters WHERE guid = %u AND login_flags = %u", playerGuid, (uint32)LOGIN_NO_FLAG ); // 0
 	CharacterDatabase.QueueAsyncQuery(q);
 }
 
diff --git a/src/arcemu-world/Chat.cpp b/src/arcemu-world/Chat.cpp
index 3af203b..1e7e9f4 100644
--- a/src/arcemu-world/Chat.cpp
+++ b/src/arcemu-world/Chat.cpp
@@ -599,6 +599,7 @@ void CommandTableStorage::Init()
 		{ "showinstances",   	'z', &ChatHandler::HandleShowInstancesCommand,	"Shows persistent instances of selected Player",                                                                 	NULL, 0, 0, 0 },
 		{ "rename",          	'm', &ChatHandler::HandleRenameCommand,       	"Renames character x to y.",                                                                                     	NULL, 0, 0, 0 },
 		{ "forcerename",     	'm', &ChatHandler::HandleForceRenameCommand,  	"Forces character x to rename his char next login",                                                              	NULL, 0, 0, 0 },
+		{ "customize",			 'm', &ChatHandler::HandleCustomizeCommand,    	"Allows character x to customize his char at next login",                                                              	NULL, 0, 0, 0 },
 		{ "repairitems",     	'n', &ChatHandler::HandleRepairItemsCommand,  	".repairitems - Repair all items from selected player",                                                          	NULL, 0, 0, 0 },
 		{ "settitle",			 'm', &ChatHandler::HandleSetTitle,				   "Adds title to a player",																					NULL, 0, 0, 0 },
 		{ "phase",           	'm', &ChatHandler::HandlePhaseCommand,        	"<phase> - Sets phase of selected player",                                                                       	NULL, 0, 0, 0 },
diff --git a/src/arcemu-world/Chat.h b/src/arcemu-world/Chat.h
index f76dd5b..ca564d9 100644
--- a/src/arcemu-world/Chat.h
+++ b/src/arcemu-world/Chat.h
@@ -542,6 +542,9 @@ class SERVER_DECL ChatHandler : public Singleton<ChatHandler>
 		bool HandleRenameCommand(const char* args, WorldSession* m_session);
 		bool HandleForceRenameCommand(const char* args, WorldSession* m_session);
 
+		//Customize
+		bool HandleCustomizeCommand(const char* args, WorldSession* m_session);
+
 		// Reputation
 		bool HandleGetStandingCommand(const char* args, WorldSession* m_session);
 		bool HandleSetStandingCommand(const char* args, WorldSession* m_session);
diff --git a/src/arcemu-world/Level3.cpp b/src/arcemu-world/Level3.cpp
index 8dd2065..d3d9739 100644
--- a/src/arcemu-world/Level3.cpp
+++ b/src/arcemu-world/Level3.cpp
@@ -2957,11 +2957,11 @@ bool ChatHandler::HandleForceRenameCommand(const char* args, WorldSession* m_ses
 	Player* plr = objmgr.GetPlayer((uint32)pi->guid);
 	if(plr == 0)
 	{
-		CharacterDatabase.Execute("UPDATE characters SET forced_rename_pending = 1 WHERE guid = %u", (uint32)pi->guid);
+		CharacterDatabase.Execute("UPDATE characters SET login_flags = %u WHERE guid = %u", (uint32)LOGIN_FORCED_RENAME, (uint32)pi->guid);
 	}
 	else
 	{
-		plr->rename_pending = true;
+		plr->login_flags = LOGIN_FORCED_RENAME;
 		plr->SaveToDB(false);
 		BlueSystemMessageToPlr(plr, "%s forced your character to be renamed next logon.", m_session->GetPlayer()->GetName());
 	}
@@ -2972,6 +2972,36 @@ bool ChatHandler::HandleForceRenameCommand(const char* args, WorldSession* m_ses
 	return true;
 }
 
+bool ChatHandler::HandleCustomizeCommand(const char* args, WorldSession* m_session)
+{
+	// prevent buffer overflow
+	if(strlen(args) > 100)
+		return false;
+	string tmp = string(args);
+	PlayerInfo* pi = objmgr.GetPlayerInfoByName(tmp.c_str());
+	if(pi == 0)
+	{
+		RedSystemMessage(m_session, "Player with that name not found.");
+		return true;
+	}
+
+	Player* plr = objmgr.GetPlayer((uint32)pi->guid);
+	if(plr == 0)
+	{
+		CharacterDatabase.Execute("UPDATE characters SET login_flags = %u WHERE guid = %u",(uint32)LOGIN_CUSTOMIZE_LOOKS, (uint32)pi->guid);
+	}
+	else
+	{
+		plr->login_flags = LOGIN_CUSTOMIZE_LOOKS;
+		plr->SaveToDB(false);
+		BlueSystemMessageToPlr(plr, "%s flagged your character for customization at next login.", m_session->GetPlayer()->GetName());
+	}
+
+	GreenSystemMessage(m_session, "%s flagged to customize his character next logon.", args);
+	sGMLog.writefromsession(m_session, "flagged %s for customization for charater (%u)", pi->name, pi->guid);
+	return true;
+}
+
 bool ChatHandler::HandleGetStandingCommand(const char* args, WorldSession* m_session)
 {
 	uint32 faction = atoi(args);
diff --git a/src/arcemu-world/ObjectMgr.cpp b/src/arcemu-world/ObjectMgr.cpp
index b26fb85..2167185 100644
--- a/src/arcemu-world/ObjectMgr.cpp
+++ b/src/arcemu-world/ObjectMgr.cpp
@@ -487,8 +487,8 @@ void ObjectMgr::LoadPlayersInfo()
 				char temp[300];
 				snprintf(temp, 300, "%s__%X__", pn->name, pn->guid);
 				Log.Notice("ObjectMgr", "Renaming duplicate player %s to %s. (%u)", pn->name, temp, pn->guid);
-				CharacterDatabase.WaitExecute("UPDATE characters SET name = '%s', forced_rename_pending = 1 WHERE guid = %u",
-				                          	CharacterDatabase.EscapeString(string(temp)).c_str(), pn->guid);
+				CharacterDatabase.WaitExecute("UPDATE characters SET name = '%s', login_flags = %u WHERE guid = %u",
+				                          	CharacterDatabase.EscapeString(string(temp)).c_str(), (uint32)LOGIN_FORCED_RENAME, pn->guid);
 
 				free(pn->name);
 				pn->name = strdup(temp);
diff --git a/src/arcemu-world/Opcodes.cpp b/src/arcemu-world/Opcodes.cpp
index 2e77e48..0aacb0b 100644
--- a/src/arcemu-world/Opcodes.cpp
+++ b/src/arcemu-world/Opcodes.cpp
@@ -1243,9 +1243,12 @@ NameTableEntry g_worldOpcodeNames[] = {
  {CMSG_LEARN_TALENTS_MULTIPLE, "CMSG_LEARN_TALENTS_MULTIPLE"},
  {CMSG_EQUIPMENT_SET_USE, "CMSG_EQUIPMENT_SET_USE"},
  {SMSG_EQUIPMENT_SET_USE_RESULT, "SMSG_EQUIPMENT_SET_USE_RESULT"},
+ {CMSG_CHAR_FACTION_CHANGE, "CMSG_CHAR_FACTION_CHANGE"},
+ {SMSG_CHAR_FACTION_CHANGE, "SMSG_CHAR_FACTION_CHANGE"},
  {MSG_SET_RAID_DIFFICULTY,	"MSG_SET_RAID_DIFFICULTY"},
  {CMSG_WORLD_STATE_UI_TIMER_UPDATE,	"CMSG_WORLD_STATE_UI_TIMER_UPDATE"},
  {SMSG_WORLD_STATE_UI_TIMER_UPDATE,	"SMSG_WORLD_STATE_UI_TIMER_UPDATE"},
+ {CMSG_CHAR_RACE_CHANGE,	"CMSG_CHAR_RACE_CHANGE"},
  {NUM_MSG_TYPES, 	"NUM_MSG_TYPES"},
  {0,			0}
 };
diff --git a/src/arcemu-world/Opcodes.h b/src/arcemu-world/Opcodes.h
index ae9a309..ff2404c 100644
--- a/src/arcemu-world/Opcodes.h
+++ b/src/arcemu-world/Opcodes.h
@@ -1258,10 +1258,13 @@ enum Opcodes
 	SMSG_UNKNOWN_1228								= 0x4CC,	//
 	CMSG_EQUIPMENT_SET_USE							= 0x4D5,	// implemented
 	SMSG_EQUIPMENT_SET_USE_RESULT					= 0x4D6,	// implemented
+	CMSG_CHAR_FACTION_CHANGE                    	= 0x4D9,	// TODO: Not implemented
+	SMSG_CHAR_FACTION_CHANGE                    	= 0x4DA,	// TODO: Not implemented
 	MSG_SET_RAID_DIFFICULTY                     	= 0x4EB,	// implemented
 	CMSG_WORLD_STATE_UI_TIMER_UPDATE            	= 0x4F6,	// implemented
 	SMSG_WORLD_STATE_UI_TIMER_UPDATE            	= 0x4F7,	// implemented
-	NUM_MSG_TYPES                               	= 0x4F8,	// max msg number
+	CMSG_CHAR_RACE_CHANGE                       	= 0x4F8,	// TODO: Not implemented
+	NUM_MSG_TYPES                               	= 0x4F9,	// max msg number
 };
 
 enum FriendsResult
diff --git a/src/arcemu-world/Player.cpp b/src/arcemu-world/Player.cpp
index d141b31..567dffe 100644
--- a/src/arcemu-world/Player.cpp
+++ b/src/arcemu-world/Player.cpp
@@ -339,7 +339,7 @@ Player::Player(uint32 guid)
 		m_arenaTeams[i] = NULL;
 	flying_aura = 0;
 	resend_speed = false;
-	rename_pending = false;
+	login_flags = LOGIN_NO_FLAG;
 	DualWield2H = false;
 	iInstanceType		= 0;
 	m_RaidDifficulty	= 0;
@@ -640,6 +640,64 @@ uint32 GetSpellForLanguage(uint32 SkillID)
 	return 0;
 }
 
+void Player::CharChange_Looks( uint64 GUID, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair )
+{
+	QueryResult* result = CharacterDatabase.Query("SELECT bytes2 FROM `characters` WHERE guid = '%u'", (uint32)GUID);
+	if (!result)
+    	return;
+
+	Field* fields = result->Fetch();
+
+	uint32 player_bytes2 = fields[0].GetUInt32();
+	player_bytes2 &= ~0xFF;
+	player_bytes2 |= facialHair;
+
+	CharacterDatabase.Execute("UPDATE `characters` SET gender = '%u', bytes = '%u', bytes2 = '%u' WHERE guid = '%u'", gender, skin | (face << 8) | (hairStyle << 16) | (hairColor << 24), player_bytes2, (uint32)GUID);
+
+	delete result;
+}
+
+//Begining of code for phase two of character customization (Race/Faction) Change.
+void Player::CharChange_Language( uint64 GUID, uint8 race )
+{
+	CharacterDatabase.Execute("DELETE FROM `playerspells` WHERE GUID = '%u' AND SpellID IN ('%u', '%u', '%u', '%u', '%u','%u', '%u', '%u', '%u', '%u');", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_ORCISH), GetSpellForLanguage(SKILL_LANG_TAURAHE), GetSpellForLanguage(SKILL_LANG_TROLL), GetSpellForLanguage(SKILL_LANG_GUTTERSPEAK), GetSpellForLanguage(SKILL_LANG_THALASSIAN), GetSpellForLanguage(SKILL_LANG_COMMON), GetSpellForLanguage(SKILL_LANG_DARNASSIAN), GetSpellForLanguage(SKILL_LANG_DRAENEI), GetSpellForLanguage(SKILL_LANG_DWARVEN), GetSpellForLanguage(SKILL_LANG_GNOMISH) );
+	switch ( race )
+	{
+		case RACE_DWARF:
+			CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_COMMON));
+        	CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_DWARVEN));
+        	break;
+    	case RACE_DRAENEI:
+			CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_COMMON));
+        	CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_DRAENEI));
+        	break;
+    	case RACE_GNOME:
+			CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_COMMON));
+        	CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_GNOMISH));
+        	break;
+    	case RACE_NIGHTELF:
+			CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_COMMON));
+        	CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_DARNASSIAN));
+        	break;
+    	case RACE_UNDEAD:
+			CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_ORCISH));
+        	CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_GUTTERSPEAK));
+        	break;
+    	case RACE_TAUREN:
+			CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_ORCISH));
+        	CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_TAURAHE));
+        	break;
+    	case RACE_TROLL:
+			CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_ORCISH));
+        	CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_TROLL));
+        	break;
+    	case RACE_BLOODELF:
+			CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_ORCISH));
+        	CharacterDatabase.Execute("INSERT INTO `playerspells` (GUID, SpellID) VALUES ('%u', '%u')", (uint32)GUID, GetSpellForLanguage(SKILL_LANG_THALASSIAN));
+        	break;
+	}
+}
+
 ///====================================================================
 ///  Create
 ///  params: p_newChar
@@ -2419,7 +2477,7 @@ void Player::SaveToDB(bool bNewCharacter /* =false */)
 
 	    	<< m_talentresettimes	   << ", "
 	    	<< m_FirstLogin			 << ", "
-	    	<< rename_pending
+	    	<< login_flags
 	    	<< "," << m_arenaPoints << ","
 	    	<< (uint32)m_StableSlotCount << ",";
 
@@ -2663,7 +2721,7 @@ bool Player::LoadFromDB(uint32 guid)
 {
 	AsyncQuery* q = new AsyncQuery(new SQLClassCallbackP0<Player>(this, &Player::LoadFromDBProc));
 
-	q->AddQuery("SELECT * FROM characters WHERE guid = %u AND forced_rename_pending = 0", guid); // 0
+	q->AddQuery("SELECT * FROM characters WHERE guid = %u AND login_flags = %u", guid, (uint32)LOGIN_NO_FLAG); // 0
 	q->AddQuery("SELECT * FROM tutorials WHERE playerId = %u", guid); // 1
 	q->AddQuery("SELECT cooldown_type, cooldown_misc, cooldown_expire_time, cooldown_spellid, cooldown_itemid FROM playercooldowns WHERE player_guid = %u", guid); // 2
 	q->AddQuery("SELECT * FROM questlog WHERE player_guid = %u", guid); // 3
@@ -2997,7 +3055,7 @@ void Player::LoadFromDBProc(QueryResultVector & results)
 	m_deathState = (DeathState)get_next_field.GetUInt32();
 	m_talentresettimes = get_next_field.GetUInt32();
 	m_FirstLogin = get_next_field.GetBool();
-	rename_pending = get_next_field.GetBool();
+	login_flags = get_next_field.GetUInt32();
 	m_arenaPoints = get_next_field.GetUInt32();
 	if(m_arenaPoints > 5000) m_arenaPoints = 5000;
 	for(uint32 z = 0; z < NUM_CHARTER_TYPES; ++z)
diff --git a/src/arcemu-world/Player.h b/src/arcemu-world/Player.h
index 69cafae..61a3357 100644
--- a/src/arcemu-world/Player.h
+++ b/src/arcemu-world/Player.h
@@ -326,6 +326,23 @@ enum PlayerFlags
 	PLAYER_FLAG_PVP					= 0x40000,
 };
 
+enum CustomizeFlags
+{
+	CHAR_CUSTOMIZE_FLAG_NONE        	= 0x00000000,		// Implemented		* Allows normal login no customization needed
+	CHAR_CUSTOMIZE_FLAG_CUSTOMIZE   	= 0x00000001,   	// Implemented		* Allows name, gender, and looks to be customized
+	CHAR_CUSTOMIZE_FLAG_FACTION     	= 0x00010000,   	// Not Implemented	* Allows name, gender, race, faction, and looks to be customized
+	CHAR_CUSTOMIZE_FLAG_RACE        	= 0x00100000    	// Not Implemented	* Allows name, gender, race, and looks to be customized
+};
+
+enum LoginFlags
+{
+	LOGIN_NO_FLAG = 0,
+	LOGIN_FORCED_RENAME = 1,
+	LOGIN_CUSTOMIZE_FACTION = 2,
+	LOGIN_CUSTOMIZE_RACE = 4,
+	LOGIN_CUSTOMIZE_LOOKS = 8,
+};
+
 enum CharterTypes
 {
 	CHARTER_TYPE_GUILD			= 0,
@@ -941,6 +958,41 @@ class SERVER_DECL Player : public Unit
 		void SendMessageToSet(WorldPacket* data, bool self, bool myteam_only = false);
 		void OutPacketToSet(uint16 Opcode, uint16 Len, const void* Data, bool self);
 
+		/////////////////////////////////////////////////////////////////////////////////////////
+		//static void CharChange_Looks( uint64 GUID, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair )
+		//  Updates database with characters new looks, gender, and name after character customization is called at login.
+		//
+		//Parameter(s)
+		//  uint64 GUID  	-  GUID of the character to customized
+		//  uint8 gender	 -  New gender of the character customized
+		//	uint8 skin		 -	New skin colour of the character customized
+		//	uint8 face		 -	New face selection of the character customized
+		//	uint8 hairStyle	 -	New hair style selected for the character customized
+		//	uint8 hairColor	 -	New hair color selected for the character customized
+		//	uint8 facialHair -	New facial hair selected for the character customized
+		//
+		//Return Value
+		//  None
+		//
+		//
+		/////////////////////////////////////////////////////////////////////////////////////////
+		static void CharChange_Looks( uint64 GUID, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair );
+
+		/////////////////////////////////////////////////////////////////////////////////////////
+		//static void CharChange_Language( uint64 GUID, uint8 race )
+		//  Updates the characters racial languages
+		//
+		//Parameter(s)
+		//  uint64 GUID  	-  GUID of the character to customized
+		//  uint8 race		 -  New race to be usedd for racial language change
+		//
+		//Return Value
+		//  None
+		//
+		//
+		/////////////////////////////////////////////////////////////////////////////////////////
+		static void CharChange_Language( uint64 GUID, uint8 race );
+
 		void AddToWorld();
 		void AddToWorld(MapMgr* pMapMgr);
 		void RemoveFromWorld();
@@ -2103,7 +2155,7 @@ class SERVER_DECL Player : public Unit
 		Charter* m_charters[NUM_CHARTER_TYPES];
 		uint32 flying_aura;
 		bool resend_speed;
-		bool rename_pending;
+		uint32 login_flags;
 		uint32 iInstanceType;
 		void SetName(string & name) { m_name = name; }
 		// spell to (delay, last time)
diff --git a/src/arcemu-world/WorldSession.cpp b/src/arcemu-world/WorldSession.cpp
index e5b1df8..41fa8af 100644
--- a/src/arcemu-world/WorldSession.cpp
+++ b/src/arcemu-world/WorldSession.cpp
@@ -545,6 +545,10 @@ void WorldSession::InitPacketHandlerTable()
 		&WorldSession::HandleCharRenameOpcode;
 	WorldPacketHandlers[CMSG_CHAR_RENAME].status = STATUS_AUTHED;
 
+	WorldPacketHandlers[CMSG_CHAR_CUSTOMIZE].handler = 
+		&WorldSession::HandleCharCustomizeLooksOpcode;
+	WorldPacketHandlers[CMSG_CHAR_CUSTOMIZE].status = STATUS_AUTHED;
+
 	WorldPacketHandlers[CMSG_PLAYER_LOGIN].handler =
 		&WorldSession::HandlePlayerLoginOpcode;
 	WorldPacketHandlers[CMSG_PLAYER_LOGIN].status = STATUS_AUTHED;
diff --git a/src/arcemu-world/WorldSession.h b/src/arcemu-world/WorldSession.h
index 266271a..277ae88 100644
--- a/src/arcemu-world/WorldSession.h
+++ b/src/arcemu-world/WorldSession.h
@@ -733,7 +733,10 @@ class SERVER_DECL WorldSession
 		uint8 TrainerGetSpellStatus(TrainerSpell* pSpell);
 		void SendMailError(uint32 error);
 
+		//At Logins
 		void HandleCharRenameOpcode(WorldPacket & recv_data);
+		void HandleCharCustomizeLooksOpcode(WorldPacket& recv_data);
+
 		void HandlePartyMemberStatsOpcode(WorldPacket & recv_data);
 		void HandleSummonResponseOpcode(WorldPacket & recv_data);
 


Attached File  Customize Phase One Version 2.patch (25.2K)
Number of downloads: 10
Attached File  rename_table Version 2.sql (108bytes)
Number of downloads: 7

This post has been edited by Wil: 19 November 2011 - 07:04 PM
Reason for edit: Updated to a new revision

Nothing
1

#2 User is offline   jackpoz 

  • ArcEmu Lemon Priest
  • PipPipPipPipPipPipPipPip
  • Group: Developers
  • Posts: 2,153
  • Joined: 19-June 08
  • Gender:Male
  • Location:Italy
  • Server OS:Windows

Posted 19 November 2011 - 04:03 AM

I'd suggest to use an enum instead of magic numbers for the flags. Also before switch(fields[16].GetUInt32()) the same value is checked if it's != 0 and != 1, but this can be handled in the default case of the switch, making the code look much cleaner (just a switch instead of if/else and nested switch).
Posted Image We develop dreams. Your dreams ;)
Posted ImagePosted Image
0

#3 User is offline   Wil 

  • Advanced Member
  • Group: Super Moderator
  • Posts: 224
  • Joined: 31-January 09
  • Gender:Male
  • Server OS:Windows

Posted 19 November 2011 - 01:08 PM

I will make those changes and re-submit the patch with those updates. TY for your suggestions
Nothing
0

#4 User is offline   jackpoz 

  • ArcEmu Lemon Priest
  • PipPipPipPipPipPipPipPip
  • Group: Developers
  • Posts: 2,153
  • Joined: 19-June 08
  • Gender:Male
  • Location:Italy
  • Server OS:Windows

Posted 19 November 2011 - 06:29 PM

The db column is a tinyint but the code tries to get a uint32, better change the db column to a bigger integer type then.
Posted Image We develop dreams. Your dreams ;)
Posted ImagePosted Image
0

#5 User is offline   Wil 

  • Advanced Member
  • Group: Super Moderator
  • Posts: 224
  • Joined: 31-January 09
  • Gender:Male
  • Server OS:Windows

Posted 19 November 2011 - 07:05 PM

I have updated the original post with changes the mysql query and updates suggested by jackpoz :)

Thanks for the suggestions
Nothing
0

#6 User is offline   Shadoxfix 

  • Enthusiast
  • PipPipPip
  • Group: Members
  • Posts: 312
  • Joined: 30-December 09
  • Gender:Male
  • Location:Netherlands

Posted 20 November 2011 - 04:54 AM

I was wondering what would you have to put in the DB to change race and looks?
Or do you have to change your race first and then change the looks?
0

#7 User is offline   Wil 

  • Advanced Member
  • Group: Super Moderator
  • Posts: 224
  • Joined: 31-January 09
  • Gender:Male
  • Server OS:Windows

Posted 20 November 2011 - 03:14 PM

That is phase two of this project, I have already started working on enabling that feature I have it working it just needs to be coded neater than it was. It allows a race change at the same time that your allowed to customize looks. Basically they are done all at the same time, faction change is the same aswell.
Nothing
0

#8 User is offline   salamanda 

  • Enthusiast
  • PipPipPip
  • Group: Members
  • Posts: 161
  • Joined: 10-July 08

Posted 08 January 2012 - 05:22 PM

Looks to be working well apart from when a player tries to change there name after being flagged for a customize, the server gets confused and treats them like the old name even though there new name is required to be interacted with.
0

#9 User is offline   Wil 

  • Advanced Member
  • Group: Super Moderator
  • Posts: 224
  • Joined: 31-January 09
  • Gender:Male
  • Server OS:Windows

Posted 12 January 2012 - 08:41 PM

That is an odd problem I will have to look and see if I can get it to do that on mine.

The player is not fully loaded when the customization happens so it shouldn't be an issue.

Thanks for the bug report on it.
Nothing
0

#10 User is offline   Wil 

  • Advanced Member
  • Group: Super Moderator
  • Posts: 224
  • Joined: 31-January 09
  • Gender:Male
  • Server OS:Windows

Posted 09 February 2012 - 09:16 AM

View Postsalamanda, on 08 January 2012 - 05:22 PM, said:

Looks to be working well apart from when a player tries to change there name after being flagged for a customize, the server gets confused and treats them like the old name even though there new name is required to be interacted with.


Could you please tell me how to duplicate this problem, I have tested this in every way i can and am unable to duplicate this issue.
Nothing
0

#11 User is offline   salamanda 

  • Enthusiast
  • PipPipPip
  • Group: Members
  • Posts: 161
  • Joined: 10-July 08

Posted 27 February 2012 - 05:50 PM

View PostWil, on 09 February 2012 - 09:16 AM, said:

Could you please tell me how to duplicate this problem, I have tested this in every way i can and am unable to duplicate this issue.


I have no idea how I produced the issue I reported, I just experimented with it some more and was unable to trigger this effect again. Sorry for the confusing report.
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users