Start work on building save data (#885)

* 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.

* Formatting

* Add required includes post merge

* Format again

* Better follow naming conventions

* Format again again

* Also fill in template data

* Fix data

* Change braces

* Match functions, consistent style, add missing annotations, some BETA annotations

---------

Co-authored-by: Christian Semmler <mail@csemmler.com>
This commit is contained in:
Mark Langen 2024-05-06 04:15:19 -07:00 committed by GitHub
parent 45f9f54f21
commit 253882bdcb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 540 additions and 41 deletions

View file

@ -7,6 +7,32 @@
class LegoEntity;
class LegoROI;
class LegoStorage;
class LegoWorld;
// SIZE 0x2c
struct LegoBuildingInfo {
enum {
c_bit1 = 0x01,
c_bit2 = 0x02,
c_bit3 = 0x04,
c_bit4 = 0x08
};
LegoEntity* m_entity; // 0x00
const char* m_hausName; // 0x04
MxU32 m_cycle1; // 0x08
MxU32 m_cycle2; // 0x0c
MxU8 m_cycle3; // 0x10
MxS8 m_unk0x11; // 0x11
MxS8 m_initialUnk0x11; // 0x12 = initial value loaded to m_unk0x11
MxU8 m_flags; // 0x13
float m_unk0x014; // 0x14
const char* m_unk0x18; // 0x18
float m_x; // 0x1c
float m_y; // 0x20
float m_z; // 0x24
undefined* m_unk0x28; // 0x28
};
// VTABLE: LEGO1 0x100d6f50
// SIZE 0x30
@ -29,13 +55,21 @@ class LegoBuildingManager : public MxCore {
void Init();
void FUN_1002fa00();
void UpdatePosition(MxS32 p_index, LegoWorld* p_world);
void FUN_1002fb30();
MxResult Write(LegoStorage* p_storage);
MxResult Read(LegoStorage* p_storage);
MxBool FUN_1002fdb0(LegoEntity* p_entity);
LegoBuildingInfo* GetInfo(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(MxS32 p_index);
MxBool FUN_10030110(LegoBuildingInfo* p_data);
void FUN_10030590();
void AdjustHeight(MxS32 p_index);
// SYNTHETIC: LEGO1 0x1002f940
// LegoBuildingManager::`scalar deleting destructor'
@ -43,7 +77,17 @@ class LegoBuildingManager : public MxCore {
private:
static char* g_customizeAnimFile;
undefined m_unk0x08[0x28]; // 0x08
MxU8 m_nextVariant; // 0x08
MxU8 m_unk0x09; // 0x09
undefined4 m_unk0x0c; // 0x0c
undefined4 m_unk0x10; // 0x10
undefined4 m_unk0x14; // 0x14
undefined4 m_unk0x18; // 0x18
undefined4 m_unk0x1c; // 0x1c
MxU8 m_unk0x20; // 0x20
undefined4 m_unk0x24; // 0x24
MxU8 m_unk0x28; // 0x28
undefined4 m_unk0x2c; // 0x2c
};
#endif // LEGOBUILDINGMANAGER_H

View file

@ -1,12 +1,204 @@
#include "legobuildingmanager.h"
#include "3dmanager/lego3dmanager.h"
#include "legoentity.h"
#include "legovideomanager.h"
#include "legoworld.h"
#include "misc.h"
#include "misc/legostorage.h"
DECOMP_SIZE_ASSERT(LegoBuildingManager, 0x30)
DECOMP_SIZE_ASSERT(LegoBuildingInfo, 0x2c)
// GLOBAL: LEGO1 0x100f3410
const char* g_buildingDataHausName[5] = {
"haus1",
"haus4",
"haus5",
"haus6",
"haus7",
};
// clang-format off
// 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
LegoBuildingInfo g_buildingInfoInit[16] = {
{
NULL, "infocen",
4, 0, 1,
-1, -1, 0x00,
8.99999f,
"edg02_74",
84.79617f, 9.0f, -10.2189f,
NULL,
},
{
NULL, "policsta",
4, 0, 1,
-1, -1, 0x10,
0.999992f,
"int33",
67.28488, 1.0f, -85.3917,
NULL,
},
{
NULL, "Jail",
4, 0, 1,
-1, -1, 0x10,
0.0f,
"edg02_50",
93.245659f, 0.0f, -48.7773f,
NULL,
},
{
NULL, "races",
4, 0, 1,
-1, -1, 0x10,
0.0f,
"int14",
-21.7321f, 0.0f, 11.23354f,
NULL,
},
{
NULL, "medcntr",
4, 0, 1,
-1, -1, 0x10,
3.99071f,
"edg02_27",
86.020737f, 4.0f, 31.35498f,
NULL,
},
{
NULL, "gas",
4, 0, 1,
-1, -1, 0x10,
0.0f,
"int24",
26.32025f, 0.0f, -2.28938f,
NULL,
},
{
NULL, "beach",
4, 0, 1,
-1, -1, 0x10,
-1.8125f,
"edg00_46",
14.375f, -1.3125f, -56.75f,
NULL,
},
{
NULL, "racef",
4, 0, 1,
-1, -1, 0x10,
0.0f,
"edg03_03",
-4.15951f, 0.0f, 5.2003198f,
NULL,
},
{
NULL, "racej",
4, 0, 1,
-1, -1, 0x10,
0.0f,
"edg03_03",
-4.15951f, 0.0f, 5.2003198f,
NULL,
},
{
NULL, "Store",
4, 0, 1,
-1, -1, 0x3e,
2.0f,
"edg02_60",
-49.4744f, 2.0f, -56.6276f,
NULL,
},
{
NULL, "Bank",
4, 0, 1,
-1, -1, 0x3e,
0.0f,
"edg02_36",
18.53531f, 0.0f, -16.6053f,
NULL,
},
{
NULL, "Post",
4, 0, 1,
-1, -1, 0x3e,
0.0f,
"edg02_58",
-33.5413f, 0.0f, -55.1791f,
NULL,
},
{
NULL, "haus1",
4, 0, 1,
-1, -1, 0x3f,
7.0625f,
"int11",
-62.7827f, 7.0f, -45.2215f,
NULL,
},
{
NULL, "haus2",
4, 0, 1,
-1, -1, 0x3e,
8.0f,
"int07",
-69.2376f, 8.0f, -6.8008099f,
NULL,
},
{
NULL, "haus3",
4, 0, 1,
-1, -1, 0x3e,
7.0f,
"edg01_24",
-69.0596f, 7.0f, -24.4928f,
NULL,
},
{
NULL, "Pizza",
4, 0, 1,
-1, -1, 0x10,
0.0f,
"int37",
-17.9438f, 0.0f, -46.827999f,
NULL,
},
};
// clang-format on
// GLOBAL: LEGO1 0x100f3738
MxU32 g_buildingCycle1Length = 6;
// GLOBAL: LEGO1 0x100f37c8
char* LegoBuildingManager::g_customizeAnimFile = NULL;
// GLOBAL: LEGO1 0x100f37cc
int g_buildingManagerConfig = 1;
MxS32 g_buildingManagerConfig = 1;
// GLOBAL: LEGO1 0x10104c30
LegoBuildingInfo g_buildingInfo[16];
// GLOBAL: LEGO1 0x100f3748
MxS32 g_buildingCycle2Length[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 0};
// FUNCTION: LEGO1 0x1002f8b0
void LegoBuildingManager::configureLegoBuildingManager(MxS32 p_buildingManagerConfig)
@ -20,22 +212,72 @@ 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_buildingInfo); i++) {
g_buildingInfo[i] = g_buildingInfoInit[i];
}
// STUB: LEGO1 0x1002fa00
m_nextVariant = 0;
m_unk0x09 = 0;
m_unk0x20 = 0;
m_unk0x24 = 0;
m_unk0x28 = 0;
}
// FUNCTION: LEGO1 0x1002fa00
// FUNCTION: BETA10 0x10063ad1
void LegoBuildingManager::FUN_1002fa00()
{
// TODO
MxS32 i;
LegoWorld* world = CurrentWorld();
for (i = 0; i < _countof(g_buildingInfo); i++) {
UpdatePosition(i, world);
}
if (g_buildingManagerConfig <= 1) {
LegoEntity* entity = (LegoEntity*) world->Find("MxEntity", g_buildingDataHausName[0]);
if (entity) {
entity->GetROI()->SetVisibility(TRUE);
m_unk0x09 = 0;
}
}
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_unk0x09 = 0;
}
// FUNCTION: LEGO1 0x1002fa90
// FUNCTION: BETA10 0x10063b88
void LegoBuildingManager::UpdatePosition(MxS32 p_index, LegoWorld* p_world)
{
LegoEntity* entity = (LegoEntity*) p_world->Find("MxEntity", g_buildingInfo[p_index].m_hausName);
if (entity) {
entity->SetType(LegoEntity::e_building);
g_buildingInfo[p_index].m_entity = entity;
LegoROI* roi = entity->GetROI();
AdjustHeight(p_index);
MxMatrix mat = roi->GetLocal2World();
mat[3][1] = g_buildingInfo[p_index].m_unk0x014;
roi->FUN_100a46b0(mat);
VideoManager()->Get3DManager()->Moved(*roi);
}
}
// STUB: LEGO1 0x1002fb30
@ -44,25 +286,214 @@ void LegoBuildingManager::FUN_1002fb30()
// TODO
}
// STUB: LEGO1 0x1002fb80
// FUNCTION: LEGO1 0x1002fb80
// FUNCTION: BETA10 0x10063cae
MxResult LegoBuildingManager::Write(LegoStorage* p_storage)
{
return SUCCESS;
MxResult result = FAILURE;
for (MxS32 i = 0; i < _countof(g_buildingInfo); i++) {
LegoBuildingInfo* info = &g_buildingInfo[i];
if (p_storage->Write(&info->m_cycle1, sizeof(info->m_cycle1)) != SUCCESS) {
goto done;
}
if (p_storage->Write(&info->m_cycle2, sizeof(info->m_cycle2)) != SUCCESS) {
goto done;
}
if (p_storage->Write(&info->m_cycle3, sizeof(info->m_cycle3)) != SUCCESS) {
goto done;
}
if (p_storage->Write(&info->m_initialUnk0x11, sizeof(info->m_initialUnk0x11)) != SUCCESS) {
goto done;
}
}
// STUB: LEGO1 0x1002fc10
if (p_storage->Write(&m_nextVariant, sizeof(m_nextVariant)) != SUCCESS) {
goto done;
}
result = SUCCESS;
done:
return result;
}
// FUNCTION: LEGO1 0x1002fc10
// FUNCTION: BETA10 0x10063dde
MxResult LegoBuildingManager::Read(LegoStorage* p_storage)
{
return SUCCESS;
MxResult result = FAILURE;
for (MxS32 i = 0; i < _countof(g_buildingInfo); i++) {
LegoBuildingInfo* info = &g_buildingInfo[i];
if (p_storage->Read(&info->m_cycle1, sizeof(info->m_cycle1)) != SUCCESS) {
goto done;
}
if (p_storage->Read(&info->m_cycle2, sizeof(info->m_cycle2)) != SUCCESS) {
goto done;
}
if (p_storage->Read(&info->m_cycle3, sizeof(info->m_cycle3)) != SUCCESS) {
goto done;
}
if (p_storage->Read(&info->m_unk0x11, sizeof(info->m_unk0x11)) != SUCCESS) {
goto done;
}
// STUB: LEGO1 0x1002fdb0
MxBool LegoBuildingManager::FUN_1002fdb0(LegoEntity* p_entity)
info->m_initialUnk0x11 = info->m_unk0x11;
AdjustHeight(i);
}
if (p_storage->Read(&m_nextVariant, sizeof(m_nextVariant)) != SUCCESS) {
goto done;
}
if (g_buildingManagerConfig <= 1) {
m_nextVariant = 0;
}
result = SUCCESS;
done:
return result;
}
// FUNCTION: LEGO1 0x1002fcc0
// FUNCTION: BETA10 0x10063f1a
void LegoBuildingManager::AdjustHeight(MxS32 p_index)
{
// TODO
if (g_buildingInfo[p_index].m_unk0x11 > 0) {
float value = g_buildingDataDownshift[p_index] - g_buildingInfo[p_index].m_unk0x11;
g_buildingInfo[p_index].m_unk0x014 =
g_buildingInfoInit[p_index].m_unk0x014 - value * g_buildingDataDownshiftScale[p_index];
}
else if (g_buildingInfo[p_index].m_unk0x11 == 0) {
float value = g_buildingDataDownshift[p_index] - g_buildingInfo[p_index].m_unk0x11;
g_buildingInfo[p_index].m_unk0x014 =
g_buildingInfoInit[p_index].m_unk0x014 - value * g_buildingDataDownshiftScale[p_index];
if (g_buildingInfo[p_index].m_entity != NULL) {
LegoROI* roi = g_buildingInfo[p_index].m_entity->GetROI();
if (roi != NULL) {
roi->SetVisibility(FALSE);
}
}
}
else {
g_buildingInfo[p_index].m_unk0x014 = g_buildingInfoInit[p_index].m_unk0x014;
}
}
// FUNCTION: LEGO1 0x1002fd70
// FUNCTION: BETA10 0x10063fc9
LegoBuildingInfo* LegoBuildingManager::GetInfo(LegoEntity* p_entity)
{
MxS32 i;
for (i = 0; i < _countof(g_buildingInfo); i++) {
if (g_buildingInfo[i].m_entity == p_entity) {
break;
}
}
if (i < _countof(g_buildingInfo)) {
return &g_buildingInfo[i];
}
return NULL;
}
// FUNCTION: LEGO1 0x1002fdb0
// FUNCTION: BETA10 0x10064101
MxBool LegoBuildingManager::IncrementVariant(LegoEntity* p_entity)
{
if (g_buildingManagerConfig <= 1) {
return TRUE;
}
LegoBuildingInfo* info = GetInfo(p_entity);
if (info != NULL && info->m_flags & LegoBuildingInfo::c_bit1 && info->m_unk0x11 == -1) {
LegoROI* roi = p_entity->GetROI();
if (++m_nextVariant >= _countof(g_buildingDataHausName)) {
m_nextVariant = 0;
}
roi->SetVisibility(FALSE);
info->m_hausName = g_buildingDataHausName[m_nextVariant];
UpdatePosition(12, CurrentWorld());
if (info->m_entity != NULL) {
info->m_entity->GetROI()->SetVisibility(TRUE);
}
return TRUE;
}
return FALSE;
}
// FUNCTION: LEGO1 0x1002fe40
// FUNCTION: BETA10 0x100641d3
MxBool LegoBuildingManager::FUN_1002fe40(LegoEntity* p_entity)
{
MxBool result = FALSE;
LegoBuildingInfo* info = GetInfo(p_entity);
if (info != NULL && info->m_flags & LegoBuildingInfo::c_bit2) {
info->m_cycle1++;
if (info->m_cycle1 >= g_buildingCycle1Length) {
info->m_cycle1 = 0;
}
result = TRUE;
}
return result;
}
// FUNCTION: LEGO1 0x1002fe80
// FUNCTION: BETA10 0x10064242
MxBool LegoBuildingManager::FUN_1002fe80(LegoEntity* p_entity)
{
MxBool result = FALSE;
LegoBuildingInfo* info = GetInfo(p_entity);
if (info != NULL && info->m_flags & LegoBuildingInfo::c_bit3) {
info->m_cycle2++;
if (info->m_cycle2 >= g_buildingCycle2Length[info - g_buildingInfo]) {
info->m_cycle2 = 0;
}
result = TRUE;
}
return result;
}
// FUNCTION: LEGO1 0x1002fed0
// FUNCTION: BETA10 0x100642c2
MxBool LegoBuildingManager::FUN_1002fed0(LegoEntity* p_entity)
{
MxBool result = FALSE;
LegoBuildingInfo* info = GetInfo(p_entity);
if (info != NULL && info->m_flags & LegoBuildingInfo::c_bit4) {
info->m_cycle3++;
if (info->m_cycle3 > 3) {
info->m_cycle3 = 0;
}
result = TRUE;
}
return result;
}
// STUB: LEGO1 0x1002ff40
MxU32 LegoBuildingManager::FUN_1002ff40(LegoEntity*, MxBool)
{
@ -89,10 +520,34 @@ 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
LegoBuildingInfo* info = GetInfo(p_entity);
if (info == NULL) {
return FALSE;
}
return FUN_10030030(info - g_buildingInfo);
}
// STUB: LEGO1 0x10030030
MxBool LegoBuildingManager::FUN_10030030(MxS32 p_index)
{
return TRUE;
}
// FUNCTION: LEGO1 0x10030110
MxBool LegoBuildingManager::FUN_10030110(LegoBuildingInfo* p_data)
{
for (MxS32 i = 0; i < _countof(g_buildingInfo); i++) {
if (&g_buildingInfo[i] == p_data) {
return FUN_10030030(i);
}
}
return FALSE;
}
// STUB: LEGO1 0x10030220

