Implemented character customize future.

Not tested, but should work...
This commit is contained in:
tomrus88 2008-12-12 01:44:52 +03:00
parent db64bf6b80
commit 0f7077546f
11 changed files with 229 additions and 72 deletions

View file

@ -0,0 +1,3 @@
INSERT INTO `mangos_string` VALUES
(345,'Forced customize for player %s will be requested at next login.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(346,'Forced customize for player %s (GUID #%u) will be requested at next login.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);

View file

@ -914,7 +914,7 @@ void WorldSession::HandleToggleCloakOpcode( WorldPacket & /*recv_data*/ )
void WorldSession::HandleChangePlayerNameOpcode(WorldPacket& recv_data)
{
CHECK_PACKET_SIZE(recv_data,8+1);
CHECK_PACKET_SIZE(recv_data, 8+1);
uint64 guid;
std::string newname;
@ -929,21 +929,20 @@ void WorldSession::HandleChangePlayerNameOpcode(WorldPacket& recv_data)
if (!result)
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
data << (uint8)CHAR_CREATE_ERROR;
data << uint8(CHAR_CREATE_ERROR);
SendPacket( &data );
return;
}
uint32 at_loginFlags;
Field *fields = result->Fetch();
at_loginFlags = fields[0].GetUInt32();
uint32 at_loginFlags = fields[0].GetUInt32();
oldname = fields[1].GetCppString();
delete result;
if (!(at_loginFlags & AT_LOGIN_RENAME))
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
data << (uint8)CHAR_CREATE_ERROR;
data << uint8(CHAR_CREATE_ERROR);
SendPacket( &data );
return;
}
@ -952,7 +951,7 @@ void WorldSession::HandleChangePlayerNameOpcode(WorldPacket& recv_data)
if(!normalizePlayerName(newname))
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
data << (uint8)CHAR_NAME_NO_NAME;
data << uint8(CHAR_NAME_NO_NAME);
SendPacket( &data );
return;
}
@ -960,7 +959,7 @@ void WorldSession::HandleChangePlayerNameOpcode(WorldPacket& recv_data)
if(!ObjectMgr::IsValidName(newname,true))
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
data << (uint8)CHAR_NAME_INVALID_CHARACTER;
data << uint8(CHAR_NAME_INVALID_CHARACTER);
SendPacket( &data );
return;
}
@ -969,7 +968,7 @@ void WorldSession::HandleChangePlayerNameOpcode(WorldPacket& recv_data)
if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname))
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
data << (uint8)CHAR_NAME_RESERVED;
data << uint8(CHAR_NAME_RESERVED);
SendPacket( &data );
return;
}
@ -977,7 +976,7 @@ void WorldSession::HandleChangePlayerNameOpcode(WorldPacket& recv_data)
if(objmgr.GetPlayerGUIDByName(newname)) // character with this name already exist
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
data << (uint8)CHAR_CREATE_ERROR;
data << uint8(CHAR_CREATE_NAME_IN_USE);
SendPacket( &data );
return;
}
@ -985,23 +984,21 @@ void WorldSession::HandleChangePlayerNameOpcode(WorldPacket& recv_data)
if(newname == oldname) // checked by client
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
data << (uint8)CHAR_NAME_FAILURE;
data << uint8(CHAR_NAME_FAILURE);
SendPacket( &data );
return;
}
// we have to check character at_login_flag & AT_LOGIN_RENAME also (fake packets hehe)
CharacterDatabase.escape_string(newname);
CharacterDatabase.PExecute("UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'", newname.c_str(), uint32(AT_LOGIN_RENAME),GUID_LOPART(guid));
CharacterDatabase.PExecute("UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'", newname.c_str(), uint32(AT_LOGIN_RENAME), GUID_LOPART(guid));
CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid ='%u'", GUID_LOPART(guid));
std::string IP_str = GetRemoteAddress();
sLog.outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s",GetAccountId(),IP_str.c_str(),oldname.c_str(),GUID_LOPART(guid),newname.c_str());
sLog.outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s", GetAccountId(), IP_str.c_str(), oldname.c_str(), GUID_LOPART(guid), newname.c_str());
WorldPacket data(SMSG_CHAR_RENAME,1+8+(newname.size()+1));
data << (uint8)RESPONSE_SUCCESS;
data << guid;
data << uint8(RESPONSE_SUCCESS);
data << uint64(guid);
data << newname;
SendPacket(&data);
}
@ -1167,3 +1164,94 @@ void WorldSession::HandleRemoveGlyph( WorldPacket & recv_data )
}
}
}
void WorldSession::HandleCharCustomize(WorldPacket& recv_data)
{
CHECK_PACKET_SIZE(recv_data, 8+1);
uint64 guid;
std::string newname;
recv_data >> guid;
recv_data >> newname;
CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+1+1+1+1+1+1);
uint8 gender, skin, face, hairStyle, hairColor, facialHair;
recv_data >> gender >> skin >> face >> hairStyle >> hairColor >> facialHair;
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;
}
Field *fields = result->Fetch();
uint32 at_loginFlags = fields[0].GetUInt32();
delete result;
if (!(at_loginFlags & AT_LOGIN_CUSTOMIZE))
{
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
data << uint8(CHAR_CREATE_ERROR);
SendPacket( &data );
return;
}
// prevent character rename to invalid name
if(!normalizePlayerName(newname))
{
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
data << uint8(CHAR_NAME_NO_NAME);
SendPacket( &data );
return;
}
if(!ObjectMgr::IsValidName(newname,true))
{
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
data << uint8(CHAR_NAME_INVALID_CHARACTER);
SendPacket( &data );
return;
}
// check name limitations
if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname))
{
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
data << uint8(CHAR_NAME_RESERVED);
SendPacket( &data );
return;
}
if(objmgr.GetPlayerGUIDByName(newname)) // character with this name already exist
{
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
data << uint8(CHAR_CREATE_NAME_IN_USE);
SendPacket( &data );
return;
}
CharacterDatabase.escape_string(newname);
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));
std::string IP_str = GetRemoteAddress();
sLog.outChar("Account: %d (IP: %s), Character guid: %u Customized to: %s", GetAccountId(), IP_str.c_str(), GUID_LOPART(guid), newname.c_str());
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);
SendPacket(&data);
}

