diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f913b36..1f3c867 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(app) add_subdirectory(async) add_subdirectory(client) +add_subdirectory(clientobject) add_subdirectory(console) add_subdirectory(cursor) add_subdirectory(db) diff --git a/src/clientobject/CMakeLists.txt b/src/clientobject/CMakeLists.txt new file mode 100644 index 0000000..d84e320 --- /dev/null +++ b/src/clientobject/CMakeLists.txt @@ -0,0 +1,16 @@ +file(GLOB PRIVATE_SOURCES "*.cpp") + +add_library(clientobject STATIC + ${PRIVATE_SOURCES} +) + +target_include_directories(clientobject + PRIVATE + ${CMAKE_SOURCE_DIR}/src +) + +target_link_libraries(clientobject + PRIVATE + storm + db +) diff --git a/src/clientobject/Unit_C.cpp b/src/clientobject/Unit_C.cpp new file mode 100644 index 0000000..fe9436a --- /dev/null +++ b/src/clientobject/Unit_C.cpp @@ -0,0 +1,43 @@ +#include "clientobject/Unit_C.hpp" + +const char* CGUnit_C::GetDisplayRaceNameFromRecord(ChrRacesRec* record, uint8_t sexIn, uint8_t* sexOut) { + const char* result; + + if (sexOut) { + *sexOut = sexIn; + } + if (!record) { + return nullptr; + } + if (!sexIn) { + if (record->m_nameMale[0]) { + return record->m_nameMale; + } + + if (record->m_nameFemale[0]) { + if (sexOut) { + *sexOut = 1; + } + return record->m_nameFemale; + } + + return record->m_name; + } + + if (sexIn != 1) { + return record->m_name; + } + + if (record->m_nameFemale[0]) { + return record->m_nameFemale; + } + + if (!record->m_nameMale[0]) { + return record->m_name; + } + + if (sexOut) { + *sexOut = 0; + } + return record->m_nameMale; +} diff --git a/src/clientobject/Unit_C.hpp b/src/clientobject/Unit_C.hpp new file mode 100644 index 0000000..01299ba --- /dev/null +++ b/src/clientobject/Unit_C.hpp @@ -0,0 +1,11 @@ +#ifndef CLIENTOBJECT_UNIT_C_HPP +#define CLIENTOBJECT_UNIT_C_HPP + +#include "db/rec/ChrRacesRec.hpp" + +class CGUnit_C { + public: + static const char* GetDisplayRaceNameFromRecord(ChrRacesRec* record, uint8_t sexIn, uint8_t* sexOut = nullptr); +}; + +#endif // CLIENTOBJECT_UNIT_C_HPP diff --git a/src/glue/CCharacterSelection.cpp b/src/glue/CCharacterSelection.cpp index 7081264..8ed69c5 100644 --- a/src/glue/CCharacterSelection.cpp +++ b/src/glue/CCharacterSelection.cpp @@ -1,6 +1,8 @@ #include "glue/CCharacterSelection.hpp" #include "model/CM2Shared.hpp" #include "ui/CSimpleModelFFX.hpp" +#include "client/ClientServices.hpp" +#include "net/Connection.hpp" TSGrowableArray CCharacterSelection::s_characterList; CSimpleModelFFX* CCharacterSelection::s_modelFrame; @@ -38,3 +40,30 @@ void CCharacterSelection::SetBackgroundModel(const char* modelPath) { void CCharacterSelection::SetCharFacing(float facing) { // TODO: } + +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]; + } + + if (CCharacterSelection::GetNumCharacters()) { + int32_t currentIndex = 0; + FrameScript_SignalEvent(8, "%d", currentIndex + 1); + } else { + int32_t currentIndex = 0; + FrameScript_SignalEvent(8, "%d", currentIndex + 1); + } + FrameScript_SignalEvent(7, nullptr); +} + +uint32_t CCharacterSelection::GetNumCharacters() { + return s_characterList.Count(); +} diff --git a/src/glue/CCharacterSelection.hpp b/src/glue/CCharacterSelection.hpp index 6d3d9ab..7d25381 100644 --- a/src/glue/CCharacterSelection.hpp +++ b/src/glue/CCharacterSelection.hpp @@ -2,11 +2,12 @@ #define GLUE_C_CHARACTER_SELECTION_HPP #include +#include "net/Types.hpp" class CSimpleModelFFX; struct CharacterSelectionDisplay { - // TODO + CHARACTER_INFO m_characterInfo; }; class CCharacterSelection { @@ -20,6 +21,9 @@ class CCharacterSelection { static void RenderPrep(); static void SetBackgroundModel(const char* modelPath); static void SetCharFacing(float facing); + static void ClearCharacterList(); + static void UpdateCharacterList(); + static uint32_t GetNumCharacters(); }; #endif diff --git a/src/glue/CGlueMgr.cpp b/src/glue/CGlueMgr.cpp index d019326..e8a43fd 100644 --- a/src/glue/CGlueMgr.cpp +++ b/src/glue/CGlueMgr.cpp @@ -1,5 +1,6 @@ #include "glue/CGlueMgr.hpp" #include "glue/CRealmList.hpp" +#include "glue/CCharacterSelection.hpp" #include "client/Client.hpp" #include "client/ClientServices.hpp" #include "gx/Coordinate.hpp" @@ -455,7 +456,7 @@ void CGlueMgr::PollAccountLogin(int32_t errorCode, const char* msg, int32_t comp } if (errorCode != 13) { - // TODO CCharacterSelection::ClearCharacterList(); + CCharacterSelection::ClearCharacterList(); if (ClientServices::GetInstance()->m_realmList.Count()) { FrameScript_SignalEvent(5, nullptr); @@ -569,8 +570,7 @@ void CGlueMgr::PollLoginServerLogin() { void CGlueMgr::PollCharacterList(int32_t errorCode, const char* msg, int32_t complete, int32_t result, WOWCS_OPS op) { FrameScript_SignalEvent(4, "%s", msg); - // TODO: if (CGlueMgr::HandleBattlenetDisconnect()) - if (false) { + if (CGlueMgr::HandleBattlenetDisconnect()) { CGlueMgr::m_idleState = IDLE_NONE; CGlueMgr::m_showedDisconnect = 0; } @@ -581,7 +581,7 @@ void CGlueMgr::PollCharacterList(int32_t errorCode, const char* msg, int32_t com if (!result) { if (errorCode == 2) { - // TODO CCharacterSelection::ClearCharacterList(); + CCharacterSelection::ClearCharacterList(); CGlueMgr::GetRealmList(true); } else { FrameScript_SignalEvent(3, "%s%s", "OKAY", msg); @@ -594,7 +594,7 @@ void CGlueMgr::PollCharacterList(int32_t errorCode, const char* msg, int32_t com CGlueMgr::m_idleState = IDLE_NONE; CGlueMgr::m_showedDisconnect = 0; FrameScript_SignalEvent(5, nullptr); - // TODO: sub_4E4610(); + CCharacterSelection::UpdateCharacterList(); if (!CGlueMgr::m_accountMsgAvailable) { return; } @@ -895,6 +895,10 @@ void CGlueMgr::UpdateCurrentScreen(const char* screen) { // TODO } +bool CGlueMgr::HandleBattlenetDisconnect() { + return false; +} + void CGlueMgr::SurveyDownloadStart() { } diff --git a/src/glue/CGlueMgr.hpp b/src/glue/CGlueMgr.hpp index 4b4d16b..627d3af 100644 --- a/src/glue/CGlueMgr.hpp +++ b/src/glue/CGlueMgr.hpp @@ -89,6 +89,7 @@ class CGlueMgr { static void Sub4D8BA0(); static void Suspend(); static void UpdateCurrentScreen(const char* screen); + static bool HandleBattlenetDisconnect(); // Survey Download System static void SurveyDownloadStart(); diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index eafbb87..9c10673 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -12,6 +12,7 @@ target_include_directories(ui target_link_libraries(ui PRIVATE client + clientobject console db event diff --git a/src/ui/ScriptFunctionsCharSelect.cpp b/src/ui/ScriptFunctionsCharSelect.cpp index 7979442..a62a526 100644 --- a/src/ui/ScriptFunctionsCharSelect.cpp +++ b/src/ui/ScriptFunctionsCharSelect.cpp @@ -6,6 +6,8 @@ #include "util/Lua.hpp" #include "util/Unimplemented.hpp" #include "glue/CGlueMgr.hpp" +#include "db/Db.hpp" +#include "clientobject/Unit_C.hpp" int32_t Script_SetCharSelectModelFrame(lua_State* L) { if (!lua_isstring(L, 1)) { @@ -42,13 +44,67 @@ int32_t Script_GetCharacterListUpdate(lua_State* L) { } int32_t Script_GetNumCharacters(lua_State* L) { - lua_pushnumber(L, CCharacterSelection::s_characterList.Count()); + lua_pushnumber(L, CCharacterSelection::GetNumCharacters()); return 1; } int32_t Script_GetCharacterInfo(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + if (!lua_isnumber(L, 1)) { + luaL_error(L, "Usage: GetCharacterInfo(index)"); + } + + int index = static_cast(lua_tonumber(L, 1)) - 1; + if (index < 0 || index > CCharacterSelection::GetNumCharacters()) { + lua_pushnil(L); // name + lua_pushnil(L); // race + lua_pushnil(L); // class + lua_pushnumber(L, 0.0); // level + lua_pushnumber(L, 0.0); // zone + lua_pushnil(L); // sex + lua_pushnil(L); // ghost + lua_pushnil(L); // PCC + lua_pushnil(L); // PRC + lua_pushnil(L); // PFC + return 10; + } + + auto& character = CCharacterSelection::s_characterList[index].m_characterInfo; + lua_pushstring(L, character.name); + + auto raceName = CGUnit_C::GetDisplayRaceNameFromRecord(g_chrRacesDB.GetRecord(character.raceID), character.sexID); + lua_pushstring(L, raceName ? raceName : ""); + + // TODO: auto className = CGUnit_C::GetDisplayClassNameFromRecord(g_chrClassesDB.GetRecord(character.classID), character.sexID); + auto className = "ClassName"; + lua_pushstring(L, className ? className : ""); + + lua_pushnumber(L, character.experienceLevel); + + // TODO: auto areaRecord = g_areaTableDB.GetRecord(character.zoneID); + void* areaRecord = nullptr; + if (areaRecord) { + // TODO: lua_pushstring(L, areaRecord->name) + } else { + lua_pushnil(L); + } + + // TODO: Use g_glueFrameScriptGenders[character.sexID] + lua_pushnumber(L, 0); + + // ghost + lua_pushboolean(L, character.flags & 0x2000); + + // PCC + lua_pushboolean(L, character.customizeFlags & 1); + + // PRC + lua_pushboolean(L, character.customizeFlags & 0x100000); + + // PFC + lua_pushboolean(L, character.customizeFlags & 0x10000); + + return 10; } int32_t Script_SelectCharacter(lua_State* L) {