Add support for character race and faction transfers.
Based (loosely) on patch by Ner'zhul, DarkXuan, and [email protected]. Fixes issue #3429. --HG-- branch : trunk
This commit is contained in:
@@ -131,14 +131,16 @@ ChatCommand * ChatHandler::getCommandTable()
|
||||
|
||||
static ChatCommand characterCommandTable[] =
|
||||
{
|
||||
{ "customize", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterCustomizeCommand, "", NULL },
|
||||
{ "deleted", SEC_GAMEMASTER, true, NULL, "", characterDeletedCommandTable},
|
||||
{ "erase", SEC_CONSOLE, true, &ChatHandler::HandleCharacterEraseCommand, "", NULL },
|
||||
{ "level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleCharacterLevelCommand, "", NULL },
|
||||
{ "rename", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterRenameCommand, "", NULL },
|
||||
{ "reputation", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterReputationCommand, "", NULL },
|
||||
{ "titles", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterTitlesCommand, "", NULL },
|
||||
{ NULL, 0, false, NULL, "", NULL }
|
||||
{ "customize", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterCustomizeCommand, "", NULL },
|
||||
{ "changefaction", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterChangeFactionCommand, "", NULL },
|
||||
{ "changerace", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterChangeRaceCommand, "", NULL },
|
||||
{ "deleted", SEC_GAMEMASTER, true, NULL, "", characterDeletedCommandTable},
|
||||
{ "erase", SEC_CONSOLE, true, &ChatHandler::HandleCharacterEraseCommand, "", NULL },
|
||||
{ "level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleCharacterLevelCommand, "", NULL },
|
||||
{ "rename", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterRenameCommand, "", NULL },
|
||||
{ "reputation", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterReputationCommand, "", NULL },
|
||||
{ "titles", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterTitlesCommand, "", NULL },
|
||||
{ NULL, 0, false, NULL, "", NULL }
|
||||
};
|
||||
|
||||
static ChatCommand channelSetCommandTable[] =
|
||||
|
||||
@@ -138,6 +138,8 @@ class ChatHandler
|
||||
bool HandleCastTargetCommand(const char *args);
|
||||
|
||||
bool HandleCharacterCustomizeCommand(const char * args);
|
||||
bool HandleCharacterChangeFactionCommand(const char * args);
|
||||
bool HandleCharacterChangeRaceCommand(const char * args);
|
||||
bool HandleCharacterDeletedDeleteCommand(const char* args);
|
||||
bool HandleCharacterDeletedListCommand(const char* args);
|
||||
bool HandleCharacterDeletedRestoreCommand(const char* args);
|
||||
|
||||
@@ -3254,6 +3254,61 @@ bool ChatHandler::HandleCharacterCustomizeCommand(const char* args)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleCharacterChangeFactionCommand(const char * args)
|
||||
{
|
||||
Player* target;
|
||||
uint64 target_guid;
|
||||
std::string target_name;
|
||||
|
||||
if(!extractPlayerTarget((char*)args,&target,&target_guid,&target_name))
|
||||
return false;
|
||||
|
||||
if(target)
|
||||
{
|
||||
// TODO : add text into database
|
||||
PSendSysMessage(LANG_CUSTOMIZE_PLAYER, GetNameLink(target).c_str());
|
||||
target->SetAtLoginFlag(AT_LOGIN_CHANGE_FACTION);
|
||||
CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '64' WHERE guid = %u", target->GetGUIDLow());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string oldNameLink = playerLink(target_name);
|
||||
|
||||
// TODO : add text into database
|
||||
PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(target_guid));
|
||||
CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '64' WHERE guid = %u", GUID_LOPART(target_guid));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleCharacterChangeRaceCommand(const char * args)
|
||||
{
|
||||
Player* target;
|
||||
uint64 target_guid;
|
||||
std::string target_name;
|
||||
if(!extractPlayerTarget((char*)args,&target,&target_guid,&target_name))
|
||||
return false;
|
||||
|
||||
if(target)
|
||||
{
|
||||
// TODO : add text into database
|
||||
PSendSysMessage(LANG_CUSTOMIZE_PLAYER, GetNameLink(target).c_str());
|
||||
target->SetAtLoginFlag(AT_LOGIN_CHANGE_RACE);
|
||||
CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '128' WHERE guid = %u", target->GetGUIDLow());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string oldNameLink = playerLink(target_name);
|
||||
|
||||
// TODO : add text into database
|
||||
PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(target_guid));
|
||||
CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '128' WHERE guid = %u", GUID_LOPART(target_guid));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleCharacterReputationCommand(const char* args)
|
||||
{
|
||||
Player* target;
|
||||
|
||||
@@ -170,6 +170,9 @@ static uint32 sTalentTabPages[MAX_CLASSES][3];
|
||||
DBCStorage <TaxiNodesEntry> sTaxiNodesStore(TaxiNodesEntryfmt);
|
||||
TaxiMask sTaxiNodesMask;
|
||||
TaxiMask sOldContinentsNodesMask;
|
||||
TaxiMask sHordeTaxiNodesMask;
|
||||
TaxiMask sAllianceTaxiNodesMask;
|
||||
TaxiMask sDeathKnightTaxiNodesMask;
|
||||
|
||||
// DBC used only for initialization sTaxiPathSetBySource at startup.
|
||||
TaxiPathSetBySource sTaxiPathSetBySource;
|
||||
@@ -515,11 +518,14 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
for (uint32 i = 1; i < sSpellStore.GetNumRows (); ++i)
|
||||
if (SpellEntry const* sInfo = sSpellStore.LookupEntry (i))
|
||||
for (int j=0; j < 3; ++j)
|
||||
if (sInfo->Effect[j] == 123 /*SPELL_EFFECT_SEND_TAXI*/)
|
||||
if (sInfo->Effect[j] == SPELL_EFFECT_SEND_TAXI)
|
||||
spellPaths.insert(sInfo->EffectMiscValue[j]);
|
||||
|
||||
memset(sTaxiNodesMask,0,sizeof(sTaxiNodesMask));
|
||||
memset(sOldContinentsNodesMask,0,sizeof(sTaxiNodesMask));
|
||||
memset(sOldContinentsNodesMask,0,sizeof(sOldContinentsNodesMask));
|
||||
memset(sHordeTaxiNodesMask,0,sizeof(sHordeTaxiNodesMask));
|
||||
memset(sAllianceTaxiNodesMask,0,sizeof(sAllianceTaxiNodesMask));
|
||||
memset(sDeathKnightTaxiNodesMask,0,sizeof(sDeathKnightTaxiNodesMask));
|
||||
for (uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
|
||||
{
|
||||
TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i);
|
||||
@@ -549,6 +555,13 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
uint32 submask = 1<<((i-1)%32);
|
||||
sTaxiNodesMask[field] |= submask;
|
||||
|
||||
if (node->MountCreatureID[0] && node->MountCreatureID[0] != 32981)
|
||||
sHordeTaxiNodesMask[field] |= submask;
|
||||
if (node->MountCreatureID[1] && node->MountCreatureID[1] != 32981)
|
||||
sAllianceTaxiNodesMask[field] |= submask;
|
||||
if (node->MountCreatureID[0] == 32981 || node->MountCreatureID[1] == 32981)
|
||||
sDeathKnightTaxiNodesMask[field] |= submask;
|
||||
|
||||
// old continent node (+ nodes virtually at old continents, check explicitly to avoid loading map files for zone info)
|
||||
if (node->map_id < 2 || i == 82 || i == 83 || i == 93 || i == 94)
|
||||
sOldContinentsNodesMask[field] |= submask;
|
||||
|
||||
@@ -153,6 +153,9 @@ extern DBCStorage <TaxiNodesEntry> sTaxiNodesStore;
|
||||
extern DBCStorage <TaxiPathEntry> sTaxiPathStore;
|
||||
extern TaxiMask sTaxiNodesMask;
|
||||
extern TaxiMask sOldContinentsNodesMask;
|
||||
extern TaxiMask sHordeTaxiNodesMask;
|
||||
extern TaxiMask sAllianceTaxiNodesMask;
|
||||
extern TaxiMask sDeathKnightTaxiNodesMask;
|
||||
extern TaxiPathSetBySource sTaxiPathSetBySource;
|
||||
extern TaxiPathNodesByPath sTaxiPathNodesByPath;
|
||||
extern DBCStorage <TotemCategoryEntry> sTotemCategoryStore;
|
||||
|
||||
@@ -1654,8 +1654,17 @@ bool Player::BuildEnumData(QueryResult_AutoPtr result, WorldPacket * p_data)
|
||||
char_flags |= CHARACTER_FLAG_DECLINED;
|
||||
|
||||
*p_data << uint32(char_flags); // character flags
|
||||
|
||||
// character customize flags
|
||||
*p_data << uint32(atLoginFlags & AT_LOGIN_CUSTOMIZE ? CHAR_CUSTOMIZE_FLAG_CUSTOMIZE : CHAR_CUSTOMIZE_FLAG_NONE);
|
||||
if (atLoginFlags & AT_LOGIN_CUSTOMIZE)
|
||||
*p_data << uint32(CHAR_CUSTOMIZE_FLAG_CUSTOMIZE);
|
||||
else if (atLoginFlags & AT_LOGIN_CHANGE_FACTION)
|
||||
*p_data << uint32(CHAR_CUSTOMIZE_FLAG_FACTION);
|
||||
else if (atLoginFlags & AT_LOGIN_CHANGE_RACE)
|
||||
*p_data << uint32(CHAR_CUSTOMIZE_FLAG_RACE);
|
||||
else
|
||||
*p_data << uint32(CHAR_CUSTOMIZE_FLAG_NONE);
|
||||
|
||||
// First login
|
||||
*p_data << uint8(atLoginFlags & AT_LOGIN_FIRST ? 1 : 0);
|
||||
|
||||
|
||||
@@ -501,6 +501,8 @@ enum AtLoginFlags
|
||||
AT_LOGIN_CUSTOMIZE = 0x08,
|
||||
AT_LOGIN_RESET_PET_TALENTS = 0x10,
|
||||
AT_LOGIN_FIRST = 0x20,
|
||||
AT_LOGIN_CHANGE_FACTION = 0x40,
|
||||
AT_LOGIN_CHANGE_RACE = 0x80
|
||||
};
|
||||
|
||||
typedef std::map<uint32, QuestStatusData> QuestStatusMap;
|
||||
|
||||
@@ -8931,3 +8931,183 @@ void ObjectMgr::LoadCreatureClassLevelStats()
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u creature base stats.", counter);
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadFactionChangeAchievements()
|
||||
{
|
||||
QueryResult_AutoPtr result = WorldDatabase.Query("SELECT alliance_id, horde_id FROM player_factionchange_achievement");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
barGoLink bar(1);
|
||||
bar.step();
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded 0 faction change achievement pairs. DB table `player_factionchange_achievement` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
barGoLink bar(result->GetRowCount());
|
||||
uint32 counter = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 alliance = fields[0].GetUInt32();
|
||||
uint32 horde = fields[1].GetUInt32();
|
||||
|
||||
if (!sAchievementStore.LookupEntry(alliance))
|
||||
{
|
||||
sLog.outErrorDb("Achievement %u referenced in `player_factionchange_achievement` does not exist, pair skipped!", alliance);
|
||||
}
|
||||
else if (!sAchievementStore.LookupEntry(horde))
|
||||
{
|
||||
sLog.outErrorDb("Achievement %u referenced in `player_factionchange_achievement` does not exist, pair skipped!", horde);
|
||||
}
|
||||
else
|
||||
{
|
||||
factionchange_achievements[alliance] = horde;
|
||||
}
|
||||
|
||||
bar.step();
|
||||
++counter;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u faction change achievement pairs.", counter);
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadFactionChangeItems()
|
||||
{
|
||||
QueryResult_AutoPtr result = WorldDatabase.Query("SELECT alliance_id, horde_id FROM player_factionchange_items");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
barGoLink bar(1);
|
||||
bar.step();
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded 0 faction change item pairs. DB table `player_factionchange_items` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
barGoLink bar(result->GetRowCount());
|
||||
uint32 counter = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 alliance = fields[0].GetUInt32();
|
||||
uint32 horde = fields[1].GetUInt32();
|
||||
|
||||
if (!GetItemPrototype(alliance))
|
||||
{
|
||||
sLog.outErrorDb("Item %u referenced in `player_factionchange_items` does not exist, pair skipped!", alliance);
|
||||
}
|
||||
else if (!GetItemPrototype(horde))
|
||||
{
|
||||
sLog.outErrorDb("Item %u referenced in `player_factionchange_items` does not exist, pair skipped!", horde);
|
||||
}
|
||||
else
|
||||
{
|
||||
factionchange_items[alliance] = horde;
|
||||
}
|
||||
|
||||
bar.step();
|
||||
++counter;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u faction change item pairs.", counter);
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadFactionChangeSpells()
|
||||
{
|
||||
QueryResult_AutoPtr result = WorldDatabase.Query("SELECT alliance_id, horde_id FROM player_factionchange_spells");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
barGoLink bar(1);
|
||||
bar.step();
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded 0 faction change spell pairs. DB table `player_factionchange_spells` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
barGoLink bar(result->GetRowCount());
|
||||
uint32 counter = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 alliance = fields[0].GetUInt32();
|
||||
uint32 horde = fields[1].GetUInt32();
|
||||
|
||||
if (!sSpellStore.LookupEntry(alliance))
|
||||
{
|
||||
sLog.outErrorDb("Spell %u referenced in `player_factionchange_spells` does not exist, pair skipped!", alliance);
|
||||
}
|
||||
else if (!sSpellStore.LookupEntry(horde))
|
||||
{
|
||||
sLog.outErrorDb("Spell %u referenced in `player_factionchange_spells` does not exist, pair skipped!", horde);
|
||||
}
|
||||
else
|
||||
{
|
||||
factionchange_spells[alliance] = horde;
|
||||
}
|
||||
|
||||
bar.step();
|
||||
++counter;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u faction change spell pairs.", counter);
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadFactionChangeReputations()
|
||||
{
|
||||
QueryResult_AutoPtr result = WorldDatabase.Query("SELECT alliance_id, horde_id FROM player_factionchange_reputations");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
barGoLink bar(1);
|
||||
bar.step();
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded 0 faction change reputation pairs. DB table `player_factionchange_reputations` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
barGoLink bar(result->GetRowCount());
|
||||
uint32 counter = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 alliance = fields[0].GetUInt32();
|
||||
uint32 horde = fields[1].GetUInt32();
|
||||
|
||||
if (!sFactionStore.LookupEntry(alliance))
|
||||
{
|
||||
sLog.outErrorDb("Reputation %u referenced in `player_factionchange_reputations` does not exist, pair skipped!", alliance);
|
||||
}
|
||||
else if (!sFactionStore.LookupEntry(horde))
|
||||
{
|
||||
sLog.outErrorDb("Reputation %u referenced in `player_factionchange_reputations` does not exist, pair skipped!", horde);
|
||||
}
|
||||
else
|
||||
{
|
||||
factionchange_reputations[alliance] = horde;
|
||||
}
|
||||
|
||||
bar.step();
|
||||
++counter;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u faction change reputation pairs.", counter);
|
||||
}
|
||||
|
||||
@@ -390,6 +390,8 @@ class ObjectMgr
|
||||
|
||||
typedef std::vector<std::string> ScriptNameMap;
|
||||
|
||||
typedef std::map<uint32, uint32> CharacterConversionMap;
|
||||
|
||||
Player* GetPlayer(const char* name) const { return sObjectAccessor.FindPlayerByName(name);}
|
||||
Player* GetPlayer(uint64 guid) const { return ObjectAccessor::FindPlayer(guid); }
|
||||
|
||||
@@ -961,6 +963,16 @@ class ObjectMgr
|
||||
value = data[loc_idx];
|
||||
}
|
||||
|
||||
CharacterConversionMap factionchange_achievements;
|
||||
CharacterConversionMap factionchange_items;
|
||||
CharacterConversionMap factionchange_spells;
|
||||
CharacterConversionMap factionchange_reputations;
|
||||
|
||||
void LoadFactionChangeAchievements();
|
||||
void LoadFactionChangeItems();
|
||||
void LoadFactionChangeSpells();
|
||||
void LoadFactionChangeReputations();
|
||||
|
||||
protected:
|
||||
|
||||
// first free id for selected id type
|
||||
|
||||
@@ -87,6 +87,12 @@ enum Races
|
||||
(1<<(RACE_GNOME-1)) |(1<<(RACE_TROLL-1)) |(1<<(RACE_BLOODELF-1))| \
|
||||
(1<<(RACE_DRAENEI-1)))
|
||||
|
||||
#define RACEMASK_ALLIANCE \
|
||||
((1<<(RACE_HUMAN-1)) | (1<<(RACE_DWARF-1)) | (1<<(RACE_NIGHTELF-1)) | \
|
||||
(1<<(RACE_GNOME-1)) | (1<<(RACE_DRAENEI-1)))
|
||||
|
||||
#define RACEMASK_HORDE RACEMASK_ALL_PLAYABLE & ~RACEMASK_ALLIANCE
|
||||
|
||||
// Class value is index in ChrClasses.dbc
|
||||
enum Classes
|
||||
{
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "UpdateMask.h"
|
||||
#include "Util.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "Battleground.h"
|
||||
|
||||
class LoginQueryHolder : public SQLQueryHolder
|
||||
{
|
||||
@@ -1327,3 +1328,319 @@ void WorldSession::HandleEquipmentSetUse(WorldPacket &recv_data)
|
||||
data << uint8(0); // 4 - equipment swap failed - inventory is full
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
std::string newname;
|
||||
uint8 gender, skin, face, hairStyle, hairColor, facialHair, race;
|
||||
recv_data >> guid;
|
||||
recv_data >> newname;
|
||||
recv_data >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face >> race;
|
||||
|
||||
QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT class, level, at_login FROM characters WHERE guid ='%u'", GUID_LOPART(guid));
|
||||
if (!result)
|
||||
{
|
||||
WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1);
|
||||
data << uint8(CHAR_CREATE_ERROR);
|
||||
SendPacket( &data );
|
||||
return;
|
||||
}
|
||||
|
||||
Field *fields = result->Fetch();
|
||||
uint32 playerClass = fields[0].GetUInt32();
|
||||
uint32 level = fields[1].GetUInt32();
|
||||
uint32 at_loginFlags = fields[2].GetUInt32();
|
||||
uint32 used_loginFlag = ((recv_data.GetOpcode() == CMSG_CHAR_RACE_CHANGE) ? AT_LOGIN_CHANGE_RACE : AT_LOGIN_CHANGE_FACTION);
|
||||
|
||||
if (!sObjectMgr.GetPlayerInfo(race, playerClass))
|
||||
{
|
||||
WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1);
|
||||
data << uint8(CHAR_CREATE_ERROR);
|
||||
SendPacket( &data );
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(at_loginFlags & used_loginFlag))
|
||||
{
|
||||
WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1);
|
||||
data << uint8(CHAR_CREATE_ERROR);
|
||||
SendPacket( &data );
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent character rename to invalid name
|
||||
if (!normalizePlayerName(newname))
|
||||
{
|
||||
WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1);
|
||||
data << uint8(CHAR_NAME_NO_NAME);
|
||||
SendPacket( &data );
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 res = ObjectMgr::CheckPlayerName(newname,true);
|
||||
if (res != CHAR_NAME_SUCCESS)
|
||||
{
|
||||
WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1);
|
||||
data << uint8(res);
|
||||
SendPacket( &data );
|
||||
return;
|
||||
}
|
||||
|
||||
// check name limitations
|
||||
if (GetSecurity() == SEC_PLAYER && sObjectMgr.IsReservedName(newname))
|
||||
{
|
||||
WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1);
|
||||
data << uint8(CHAR_NAME_RESERVED);
|
||||
SendPacket( &data );
|
||||
return;
|
||||
}
|
||||
|
||||
// character with this name already exist
|
||||
if (uint64 newguid = sObjectMgr.GetPlayerGUIDByName(newname))
|
||||
{
|
||||
if (newguid != guid)
|
||||
{
|
||||
WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1);
|
||||
data << uint8(CHAR_CREATE_NAME_IN_USE);
|
||||
SendPacket( &data );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CharacterDatabase.escape_string(newname);
|
||||
Player::Customize(guid, gender, skin, face, hairStyle, hairColor, facialHair);
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
trans->PAppend("UPDATE `characters` SET name = '%s', race = '%u', at_login = at_login & ~ %u WHERE guid ='%u'", newname.c_str(), race, uint32(used_loginFlag), GUID_LOPART(guid));
|
||||
trans->PAppend("DELETE FROM character_declinedname WHERE guid ='%u'", GUID_LOPART(guid));
|
||||
|
||||
BattlegroundTeamId team;
|
||||
|
||||
// Search each faction is targeted
|
||||
switch(race)
|
||||
{
|
||||
case RACE_ORC:
|
||||
case RACE_TAUREN:
|
||||
case RACE_UNDEAD_PLAYER:
|
||||
case RACE_TROLL:
|
||||
case RACE_BLOODELF:
|
||||
team = BG_TEAM_HORDE;
|
||||
break;
|
||||
default:
|
||||
team = BG_TEAM_ALLIANCE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Switch Languages
|
||||
// delete all languages first
|
||||
trans->PAppend("DELETE FROM `character_skills` WHERE `skill` IN (98, 113, 759, 111, 313, 109, 115, 315, 673, 137) AND `guid`='%u'", GUID_LOPART(guid));
|
||||
|
||||
// now add them back
|
||||
if (team == BG_TEAM_ALLIANCE)
|
||||
{
|
||||
trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 98, 300, 300)", GUID_LOPART(guid));
|
||||
switch (race)
|
||||
{
|
||||
case RACE_DWARF:
|
||||
trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 111, 300, 300)", GUID_LOPART(guid));
|
||||
break;
|
||||
case RACE_DRAENEI:
|
||||
trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 759, 300, 300)", GUID_LOPART(guid));
|
||||
break;
|
||||
case RACE_GNOME:
|
||||
trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 313, 300, 300)", GUID_LOPART(guid));
|
||||
break;
|
||||
case RACE_NIGHTELF:
|
||||
trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 113, 300, 300)", GUID_LOPART(guid));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (team == BG_TEAM_HORDE)
|
||||
{
|
||||
trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 109, 300, 300)", GUID_LOPART(guid));
|
||||
switch (race)
|
||||
{
|
||||
case RACE_UNDEAD_PLAYER:
|
||||
trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 673, 300, 300)", GUID_LOPART(guid));
|
||||
break;
|
||||
case RACE_TAUREN:
|
||||
trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 115, 300, 300)", GUID_LOPART(guid));
|
||||
break;
|
||||
case RACE_TROLL:
|
||||
trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 315, 300, 300)", GUID_LOPART(guid));
|
||||
break;
|
||||
case RACE_BLOODELF:
|
||||
trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 137, 300, 300)", GUID_LOPART(guid));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(recv_data.GetOpcode() == CMSG_CHAR_FACTION_CHANGE)
|
||||
{
|
||||
// Delete all Flypaths
|
||||
trans->PAppend("UPDATE `characters` SET taxi_path = '' WHERE guid ='%u'",GUID_LOPART(guid));
|
||||
|
||||
if (level > 7)
|
||||
{
|
||||
// Update Taxi path
|
||||
// this doesn't seem to be 100% blizzlike... but it can't really be helped.
|
||||
std::ostringstream taximaskstream;
|
||||
uint32 numFullTaximasks = level / 7;
|
||||
if (numFullTaximasks > 11)
|
||||
numFullTaximasks = 11;
|
||||
if (team == BG_TEAM_ALLIANCE)
|
||||
{
|
||||
if (playerClass != CLASS_DEATH_KNIGHT)
|
||||
{
|
||||
for (uint8 i = 0; i < numFullTaximasks; ++i)
|
||||
taximaskstream << uint32(sAllianceTaxiNodesMask[i]) << " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint8 i = 0; i < numFullTaximasks; ++i)
|
||||
taximaskstream << uint32(sAllianceTaxiNodesMask[i] | sDeathKnightTaxiNodesMask[i]) << " ";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (playerClass != CLASS_DEATH_KNIGHT)
|
||||
{
|
||||
for (uint8 i = 0; i < numFullTaximasks; ++i)
|
||||
taximaskstream << uint32(sHordeTaxiNodesMask[i]) << " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint8 i = 0; i < numFullTaximasks; ++i)
|
||||
taximaskstream << uint32(sHordeTaxiNodesMask[i] | sDeathKnightTaxiNodesMask[i]) << " ";
|
||||
}
|
||||
}
|
||||
|
||||
uint32 numEmptyTaximasks = 11 - numFullTaximasks;
|
||||
for (uint8 i = 0; i < numEmptyTaximasks; ++i)
|
||||
taximaskstream << "0 ";
|
||||
taximaskstream << "0";
|
||||
std::string taximask = taximaskstream.str();
|
||||
trans->PAppend("UPDATE `characters` SET `taximask`= '%s' WHERE `guid` = '%u'", taximask.c_str(), GUID_LOPART(guid));
|
||||
}
|
||||
|
||||
// Delete all current quests
|
||||
trans->PAppend("DELETE FROM `character_queststatus` WHERE `status` = 3 AND guid ='%u'",GUID_LOPART(guid));
|
||||
|
||||
// Delete record of the faction old completed quests
|
||||
{
|
||||
std::ostringstream quests;
|
||||
ObjectMgr::QuestMap const& qTemplates = sObjectMgr.GetQuestTemplates();
|
||||
for (ObjectMgr::QuestMap::const_iterator iter = qTemplates.begin(); iter != qTemplates.end(); ++iter)
|
||||
{
|
||||
Quest *qinfo = iter->second;
|
||||
uint32 requiredRaces = qinfo->GetRequiredRaces();
|
||||
if (team == BG_TEAM_ALLIANCE)
|
||||
{
|
||||
if (requiredRaces & RACEMASK_ALLIANCE)
|
||||
{
|
||||
quests << uint32(qinfo->GetQuestId());
|
||||
quests << ",";
|
||||
}
|
||||
}
|
||||
else // if (team == BG_TEAM_HORDE)
|
||||
{
|
||||
if (requiredRaces & RACEMASK_HORDE)
|
||||
{
|
||||
quests << uint32(qinfo->GetQuestId());
|
||||
quests << ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string questsStr = quests.str();
|
||||
questsStr = questsStr.substr(0, questsStr.length() - 1);
|
||||
|
||||
trans->PAppend("DELETE FROM `character_queststatus` WHERE guid= '%u' AND quest IN (%s)",GUID_LOPART(guid),questsStr.c_str());
|
||||
}
|
||||
|
||||
if (!sWorld.getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD))
|
||||
{
|
||||
// Reset guild
|
||||
trans->PAppend("DELETE FROM `guild_member` WHERE `guid`= '%u'",GUID_LOPART(guid));
|
||||
}
|
||||
|
||||
if (!sWorld.getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND))
|
||||
{
|
||||
// Delete Friend List
|
||||
trans->PAppend("DELETE FROM `character_social` WHERE `guid`= '%u'",GUID_LOPART(guid));
|
||||
trans->PAppend("DELETE FROM `character_social` WHERE `friend`= '%u'",GUID_LOPART(guid));
|
||||
}
|
||||
|
||||
// Leave Arena Teams
|
||||
Player::LeaveAllArenaTeams(GUID_LOPART(guid));
|
||||
|
||||
// Reset homebind and position
|
||||
trans->PAppend("DELETE FROM `character_homebind` WHERE guid = '%u'",GUID_LOPART(guid));
|
||||
if(team == BG_TEAM_ALLIANCE)
|
||||
{
|
||||
trans->PAppend("INSERT INTO `character_homebind` VALUES (%u,0,1519,-8867.68,673.373,97.9034)",GUID_LOPART(guid));
|
||||
Player::SavePositionInDB(0, -8867.68f, 673.373f, 97.9034f, 0.0f, 1519, GUID_LOPART(guid));
|
||||
}
|
||||
else
|
||||
{
|
||||
trans->PAppend("INSERT INTO `character_homebind` VALUES (%u,1,1637,1633.33,-4439.11,15.7588)",GUID_LOPART(guid));
|
||||
Player::SavePositionInDB(1, 1633.33f, -4439.11f, 15.7588f, 0.0f, 1637, GUID_LOPART(guid));
|
||||
}
|
||||
|
||||
// Achievement conversion
|
||||
for (std::map<uint32, uint32>::const_iterator it = sObjectMgr.factionchange_achievements.begin(); it != sObjectMgr.factionchange_achievements.end(); ++it)
|
||||
{
|
||||
uint32 achiev_alliance = it->first;
|
||||
uint32 achiev_horde = it->second;
|
||||
trans->PAppend("UPDATE `character_achievement` SET achievement = '%u' where achievement = '%u' AND guid = '%u'",
|
||||
team == BG_TEAM_ALLIANCE ? achiev_alliance : achiev_horde, team == BG_TEAM_ALLIANCE ? achiev_horde : achiev_alliance, GUID_LOPART(guid));
|
||||
}
|
||||
|
||||
// Item conversion
|
||||
for (std::map<uint32, uint32>::const_iterator it = sObjectMgr.factionchange_items.begin(); it != sObjectMgr.factionchange_items.end(); ++it)
|
||||
{
|
||||
uint32 item_alliance = it->first;
|
||||
uint32 item_horde = it->second;
|
||||
trans->PAppend("UPDATE `character_inventory` SET item = '%u' where item = '%u' AND guid = '%u'",
|
||||
team == BG_TEAM_ALLIANCE ? item_alliance : item_horde, team == BG_TEAM_ALLIANCE ? item_horde : item_alliance, guid);
|
||||
}
|
||||
|
||||
// Spell conversion
|
||||
for (std::map<uint32, uint32>::const_iterator it = sObjectMgr.factionchange_spells.begin(); it != sObjectMgr.factionchange_spells.end(); ++it)
|
||||
{
|
||||
uint32 spell_alliance = it->first;
|
||||
uint32 spell_horde = it->second;
|
||||
trans->PAppend("UPDATE `character_spell` SET spell = '%u' where spell = '%u' AND guid = '%u'",
|
||||
team == BG_TEAM_ALLIANCE ? spell_alliance : spell_horde, team == BG_TEAM_ALLIANCE ? spell_horde : spell_alliance, GUID_LOPART(guid));
|
||||
}
|
||||
|
||||
// Reputation conversion
|
||||
for (std::map<uint32, uint32>::const_iterator it = sObjectMgr.factionchange_reputations.begin(); it != sObjectMgr.factionchange_reputations.end(); ++it)
|
||||
{
|
||||
uint32 reputation_alliance = it->first;
|
||||
uint32 reputation_horde = it->second;
|
||||
trans->PAppend("DELETE FROM character_reputation WHERE faction = '%u' AND guid = '%u'",
|
||||
team == BG_TEAM_ALLIANCE ? reputation_alliance : reputation_horde, GUID_LOPART(guid));
|
||||
trans->PAppend("UPDATE `character_reputation` SET faction = '%u' where faction = '%u' AND guid = '%u'",
|
||||
team == BG_TEAM_ALLIANCE ? reputation_alliance : reputation_horde, team == BG_TEAM_ALLIANCE ? reputation_horde : reputation_alliance, GUID_LOPART(guid));
|
||||
}
|
||||
}
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
std::string IP_str = GetRemoteAddress();
|
||||
sLog.outDebug("Account: %d (IP: %s), Character guid: %u Change Race/Faction to: %s", GetAccountId(), IP_str.c_str(), GUID_LOPART(guid), newname.c_str());
|
||||
|
||||
WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1 + 8 + (newname.size() + 1) + 1 + 1 + 1 + 1 + 1 + 1 + 1);
|
||||
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);
|
||||
data << uint8(race);
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
@@ -1269,7 +1269,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
|
||||
/*0x4D6*/ { "SMSG_EQUIPMENT_SET_USE_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
|
||||
/*0x4D7*/ { "UMSG_UNKNOWN_1239", STATUS_NEVER, &WorldSession::Handle_NULL },
|
||||
/*0x4D8*/ { "SMSG_UNKNOWN_1240", STATUS_NEVER, &WorldSession::Handle_ServerSide },
|
||||
/*0x4D9*/ { "CMSG_CHAR_FACTION_CHANGE", STATUS_NEVER, &WorldSession::Handle_NULL },
|
||||
/*0x4D9*/ { "CMSG_CHAR_FACTION_CHANGE", STATUS_AUTHED, &WorldSession::HandleCharFactionOrRaceChange },
|
||||
/*0x4DA*/ { "SMSG_CHAR_FACTION_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
|
||||
/*0x4DB*/ { "UMSG_UNKNOWN_1243", STATUS_NEVER, &WorldSession::Handle_NULL },
|
||||
/*0x4DC*/ { "UMSG_UNKNOWN_1244", STATUS_NEVER, &WorldSession::Handle_NULL },
|
||||
@@ -1300,7 +1300,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
|
||||
/*0x4F5*/ { "UMSG_UNKNOWN_1269", STATUS_NEVER, &WorldSession::Handle_NULL },
|
||||
/*0x4F6*/ { "CMSG_WORLD_STATE_UI_TIMER_UPDATE", STATUS_LOGGEDIN, &WorldSession::HandleWorldStateUITimerUpdate },
|
||||
/*0x4F7*/ { "SMSG_WORLD_STATE_UI_TIMER_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
|
||||
/*0x4F8*/ { "CMSG_CHAR_RACE_CHANGE", STATUS_NEVER, &WorldSession::Handle_NULL },
|
||||
/*0x4F8*/ { "CMSG_CHAR_RACE_CHANGE", STATUS_AUTHED, &WorldSession::HandleCharFactionOrRaceChange },
|
||||
/*0x4F9*/ { "UMSG_UNKNOWN_1273", STATUS_NEVER, &WorldSession::Handle_NULL },
|
||||
/*0x4FA*/ { "SMSG_TALENTS_INVOLUNTARILY_RESET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
|
||||
/*0x4FB*/ { "UMSG_UNKNOWN_1275", STATUS_NEVER, &WorldSession::Handle_NULL },
|
||||
|
||||
@@ -323,6 +323,7 @@ class WorldSession
|
||||
void HandlePlayerLoginOpcode(WorldPacket& recvPacket);
|
||||
void HandleCharEnum(QueryResult_AutoPtr result);
|
||||
void HandlePlayerLogin(LoginQueryHolder * holder);
|
||||
void HandleCharFactionOrRaceChange(WorldPacket& recv_data);
|
||||
|
||||
// played time
|
||||
void HandlePlayedTime(WorldPacket& recvPacket);
|
||||
|
||||
@@ -1578,6 +1578,18 @@ void World::SetInitialWorldSettings()
|
||||
sLog.outString("Loading Conditions...");
|
||||
sConditionMgr.LoadConditions();
|
||||
|
||||
sLog.outString("Loading faction change achievement pairs...");
|
||||
sObjectMgr.LoadFactionChangeAchievements();
|
||||
|
||||
sLog.outString("Loading faction change spell pairs...");
|
||||
sObjectMgr.LoadFactionChangeSpells();
|
||||
|
||||
sLog.outString("Loading faction change item pairs...");
|
||||
sObjectMgr.LoadFactionChangeItems();
|
||||
|
||||
sLog.outString("Loading faction change reputation pairs...");
|
||||
sObjectMgr.LoadFactionChangeReputations();
|
||||
|
||||
sLog.outString("Loading GM tickets...");
|
||||
sTicketMgr.LoadGMTickets();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user