From 98111f2920475fa0fa2db23815d95043557ed14f Mon Sep 17 00:00:00 2001 From: VDm Date: Sun, 6 Apr 2025 16:16:43 +0400 Subject: [PATCH] feat(glue): implement character deletion --- src/client/ClientServices.cpp | 120 ++++++++++++++++++++++ src/client/ClientServices.hpp | 2 + src/clientobject/Player_C.cpp | 51 ++++++++++ src/clientobject/Player_C.hpp | 14 +++ src/clientobject/Types.hpp | 14 +++ src/glue/CGlueMgr.cpp | 42 ++++++++ src/glue/CGlueMgr.hpp | 2 + src/net/connection/ClientConnection.cpp | 126 ++++-------------------- src/net/connection/ClientConnection.hpp | 1 + src/net/connection/RealmConnection.cpp | 10 +- src/net/connection/RealmConnection.hpp | 1 + src/ui/ScriptFunctionsCharSelect.cpp | 10 +- 12 files changed, 283 insertions(+), 110 deletions(-) create mode 100644 src/clientobject/Player_C.cpp create mode 100644 src/clientobject/Player_C.hpp create mode 100644 src/clientobject/Types.hpp diff --git a/src/client/ClientServices.cpp b/src/client/ClientServices.cpp index fde53d0..bfb1d39 100644 --- a/src/client/ClientServices.cpp +++ b/src/client/ClientServices.cpp @@ -9,6 +9,113 @@ #include #include +static const char* s_errorCodeTokens[] = { + "RESPONSE_SUCCESS", + "RESPONSE_FAILURE", + "RESPONSE_CANCELLED", + "RESPONSE_DISCONNECTED", + "RESPONSE_FAILED_TO_CONNECT", + "RESPONSE_CONNECTED", + "RESPONSE_VERSION_MISMATCH", + "CSTATUS_CONNECTING", + "CSTATUS_NEGOTIATING_SECURITY", + "CSTATUS_NEGOTIATION_COMPLETE", + "CSTATUS_NEGOTIATION_FAILED", + "CSTATUS_AUTHENTICATING", + "AUTH_OK", + "AUTH_FAILED", + "AUTH_REJECT", + "AUTH_BAD_SERVER_PROOF", + "AUTH_UNAVAILABLE", + "AUTH_SYSTEM_ERROR", + "AUTH_BILLING_ERROR", + "AUTH_BILLING_EXPIRED", + "AUTH_VERSION_MISMATCH", + "AUTH_UNKNOWN_ACCOUNT", + "AUTH_INCORRECT_PASSWORD", + "AUTH_SESSION_EXPIRED", + "AUTH_SERVER_SHUTTING_DOWN", + "AUTH_ALREADY_LOGGING_IN", + "AUTH_LOGIN_SERVER_NOT_FOUND", + "AUTH_WAIT_QUEUE", + "AUTH_BANNED", + "AUTH_ALREADY_ONLINE", + "AUTH_NO_TIME", + "AUTH_DB_BUSY", + "AUTH_SUSPENDED", + "AUTH_PARENTAL_CONTROL", + "AUTH_LOCKED_ENFORCED", + "REALM_LIST_IN_PROGRESS", + "REALM_LIST_SUCCESS", + "REALM_LIST_FAILED", + "REALM_LIST_INVALID", + "REALM_LIST_REALM_NOT_FOUND", + "ACCOUNT_CREATE_IN_PROGRESS", + "ACCOUNT_CREATE_SUCCESS", + "ACCOUNT_CREATE_FAILED", + "CHAR_LIST_RETRIEVING", + "CHAR_LIST_RETRIEVED", + "CHAR_LIST_FAILED", + "CHAR_CREATE_IN_PROGRESS", + "CHAR_CREATE_SUCCESS", + "CHAR_CREATE_ERROR", + "CHAR_CREATE_FAILED", + "CHAR_CREATE_NAME_IN_USE", + "CHAR_CREATE_DISABLED", + "CHAR_CREATE_PVP_TEAMS_VIOLATION", + "CHAR_CREATE_SERVER_LIMIT", + "CHAR_CREATE_ACCOUNT_LIMIT", + "CHAR_CREATE_SERVER_QUEUE", + "CHAR_CREATE_ONLY_EXISTING", + "CHAR_CREATE_EXPANSION", + "CHAR_CREATE_EXPANSION_CLASS", + "CHAR_CREATE_LEVEL_REQUIREMENT", + "CHAR_CREATE_UNIQUE_CLASS_LIMIT", + "CHAR_CREATE_CHARACTER_IN_GUILD", + "CHAR_CREATE_RESTRICTED_RACECLASS", + "CHAR_CREATE_CHARACTER_CHOOSE_RACE", + "CHAR_CREATE_CHARACTER_ARENA_LEADER", + "CHAR_CREATE_CHARACTER_DELETE_MAIL", + "CHAR_CREATE_CHARACTER_SWAP_FACTION", + "CHAR_CREATE_CHARACTER_RACE_ONLY", + "CHAR_CREATE_CHARACTER_GOLD_LIMIT", + "CHAR_CREATE_FORCE_LOGIN", + "CHAR_DELETE_IN_PROGRESS", + "CHAR_DELETE_SUCCESS", + "CHAR_DELETE_FAILED", + "CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER", + "CHAR_DELETE_FAILED_GUILD_LEADER", + "CHAR_DELETE_FAILED_ARENA_CAPTAIN", + "CHAR_LOGIN_IN_PROGRESS", + "CHAR_LOGIN_SUCCESS", + "CHAR_LOGIN_NO_WORLD", + "CHAR_LOGIN_DUPLICATE_CHARACTER", + "CHAR_LOGIN_NO_INSTANCES", + "CHAR_LOGIN_FAILED", + "CHAR_LOGIN_DISABLED", + "CHAR_LOGIN_NO_CHARACTER", + "CHAR_LOGIN_LOCKED_FOR_TRANSFER", + "CHAR_LOGIN_LOCKED_BY_BILLING", + "CHAR_LOGIN_LOCKED_BY_MOBILE_AH", + "CHAR_NAME_SUCCESS", + "CHAR_NAME_FAILURE", + "CHAR_NAME_NO_NAME", + "CHAR_NAME_TOO_SHORT", + "CHAR_NAME_TOO_LONG", + "CHAR_NAME_INVALID_CHARACTER", + "CHAR_NAME_MIXED_LANGUAGES", + "CHAR_NAME_PROFANE", + "CHAR_NAME_RESERVED", + "CHAR_NAME_INVALID_APOSTROPHE", + "CHAR_NAME_MULTIPLE_APOSTROPHES", + "CHAR_NAME_THREE_CONSECUTIVE", + "CHAR_NAME_INVALID_SPACE", + "CHAR_NAME_CONSECUTIVE_SPACES", + "CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS", + "CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END", + "CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME", +}; + ClientConnection* g_clientConnection; char ClientServices::s_accountName[1280]; @@ -27,6 +134,14 @@ CVar* ClientServices::s_darkPortalVar = nullptr; CVar* ClientServices::s_ServerAlertVar = nullptr; CVar* ClientServices::s_realmListVar = nullptr; +const char* ClientServices::GetErrorToken(uint32_t token) { + if (token < sizeof(s_errorCodeTokens) / sizeof(s_errorCodeTokens[0])) { + return s_errorCodeTokens[token]; + } else { + return ""; + } +} + void ClientServices::ConnectToSelectedServer() { if (!ClientServices::s_selectRealmInfoValid && !ClientServices::SetSelectedRealmInfo(0)) { ClientServices::Connection()->Complete(0, 39); @@ -116,6 +231,11 @@ const REALM_INFO* ClientServices::GetSelectedRealm() { return &ClientServices::s_selectRealmInfo; } +void ClientServices::CharacterDelete(uint64_t guid) { + STORM_ASSERT(ClientServices::s_currentConnection); + ClientServices::s_currentConnection->DeleteCharacter(guid); +} + void ClientServices::Initialize() { if (!g_clientConnection) { ClientServices::s_clientRealmResponse = NEW(ClientRealmResponseAdapter); diff --git a/src/client/ClientServices.hpp b/src/client/ClientServices.hpp index b3bcf75..91b08a5 100644 --- a/src/client/ClientServices.hpp +++ b/src/client/ClientServices.hpp @@ -32,6 +32,7 @@ class ClientServices : public LoginResponse { static CVar* s_patchListVar; // Static functions + static const char* GetErrorToken(uint32_t token); static void ConnectToSelectedServer(); static ClientConnection* Connection(); static ClientServices* GetInstance(); @@ -43,6 +44,7 @@ class ClientServices : public LoginResponse { static REALM_INFO* GetRealmInfoByIndex(int32_t index); static const char* GetSelectedRealmName(); static const REALM_INFO* GetSelectedRealm(); + static void CharacterDelete(uint64_t guid); static void Initialize(); static Login* LoginConnection(); static void Logon(const char* accountName, const char* password); diff --git a/src/clientobject/Player_C.cpp b/src/clientobject/Player_C.cpp new file mode 100644 index 0000000..95b0564 --- /dev/null +++ b/src/clientobject/Player_C.cpp @@ -0,0 +1,51 @@ +#include "clientobject/Player_C.hpp" +#include "clientobject/Types.hpp" +#include "db/Db.hpp" +#include + + +const CreatureModelDataRec* Player_C_GetModelName(uint32_t race, uint32_t sex) { + STORM_ASSERT(sex < UNITSEX_LAST); + + auto displayId = Player_C_GetDisplayId(race, sex); + auto record = g_creatureDisplayInfoDB.GetRecord(displayId); + if (!record) { + SErrPrepareAppFatal(__FILE__, __LINE__); + SErrDisplayAppFatal("Error, unknown displayInfo %d specified for player race %d sex %d!", displayId, race, sex); + } + + auto modelData = g_creatureModelDataDB.GetRecord(record->m_modelID); + if (!modelData) { + SErrPrepareAppFatal(__FILE__, __LINE__); + SErrDisplayAppFatal("Error, unknown model record %d specified for player race %d sex %d!", record->m_modelID, race, sex); + } + + return modelData; +} + +uint32_t Player_C_GetDisplayId(uint32_t race, uint32_t sex) { + STORM_ASSERT(sex < UNITSEX_LAST); + + auto record = g_chrRacesDB.GetRecord(race); + if (!record) { + SErrPrepareAppFatal(__FILE__, __LINE__); + SErrDisplayAppFatal("Error, race %d not found in race table!", race); + } + + if (sex == UNITSEX_MALE) { + return record->m_maleDisplayID; + } + + if (sex == UNITSEX_FEMALE) { + return record->m_femaleDisplayID; + } + + if (sex == UNITSEX_NONE) { + SErrPrepareAppFatal(__FILE__, __LINE__); + SErrDisplayAppFatal("Error, attempted to look up model for player with sex %d (UNITSEX_NONE), all players have sex! =D", 2); + } + + SErrPrepareAppFatal(__FILE__, __LINE__); + SErrDisplayAppFatal("Error, unrecognized sex code %d!", sex); + return 0; +} diff --git a/src/clientobject/Player_C.hpp b/src/clientobject/Player_C.hpp new file mode 100644 index 0000000..10ce0c4 --- /dev/null +++ b/src/clientobject/Player_C.hpp @@ -0,0 +1,14 @@ +#ifndef CLIENTOBJECT_PLAYER_C_HPP +#define CLIENTOBJECT_PLAYER_C_HPP + +#include + + +class CreatureModelDataRec; + + +const CreatureModelDataRec* Player_C_GetModelName(uint32_t race, uint32_t sex); +uint32_t Player_C_GetDisplayId(uint32_t race, uint32_t sex); + + +#endif // CLIENTOBJECT_PLAYER_C_HPP diff --git a/src/clientobject/Types.hpp b/src/clientobject/Types.hpp new file mode 100644 index 0000000..a5028e1 --- /dev/null +++ b/src/clientobject/Types.hpp @@ -0,0 +1,14 @@ +#ifndef CLIENTOBJECT_TYPES_HPP +#define CLIENTOBJECT_TYPES_HPP + + +enum UNIT_SEX { + UNITSEX_MALE = 0x0, + UNITSEX_FEMALE = 0x1, + UNITSEX_NONE = 0x2, + UNITSEX_LAST = 0x3, + UNITSEX_BOTH = 0x3, +}; + + +#endif diff --git a/src/glue/CGlueMgr.cpp b/src/glue/CGlueMgr.cpp index 0d8453e..c160892 100644 --- a/src/glue/CGlueMgr.cpp +++ b/src/glue/CGlueMgr.cpp @@ -302,6 +302,11 @@ int32_t CGlueMgr::Idle(const void* a1, void* a2) { break; } + case IDLE_DELETE_CHARACTER: { + CGlueMgr::PollDeleteCharacter(errorCode, msg, complete, result, op); + break; + } + case IDLE_ENTER_WORLD: { CGlueMgr::PollEnterWorld(); break; @@ -624,6 +629,29 @@ void CGlueMgr::PollCharacterList(int32_t errorCode, const char* msg, int32_t com CGlueMgr::m_accountMsgAvailable = 0; } +void CGlueMgr::PollDeleteCharacter(int32_t errorCode, const char* msg, int32_t complete, int32_t result, WOWCS_OPS op) { + FrameScript_SignalEvent(4, "%s", msg); + + if (CGlueMgr::HandleBattlenetDisconnect()) { + CGlueMgr::m_idleState = IDLE_NONE; + CGlueMgr::m_showedDisconnect = 0; + } + + if (!complete) { + return; + } + + if (result) { + FrameScript_SignalEvent(13, 0); + CGlueMgr::GetCharacterList(); + return; + } + + FrameScript_SignalEvent(3, "%s%s", "OKAY", msg); + CGlueMgr::m_idleState = IDLE_NONE; + CGlueMgr::m_showedDisconnect = 0; +} + void CGlueMgr::PollUserSurvey() { if (CGlueMgr::m_surveyDownload && false /* virtual call */) { if (CGlueMgr::m_executedSurvey) { @@ -920,6 +948,20 @@ bool CGlueMgr::HandleBattlenetDisconnect() { return false; } +void CGlueMgr::DeleteCharacter(uint64_t guid) { + if (!guid) { + return; + } + + CGlueMgr::m_idleState = IDLE_DELETE_CHARACTER; + CGlueMgr::m_showedDisconnect = 0; + + auto errorText = ClientServices::GetErrorToken(70); + auto text = FrameScript_GetText(errorText, -1, GENDER_NOT_APPLICABLE); + FrameScript_SignalEvent(3u, "%s%s", "CANCEL", text); + ClientServices::CharacterDelete(guid); +} + void CGlueMgr::PollEnterWorld() { //if (!LoadingScreenDrawing()) // return; diff --git a/src/glue/CGlueMgr.hpp b/src/glue/CGlueMgr.hpp index 5623dad..e7d72b8 100644 --- a/src/glue/CGlueMgr.hpp +++ b/src/glue/CGlueMgr.hpp @@ -87,6 +87,7 @@ class CGlueMgr { static void PollAccountLogin(int32_t errorCode, const char* msg, int32_t complete, int32_t result, WOWCS_OPS op); static void PollLoginServerLogin(); static void PollCharacterList(int32_t errorCode, const char* msg, int32_t complete, int32_t result, WOWCS_OPS op); + static void PollDeleteCharacter(int32_t errorCode, const char* msg, int32_t complete, int32_t result, WOWCS_OPS op); static void PollUserSurvey(); static void Resume(); static void SetCurrentAccount(const char* accountName); @@ -97,6 +98,7 @@ class CGlueMgr { static void Suspend(); static void UpdateCurrentScreen(const char* screen); static bool HandleBattlenetDisconnect(); + static void DeleteCharacter(uint64_t guid); static void PollEnterWorld(); diff --git a/src/net/connection/ClientConnection.cpp b/src/net/connection/ClientConnection.cpp index 61025ab..e02187a 100644 --- a/src/net/connection/ClientConnection.cpp +++ b/src/net/connection/ClientConnection.cpp @@ -3,113 +3,8 @@ #include "client/ClientServices.hpp" #include "ui/FrameScript.hpp" #include +#include -const char* s_errorCodeTokens[] = { - "RESPONSE_SUCCESS", - "RESPONSE_FAILURE", - "RESPONSE_CANCELLED", - "RESPONSE_DISCONNECTED", - "RESPONSE_FAILED_TO_CONNECT", - "RESPONSE_CONNECTED", - "RESPONSE_VERSION_MISMATCH", - "CSTATUS_CONNECTING", - "CSTATUS_NEGOTIATING_SECURITY", - "CSTATUS_NEGOTIATION_COMPLETE", - "CSTATUS_NEGOTIATION_FAILED", - "CSTATUS_AUTHENTICATING", - "AUTH_OK", - "AUTH_FAILED", - "AUTH_REJECT", - "AUTH_BAD_SERVER_PROOF", - "AUTH_UNAVAILABLE", - "AUTH_SYSTEM_ERROR", - "AUTH_BILLING_ERROR", - "AUTH_BILLING_EXPIRED", - "AUTH_VERSION_MISMATCH", - "AUTH_UNKNOWN_ACCOUNT", - "AUTH_INCORRECT_PASSWORD", - "AUTH_SESSION_EXPIRED", - "AUTH_SERVER_SHUTTING_DOWN", - "AUTH_ALREADY_LOGGING_IN", - "AUTH_LOGIN_SERVER_NOT_FOUND", - "AUTH_WAIT_QUEUE", - "AUTH_BANNED", - "AUTH_ALREADY_ONLINE", - "AUTH_NO_TIME", - "AUTH_DB_BUSY", - "AUTH_SUSPENDED", - "AUTH_PARENTAL_CONTROL", - "AUTH_LOCKED_ENFORCED", - "REALM_LIST_IN_PROGRESS", - "REALM_LIST_SUCCESS", - "REALM_LIST_FAILED", - "REALM_LIST_INVALID", - "REALM_LIST_REALM_NOT_FOUND", - "ACCOUNT_CREATE_IN_PROGRESS", - "ACCOUNT_CREATE_SUCCESS", - "ACCOUNT_CREATE_FAILED", - "CHAR_LIST_RETRIEVING", - "CHAR_LIST_RETRIEVED", - "CHAR_LIST_FAILED", - "CHAR_CREATE_IN_PROGRESS", - "CHAR_CREATE_SUCCESS", - "CHAR_CREATE_ERROR", - "CHAR_CREATE_FAILED", - "CHAR_CREATE_NAME_IN_USE", - "CHAR_CREATE_DISABLED", - "CHAR_CREATE_PVP_TEAMS_VIOLATION", - "CHAR_CREATE_SERVER_LIMIT", - "CHAR_CREATE_ACCOUNT_LIMIT", - "CHAR_CREATE_SERVER_QUEUE", - "CHAR_CREATE_ONLY_EXISTING", - "CHAR_CREATE_EXPANSION", - "CHAR_CREATE_EXPANSION_CLASS", - "CHAR_CREATE_LEVEL_REQUIREMENT", - "CHAR_CREATE_UNIQUE_CLASS_LIMIT", - "CHAR_CREATE_CHARACTER_IN_GUILD", - "CHAR_CREATE_RESTRICTED_RACECLASS", - "CHAR_CREATE_CHARACTER_CHOOSE_RACE", - "CHAR_CREATE_CHARACTER_ARENA_LEADER", - "CHAR_CREATE_CHARACTER_DELETE_MAIL", - "CHAR_CREATE_CHARACTER_SWAP_FACTION", - "CHAR_CREATE_CHARACTER_RACE_ONLY", - "CHAR_CREATE_CHARACTER_GOLD_LIMIT", - "CHAR_CREATE_FORCE_LOGIN", - "CHAR_DELETE_IN_PROGRESS", - "CHAR_DELETE_SUCCESS", - "CHAR_DELETE_FAILED", - "CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER", - "CHAR_DELETE_FAILED_GUILD_LEADER", - "CHAR_DELETE_FAILED_ARENA_CAPTAIN", - "CHAR_LOGIN_IN_PROGRESS", - "CHAR_LOGIN_SUCCESS", - "CHAR_LOGIN_NO_WORLD", - "CHAR_LOGIN_DUPLICATE_CHARACTER", - "CHAR_LOGIN_NO_INSTANCES", - "CHAR_LOGIN_FAILED", - "CHAR_LOGIN_DISABLED", - "CHAR_LOGIN_NO_CHARACTER", - "CHAR_LOGIN_LOCKED_FOR_TRANSFER", - "CHAR_LOGIN_LOCKED_BY_BILLING", - "CHAR_LOGIN_LOCKED_BY_MOBILE_AH", - "CHAR_NAME_SUCCESS", - "CHAR_NAME_FAILURE", - "CHAR_NAME_NO_NAME", - "CHAR_NAME_TOO_SHORT", - "CHAR_NAME_TOO_LONG", - "CHAR_NAME_INVALID_CHARACTER", - "CHAR_NAME_MIXED_LANGUAGES", - "CHAR_NAME_PROFANE", - "CHAR_NAME_RESERVED", - "CHAR_NAME_INVALID_APOSTROPHE", - "CHAR_NAME_MULTIPLE_APOSTROPHES", - "CHAR_NAME_THREE_CONSECUTIVE", - "CHAR_NAME_INVALID_SPACE", - "CHAR_NAME_CONSECUTIVE_SPACES", - "CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS", - "CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END", - "CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME", -}; void ClientConnection::AccountLogin(const char* name, const char* password, int32_t region, int32_t locale) { STORM_ASSERT(this->m_statusComplete == 1); @@ -157,6 +52,19 @@ void ClientConnection::CharacterLogin(uint64_t id) { } } +void ClientConnection::DeleteCharacter(uint64_t guid) { + this->Initiate(COP_DELETE_CHARACTER, 70, nullptr); + if (this->m_connected) { + CDataStore msg; + msg.Put(static_cast(CMSG_CHAR_DELETE)); + msg.Put(guid); + msg.Finalize(); + this->Send(&msg); + } else { + this->Cancel(4); + } +} + void ClientConnection::Cancel(int32_t errorCode) { this->Complete(0, errorCode); } @@ -227,8 +135,10 @@ int32_t ClientConnection::PollStatus(WOWCS_OPS& op, const char** msg, int32_t& r static char altText[256]; if (this->m_statusComplete) { - auto text = errorCode >= 0 && errorCode < 104 - ? FrameScript_GetText(s_errorCodeTokens[errorCode], -1, GENDER_NOT_APPLICABLE) + auto errorText = ClientServices::GetErrorToken(errorCode); + + auto text = errorText[0] + ? FrameScript_GetText(errorText, -1, GENDER_NOT_APPLICABLE) : nullptr; if (!text) { diff --git a/src/net/connection/ClientConnection.hpp b/src/net/connection/ClientConnection.hpp index 2b79dd9..bb88880 100644 --- a/src/net/connection/ClientConnection.hpp +++ b/src/net/connection/ClientConnection.hpp @@ -30,6 +30,7 @@ class ClientConnection : public RealmConnection { void GetCharacterList(); void EnumerateCharacters(ENUMERATE_CHARACTERS_CALLBACK fcn, void* param); void CharacterLogin(uint64_t id); + void DeleteCharacter(uint64_t guid); void Cancel(int32_t errorCode); void Cleanup(); void Connect(); diff --git a/src/net/connection/RealmConnection.cpp b/src/net/connection/RealmConnection.cpp index 1a24ca4..1133592 100644 --- a/src/net/connection/RealmConnection.cpp +++ b/src/net/connection/RealmConnection.cpp @@ -1,5 +1,6 @@ #include "net/connection/RealmConnection.hpp" #include "net/connection/RealmResponse.hpp" +#include "net/connection/ClientConnection.hpp" #include "net/Types.hpp" #include #include @@ -29,7 +30,7 @@ int32_t RealmConnection::MessageHandler(void* param, NETMESSAGE msgId, uint32_t } case SMSG_DELETE_CHAR: { - // TODO + result = connection->HandleCharacterDelete(msgId, time, msg); break; } @@ -271,6 +272,13 @@ int32_t RealmConnection::HandleCharEnum(uint32_t msgId, uint32_t time, CDataStor return 1; } +int32_t RealmConnection::HandleCharacterDelete(uint32_t msgId, uint32_t time, CDataStore* msg) { + uint8_t result; + msg->Get(result); + static_cast(this)->Complete(1, result); + return 1; +} + void RealmConnection::SetSelectedRealm(uint32_t a2, uint32_t a3, uint32_t a4) { // TODO } diff --git a/src/net/connection/RealmConnection.hpp b/src/net/connection/RealmConnection.hpp index 211060e..03ebaf7 100644 --- a/src/net/connection/RealmConnection.hpp +++ b/src/net/connection/RealmConnection.hpp @@ -41,6 +41,7 @@ class RealmConnection : public NetClient { RealmConnection(RealmResponse* realmResponse); int32_t HandleAuthResponse(uint32_t msgId, uint32_t time, CDataStore* msg); int32_t HandleCharEnum(uint32_t msgId, uint32_t time, CDataStore* msg); + int32_t HandleCharacterDelete(uint32_t msgId, uint32_t time, CDataStore* msg); void SetSelectedRealm(uint32_t a2, uint32_t a3, uint32_t a4); void RequestCharacterEnum(); void RequestCharacterLogin(uint64_t id); diff --git a/src/ui/ScriptFunctionsCharSelect.cpp b/src/ui/ScriptFunctionsCharSelect.cpp index c862f3a..122189f 100644 --- a/src/ui/ScriptFunctionsCharSelect.cpp +++ b/src/ui/ScriptFunctionsCharSelect.cpp @@ -122,7 +122,15 @@ int32_t Script_SelectCharacter(lua_State* L) { } int32_t Script_DeleteCharacter(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + if (!lua_isnumber(L, 1)) { + luaL_error(L, "Usage: DeleteCharacter(index)"); + } + + int32_t index = static_cast(lua_tonumber(L, 1)) - 1; + if (index >= 0 && index < CCharacterSelection::GetNumCharacters()) { + CGlueMgr::DeleteCharacter(CCharacterSelection::s_characterList[index].m_characterInfo.guid); + } + return 0; } int32_t Script_RenameCharacter(lua_State* L) {