feat(glue): update Character Selection screen to support switching

This commit is contained in:
VDm 2025-04-05 01:42:43 +04:00
parent bf734b5b20
commit 0c39457ed1
10 changed files with 117 additions and 24 deletions

View File

@ -33,6 +33,7 @@ CVar* Client::g_accountUsesTokenVar;
CVar* Client::g_movieVar;
CVar* Client::g_expansionMovieVar;
CVar* Client::g_movieSubtitleVar;
CVar* Client::g_lastCharacterIndex;
HEVENTCONTEXT Client::g_clientEventContext;
@ -83,6 +84,7 @@ void ClientRegisterConsoleCommands() {
Client::g_movieVar = CVar::Register("movie", "Show movie on startup", 0, "1", nullptr, game);
Client::g_expansionMovieVar = CVar::Register("expansionMovie", "Show expansion movie on startup", 0, "1", nullptr, game);
Client::g_movieSubtitleVar = CVar::Register("movieSubtitle", "Show movie subtitles", 0, "0", nullptr, game);
Client::g_lastCharacterIndex = CVar::Register("lastCharacterIndex", "Last character selected", 0, "0", nullptr, game);
// TODO
}

View File

@ -14,6 +14,7 @@ namespace Client {
extern CVar* g_movieVar;
extern CVar* g_expansionMovieVar;
extern CVar* g_movieSubtitleVar;
extern CVar* g_lastCharacterIndex;
extern HEVENTCONTEXT g_clientEventContext;
extern char g_currentLocaleName[5];
}

View File

@ -73,9 +73,15 @@ void ClientServices::GetRealmList() {
}
void ClientServices::GetCharacterList() {
STORM_ASSERT(ClientServices::s_currentConnection);
ClientServices::s_currentConnection->GetCharacterList();
}
void ClientServices::EnumerateCharacters(ENUMERATE_CHARACTERS_CALLBACK fcn, void* param) {
STORM_ASSERT(ClientServices::s_currentConnection);
ClientServices::s_currentConnection->EnumerateCharacters(fcn, param);
}
void ClientServices::CharacterLogin(uint64_t id, const C3Vector& position) {
ClientServices::s_currentConnection->CharacterLogin(id);
}

View File