View file

@ -40,7 +40,7 @@ MxU32 g_unk0x100fc4ec = 2;
MxU32 g_unk0x100fc4f0 = 0;
// GLOBAL: LEGO1 0x10104f20
LegoCharacterInfo g_chracterInfo[66];
LegoCharacterInfo g_characterInfo[66];
// FUNCTION: LEGO1 0x10082a20
LegoCharacterManager::LegoCharacterManager()
@ -55,22 +55,22 @@ LegoCharacterManager::LegoCharacterManager()
// FUNCTION: LEGO1 0x10083270
void LegoCharacterManager::Init()
{
for (MxS32 i = 0; i < _countof(g_chracterInfo); i++) {
g_chracterInfo[i] = g_characterInfoInit[i];
for (MxS32 i = 0; i < _countof(g_characterInfo); i++) {
g_characterInfo[i] = g_characterInfoInit[i];
}
}
// FUNCTION: LEGO1 0x100832a0
void LegoCharacterManager::FUN_100832a0()
{
for (MxS32 i = 0; i < _countof(g_chracterInfo); i++) {
LegoCharacterInfo* info = GetInfo(g_chracterInfo[i].m_name);
for (MxS32 i = 0; i < _countof(g_characterInfo); i++) {
LegoCharacterInfo* info = GetInfo(g_characterInfo[i].m_name);
if (info != NULL) {
LegoExtraActor* actor = info->m_actor;
if (actor != NULL && actor->IsA("LegoExtraActor")) {
LegoROI* roi = g_chracterInfo[i].m_roi;
LegoROI* roi = g_characterInfo[i].m_roi;
MxU32 refCount = GetRefCount(roi);
while (refCount != 0) {
@ -87,8 +87,8 @@ MxResult LegoCharacterManager::Write(LegoStorage* p_storage)
{
MxResult result = FAILURE;
for (MxS32 i = 0; i < _countof(g_chracterInfo); i++) {
LegoCharacterInfo* info = &g_chracterInfo[i];
for (MxS32 i = 0; i < _countof(g_characterInfo); i++) {
LegoCharacterInfo* info = &g_characterInfo[i];
if (p_storage->Write(&info->m_unk0x0c, sizeof(info->m_unk0x0c)) != SUCCESS) {
goto done;
@ -142,8 +142,8 @@ MxResult LegoCharacterManager::Read(LegoStorage* p_storage)
{
MxResult result = FAILURE;
for (MxS32 i = 0; i < _countof(g_chracterInfo); i++) {
LegoCharacterInfo* info = &g_chracterInfo[i];
for (MxS32 i = 0; i < _countof(g_characterInfo); i++) {
LegoCharacterInfo* info = &g_characterInfo[i];
if (p_storage->Read(&info->m_unk0x0c, sizeof(info->m_unk0x0c)) != SUCCESS) {
goto done;
@ -588,8 +588,8 @@ MxBool LegoCharacterManager::FUN_100849a0(LegoROI* p_roi, LegoTextureInfo* p_tex
// FUNCTION: LEGO1 0x10084c00
MxBool LegoCharacterManager::Exists(const char* p_key)
{
for (MxU32 i = 0; i < _countof(g_chracterInfo); i++) {
if (!strcmpi(g_chracterInfo[i].m_name, p_key)) {
for (MxU32 i = 0; i < _countof(g_characterInfo); i++) {
if (!strcmpi(g_characterInfo[i].m_name, p_key)) {
return TRUE;
}
}
@ -614,14 +614,14 @@ LegoCharacterInfo* LegoCharacterManager::GetInfo(const char* p_key)
{
MxU32 i;
for (i = 0; i < _countof(g_chracterInfo); i++) {
if (!strcmpi(g_chracterInfo[i].m_name, p_key)) {
for (i = 0; i < _countof(g_characterInfo); i++) {
if (!strcmpi(g_characterInfo[i].m_name, p_key)) {
break;
}
}
if (i < _countof(g_chracterInfo)) {
return &g_chracterInfo[i];
if (i < _countof(g_characterInfo)) {
return &g_characterInfo[i];
}
return NULL;
@ -632,14 +632,14 @@ LegoCharacterInfo* LegoCharacterManager::GetInfo(LegoROI* p_roi)
{
MxU32 i;
for (i = 0; i < _countof(g_chracterInfo); i++) {
if (g_chracterInfo[i].m_roi == p_roi) {
for (i = 0; i < _countof(g_characterInfo); i++) {
if (g_characterInfo[i].m_roi == p_roi) {
break;
}
}
if (i < _countof(g_chracterInfo)) {
return &g_chracterInfo[i];
if (i < _countof(g_characterInfo)) {
return &g_characterInfo[i];
}
return NULL;

View file

@ -294,7 +294,7 @@ void LegoEntity::VTable0x3c()
PlantManager()->FUN_100269e0(this);
break;
case e_building:
BuildingManager()->FUN_1002fdb0(this);
BuildingManager()->IncrementVariant(this);
break;
}