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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 8013699c..482ecd9e 100644 --- a/LEGO1/lego/legoomni/include/legounksavedatawriter.h +++ b/LEGO1/lego/legoomni/include/legounksavedatawriter.h @@ -56,6 +56,7 @@ public: 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..9c794f97 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,58 +158,219 @@ 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 MxResult LegoGameState::Save(MxULong p_slot) { - MxResult result; InfocenterState* infocenterState = (InfocenterState*) GameState()->GetState("InfocenterState"); if (!infocenterState || !infocenterState->HasRegistered()) { - result = SUCCESS; + return SUCCESS; } - else { - result = FAILURE; - MxVariableTable* variableTable = VariableTable(); - 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); - for (MxS32 i = 0; i < sizeof(g_colorSaveData) / sizeof(g_colorSaveData[0]); ++i) { - if (WriteVariable(&fileStream, variableTable, g_colorSaveData[i].m_targetName) == FAILURE) { - return result; - } - } + MxResult result = FAILURE; + LegoFile fileStream; + MxVariableTable* variableTable = VariableTable(); + MxS16 count = 0; + MxU32 i; + MxS32 j; + MxU16 area; - if (WriteVariable(&fileStream, variableTable, "backgroundcolor") != FAILURE) { - if (WriteVariable(&fileStream, variableTable, "lightposition") != FAILURE) { - WriteEndOfVariables(&fileStream); + MxString savePath; + GetFileSavePath(&savePath, p_slot); - // TODO: Calls down to more aggregate writing functions - return SUCCESS; - } - } + if (fileStream.Open(savePath.GetData(), LegoFile::c_write) == FAILURE) { + goto done; + } + + Write(&fileStream, 0x1000c); + Write(&fileStream, m_unk0x24); + Write(&fileStream, (MxU16) m_currentAct); + Write(&fileStream, m_actorId); + + for (i = 0; i < _countof(g_colorSaveData); i++) { + if (WriteVariable(&fileStream, variableTable, g_colorSaveData[i].m_targetName) == FAILURE) { + goto done; } } + + if (WriteVariable(&fileStream, variableTable, "backgroundcolor") == FAILURE) { + goto done; + } + if (WriteVariable(&fileStream, variableTable, "lightposition") == FAILURE) { + goto done; + } + + WriteEndOfVariables(&fileStream); + UnkSaveDataWriter()->WriteSaveData3(&fileStream); + PlantManager()->Save(&fileStream); + result = BuildingManager()->Save(&fileStream); + + for (j = 0; j < m_stateCount; j++) { + if (m_stateArray[j]->VTable0x14()) { + count++; + } + } + + Write(&fileStream, count); + + for (j = 0; j < m_stateCount; j++) { + if (m_stateArray[j]->VTable0x14()) { + m_stateArray[j]->VTable0x1c(&fileStream); + } + } + + area = m_unk0x42c; + Write(&fileStream, (MxU16) area); + SerializeScoreHistory(2); + m_isDirty = FALSE; + +done: 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; + + for (MxS32 count = 0; count < stateCount; count++) { + if (!stateArray[count]->SetFlag() && stateArray[count]->VTable0x14()) { + delete stateArray[count]; + } + else { + RegisterState(stateArray[count]); + stateArray[count] = NULL; + } + } + + 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) { + goto done; + } + + MxU32 version, status; + MxS16 count, area, act; + const char* lightPosition; + + Read(&fileStream, &version); + + if (version != 0x1000c) { + OmniError("Saved game version mismatch", 0); + goto done; + } + + Read(&fileStream, &m_unk0x24); + + Read(&fileStream, &act); + SetCurrentAct((Act) act); + + Read(&fileStream, &m_actorId); + if (m_actorId) { + SetActor(m_actorId); + } + + do { + status = ReadVariable(&fileStream, variableTable); + if (status == 1) { + goto done; + } + } while (status != 2); + + m_backgroundColor->SetLights(); + lightPosition = VariableTable()->GetVariable("lightposition"); + + if (lightPosition) { + SetLightPosition(atoi(lightPosition)); + } + + if (UnkSaveDataWriter()->ReadSaveData3(&fileStream) == FAILURE) { + goto done; + } + if (PlantManager()->Load(&fileStream) == FAILURE) { + goto done; + } + if (BuildingManager()->Load(&fileStream) == FAILURE) { + goto done; + } + if (DeleteState() != SUCCESS) { + goto done; + } + + char stateName[80]; + Read(&fileStream, &count); + + if (count) { + for (MxS16 i = 0; i < count; i++) { + MxS16 stateNameLength; + Read(&fileStream, &stateNameLength); + Read(&fileStream, stateName, (MxULong) stateNameLength); + stateName[stateNameLength] = 0; + + LegoState* state = GetState(stateName); + if (!state) { + state = CreateState(stateName); + + if (!state) { + goto done; + } + } + + state->VTable0x1c(&fileStream); + } + } + + Read(&fileStream, &area); + + if (m_currentAct == 0) { + m_unk0x42c = e_noArea; + } + else { + m_unk0x42c = (Area) area; + } + + result = SUCCESS; + m_isDirty = FALSE; + +done: + 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 ad3f91c6..74d1ff22 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..daa3153d 100644 --- a/LEGO1/lego/sources/misc/legostorage.h +++ b/LEGO1/lego/sources/misc/legostorage.h @@ -22,16 +22,16 @@ public: // FUNCTION: LEGO1 0x10045ad0 virtual ~LegoStorage() {} - 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; // vtable+0x04 + virtual LegoResult Write(const void* p_buffer, LegoU32 p_size) = 0; // vtable+0x08 + virtual LegoResult GetPosition(LegoU32& p_position) = 0; // vtable+0x0c + virtual LegoResult SetPosition(LegoU32 p_position) = 0; // vtable+0x10 // FUNCTION: LEGO1 0x10045ae0 - virtual LegoBool IsWriteMode() { return m_mode == c_write; } + virtual LegoBool IsWriteMode() { return m_mode == c_write; } // vtable+0x14 // FUNCTION: LEGO1 0x10045af0 - virtual LegoBool IsReadMode() { return m_mode == c_read; } + virtual LegoBool IsReadMode() { return m_mode == c_read; } // vtable+0x18 // SYNTHETIC: LEGO1 0x10045b00 // LegoStorage::`scalar deleting destructor' @@ -40,23 +40,35 @@ protected: LegoU8 m_mode; // 0x04 }; +template +inline void Read(LegoStorage* p_storage, T* p_variable, LegoU32 p_size = sizeof(T)) +{ + p_storage->Read(p_variable, p_size); +} + +template +inline void Write(LegoStorage* p_storage, T p_variable) +{ + p_storage->Write(&p_variable, sizeof(p_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; // vtable+0x04 + LegoResult Write(const void* p_buffer, LegoU32 p_size) override; // vtable+0x08 // FUNCTION: LEGO1 0x100994a0 - LegoResult GetPosition(LegoU32& p_position) override + LegoResult GetPosition(LegoU32& p_position) override // vtable+0x0c { p_position = m_position; return SUCCESS; } // FUNCTION: LEGO1 0x100994b0 - LegoResult SetPosition(LegoU32 p_position) override + LegoResult SetPosition(LegoU32 p_position) override // vtable+0x10 { m_position = p_position; return SUCCESS; @@ -79,10 +91,10 @@ 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; + LegoResult Read(void* p_buffer, LegoU32 p_size) override; // vtable+0x04 + LegoResult Write(const void* p_buffer, LegoU32 p_size) override; // vtable+0x08 + LegoResult GetPosition(LegoU32& p_position) override; // vtable+0x0c + LegoResult SetPosition(LegoU32 p_position) override; // vtable+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..801ca3c1 100644 --- a/LEGO1/omni/include/mxutil.h +++ b/LEGO1/omni/include/mxutil.h @@ -72,7 +72,8 @@ MxBool GetRectIntersection( ); void MakeSourceName(char*, const char*); -void SetOmniUserMessage(void (*)(const char*, int)); +void OmniError(const char* p_message, MxS32 p_status); +void SetOmniUserMessage(void (*p_omniUserMessage)(const char*, MxS32)); MxBool ContainsPresenter(MxCompositePresenterList& p_presenterList, MxPresenter* p_presenter); void FUN_100b7220(MxDSAction* p_action, MxU32 p_newFlags, MxBool p_setFlags); MxDSObject* CreateStreamObject(MxDSFile*, MxS16); diff --git a/LEGO1/omni/src/common/mxutil.cpp b/LEGO1/omni/src/common/mxutil.cpp index 5ffab77c..61af4f6e 100644 --- a/LEGO1/omni/src/common/mxutil.cpp +++ b/LEGO1/omni/src/common/mxutil.cpp @@ -127,10 +127,21 @@ MxBool ContainsPresenter(MxCompositePresenterList& p_presenterList, MxPresenter* return FALSE; } -// FUNCTION: LEGO1 0x100b7210 -void SetOmniUserMessage(void (*p_userMsg)(const char*, int)) +// FUNCTION: LEGO1 0x100b71e0 +void OmniError(const char* p_message, MxS32 p_status) { - g_omniUserMessage = p_userMsg; + if (g_omniUserMessage) { + g_omniUserMessage(p_message, p_status); + } + else if (p_status) { + abort(); + } +} + +// FUNCTION: LEGO1 0x100b7210 +void SetOmniUserMessage(void (*p_omniUserMessage)(const char*, MxS32)) +{ + g_omniUserMessage = p_omniUserMessage; } // FUNCTION: LEGO1 0x100b7220