@ -38,6 +38,7 @@ class ClientServices : public LoginResponse {
static void SetMessageHandler(NETMESSAGE msgId, MESSAGE_HANDLER handler, void* param);
static void GetRealmList();
static void GetCharacterList();
static void EnumerateCharacters(ENUMERATE_CHARACTERS_CALLBACK fcn, void* param);
static void CharacterLogin(uint64_t id, const C3Vector& position);
static REALM_INFO* GetRealmInfoByIndex(int32_t index);
static const char* GetSelectedRealmName();

View File

@ -2,33 +2,48 @@
#include "model/CM2Shared.hpp"
#include "ui/CSimpleModelFFX.hpp"
#include "client/ClientServices.hpp"
#include "client/Client.hpp"
#include "console/CVar.hpp"
#include "net/Connection.hpp"
CSimpleModelFFX* CCharacterSelection::m_modelFrame = nullptr;
uint32_t CCharacterSelection::m_characterCount = 0;
float CCharacterSelection::m_charFacing = 0.0f;
uint32_t CCharacterSelection::m_restrictHuman = 0;
uint32_t CCharacterSelection::m_restrictDwarf = 0;
uint32_t CCharacterSelection::m_restrictGnome = 0;
uint32_t CCharacterSelection::m_restrictNightElf = 0;
uint32_t CCharacterSelection::m_restrictDraenei = 0;
uint32_t CCharacterSelection::m_restrictOrc = 0;
uint32_t CCharacterSelection::m_restrictTroll = 0;
uint32_t CCharacterSelection::m_restrictTauren = 0;
uint32_t CCharacterSelection::m_restrictUndead = 0;
uint32_t CCharacterSelection::m_restrictBloodElf = 0;
TSGrowableArray<CharacterSelectionDisplay> CCharacterSelection::s_characterList;
CSimpleModelFFX* CCharacterSelection::s_modelFrame;
float CCharacterSelection::s_charFacing = 0.0f;
int32_t CCharacterSelection::m_selectionIndex = 0;
void CCharacterSelection::RenderPrep() {
// TODO
}
void CCharacterSelection::SetBackgroundModel(const char* modelPath) {
if (!CCharacterSelection::s_modelFrame || !modelPath || !*modelPath) {
if (!CCharacterSelection::m_modelFrame || !modelPath || !*modelPath) {
return;
}
auto model = CCharacterSelection::s_modelFrame->m_model;
auto model = CCharacterSelection::m_modelFrame->m_model;
// Check if already set
if (model && !SStrCmpI(modelPath, model->m_shared->m_filePath, STORM_MAX_STR)) {
return;
}
CCharacterSelection::s_modelFrame->SetModel(modelPath);
CCharacterSelection::m_modelFrame->SetModel(modelPath);
// TODO BYTE1(CCharacterSelection::m_modelFrame->simplemodelffx_dword510[3]) = 1;
model = CCharacterSelection::s_modelFrame->m_model;
model = CCharacterSelection::m_modelFrame->m_model;
if (model) {
// TODO lighting callback + arg
@ -37,8 +52,18 @@ void CCharacterSelection::SetBackgroundModel(const char* modelPath) {
}
}
void CCharacterSelection::EnumerateCharactersCallback(CHARACTER_INFO& info, void* param) {
auto character = CCharacterSelection::s_characterList.New();
character->m_characterInfo = info;
// TODO: LoadAddOnEnableState(a1 + 8);
}
void CCharacterSelection::ShowCharacter() {
// TODO
}
void CCharacterSelection::SetCharFacing(float facing) {
// TODO:
// TODO
}
void CCharacterSelection::ClearCharacterList() {
@ -46,20 +71,42 @@ void CCharacterSelection::ClearCharacterList() {
void CCharacterSelection::UpdateCharacterList() {
// TODO: ClearAddOnEnableState(0);
// TODO: Proper implementation
auto& received = ClientServices::Connection()->m_characterList;
CCharacterSelection::s_characterList.SetCount(received.Count());
for (uint32_t i = 0; i < received.Count(); ++i) {
CCharacterSelection::s_characterList[i].m_characterInfo = received[i];
}
CCharacterSelection::s_characterList.SetCount(0);
if (CCharacterSelection::GetNumCharacters()) {
int32_t currentIndex = 0;
FrameScript_SignalEvent(8, "%d", currentIndex + 1);
CCharacterSelection::m_restrictHuman = 0;
CCharacterSelection::m_restrictDwarf = 0;
CCharacterSelection::m_restrictGnome = 0;
CCharacterSelection::m_restrictNightElf = 0;
CCharacterSelection::m_restrictDraenei = 0;
CCharacterSelection::m_restrictOrc = 0;
CCharacterSelection::m_restrictTroll = 0;
CCharacterSelection::m_restrictTauren = 0;
CCharacterSelection::m_restrictUndead = 0;
CCharacterSelection::m_restrictBloodElf = 0;
ClientServices::EnumerateCharacters(&CCharacterSelection::EnumerateCharactersCallback, nullptr);
if (CCharacterSelection::s_characterList.Count()) {
// TODO: Apply restrictions (m_restrictHuman, etc)
// TODO: CRealmList::m_preferredCategory = 0;
int32_t selectionIndex = Client::g_lastCharacterIndex->GetInt();
if (selectionIndex < 0 || selectionIndex >= CCharacterSelection::s_characterList.Count()) {
selectionIndex = 0;
}
CCharacterSelection::m_selectionIndex = selectionIndex;
CCharacterSelection::ShowCharacter();
FrameScript_SignalEvent(8, "%d", CCharacterSelection::m_selectionIndex + 1);
} else {
int32_t currentIndex = 0;
FrameScript_SignalEvent(8, "%d", currentIndex + 1);
CCharacterSelection::m_selectionIndex = 0;
CCharacterSelection::ShowCharacter();
FrameScript_SignalEvent(8, "%d", CCharacterSelection::m_selectionIndex + 1);
if (CCharacterSelection::m_modelFrame) {
// TODO
}
}
FrameScript_SignalEvent(7, nullptr);
}

View File

@ -13,13 +13,27 @@ struct CharacterSelectionDisplay {
class CCharacterSelection {
public:
// Static variables
static CSimpleModelFFX* m_modelFrame;
static uint32_t m_characterCount;
static float m_charFacing;
static uint32_t m_restrictHuman;
static uint32_t m_restrictDwarf;
static uint32_t m_restrictGnome;
static uint32_t m_restrictNightElf;
static uint32_t m_restrictDraenei;
static uint32_t m_restrictOrc;
static uint32_t m_restrictTroll;
static uint32_t m_restrictTauren;
static uint32_t m_restrictUndead;
static uint32_t m_restrictBloodElf;
static TSGrowableArray<CharacterSelectionDisplay> s_characterList;
static CSimpleModelFFX* s_modelFrame;
static float s_charFacing;
static int32_t m_selectionIndex;
// Static functions
static void RenderPrep();
static void SetBackgroundModel(const char* modelPath);
static void EnumerateCharactersCallback(CHARACTER_INFO& info, void* param);
static void ShowCharacter();
static void SetCharFacing(float facing);
static void ClearCharacterList();
static void UpdateCharacterList();

View File

@ -1285,5 +1285,7 @@ struct CHARACTER_INFO {
uint8_t firstLogin;
};
typedef void (*ENUMERATE_CHARACTERS_CALLBACK)(CHARACTER_INFO&, void*);
#endif

View File

@ -141,6 +141,13 @@ void ClientConnection::GetCharacterList() {
}
}
void ClientConnection::EnumerateCharacters(ENUMERATE_CHARACTERS_CALLBACK fcn, void* param) {
STORM_ASSERT(fcn);
for (uint32_t i = 0; i < this->m_characterList.Count(); ++i) {
fcn(this->m_characterList[i], param);
}
}
void ClientConnection::CharacterLogin(uint64_t id) {
this->Initiate(COP_LOGIN_CHARACTER, 76, nullptr);
if (this->m_connected) {

View File

@ -28,6 +28,7 @@ class ClientConnection : public RealmConnection {
void AccountLogin_Finish(int32_t authResult);
void AccountLogin_Queued();
void GetCharacterList();
void EnumerateCharacters(ENUMERATE_CHARACTERS_CALLBACK fcn, void* param);
void CharacterLogin(uint64_t id);
void Cancel(int32_t errorCode);
void Cleanup();

View File

@ -19,7 +19,7 @@ int32_t Script_SetCharSelectModelFrame(lua_State* L) {
auto frame = CScriptObject::GetScriptObjectByName(name, type);
if (frame) {
CCharacterSelection::s_modelFrame = static_cast<CSimpleModelFFX*>(frame);
CCharacterSelection::m_modelFrame = static_cast<CSimpleModelFFX*>(frame);
}
return 0;
@ -54,7 +54,7 @@ int32_t Script_GetCharacterInfo(lua_State* L) {
luaL_error(L, "Usage: GetCharacterInfo(index)");
}
int index = static_cast<int>(lua_tonumber(L, 1)) - 1;
int32_t index = static_cast<int32_t>(lua_tonumber(L, 1)) - 1;
if (index < 0 || index > CCharacterSelection::GetNumCharacters()) {
lua_pushnil(L); // name
lua_pushnil(L); // race
@ -108,7 +108,19 @@ int32_t Script_GetCharacterInfo(lua_State* L) {
}
int32_t Script_SelectCharacter(lua_State* L) {
WHOA_UNIMPLEMENTED(0);
if (!lua_isnumber(L, 1)) {
luaL_error(L, "Usage: SelectCharacter(index)");
}
int32_t index = static_cast<int32_t>(lua_tonumber(L, 1)) - 1;
if (index < 1 || index >= CCharacterSelection::GetNumCharacters()) {
index = 0;
}
CCharacterSelection::m_selectionIndex = index;
CCharacterSelection::ShowCharacter();
FrameScript_SignalEvent(8u, "%d", CCharacterSelection::m_selectionIndex + 1);
return 0;
}
int32_t Script_DeleteCharacter(lua_State* L) {
@ -131,7 +143,7 @@ int32_t Script_UpdateSelectionCustomizationScene(lua_State* L) {
int32_t Script_GetCharacterSelectFacing(lua_State* L) {
// Radian to Degree
lua_pushnumber(L, CCharacterSelection::s_charFacing * 57.29578f);
lua_pushnumber(L, CCharacterSelection::m_charFacing * 57.29578f);
return 1;
}