From 7cd19ed475813d39943ae1bf88a12a54089547cd Mon Sep 17 00:00:00 2001 From: Mark Langen Date: Sun, 5 May 2024 03:49:46 -0700 Subject: [PATCH] Start work on building save data * Add LegoBuildingData struct to LegoBuildingManager, naming mirrors LegoCharacterData in LegoCharacterManager. * 100% match of many methods in LegoBuildingManager using the struct. --- .../legoomni/include/legobuildingmanager.h | 26 +- .../src/build/legobuildingmanager.cpp | 294 +++++++++++++++++- LEGO1/lego/legoomni/src/entity/legoentity.cpp | 2 +- LEGO1/mxgeometry/mxmatrix.h | 4 + 4 files changed, 306 insertions(+), 20 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legobuildingmanager.h b/LEGO1/lego/legoomni/include/legobuildingmanager.h index b82b7b06..a00c3a6b 100644 --- a/LEGO1/lego/legoomni/include/legobuildingmanager.h +++ b/LEGO1/lego/legoomni/include/legobuildingmanager.h @@ -7,6 +7,8 @@ class LegoEntity; class LegoROI; +class LegoWorld; +struct LegoBuildingData; // VTABLE: LEGO1 0x100d6f50 // SIZE 0x30 @@ -29,13 +31,21 @@ class LegoBuildingManager : public MxCore { void Init(); void FUN_1002fa00(); + void UpdatePosition(int p_index, LegoWorld* p_world); void FUN_1002fb30(); MxResult Write(LegoStorage* p_storage); MxResult Read(LegoStorage* p_storage); - MxBool FUN_1002fdb0(LegoEntity* p_entity); + LegoBuildingData* GetData(LegoEntity* p_entity); + MxBool IncrementVariant(LegoEntity* p_entity); + MxBool FUN_1002fe40(LegoEntity* p_entity); + MxBool FUN_1002fe80(LegoEntity* p_entity); + MxBool FUN_1002fed0(LegoEntity* p_entity); MxU32 FUN_1002ff40(LegoEntity*, MxBool); - void FUN_10030000(LegoEntity* p_entity); + MxBool FUN_10030000(LegoEntity* p_entity); + MxBool FUN_10030030(int p_index); + MxBool FUN_10030110(LegoBuildingData* p_data); void FUN_10030590(); + void AdjustHeight(int p_index); // SYNTHETIC: LEGO1 0x1002f940 // LegoBuildingManager::`scalar deleting destructor' @@ -43,7 +53,17 @@ class LegoBuildingManager : public MxCore { private: static char* g_customizeAnimFile; - undefined m_unk0x08[0x28]; // 0x08 + MxU8 m_nextVariant; // 0x08 + MxU8 m_unk1; + void* m_pSomething; + undefined4 m_unk2; // 0x10 + undefined4 m_unk3; + undefined4 m_unk4; + undefined4 m_unk5; + MxU8 m_unk6; // 0x20 + undefined4 m_unk7; // 0x24 + MxU8 m_unk8; + undefined4 m_unk9; // 0x2c }; #endif // LEGOBUILDINGMANAGER_H diff --git a/LEGO1/lego/legoomni/src/build/legobuildingmanager.cpp b/LEGO1/lego/legoomni/src/build/legobuildingmanager.cpp index 1b7c4273..26d911e8 100644 --- a/LEGO1/lego/legoomni/src/build/legobuildingmanager.cpp +++ b/LEGO1/lego/legoomni/src/build/legobuildingmanager.cpp @@ -1,13 +1,71 @@ #include "legobuildingmanager.h" +#include "legoentity.h" + +#include "legoworld.h" +#include "misc.h" + DECOMP_SIZE_ASSERT(LegoBuildingManager, 0x30) +struct LegoBuildingData { + LegoEntity* m_pEntity; + const char* m_hausName; + MxU32 m_int1; + MxU32 m_int2; + MxU8 m_byte1; + MxS8 m_byte2; + MxS8 m_initialByte2; + MxU8 m_flags; + float m_float; + char m_unk[16]; + undefined4 m_something; +}; + +DECOMP_SIZE_ASSERT(LegoBuildingData, 0x2c); + +// GLOBAL: LEGO1 0x100f3410 +const char* g_buildingDataHausName[5] = { + "haus1", + "haus4", + "haus5", + "haus6", + "haus7", +}; + +// GLOBAL: LEGO1 0x100f3428 +float g_buildingDataDownshiftScale[16] = { + 0.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, +}; + +// GLOBAL: LEGO1 0x100f3468 +MxU8 g_buildingDataDownshift[16] = { + 5, 5, 5, 5, + 3, 5, 5, 5, + 3, 5, 5, 5, + 5, 5, 5, 5, +}; + +// GLOBAL: LEGO1 0x100f3478 +LegoBuildingData g_buildingDataTemplate[16]; + +// GLOBAL: LEGO1 0x100f3738 +MxU32 g_buildingCycle1Length = 6; + // GLOBAL: LEGO1 0x100f37c8 char* LegoBuildingManager::g_customizeAnimFile = NULL; // GLOBAL: LEGO1 0x100f37cc int g_buildingManagerConfig = 1; +// GLOBAL: LEGO1 0x10104c30 +LegoBuildingData g_buildingData[16]; + +// Unclear what the offset of this global is. +int g_buildingCycle2Length[16]; + // FUNCTION: LEGO1 0x1002f8b0 void LegoBuildingManager::configureLegoBuildingManager(MxS32 p_buildingManagerConfig) { @@ -20,22 +78,66 @@ LegoBuildingManager::LegoBuildingManager() Init(); } -// STUB: LEGO1 0x1002f960 +// FUNCTION: LEGO1 0x1002f960 LegoBuildingManager::~LegoBuildingManager() { - // TODO + delete g_customizeAnimFile; } -// STUB: LEGO1 0x1002f9d0 +// FUNCTION: LEGO1 0x1002f9d0 void LegoBuildingManager::Init() { - // TODO + for (MxS32 i = 0; i < _countof(g_buildingData); i++) { + g_buildingData[i] = g_buildingDataTemplate[i]; + } + + m_nextVariant = 0; + m_unk1 = 0; + m_unk6 = 0; + m_unk7 = 0; + m_unk8 = 0; } -// STUB: LEGO1 0x1002fa00 +// FUNCTION: LEGO1 0x1002fa00 void LegoBuildingManager::FUN_1002fa00() { - // TODO + MxS32 i = 0; + LegoWorld* world = CurrentWorld(); + for (; i < _countof(g_buildingData); i++) { + UpdatePosition(i, world); + } + if (g_buildingManagerConfig <= 1) { + LegoEntity* entity = (LegoEntity*)world->Find("MxEntity", g_buildingDataHausName[0]); + if (entity) { + entity->GetROI()->SetVisibility(TRUE); + m_unk1 = 0; + return; + } + } else { + for (i = 0; i < _countof(g_buildingDataHausName); i++) { + LegoEntity* entity = (LegoEntity*)world->Find("MxEntity", g_buildingDataHausName[i]); + if (entity) + entity->GetROI()->SetVisibility(m_nextVariant == i); + } + } + m_unk1 = 0; +} + +// FUNCTION: LEGO1 0x1002fa90 +void LegoBuildingManager::UpdatePosition(int p_index, LegoWorld* p_world) +{ + LegoEntity* entity = (LegoEntity*)p_world->Find( + "MxEntity", g_buildingData[p_index].m_hausName); + if (entity) { + entity->SetType(3); + g_buildingData[p_index].m_pEntity = entity; + LegoROI* roi = entity->GetROI(); + AdjustHeight(p_index); + MxMatrix mat = roi->GetLocal2World(); + mat.SetY(g_buildingData[p_index].m_float); + roi->FUN_100a46b0(mat); + VideoManager()->Get3DManager()->GetLego3DView()->Moved(*roi); + } } // STUB: LEGO1 0x1002fb30 @@ -44,25 +146,164 @@ void LegoBuildingManager::FUN_1002fb30() // TODO } -// STUB: LEGO1 0x1002fb80 +// FUNCTION: LEGO1 0x1002fb80 MxResult LegoBuildingManager::Write(LegoStorage* p_storage) { - return SUCCESS; + MxResult result = FAILURE; + for (MxS32 i = 0; i < _countof(g_buildingData); i++) { + LegoBuildingData* data = &g_buildingData[i]; + if (p_storage->Write(&data->m_int1, 4) != SUCCESS) + goto done; + if (p_storage->Write(&data->m_int2, 4) != SUCCESS) + goto done; + if (p_storage->Write(&data->m_byte1, 1) != SUCCESS) + goto done; + if (p_storage->Write(&data->m_initialByte2, 1) != SUCCESS) + goto done; + } + if (p_storage->Write(&m_nextVariant, 1) != SUCCESS) + goto done; + + result = SUCCESS; +done: + return result; } -// STUB: LEGO1 0x1002fc10 +// FUNCTION: LEGO1 0x1002fc10 MxResult LegoBuildingManager::Read(LegoStorage* p_storage) { - return SUCCESS; + MxResult result = FAILURE; + for (MxS32 i = 0; i < _countof(g_buildingData); i++) { + LegoBuildingData* data = &g_buildingData[i]; + + if (p_storage->Read(&data->m_int1, 4) != SUCCESS) + goto done; + if (p_storage->Read(&data->m_int2, 4) != SUCCESS) + goto done; + if (p_storage->Read(&data->m_byte1, 1) != SUCCESS) + goto done; + if (p_storage->Read(&data->m_byte2, 1) != SUCCESS) + goto done; + data->m_initialByte2 = data->m_byte2; + AdjustHeight(i); + } + + if (p_storage->Read(&m_nextVariant, 1) != SUCCESS) + goto done; + + if (g_buildingManagerConfig <= 1) + m_nextVariant = 0; + + result = SUCCESS; +done: + return result; } -// STUB: LEGO1 0x1002fdb0 -MxBool LegoBuildingManager::FUN_1002fdb0(LegoEntity* p_entity) +// FUNCTION: LEGO1 0x1002fcc0 +void LegoBuildingManager::AdjustHeight(int p_i) { - // TODO + // Not close assembly yet. + // Does not use any member variables but we can be sure that + // this is a THISCALL method because LegoBuildingManager::Read + // goes to the trouble of restoring ECX before calling it. + MxS8 value = g_buildingData[p_i].m_byte2; + if (value > 0) { + g_buildingData[p_i].m_float = g_buildingDataTemplate[p_i].m_float - + (g_buildingDataDownshift[p_i] - value) * g_buildingDataDownshiftScale[p_i]; + } else if (value == 0) { + g_buildingData[p_i].m_float = g_buildingDataTemplate[p_i].m_float - + g_buildingDataDownshift[p_i] * g_buildingDataDownshiftScale[p_i]; + if (g_buildingData[p_i].m_pEntity != NULL) + { + LegoROI* roi = g_buildingData[p_i].m_pEntity->GetROI(); + if (roi != NULL) + roi->SetVisibility(FALSE); + } + } else { + g_buildingData[p_i].m_float = g_buildingDataTemplate[p_i].m_float; + } +} + +// FUNCTION: LEGO1 0x1002fd70 +LegoBuildingData* LegoBuildingManager::GetData(LegoEntity* p_entity) +{ + MxS32 i; + for (i = 0; i < _countof(g_buildingData); i++) { + if (g_buildingData[i].m_pEntity == p_entity) + break; + } + if (i < _countof(g_buildingData)) + return &g_buildingData[i]; + return NULL; +} + +// FUNCTION: LEGO1 0x1002fdb0 +MxBool LegoBuildingManager::IncrementVariant(LegoEntity* p_entity) +{ + if (g_buildingManagerConfig <= 1) + return TRUE; + + LegoBuildingData* data = GetData(p_entity); + if (data != NULL && (data->m_flags & 1) && data->m_byte2 == -1) { + LegoROI* roi = p_entity->GetROI(); + if (++m_nextVariant >= _countof(g_buildingDataHausName)) + m_nextVariant = 0; + + roi->SetVisibility(FALSE); + data->m_hausName = g_buildingDataHausName[m_nextVariant]; + UpdatePosition(12, CurrentWorld()); + if (data->m_pEntity != NULL) + data->m_pEntity->GetROI()->SetVisibility(TRUE); + return TRUE; + } return FALSE; } +// FUNCTION: LEGO1 0x1002fe40 +MxBool LegoBuildingManager::FUN_1002fe40(LegoEntity* p_entity) +{ + MxBool result = FALSE; + LegoBuildingData* data = GetData(p_entity); + if (data != NULL && (data->m_flags & 2)) { + data->m_int1++; + if (data->m_int1 >= g_buildingCycle1Length) { + data->m_int1 = 0; + } + result = TRUE; + } + return result; +} + +// FUNCTION: LEGO1 0x1002fe80 +MxBool LegoBuildingManager::FUN_1002fe80(LegoEntity* p_entity) +{ + MxBool result = FALSE; + LegoBuildingData* data = GetData(p_entity); + if (data != NULL && (data->m_flags & 4)) { + data->m_int2++; + if (data->m_int2 >= g_buildingCycle2Length[data - g_buildingData]) { + data->m_int2 = 0; + } + result = TRUE; + } + return result; +} + +// FUNCTION: LEGO1 0x1002fed0 +MxBool LegoBuildingManager::FUN_1002fed0(LegoEntity* p_entity) +{ + MxBool result = FALSE; + LegoBuildingData* data = GetData(p_entity); + if (data != NULL && (data->m_flags & 8)) { + data->m_byte1++; + if (data->m_byte1 > 3) { + data->m_byte1 = 0; + } + result = TRUE; + } + return result; +} + // STUB: LEGO1 0x1002ff40 MxU32 LegoBuildingManager::FUN_1002ff40(LegoEntity*, MxBool) { @@ -89,10 +330,31 @@ void LegoBuildingManager::SetCustomizeAnimFile(const char* p_value) } } -// STUB: LEGO1 0x10030000 -void LegoBuildingManager::FUN_10030000(LegoEntity* p_entity) +// FUNCTION: LEGO1 0x10030000 +MxBool LegoBuildingManager::FUN_10030000(LegoEntity* p_entity) { - // TODO + LegoBuildingData* data = GetData(p_entity); + if (data == NULL) + return FALSE; + + return FUN_10030030(data - g_buildingData); +} + +// STUB: LEGO1 0x10030030 +MxBool LegoBuildingManager::FUN_10030030(int p_index) +{ + return TRUE; +} + +// FUNCTION: LEGO1 0x10030110 +MxBool LegoBuildingManager::FUN_10030110(LegoBuildingData* p_data) +{ + for (MxS32 i = 0; i < _countof(g_buildingData); i++) { + if (&g_buildingData[i] == p_data) { + return FUN_10030030(i); + } + } + return FALSE; } // STUB: LEGO1 0x10030220 diff --git a/LEGO1/lego/legoomni/src/entity/legoentity.cpp b/LEGO1/lego/legoomni/src/entity/legoentity.cpp index a55693f9..20cc85df 100644 --- a/LEGO1/lego/legoomni/src/entity/legoentity.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoentity.cpp @@ -290,7 +290,7 @@ void LegoEntity::VTable0x3c() PlantManager()->FUN_100269e0(this); break; case e_building: - BuildingManager()->FUN_1002fdb0(this); + BuildingManager()->IncrementVariant(this); break; } diff --git a/LEGO1/mxgeometry/mxmatrix.h b/LEGO1/mxgeometry/mxmatrix.h index f6d0cece..17f5c05e 100644 --- a/LEGO1/mxgeometry/mxmatrix.h +++ b/LEGO1/mxgeometry/mxmatrix.h @@ -18,6 +18,10 @@ class MxMatrix : public Matrix4 { float* operator[](int idx) { return m_data[idx]; } const float* operator[](int idx) const { return m_data[idx]; } + inline void SetX(float p_x) { m_data[3][0] = p_x; } + inline void SetY(float p_y) { m_data[3][1] = p_y; } + inline void SetZ(float p_z) { m_data[3][2] = p_z; } + // FUNCTION: LEGO1 0x10002850 void operator=(const Matrix4& p_matrix) override { Equals(p_matrix); } // vtable+0x28