View file

@ -555,6 +555,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "sendmail", SEC_MODERATOR, true, &ChatHandler::HandleSendMailCommand, "", NULL },
{ "sendmoney", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMoneyCommand, "", NULL },
{ "rename", SEC_GAMEMASTER, true, &ChatHandler::HandleRenameCommand, "", NULL },
{ "customize", SEC_GAMEMASTER, true, &ChatHandler::HandleCustomizeCommand, "", NULL },
{ "loadscripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLoadScriptsCommand, "", NULL },
{ "mute", SEC_GAMEMASTER, true, &ChatHandler::HandleMuteCommand, "", NULL },
{ "unmute", SEC_GAMEMASTER, true, &ChatHandler::HandleUnmuteCommand, "", NULL },

View file

@ -406,6 +406,7 @@ class ChatHandler
bool HandleSendChannelNotifyCommand(const char* args);
bool HandleSendChatMsgCommand(const char* args);
bool HandleRenameCommand(const char * args);
bool HandleCustomizeCommand(const char * args);
bool HandleLoadPDumpCommand(const char *args);
bool HandleWritePDumpCommand(const char *args);
bool HandleCastCommand(const char *args);

View file

@ -326,6 +326,8 @@ enum MangosStrings
LANG_CREATURE_NOT_FOLLOW_YOU_NOW = 342,
LANG_CREATURE_NON_TAMEABLE = 343,
LANG_YOU_ALREADY_HAVE_PET = 344,
LANG_CUSTOMIZE_PLAYER = 345,
LANG_CUSTOMIZE_PLAYER_GUID = 346,
// Room for more level 2 345-399 not used
// level 3 chat

View file

@ -3356,6 +3356,59 @@ bool ChatHandler::HandleRenameCommand(const char* args)
return true;
}
// customize characters
bool ChatHandler::HandleCustomizeCommand(const char* args)
{
Player* target = NULL;
uint64 targetGUID = 0;
std::string oldname;
char* px = strtok((char*)args, " ");
if(px)
{
oldname = px;
if(!normalizePlayerName(oldname))
{
SendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
target = objmgr.GetPlayer(oldname.c_str());
if (!target)
targetGUID = objmgr.GetPlayerGUIDByName(oldname);
}
if(!target && !targetGUID)
{
target = getSelectedPlayer();
}
if(!target && !targetGUID)
{
SendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
if(target)
{
PSendSysMessage(LANG_CUSTOMIZE_PLAYER, target->GetName());
target->SetAtLoginFlag(AT_LOGIN_CUSTOMIZE);
CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '8' WHERE guid = '%u'", target->GetGUIDLow());
}
else
{
PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldname.c_str(), GUID_LOPART(targetGUID));
CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '8' WHERE guid = '%u'", GUID_LOPART(targetGUID));
}
return true;
}
//spawn go
bool ChatHandler::HandleGameObjectCommand(const char* args)
{

View file

@ -1165,7 +1165,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
/*0x470*/ { "CMSG_SET_CRITERIA_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x471*/ { "SMSG_GROUP_SWAP_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x472*/ { "CMSG_UNITANIMTIER_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x473*/ { "CMSG_CHAR_CUSTOMIZE", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x473*/ { "CMSG_CHAR_CUSTOMIZE", STATUS_AUTHED, &WorldSession::HandleCharCustomize },
/*0x474*/ { "SMSG_CHAR_CUSTOMIZE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x475*/ { "SMSG_PET_RENAMEABLE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x476*/ { "CMSG_REQUEST_VEHICLE_EXIT", STATUS_NEVER, &WorldSession::Handle_NULL },

View file

@ -1329,13 +1329,15 @@ void Player::setDeathState(DeathState s)
void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
{
*p_data << GetGUID();
Field *fields = result->Fetch();
*p_data << uint64(GetGUID());
*p_data << m_name;
*p_data << getRace();
*p_data << uint8(getRace());
uint8 pClass = getClass();
*p_data << pClass;
*p_data << getGender();
*p_data << uint8(pClass);
*p_data << uint8(getGender());
uint32 bytes = GetUInt32Value(PLAYER_BYTES);
*p_data << uint8(bytes);
@ -1350,14 +1352,15 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
// do not use GetMap! it will spawn a new instance since the bound instances are not loaded
uint32 zoneId = MapManager::Instance().GetZoneId(GetMapId(), GetPositionX(),GetPositionY());
sLog.outDebug("Player::BuildEnumData: m:%u, x:%f, y:%f, z:%f zone:%u", GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), zoneId);
*p_data << zoneId;
*p_data << GetMapId();
*p_data << uint32(zoneId);
*p_data << uint32(GetMapId());
*p_data << GetPositionX();
*p_data << GetPositionY();
*p_data << GetPositionZ();
*p_data << (result ? result->Fetch()[13].GetUInt32() : 0);
// guild id
*p_data << (result ? fields[13].GetUInt32() : 0);
uint32 char_flags = 0;
if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM))
@ -1368,14 +1371,13 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
char_flags |= CHARACTER_FLAG_GHOST;
if(HasAtLoginFlag(AT_LOGIN_RENAME))
char_flags |= CHARACTER_FLAG_RENAME;
// always send the flag if declined names aren't used
// to let the client select a default method of declining the name
if(!sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) || (result && result->Fetch()[14].GetCppString() != ""))
if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) && (fields[14].GetCppString() != ""))
char_flags |= CHARACTER_FLAG_DECLINED;
*p_data << (uint32)char_flags; // character flags
*p_data << (uint32)0; // new wotlk
*p_data << (uint8)1; // unknown
*p_data << uint32(char_flags); // character flags
// character customize (flags?)
*p_data << uint32(HasAtLoginFlag(AT_LOGIN_CUSTOMIZE) ? 1 : 0);
*p_data << uint8(1); // unknown
// Pets info
{
@ -1386,8 +1388,6 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
// show pet at selection character in character list only for non-ghost character
if(result && isAlive() && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER))
{
Field* fields = result->Fetch();
uint32 entry = fields[10].GetUInt32();
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(entry);
if(cInfo)
@ -1398,36 +1398,11 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
}
}
*p_data << (uint32)petDisplayId;
*p_data << (uint32)petLevel;
*p_data << (uint32)petFamily;
*p_data << uint32(petDisplayId);
*p_data << uint32(petLevel);
*p_data << uint32(petFamily);
}
/*ItemPrototype const *items[EQUIPMENT_SLOT_END];
for (int i = 0; i < EQUIPMENT_SLOT_END; i++)
items[i] = NULL;
QueryResult *result = CharacterDatabase.PQuery("SELECT slot,item_template FROM character_inventory WHERE guid = '%u' AND bag = 0",GetGUIDLow());
if (result)
{
do
{
Field *fields = result->Fetch();
uint8 slot = fields[0].GetUInt8() & 255;
uint32 item_id = fields[1].GetUInt32();
if( slot >= EQUIPMENT_SLOT_END )
continue;
items[slot] = objmgr.GetItemPrototype(item_id);
if(!items[slot])
{
sLog.outError( "Player::BuildEnumData: Player %s have unknown item (id: #%u) in inventory, skipped.", GetName(),item_id );
continue;
}
} while (result->NextRow());
delete result;
}*/
for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; slot++)
{
uint32 visualbase = PLAYER_VISIBLE_ITEM_1_0 + (slot * MAX_VISIBLE_ITEM_OFFSET);
@ -1444,20 +1419,20 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
if (proto != NULL)
{
*p_data << (uint32)proto->DisplayInfoID;
*p_data << (uint8)proto->InventoryType;
*p_data << (uint32)(enchant?enchant->aura_id:0);
*p_data << uint32(proto->DisplayInfoID);
*p_data << uint8(proto->InventoryType);
*p_data << uint32(enchant ? enchant->aura_id : 0);
}
else
{
*p_data << (uint32)0;
*p_data << (uint8)0;
*p_data << (uint32)0; // enchant?
*p_data << uint32(0);
*p_data << uint8(0);
*p_data << uint32(0); // enchant?
}
}
*p_data << (uint32)0; // first bag display id
*p_data << (uint8)0; // first bag inventory type
*p_data << (uint32)0; // enchant?
*p_data << uint32(0); // first bag display id
*p_data << uint8(0); // first bag inventory type
*p_data << uint32(0); // enchant?
}
bool Player::ToggleAFK()
@ -15791,6 +15766,36 @@ void Player::SetFloatValueInDB(uint16 index, float value, uint64 guid)
Player::SetUInt32ValueInDB(index, temp, guid);
}
void Player::Customize(uint64 guid, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair)
{
Tokens tokens;
if(!LoadValuesArrayFromDB(tokens,guid))
return;
uint32 player_bytes = atol(tokens[PLAYER_BYTES].c_str());
((uint8*)player_bytes)[0] = skin;
((uint8*)player_bytes)[1] = face;
((uint8*)player_bytes)[2] = hairStyle;
((uint8*)player_bytes)[3] = hairColor;
char buf[11];
snprintf(buf,11,"%u",player_bytes);
tokens[PLAYER_BYTES] = buf;
uint32 player_bytes2 = atol(tokens[PLAYER_BYTES_2].c_str());
((uint8*)player_bytes2)[0] = facialHair;
char buf2[11];
snprintf(buf2,11,"%u",player_bytes2);
tokens[PLAYER_BYTES_2] = buf;
uint32 player_bytes3 = atol(tokens[PLAYER_BYTES_3].c_str());
((uint8*)player_bytes3)[0] = gender;
char buf3[11];
snprintf(buf3,11,"%u",player_bytes3);
tokens[PLAYER_BYTES_3] = buf;
SaveValuesArrayInDB(tokens,guid);
}
void Player::SendAttackSwingNotStanding()
{
WorldPacket data(SMSG_ATTACKSWING_NOTSTANDING, 0);

View file

@ -548,7 +548,8 @@ enum AtLoginFlags
AT_LOGIN_NONE = 0,
AT_LOGIN_RENAME = 1,
AT_LOGIN_RESET_SPELLS = 2,
AT_LOGIN_RESET_TALENTS = 4
AT_LOGIN_RESET_TALENTS = 4,
AT_LOGIN_CUSTOMIZE = 8
};
typedef std::map<uint32, QuestStatusData> QuestStatusMap;
@ -1333,6 +1334,7 @@ class MANGOS_DLL_SPEC Player : public Unit
static void SetFloatValueInArray(Tokens& data,uint16 index, float value);
static void SetUInt32ValueInDB(uint16 index, uint32 value, uint64 guid);
static void SetFloatValueInDB(uint16 index, float value, uint64 guid);
static void Customize(uint64 guid, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair);
static void SavePositionInDB(uint32 mapid, float x,float y,float z,float o,uint32 zone,uint64 guid);
bool m_mailsLoaded;

View file

@ -664,6 +664,7 @@ class MANGOS_DLL_SPEC WorldSession
void HandleSpellClick(WorldPacket& recv_data);
void HandleAlterAppearance(WorldPacket& recv_data);
void HandleRemoveGlyph(WorldPacket& recv_data);
void HandleCharCustomize(WorldPacket& recv_data);
void HandleInspectAchievements(WorldPacket& recv_data);
private:
// private trade methods

View file

@ -40,7 +40,8 @@ struct AchievementEntry
uint32 ID; // 0
uint32 factionFlag; // 1 -1=all, 0=horde, 1=alliance
uint32 mapID; // 2 -1=none
//char *name[16]; // 3-19
//uint32 unk; // 3
//char *name[16]; // 4-19
//uint32 name_flags; // 20
//char *description[16]; // 21-36
//uint32 desc_flags; // 37
@ -48,7 +49,7 @@ struct AchievementEntry
uint32 points; // 39 reward points
//uint32 OrderInCategory; // 40
uint32 flags; // 41
//uint32 flags; // 42 not flags, some unknown value...
//uint32 icon; // 42 icon
//char *unk1[16]; // 43-58
//uint32 unk_flags; // 59
//uint32 count; // 60