From b4ff9994e2a05b577cbbbf646e97626a609dddf3 Mon Sep 17 00:00:00 2001 From: VDm Date: Sun, 18 May 2025 14:58:01 +0400 Subject: [PATCH] feat(ui): implement script methods for character creation screen --- src/client/ClientServices.cpp | 4 ++ src/client/ClientServices.hpp | 1 + src/glue/CCharacterCreation.cpp | 12 ++++ src/glue/CCharacterCreation.hpp | 3 + src/net/connection/RealmConnection.cpp | 4 ++ src/net/connection/RealmConnection.hpp | 1 + src/ui/FrameScript.cpp | 1 + src/ui/FrameScript.hpp | 1 + src/ui/ScriptFunctionsCharCreate.cpp | 80 ++++++++++++++++++-------- src/util/SFile.cpp | 5 ++ src/util/SFile.hpp | 1 + 11 files changed, 90 insertions(+), 23 deletions(-) diff --git a/src/client/ClientServices.cpp b/src/client/ClientServices.cpp index 7686ab6..fdffbdb 100644 --- a/src/client/ClientServices.cpp +++ b/src/client/ClientServices.cpp @@ -423,6 +423,10 @@ bool ClientServices::LoadCDKey() { return true; } +int32_t ClientServices::GetExpansionLevel() { + return ClientServices::Connection()->GetExpansionLevel(); +} + void ClientServices::InitLoginServerCVars(int32_t overwrite, const char* locale) { if ((ClientServices::s_realmListBNVar == nullptr || ClientServices::s_realmListVar == nullptr) || overwrite != 0 ) { ClientServices::s_decorateAccountName = CVar::Register( diff --git a/src/client/ClientServices.hpp b/src/client/ClientServices.hpp index 0e96354..0016d0a 100644 --- a/src/client/ClientServices.hpp +++ b/src/client/ClientServices.hpp @@ -56,6 +56,7 @@ class ClientServices : public LoginResponse { static const char* GetDefaultRealmlistString(); static const char* GetDefaultPatchListString(); static bool LoadCDKey(); + static int32_t GetExpansionLevel(); // Virtual member functions virtual int32_t GetLoginServerType(); diff --git a/src/glue/CCharacterCreation.cpp b/src/glue/CCharacterCreation.cpp index c1dd388..c609e9b 100644 --- a/src/glue/CCharacterCreation.cpp +++ b/src/glue/CCharacterCreation.cpp @@ -183,3 +183,15 @@ void CCharacterCreation::RandomizeCharFeatures() { CCharacterCreation::m_prevHairStyleIndex = info.hairStyleID; CCharacterCreation::m_prevFacialFeatureIndex = info.facialFeatureID; } + +void CCharacterCreation::SetSelectedRace(int32_t raceID) { + // TODO +} + +void CCharacterCreation::SetSelectedSex(int32_t sexID) { + // TODO +} + +void CCharacterCreation::SetSelectedClass(int32_t classID) { + // TODO +} diff --git a/src/glue/CCharacterCreation.hpp b/src/glue/CCharacterCreation.hpp index 13521a3..e99cf09 100644 --- a/src/glue/CCharacterCreation.hpp +++ b/src/glue/CCharacterCreation.hpp @@ -38,6 +38,9 @@ class CCharacterCreation { static void CalcClasses(uint32_t raceID); static void InitCharacterComponent(ComponentData* data, int32_t randomize); static void RandomizeCharFeatures(); + static void SetSelectedRace(int32_t raceID); + static void SetSelectedSex(int32_t sexID); + static void SetSelectedClass(int32_t classID); }; #endif // GLUE_C_CHARACTER_CREATION_HPP diff --git a/src/net/connection/RealmConnection.cpp b/src/net/connection/RealmConnection.cpp index 1133592..de2d81b 100644 --- a/src/net/connection/RealmConnection.cpp +++ b/src/net/connection/RealmConnection.cpp @@ -297,3 +297,7 @@ void RealmConnection::RequestCharacterLogin(uint64_t id) { msg.Finalize(); this->Send(&msg); } + +int32_t RealmConnection::GetExpansionLevel() const { + return this->m_accountExpansion; +} diff --git a/src/net/connection/RealmConnection.hpp b/src/net/connection/RealmConnection.hpp index 03ebaf7..1fd3d06 100644 --- a/src/net/connection/RealmConnection.hpp +++ b/src/net/connection/RealmConnection.hpp @@ -45,6 +45,7 @@ class RealmConnection : public NetClient { void SetSelectedRealm(uint32_t a2, uint32_t a3, uint32_t a4); void RequestCharacterEnum(); void RequestCharacterLogin(uint64_t id); + int32_t GetExpansionLevel() const; }; #endif diff --git a/src/ui/FrameScript.cpp b/src/ui/FrameScript.cpp index 47903d2..91bd15e 100644 --- a/src/ui/FrameScript.cpp +++ b/src/ui/FrameScript.cpp @@ -15,6 +15,7 @@ const char* g_glueScriptEvents[41]; const char* g_scriptEvents[722]; +int32_t g_glueFrameScriptGenders[3] = { 2, 3, 1 }; void* FrameScript::s_mempool; lua_State* FrameScript::s_context; diff --git a/src/ui/FrameScript.hpp b/src/ui/FrameScript.hpp index 11af907..281e265 100644 --- a/src/ui/FrameScript.hpp +++ b/src/ui/FrameScript.hpp @@ -42,6 +42,7 @@ class FrameScript_EventObject : public TSHashObject int32_t Script_SetCharCustomizeFrame(lua_State* L) { @@ -93,31 +96,37 @@ int32_t Script_GetFactionForRace(lua_State* L) { } int32_t Script_GetAvailableRaces(lua_State* L) { + auto sexID = CCharacterCreation::m_character->m_data.m_info.sexID; + for (uint32_t i = 0; i < CCharacterCreation::m_races.Count(); ++i) { auto raceRecord = g_chrRacesDB.GetRecord(CCharacterCreation::m_races[i]); - auto raceName = CGUnit_C::GetDisplayRaceNameFromRecord( - raceRecord, - CCharacterCreation::m_character->m_data.m_info.sexID); + auto raceName = CGUnit_C::GetDisplayRaceNameFromRecord(raceRecord, sexID); lua_pushstring(L, raceName); - lua_pushstring(L, raceRecord ? raceRecord->m_clientFileString : nullptr); - // TODO: Expansion Check - lua_pushnumber(L, 1.0); + if (raceRecord) { + lua_pushstring(L, raceRecord->m_clientFileString); + bool available = ClientServices::GetExpansionLevel() >= raceRecord->m_requiredExpansion; + lua_pushnumber(L, available ? 1.0 : 0.0); + } else { + lua_pushstring(L, nullptr); + lua_pushnumber(L, 0.0); + } } return CCharacterCreation::m_races.Count() * 3; } int32_t Script_GetAvailableClasses(lua_State* L) { + auto sexID = CCharacterCreation::m_character->m_data.m_info.sexID; + for (int32_t i = 0; i < g_chrClassesDB.GetNumRecords(); ++i) { auto record = g_chrClassesDB.GetRecordByIndex(i); - auto className = CGUnit_C::GetDisplayClassNameFromRecord( - record, - CCharacterCreation::m_character->m_data.m_info.sexID); + auto className = CGUnit_C::GetDisplayClassNameFromRecord(record, sexID); + if (className) { lua_pushstring(L, className); lua_pushstring(L, record->m_filename); - // TODO: Expansion Check - lua_pushnumber(L, 1.0); + bool available = ClientServices::GetExpansionLevel() >= record->m_requiredExpansion; + lua_pushnumber(L, available ? 1.0 : 0.0); } else { lua_pushnil(L); lua_pushnil(L); @@ -128,16 +137,17 @@ int32_t Script_GetAvailableClasses(lua_State* L) { } int32_t Script_GetClassesForRace(lua_State* L) { + auto sexID = CCharacterCreation::m_character->m_data.m_info.sexID; + for (uint32_t i = 0; i < CCharacterCreation::m_classes.Count(); ++i) { auto record = CCharacterCreation::m_classes[i]; - auto className = CGUnit_C::GetDisplayClassNameFromRecord( - record, - CCharacterCreation::m_character->m_data.m_info.sexID); + auto className = CGUnit_C::GetDisplayClassNameFromRecord(record, sexID); + if (className) { lua_pushstring(L, className); lua_pushstring(L, record->m_filename); - // TODO: Expansion Check - lua_pushnumber(L, 1.0); + bool available = ClientServices::GetExpansionLevel() >= record->m_requiredExpansion; + lua_pushnumber(L, available ? 1.0 : 0.0); } else { lua_pushnil(L); lua_pushnil(L); @@ -182,8 +192,8 @@ int32_t Script_GetSelectedRace(lua_State* L) { } int32_t Script_GetSelectedSex(lua_State* L) { - // TODO: g_glueFrameScriptGenders[CCharacterCreation::m_character->m_data.m_info.sexID] - lua_pushnumber(L, 2.0); + auto sexID = CCharacterCreation::m_character->m_data.m_info.sexID; + lua_pushnumber(L, g_glueFrameScriptGenders[sexID]); return 1; } @@ -218,15 +228,40 @@ int32_t Script_GetSelectedClass(lua_State* L) { } int32_t Script_SetSelectedRace(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + if (!lua_isnumber(L, 1)) { + return luaL_error(L, "Usage: SetSelectedRace(index)"); + } + + int32_t raceID = static_cast(lua_tonumber(L, 1)) - 1; + CCharacterCreation::SetSelectedRace(raceID); + return 0; } int32_t Script_SetSelectedSex(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + if (!lua_isnumber(L, 1)) { + return luaL_error(L, "Usage: SetSelectedSex(index)"); + } + + int32_t sexID = static_cast(lua_tonumber(L, 1)); + for (int32_t i = 0; i < 3; ++i) { + if (g_glueFrameScriptGenders[i] == sexID) { + CCharacterCreation::SetSelectedSex(i); + } + } + return 0; } int32_t Script_SetSelectedClass(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + if (!lua_isnumber(L, 1)) { + return luaL_error(L, "Usage: SetSelectedSex(index)"); + } + + int32_t index = static_cast(lua_tonumber(L, 1)) - 1; + + // NOTICE: Original client has access violation issue in this method + auto record = g_chrClassesDB.GetRecordByIndex(index); + CCharacterCreation::SetSelectedClass(record ? record->m_ID : 0); + return 0; } int32_t Script_UpdateCustomizationBackground(lua_State* L) { @@ -290,8 +325,7 @@ int32_t Script_IsRaceClassRestricted(lua_State* L) { } int32_t Script_GetCreateBackgroundModel(lua_State* L) { - // TODO - if (false /* SFile::IsTrial() */) { + if (SFile::IsTrial()) { lua_pushstring(L, "CharacterSelect"); return 1; } diff --git a/src/util/SFile.cpp b/src/util/SFile.cpp index fab5907..69324e6 100644 --- a/src/util/SFile.cpp +++ b/src/util/SFile.cpp @@ -307,3 +307,8 @@ int32_t SFile::RebuildHash() { // TODO return 1; } + +int32_t SFile::IsTrial() { + // TODO + return 0; +} diff --git a/src/util/SFile.hpp b/src/util/SFile.hpp index 350859d..6afd740 100644 --- a/src/util/SFile.hpp +++ b/src/util/SFile.hpp @@ -41,6 +41,7 @@ class SFile { static int32_t GetDataPath(char* path, size_t capacity); static int32_t SetDataPathAlternate(const char* path); static int32_t RebuildHash(); + static int32_t IsTrial(); // Member variables SFILE_TYPE m_type;