aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp1
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.h1
-rw-r--r--src/server/game/Accounts/RBAC.h2
-rw-r--r--src/server/game/Miscellaneous/Language.h3
-rw-r--r--src/server/game/World/World.cpp9
-rw-r--r--src/server/game/World/World.h1
-rw-r--r--src/server/scripts/Commands/cs_character.cpp81
7 files changed, 96 insertions, 2 deletions
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index d0227fde660..53e8ecde2f9 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -196,6 +196,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_GIFT, "DELETE FROM character_gifts WHERE item_guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_GIFT_BY_ITEM, "SELECT entry, flags FROM character_gifts WHERE item_guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_ACCOUNT_BY_NAME, "SELECT account FROM characters WHERE name = ?", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_UPD_ACCOUNT_BY_GUID, "UPDATE characters SET account = ? WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_ACCOUNT_INSTANCE_LOCK_TIMES, "DELETE FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_ACCOUNT_INSTANCE_LOCK_TIMES, "INSERT INTO account_instance_times (accountId, instanceId, releaseTime) VALUES (?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_MATCH_MAKER_RATING, "SELECT matchMakerRating FROM character_arena_stats WHERE guid = ? AND slot = ?", CONNECTION_SYNCH);
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h
index c4c081ab73a..2c31b819593 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.h
+++ b/src/server/database/Database/Implementation/CharacterDatabase.h
@@ -165,6 +165,7 @@ enum CharacterDatabaseStatements : uint32
CHAR_DEL_GIFT,
CHAR_SEL_CHARACTER_GIFT_BY_ITEM,
CHAR_SEL_ACCOUNT_BY_NAME,
+ CHAR_UPD_ACCOUNT_BY_GUID,
CHAR_DEL_ACCOUNT_INSTANCE_LOCK_TIMES,
CHAR_INS_ACCOUNT_INSTANCE_LOCK_TIMES,
CHAR_SEL_MATCH_MAKER_RATING,
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index 0c1cb84d270..018f4e0c73f 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -603,7 +603,7 @@ enum RBACPermissions
RBAC_PERM_COMMAND_RELOAD_SPELL_LOOT_TEMPLATE = 695,
RBAC_PERM_COMMAND_RELOAD_SPELL_LINKED_SPELL = 696,
RBAC_PERM_COMMAND_RELOAD_SPELL_PET_AURAS = 697,
- // 698 - reuse
+ RBAC_PERM_COMMAND_CHARACTER_CHANGEACCOUNT = 698,
RBAC_PERM_COMMAND_RELOAD_SPELL_PROC = 699,
RBAC_PERM_COMMAND_RELOAD_SPELL_SCRIPTS = 700,
RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION = 701,
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 039c3b81604..820edc8adb9 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -927,7 +927,8 @@ enum TrinityStrings
LANG_ACCOUNT_BNET_NOT_LINKED = 1189,
LANG_DISALLOW_TICKETS_CONFIG = 1190,
LANG_BAN_EXISTS = 1191,
- // Room for more level 3 1192-1198 not used
+ LANG_CHANGEACCOUNT_SUCCESS = 1192,
+ // Room for more level 3 1193-1198 not used
// Debug commands
LANG_DEBUG_AREATRIGGER_LEFT = 1999,
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 23a62783c83..bafc5207656 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -3616,6 +3616,15 @@ void World::UpdateCharacterInfoLevel(ObjectGuid const& guid, uint8 level)
itr->second.Level = level;
}
+void World::UpdateCharacterInfoAccount(ObjectGuid const& guid, uint32 accountId)
+{
+ auto itr = _characterInfoStore.find(guid);
+ if (itr == _characterInfoStore.end())
+ return;
+
+ itr->second.AccountId = accountId;
+}
+
void World::UpdateCharacterInfoDeleted(ObjectGuid const& guid, bool deleted, std::string const* name /*= nullptr*/)
{
CharacterInfoContainer::iterator itr = _characterInfoStore.find(guid);
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 16850da37ae..e7eb8c84d4c 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -794,6 +794,7 @@ class TC_GAME_API World
bool HasCharacterInfo(ObjectGuid const& guid) { return _characterInfoStore.find(guid) != _characterInfoStore.end(); }
void UpdateCharacterInfo(ObjectGuid const& guid, std::string const& name, uint8 gender = GENDER_NONE, uint8 race = RACE_NONE);
void UpdateCharacterInfoLevel(ObjectGuid const& guid, uint8 level);
+ void UpdateCharacterInfoAccount(ObjectGuid const& guid, uint32 accountId);
void UpdateCharacterInfoDeleted(ObjectGuid const& guid, bool deleted, std::string const* name = nullptr);
uint32 GetCleaningFlags() const { return m_CleaningFlags; }
diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp
index 9107c0c2ebb..f62ae5f45ca 100644
--- a/src/server/scripts/Commands/cs_character.cpp
+++ b/src/server/scripts/Commands/cs_character.cpp
@@ -61,6 +61,7 @@ public:
{ "customize", rbac::RBAC_PERM_COMMAND_CHARACTER_CUSTOMIZE, true, &HandleCharacterCustomizeCommand, "", },
{ "changefaction", rbac::RBAC_PERM_COMMAND_CHARACTER_CHANGEFACTION, true, &HandleCharacterChangeFactionCommand, "", },
{ "changerace", rbac::RBAC_PERM_COMMAND_CHARACTER_CHANGERACE, true, &HandleCharacterChangeRaceCommand, "", },
+ { "changeaccount", rbac::RBAC_PERM_COMMAND_CHARACTER_CHANGEACCOUNT, true, &HandleCharacterChangeAccountCommand, "", },
{ "deleted", rbac::RBAC_PERM_COMMAND_CHARACTER_DELETED, true, NULL, "", characterDeletedCommandTable },
{ "erase", rbac::RBAC_PERM_COMMAND_CHARACTER_ERASE, true, &HandleCharacterEraseCommand, "", },
{ "level", rbac::RBAC_PERM_COMMAND_CHARACTER_LEVEL, true, &HandleCharacterLevelCommand, "", },
@@ -551,6 +552,86 @@ public:
return true;
}
+ static bool HandleCharacterChangeAccountCommand(ChatHandler* handler, char const* args)
+ {
+ char* playerNameStr;
+ char* accountNameStr;
+ handler->extractOptFirstArg(const_cast<char*>(args), &playerNameStr, &accountNameStr);
+ if (!accountNameStr)
+ return false;
+
+ ObjectGuid targetGuid;
+ std::string targetName;
+ if (!handler->extractPlayerTarget(playerNameStr, nullptr, &targetGuid, &targetName))
+ return false;
+
+ CharacterInfo const* characterInfo = sWorld->GetCharacterInfo(targetGuid);
+ if (!characterInfo)
+ {
+ handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 oldAccountId = characterInfo->AccountId;
+ uint32 newAccountId = oldAccountId;
+
+ std::string accountName(accountNameStr);
+ if (!Utf8ToUpperOnlyLatin(accountName))
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME);
+ stmt->setString(0, accountName);
+ if (PreparedQueryResult result = LoginDatabase.Query(stmt))
+ newAccountId = (*result)[0].GetUInt32();
+ else
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ // nothing to do :)
+ if (newAccountId == oldAccountId)
+ return true;
+
+ if (uint32 charCount = AccountMgr::GetCharactersCount(newAccountId))
+ {
+ if (charCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM))
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_CHARACTER_LIST_FULL, accountName.c_str(), newAccountId);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+ }
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_BY_GUID);
+ stmt->setUInt32(0, newAccountId);
+ stmt->setUInt32(1, targetGuid.GetCounter());
+ CharacterDatabase.DirectExecute(stmt);
+
+ sWorld->UpdateRealmCharCount(oldAccountId);
+ sWorld->UpdateRealmCharCount(newAccountId);
+
+ sWorld->UpdateCharacterInfoAccount(targetGuid, newAccountId);
+
+ handler->PSendSysMessage(LANG_CHANGEACCOUNT_SUCCESS, targetName.c_str(), accountName.c_str());
+
+ std::string logString = Trinity::StringFormat("changed ownership of player %s (%s) from account %u to account %u", targetName.c_str(), targetGuid.ToString().c_str(), oldAccountId, newAccountId);
+ if (WorldSession* session = handler->GetSession())
+ {
+ if (Player* player = session->GetPlayer())
+ sLog->outCommand(session->GetAccountId(), "GM %s (Account: %u) %s", player->GetName().c_str(), session->GetAccountId(), logString.c_str());
+ }
+ else
+ sLog->outCommand(0, "%s %s", handler->GetTrinityString(LANG_CONSOLE), logString.c_str());
+ return true;
+ }
+
static bool HandleCharacterReputationCommand(ChatHandler* handler, char const* args)
{
Player* target;