From a4983196108a3c003244538656630260a7b30998 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 27 Feb 2024 13:19:00 -0500 Subject: [PATCH] Implement Save, Load, DeleteState --- .../legoomni/include/legobackgroundcolor.h | 2 + .../legoomni/include/legobuildingmanager.h | 3 + LEGO1/lego/legoomni/include/legogamestate.h | 5 +- .../lego/legoomni/include/legoplantmanager.h | 3 + .../legoomni/include/legounksavedatawriter.h | 1 + LEGO1/lego/legoomni/include/legoutil.h | 1 + .../src/build/legobuildingmanager.cpp | 12 ++ .../src/common/legobackgroundcolor.cpp | 13 ++ .../legoomni/src/common/legogamestate.cpp | 166 ++++++++++++++++-- .../legoomni/src/common/legoplantmanager.cpp | 12 ++ .../src/common/legounksavedatawriter.cpp | 6 + LEGO1/lego/legoomni/src/common/legoutil.cpp | 5 + LEGO1/lego/legoomni/src/entity/legoworld.cpp | 2 +- LEGO1/lego/sources/misc/legostorage.h | 45 +++-- LEGO1/omni/include/mxutil.h | 1 + LEGO1/omni/src/common/mxutil.cpp | 11 ++ 16 files changed, 253 insertions(+), 35 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legobackgroundcolor.h b/LEGO1/lego/legoomni/include/legobackgroundcolor.h index 672e39be..3a301a39 100644 --- a/LEGO1/lego/legoomni/include/legobackgroundcolor.h +++ b/LEGO1/lego/legoomni/include/legobackgroundcolor.h @@ -9,6 +9,8 @@ class LegoBackgroundColor : public MxVariable { public: LegoBackgroundColor(const char* p_key, const char* p_value); void SetValue(const char* p_colorString) override; + void SetLights(float p_r, float p_g, float p_b); + void SetLights(); private: float m_h; diff --git a/LEGO1/lego/legoomni/include/legobuildingmanager.h b/LEGO1/lego/legoomni/include/legobuildingmanager.h index f6b5c0e6..2c50c027 100644 --- a/LEGO1/lego/legoomni/include/legobuildingmanager.h +++ b/LEGO1/lego/legoomni/include/legobuildingmanager.h @@ -2,6 +2,7 @@ #define LEGOBUILDINGMANAGER_H #include "decomp.h" +#include "lego/sources/misc/legostorage.h" #include "mxcore.h" // VTABLE: LEGO1 0x100d6f50 @@ -25,6 +26,8 @@ class LegoBuildingManager : public MxCore { void FUN_1002fa00(); void FUN_1002fb30(); + MxResult Save(LegoStorage* p_storage); + MxResult Load(LegoStorage* p_storage); void FUN_10030590(); // SYNTHETIC: LEGO1 0x1002f940 diff --git a/LEGO1/lego/legoomni/include/legogamestate.h b/LEGO1/lego/legoomni/include/legogamestate.h index 59dc8784..d35c0764 100644 --- a/LEGO1/lego/legoomni/include/legogamestate.h +++ b/LEGO1/lego/legoomni/include/legogamestate.h @@ -120,8 +120,9 @@ class LegoGameState { LegoGameState(); ~LegoGameState(); - MxResult Load(MxULong); MxResult Save(MxULong); + MxResult DeleteState(); + MxResult Load(MxULong); void SerializePlayersInfo(MxS16); void SerializeScoreHistory(MxS16 p_flags); void SetSavePath(char*); @@ -152,7 +153,7 @@ class LegoGameState { void SetCurrentAct(Act p_currentAct); void FindLoadedAct(); void SetActor(MxU8 p_actorId); - void FUN_10039940(); + void ResetROI(); private: void RegisterState(LegoState* p_state); diff --git a/LEGO1/lego/legoomni/include/legoplantmanager.h b/LEGO1/lego/legoomni/include/legoplantmanager.h index 5d64ca27..622eb500 100644 --- a/LEGO1/lego/legoomni/include/legoplantmanager.h +++ b/LEGO1/lego/legoomni/include/legoplantmanager.h @@ -2,6 +2,7 @@ #define LEGOPLANTMANAGER_H #include "decomp.h" +#include "lego/sources/misc/legostorage.h" #include "mxcore.h" // VTABLE: LEGO1 0x100d6758 @@ -22,6 +23,8 @@ class LegoPlantManager : public MxCore { void FUN_10026360(MxS32 p_scriptIndex); void FUN_100263a0(undefined4 p_und); + void Save(LegoStorage* p_storage); + MxResult Load(LegoStorage* p_storage); void FUN_10027120(); static void SetCustomizeAnimFile(const char* p_value); diff --git a/LEGO1/lego/legoomni/include/legounksavedatawriter.h b/LEGO1/lego/legoomni/include/legounksavedatawriter.h index deea67b0..6a6864f0 100644 --- a/LEGO1/lego/legoomni/include/legounksavedatawriter.h +++ b/LEGO1/lego/legoomni/include/legounksavedatawriter.h @@ -56,6 +56,7 @@ class LegoUnkSaveDataWriter { LegoUnkSaveDataWriter(); MxResult WriteSaveData3(LegoStorage* p_storage); + MxResult ReadSaveData3(LegoStorage* p_storage); LegoROI* FUN_10083500(const char*, MxBool); static void InitSaveData(); diff --git a/LEGO1/lego/legoomni/include/legoutil.h b/LEGO1/lego/legoomni/include/legoutil.h index 0b35fc61..01f6c516 100644 --- a/LEGO1/lego/legoomni/include/legoutil.h +++ b/LEGO1/lego/legoomni/include/legoutil.h @@ -41,6 +41,7 @@ void FUN_1003ef00(MxBool); void SetAppCursor(WPARAM p_wparam); MxBool FUN_1003ef60(); MxBool RemoveFromWorld(MxAtomId& p_atomId1, MxS32 p_id1, MxAtomId& p_atomId2, MxS32 p_id2); +void SetLightPosition(MxU32); NamedTexture* ReadNamedTexture(LegoFile* p_file); void FUN_1003f540(LegoFile* p_file, const char* p_filename); void WriteNamedTexture(LegoFile* p_file, NamedTexture* p_texture); diff --git a/LEGO1/lego/legoomni/src/build/legobuildingmanager.cpp b/LEGO1/lego/legoomni/src/build/legobuildingmanager.cpp index ddb2788d..42b161f5 100644 --- a/LEGO1/lego/legoomni/src/build/legobuildingmanager.cpp +++ b/LEGO1/lego/legoomni/src/build/legobuildingmanager.cpp @@ -44,6 +44,18 @@ void LegoBuildingManager::FUN_1002fb30() // TODO } +// STUB: LEGO1 0x1002fb80 +MxResult LegoBuildingManager::Save(LegoStorage* p_storage) +{ + return SUCCESS; +} + +// STUB: LEGO1 0x1002fc10 +MxResult LegoBuildingManager::Load(LegoStorage* p_storage) +{ + return SUCCESS; +} + // FUNCTION: LEGO1 0x1002ff90 void LegoBuildingManager::SetCustomizeAnimFile(const char* p_value) { diff --git a/LEGO1/lego/legoomni/src/common/legobackgroundcolor.cpp b/LEGO1/lego/legoomni/src/common/legobackgroundcolor.cpp index 461e84db..e6cd3fed 100644 --- a/LEGO1/lego/legoomni/src/common/legobackgroundcolor.cpp +++ b/LEGO1/lego/legoomni/src/common/legobackgroundcolor.cpp @@ -66,3 +66,16 @@ void LegoBackgroundColor::SetValue(const char* p_colorString) delete[] colorStringCopy; } + +// STUB: LEGO1 0x1003c400 +void LegoBackgroundColor::SetLights(float p_r, float p_g, float p_b) +{ +} + +// FUNCTION: LEGO1 0x1003c4b0 +void LegoBackgroundColor::SetLights() +{ + float convertedR, convertedG, convertedB; + ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB); + SetLights(convertedR, convertedG, convertedB); +} diff --git a/LEGO1/lego/legoomni/src/common/legogamestate.cpp b/LEGO1/lego/legoomni/src/common/legogamestate.cpp index 9f1c6482..6cfc80d8 100644 --- a/LEGO1/lego/legoomni/src/common/legogamestate.cpp +++ b/LEGO1/lego/legoomni/src/common/legogamestate.cpp @@ -5,8 +5,10 @@ #include "infocenterstate.h" #include "islepathactor.h" #include "legoanimationmanager.h" +#include "legobuildingmanager.h" #include "legonavcontroller.h" #include "legoomni.h" +#include "legoplantmanager.h" #include "legostate.h" #include "legounksavedatawriter.h" #include "legoutil.h" @@ -156,10 +158,19 @@ void LegoGameState::SetActor(MxU8 p_actorId) SetCurrentActor(newActor); } -// STUB: LEGO1 0x10039940 -void LegoGameState::FUN_10039940() +// FUNCTION: LEGO1 0x10039940 +void LegoGameState::ResetROI() { - // TODO + if (m_actorId) { + IslePathActor* actor = CurrentActor(); + if (actor) { + LegoROI* roi = actor->GetROI(); + if (roi) { + VideoManager()->Get3DManager()->GetLego3DView()->Remove(*roi); + VideoManager()->Get3DManager()->GetLego3DView()->Add(*roi); + } + } + } } // FUNCTION: LEGO1 0x10039980 @@ -173,16 +184,18 @@ MxResult LegoGameState::Save(MxULong p_slot) } else { result = FAILURE; + LegoFile fileStream; MxVariableTable* variableTable = VariableTable(); + MxU16 count = 0; MxString savePath; GetFileSavePath(&savePath, p_slot); - LegoFile fileStream; if (fileStream.Open(savePath.GetData(), LegoFile::c_write) != FAILURE) { - MxU32 maybeVersion = 0x1000C; - fileStream.Write(&maybeVersion, 4); - fileStream.Write(&m_unk0x24, 2); - fileStream.Write(&m_currentAct, 2); - fileStream.Write(&m_actorId, 1); + MxU32 version = 0x1000C; + Write(&fileStream, &version); + Write(&fileStream, &m_unk0x24); + MxU16 act = m_currentAct; + Write(&fileStream, &act); + Write(&fileStream, &m_actorId); for (MxS32 i = 0; i < sizeof(g_colorSaveData) / sizeof(g_colorSaveData[0]); ++i) { if (WriteVariable(&fileStream, variableTable, g_colorSaveData[i].m_targetName) == FAILURE) { @@ -193,21 +206,142 @@ MxResult LegoGameState::Save(MxULong p_slot) if (WriteVariable(&fileStream, variableTable, "backgroundcolor") != FAILURE) { if (WriteVariable(&fileStream, variableTable, "lightposition") != FAILURE) { WriteEndOfVariables(&fileStream); - - // TODO: Calls down to more aggregate writing functions - return SUCCESS; + UnkSaveDataWriter()->WriteSaveData3(&fileStream); + PlantManager()->Save(&fileStream); + result = BuildingManager()->Save(&fileStream); + for (MxS32 i = 0; i < m_stateCount; i++) { + if (m_stateArray[i]->VTable0x14()) { + count++; + } + } + Write(&fileStream, &count); + for (MxS32 j = 0; j < m_stateCount; j++) { + if (m_stateArray[j]->VTable0x14()) { + m_stateArray[j]->VTable0x1c(&fileStream); + } + } + MxU16 area = m_unk0x42c; + Write(&fileStream, &area); + SerializeScoreHistory(2); + m_isDirty = FALSE; } } + return result; } } return result; } -// STUB: LEGO1 0x10039c60 -MxResult LegoGameState::Load(MxULong) +// FUNCTION: LEGO1 0x10039bf0 +MxResult LegoGameState::DeleteState() { - // TODO - return 0; + MxS16 stateCount = m_stateCount; + LegoState** stateArray = m_stateArray; + m_stateCount = 0; + m_stateArray = NULL; + if (stateCount > 0) { + MxS32 count = stateCount; + LegoState** iter = stateArray; + do { + if (!(*iter)->SetFlag() && (*iter)->VTable0x14()) { + delete *iter; + } + else { + RegisterState(*iter); + *iter = NULL; + } + iter++; + } while (--count); + } + delete[] stateArray; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10039c60 +MxResult LegoGameState::Load(MxULong p_slot) +{ + MxResult result = FAILURE; + LegoFile fileStream; + MxVariableTable* variableTable = VariableTable(); + MxString savePath; + GetFileSavePath(&savePath, p_slot); + if (fileStream.Open(savePath.GetData(), LegoFile::c_read) != FAILURE) { + MxU32 version; + Read(&fileStream, &version, 4); + if (version != 0x1000C) { + OmniError("Saved game version mismatch", 0); + goto checkErr; + } + Read(&fileStream, &m_unk0x24, 2); + MxS16 act; + Read(&fileStream, &act, 2); + SetCurrentAct((Act) act); + Read(&fileStream, &m_actorId, 1); + if (m_actorId) { + SetActor(m_actorId); + } + MxU32 status; + do { + MxU32 status = ReadVariable(&fileStream, variableTable); + if (status == 1) { + goto checkErr; + } + } while (status != 2); + m_backgroundColor->SetLights(); + const char* lightPosition = VariableTable()->GetVariable("lightposition"); + if (lightPosition) { + SetLightPosition(atoi(lightPosition)); + } + + if (UnkSaveDataWriter()->ReadSaveData3(&fileStream) == FAILURE) { + goto checkErr; + } + + if (PlantManager()->Load(&fileStream) == FAILURE) { + goto checkErr; + } + + if (BuildingManager()->Load(&fileStream) == FAILURE) { + goto checkErr; + } + + if (DeleteState() != SUCCESS) { + goto checkErr; + } + + MxS16 count; + MxS16 stateNameLength; + char stateName[80]; + Read(&fileStream, &count, 2); + for (MxS16 i = 0; i < count; i++) { + Read(&fileStream, &stateNameLength, 2); + Read(&fileStream, stateName, (int) stateNameLength); + stateName[stateNameLength] = 0; + LegoState* state = GetState(stateName); + if (!state) { + state = CreateState(stateName); + if (!state) { + goto checkErr; + } + } + state->VTable0x1c(&fileStream); + } + MxS16 area; + Read(&fileStream, &area, 2); + if (m_currentAct == 0) { + m_unk0x42c = e_noArea; + } + else { + m_unk0x42c = (Area) area; + } + result = SUCCESS; + m_isDirty = FALSE; + } +checkErr: + if (result != SUCCESS) { + OmniError("Game state loading was not successful!", 0); + } + return result; } // FUNCTION: LEGO1 0x10039f00 diff --git a/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp b/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp index 2b2cc4e9..11f722e8 100644 --- a/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp @@ -35,6 +35,18 @@ void LegoPlantManager::FUN_100263a0(undefined4 p_und) // TODO } +// STUB: LEGO1 0x10026720 +void LegoPlantManager::Save(LegoStorage* p_storage) +{ + // TODO +} + +// STUB: LEGO1 0x100267b0 +MxResult LegoPlantManager::Load(LegoStorage* p_storage) +{ + return SUCCESS; +} + // FUNCTION: LEGO1 0x10026be0 void LegoPlantManager::SetCustomizeAnimFile(const char* p_value) { diff --git a/LEGO1/lego/legoomni/src/common/legounksavedatawriter.cpp b/LEGO1/lego/legoomni/src/common/legounksavedatawriter.cpp index 52c57f71..3210fe7b 100644 --- a/LEGO1/lego/legoomni/src/common/legounksavedatawriter.cpp +++ b/LEGO1/lego/legoomni/src/common/legounksavedatawriter.cpp @@ -90,6 +90,12 @@ MxResult LegoUnkSaveDataWriter::WriteSaveData3(LegoStorage* p_storage) return result; } +// STUB: LEGO1 0x100833f0 +MxResult LegoUnkSaveDataWriter::ReadSaveData3(LegoStorage* p_storage) +{ + return SUCCESS; +} + // STUB: LEGO1 0x10083500 LegoROI* LegoUnkSaveDataWriter::FUN_10083500(const char* p_key, MxBool p_option) { diff --git a/LEGO1/lego/legoomni/src/common/legoutil.cpp b/LEGO1/lego/legoomni/src/common/legoutil.cpp index fabe18d6..970ba3df 100644 --- a/LEGO1/lego/legoomni/src/common/legoutil.cpp +++ b/LEGO1/lego/legoomni/src/common/legoutil.cpp @@ -291,6 +291,11 @@ MxBool FUN_1003ef60() return TRUE; } +// STUB: LEGO1 0x1003f0d0 +void SetLightPosition(MxU32) +{ +} + // STUB: LEGO1 0x1003f3b0 NamedTexture* ReadNamedTexture(LegoFile* p_file) { diff --git a/LEGO1/lego/legoomni/src/entity/legoworld.cpp b/LEGO1/lego/legoomni/src/entity/legoworld.cpp index ad66e1cf..2f24feb9 100644 --- a/LEGO1/lego/legoomni/src/entity/legoworld.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoworld.cpp @@ -581,7 +581,7 @@ void LegoWorld::Enable(MxBool p_enable) AnimationManager()->FUN_1005f0b0(); } - GameState()->FUN_10039940(); + GameState()->ResetROI(); SetIsWorldActive(TRUE); } } diff --git a/LEGO1/lego/sources/misc/legostorage.h b/LEGO1/lego/sources/misc/legostorage.h index 08e295f4..df8dd072 100644 --- a/LEGO1/lego/sources/misc/legostorage.h +++ b/LEGO1/lego/sources/misc/legostorage.h @@ -20,18 +20,18 @@ class LegoStorage { LegoStorage() : m_mode(0) {} // FUNCTION: LEGO1 0x10045ad0 - virtual ~LegoStorage() {} + virtual ~LegoStorage() {} // 0x00 - virtual LegoResult Read(void* p_buffer, LegoU32 p_size) = 0; - virtual LegoResult Write(const void* p_buffer, LegoU32 p_size) = 0; - virtual LegoResult GetPosition(LegoU32& p_position) = 0; - virtual LegoResult SetPosition(LegoU32 p_position) = 0; + virtual LegoResult Read(void* p_buffer, LegoU32 p_size) = 0; // 0x04 + virtual LegoResult Write(const void* p_buffer, LegoU32 p_size) = 0; // 0x08 + virtual LegoResult GetPosition(LegoU32& p_position) = 0; // 0x0c + virtual LegoResult SetPosition(LegoU32 p_position) = 0; // 0x10 // FUNCTION: LEGO1 0x10045ae0 - virtual LegoBool IsWriteMode() { return m_mode == c_write; } + virtual LegoBool IsWriteMode() { return m_mode == c_write; } // 0x14 // FUNCTION: LEGO1 0x10045af0 - virtual LegoBool IsReadMode() { return m_mode == c_read; } + virtual LegoBool IsReadMode() { return m_mode == c_read; } // 0x14 // SYNTHETIC: LEGO1 0x10045b00 // LegoStorage::`scalar deleting destructor' @@ -40,23 +40,36 @@ class LegoStorage { LegoU8 m_mode; // 0x04 }; +template +inline void Read(LegoStorage* p_storage, T* p_variable, const MxS32 p_size) +{ + p_storage->Read(p_variable, p_size); +} + +template +inline void Write(LegoStorage* p_storage, T* p_variable) +{ + T variable = *p_variable; + p_storage->Write(&variable, sizeof(variable)); +} + // VTABLE: LEGO1 0x100db710 // SIZE 0x10 class LegoMemory : public LegoStorage { public: LegoMemory(void* p_buffer); - LegoResult Read(void* p_buffer, LegoU32 p_size) override; - LegoResult Write(const void* p_buffer, LegoU32 p_size) override; + LegoResult Read(void* p_buffer, LegoU32 p_size) override; // 0x04 + LegoResult Write(const void* p_buffer, LegoU32 p_size) override; // 0x08 // FUNCTION: LEGO1 0x100994a0 - LegoResult GetPosition(LegoU32& p_position) override + LegoResult GetPosition(LegoU32& p_position) override // 0x0c { p_position = m_position; return SUCCESS; } // FUNCTION: LEGO1 0x100994b0 - LegoResult SetPosition(LegoU32 p_position) override + LegoResult SetPosition(LegoU32 p_position) override // 0x10 { m_position = p_position; return SUCCESS; @@ -78,11 +91,11 @@ class LegoMemory : public LegoStorage { class LegoFile : public LegoStorage { public: LegoFile(); - ~LegoFile() override; - LegoResult Read(void* p_buffer, LegoU32 p_size) override; - LegoResult Write(const void* p_buffer, LegoU32 p_size) override; - LegoResult GetPosition(LegoU32& p_position) override; - LegoResult SetPosition(LegoU32 p_position) override; + ~LegoFile() override; // 0x00 + LegoResult Read(void* p_buffer, LegoU32 p_size) override; // 0x04 + LegoResult Write(const void* p_buffer, LegoU32 p_size) override; // 0x08 + LegoResult GetPosition(LegoU32& p_position) override; // 0x0c + LegoResult SetPosition(LegoU32 p_position) override; // 0x10 LegoResult Open(const char* p_name, LegoU32 p_mode); // FUNCTION: LEGO1 0x100343d0 diff --git a/LEGO1/omni/include/mxutil.h b/LEGO1/omni/include/mxutil.h index c85259bb..36cba66d 100644 --- a/LEGO1/omni/include/mxutil.h +++ b/LEGO1/omni/include/mxutil.h @@ -72,6 +72,7 @@ MxBool GetRectIntersection( ); void MakeSourceName(char*, const char*); +void OmniError(char* p_message, int p_status); void SetOmniUserMessage(void (*)(const char*, int)); MxBool ContainsPresenter(MxCompositePresenterList& p_presenterList, MxPresenter* p_presenter); void FUN_100b7220(MxDSAction* p_action, MxU32 p_newFlags, MxBool p_setFlags); diff --git a/LEGO1/omni/src/common/mxutil.cpp b/LEGO1/omni/src/common/mxutil.cpp index 5ffab77c..25b63dbe 100644 --- a/LEGO1/omni/src/common/mxutil.cpp +++ b/LEGO1/omni/src/common/mxutil.cpp @@ -127,6 +127,17 @@ MxBool ContainsPresenter(MxCompositePresenterList& p_presenterList, MxPresenter* return FALSE; } +// FUNCTION: LEGO1 0x100b71e0 +void OmniError(char* p_message, int p_status) +{ + if (g_omniUserMessage) { + g_omniUserMessage(p_message, p_status); + } + else if (p_status) { + abort(); + } +} + // FUNCTION: LEGO1 0x100b7210 void SetOmniUserMessage(void (*p_userMsg)(const char*, int)) {