From da699974802c53007db89beac91c8a3258600546 Mon Sep 17 00:00:00 2001 From: Sebastian Mischke Date: Sat, 10 Jan 2026 19:49:04 +0100 Subject: [PATCH 01/23] Clear unknowns in `LegoRaceMap` (#1705) * Rename FUN_1005d4b0 to UpdateMapLocatorPosition * Rename m_unk0x08 to m_mapEnabled * Rename m_unk0x14 to m_worldXOffset * Rename m_unk0x1c to m_worldYOffset * Rename m_unk0x18 to m_worldXScale * Rename m_unk0x20 to m_worldYScale * Rename m_unk0x24 to m_screenXScale * Rename m_unk0x28 to m_screenYScale * Rename m_unk0x2c to m_screenXOffset * Rename m_unk0x30 to m_screenYOffset * Rename worldY to worldZ --------- Co-authored-by: Christian Semmler --- LEGO1/lego/legoomni/include/legoracemap.h | 24 +++++++------- LEGO1/lego/legoomni/src/race/legoracemap.cpp | 34 ++++++++++---------- LEGO1/lego/legoomni/src/race/legoracers.cpp | 4 +-- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoracemap.h b/LEGO1/lego/legoomni/include/legoracemap.h index 562581fa..448f11fa 100644 --- a/LEGO1/lego/legoomni/include/legoracemap.h +++ b/LEGO1/lego/legoomni/include/legoracemap.h @@ -26,7 +26,7 @@ class LegoRaceMap : public virtual LegoRaceActor { void Animate(float p_time) override = 0; // vtable+0x70 // LegoRaceMap vtable - virtual void FUN_1005d4b0(); // vtable+0x00 + virtual void UpdateMapLocatorPosition(); // vtable+0x00 // SYNTHETIC: LEGO1 0x10012c50 // LegoRaceMap::`vbase destructor' @@ -35,28 +35,28 @@ class LegoRaceMap : public virtual LegoRaceActor { // LegoRaceMap::`scalar deleting destructor' private: - MxBool m_unk0x08; // 0x08 + MxBool m_mapEnabled; // 0x08 MxStillPresenter* m_stillPresenter; // 0x0c // variable name verified by BETA10 0x100ca82b MxControlPresenter* m_Map_Ctl; // 0x10 // likely an x-offset of the race map in world space - float m_unk0x14; // 0x14 + float m_worldXOffset; // 0x14 // inversely scales the map in x direction (either convert world->screen space or to control the size) - float m_unk0x18; // 0x18 - // likely a y-offset of the race map in world space - float m_unk0x1c; // 0x1c - // inversely scales the map in y direction (either convert world->screen space or to control the size) - float m_unk0x20; // 0x20 + float m_worldXScale; // 0x18 + // likely a z-offset of the race map in world space + float m_worldZOffset; // 0x1c + // inversely scales the map in z direction (either convert world->screen space or to control the size) + float m_worldZScale; // 0x20 // scales the map in x direction (either convert world->screen space or to change the size) - float m_unk0x24; // 0x24 + float m_screenXScale; // 0x24 // scales the map in y direction (either convert world->screen space or to change the size) - float m_unk0x28; // 0x28 + float m_screenYScale; // 0x28 // likely an x-offset of the race map in screen space - float m_unk0x2c; // 0x2c + float m_screenXOffset; // 0x2c // likely a y-offset of the race map in screen space - float m_unk0x30; // 0x30 + float m_screenYOffset; // 0x30 }; // GLOBAL: LEGO1 0x100d8848 diff --git a/LEGO1/lego/legoomni/src/race/legoracemap.cpp b/LEGO1/lego/legoomni/src/race/legoracemap.cpp index 9637114d..cbc1cbb2 100644 --- a/LEGO1/lego/legoomni/src/race/legoracemap.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracemap.cpp @@ -15,7 +15,7 @@ DECOMP_SIZE_ASSERT(LegoRaceMap, 0x1b4) // FUNCTION: BETA10 0x100ca2c0 LegoRaceMap::LegoRaceMap() { - m_unk0x08 = FALSE; + m_mapEnabled = FALSE; m_stillPresenter = NULL; m_Map_Ctl = 0; ControlManager()->Register(this); @@ -54,42 +54,42 @@ void LegoRaceMap::ParseAction(char* p_extra) if (KeyValueStringParse(value, g_mapGeometry, p_extra)) { char* token = strtok(value, g_parseExtraTokens); if (token != NULL) { - m_unk0x14 = atof(token); + m_worldXOffset = atof(token); } token = strtok(NULL, g_parseExtraTokens); if (token != NULL) { - m_unk0x18 = atof(token); + m_worldXScale = atof(token); } token = strtok(NULL, g_parseExtraTokens); if (token != NULL) { - m_unk0x1c = atof(token); + m_worldZOffset = atof(token); } token = strtok(NULL, g_parseExtraTokens); if (token != NULL) { - m_unk0x20 = atof(token); + m_worldZScale = atof(token); } token = strtok(NULL, g_parseExtraTokens); if (token != NULL) { - m_unk0x24 = atof(token); + m_screenXScale = atof(token); } token = strtok(NULL, g_parseExtraTokens); if (token != NULL) { - m_unk0x28 = atof(token); + m_screenYScale = atof(token); } token = strtok(NULL, g_parseExtraTokens); if (token != NULL) { - m_unk0x2c = atof(token); + m_screenXOffset = atof(token); } token = strtok(NULL, g_parseExtraTokens); if (token != NULL) { - m_unk0x30 = atof(token); + m_screenYOffset = atof(token); } } @@ -106,13 +106,13 @@ void LegoRaceMap::ParseAction(char* p_extra) // FUNCTION: LEGO1 0x1005d4b0 // FUNCTION: BETA10 0x100ca849 -void LegoRaceMap::FUN_1005d4b0() +void LegoRaceMap::UpdateMapLocatorPosition() { - if (m_unk0x08) { - short xPos = (GetWorldPosition()[0] - m_unk0x14) / m_unk0x18 * m_unk0x24; - short yPos = (GetWorldPosition()[2] - m_unk0x1c) / m_unk0x20 * m_unk0x28; + if (m_mapEnabled) { + short xPos = (GetWorldPosition()[0] - m_worldXOffset) / m_worldXScale * m_screenXScale; + short yPos = (GetWorldPosition()[2] - m_worldZOffset) / m_worldZScale * m_screenYScale; - m_stillPresenter->SetPosition(xPos + m_unk0x2c, m_unk0x30 - yPos); + m_stillPresenter->SetPosition(xPos + m_screenXOffset, m_screenYOffset - yPos); } } @@ -130,12 +130,12 @@ MxLong LegoRaceMap::Notify(MxParam& p_param) m_Map_Ctl->GetAction()->GetObjectId() == ((LegoControlManagerNotificationParam&) p_param).m_clickedObjectId) { if (((LegoControlManagerNotificationParam&) p_param).m_enabledChild == 1) { - m_unk0x08 = TRUE; - FUN_1005d4b0(); + m_mapEnabled = TRUE; + UpdateMapLocatorPosition(); m_stillPresenter->Enable(TRUE); } else { - m_unk0x08 = FALSE; + m_mapEnabled = FALSE; m_stillPresenter->Enable(FALSE); } } diff --git a/LEGO1/lego/legoomni/src/race/legoracers.cpp b/LEGO1/lego/legoomni/src/race/legoracers.cpp index 8b1142f9..d338c861 100644 --- a/LEGO1/lego/legoomni/src/race/legoracers.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracers.cpp @@ -411,7 +411,7 @@ void LegoRaceCar::Animate(float p_time) } if (LegoCarRaceActor::m_animState == 1) { - FUN_1005d4b0(); + UpdateMapLocatorPosition(); if (!m_userNavFlag) { FUN_10080590(p_time); @@ -610,7 +610,7 @@ void LegoJetski::Animate(float p_time) LegoJetskiRaceActor::Animate(p_time); if (LegoCarRaceActor::m_animState == 1) { - FUN_1005d4b0(); + UpdateMapLocatorPosition(); if (!m_userNavFlag) { FUN_10080590(p_time); From 4bcc2b964bc293a0afdecbf21d679b8752b72711 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Sat, 10 Jan 2026 20:00:26 +0100 Subject: [PATCH 02/23] Clear unknowns in `LegoUnknown` and rename to `LegoSpline` (#1711) --- CMakeLists.txt | 2 +- LEGO1/lego/legoomni/include/legopathactor.h | 4 +- .../lego/legoomni/src/paths/legopathactor.cpp | 6 +- LEGO1/lego/sources/misc/legospline.cpp | 88 +++++++++++++++++++ LEGO1/lego/sources/misc/legospline.h | 27 ++++++ LEGO1/lego/sources/misc/legounknown.cpp | 86 ------------------ LEGO1/lego/sources/misc/legounknown.h | 27 ------ 7 files changed, 121 insertions(+), 119 deletions(-) create mode 100644 LEGO1/lego/sources/misc/legospline.cpp create mode 100644 LEGO1/lego/sources/misc/legospline.h delete mode 100644 LEGO1/lego/sources/misc/legounknown.cpp delete mode 100644 LEGO1/lego/sources/misc/legounknown.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6485e070..0b7cbf0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,11 +189,11 @@ function(add_lego_libraries NAME) add_library(misc${ARG_SUFFIX} STATIC LEGO1/lego/sources/misc/legotexture.cpp + LEGO1/lego/sources/misc/legospline.cpp LEGO1/lego/sources/misc/legostorage.cpp LEGO1/lego/sources/misc/legoimage.cpp LEGO1/lego/sources/misc/legocontainer.cpp LEGO1/lego/sources/misc/legotree.cpp - LEGO1/lego/sources/misc/legounknown.cpp ) list(APPEND list_targets misc${ARG_SUFFIX}) set_property(TARGET misc${ARG_SUFFIX} PROPERTY ARCHIVE_OUTPUT_NAME "misc$<$:d>${ARG_SUFFIX}") diff --git a/LEGO1/lego/legoomni/include/legopathactor.h b/LEGO1/lego/legoomni/include/legopathactor.h index 2f1d8862..35baafbd 100644 --- a/LEGO1/lego/legoomni/include/legopathactor.h +++ b/LEGO1/lego/legoomni/include/legopathactor.h @@ -2,7 +2,7 @@ #define LEGOPATHACTOR_H #include "legoactor.h" -#include "misc/legounknown.h" +#include "misc/legospline.h" #include "mxtypes.h" struct LegoEdge; @@ -194,7 +194,7 @@ class LegoPathActor : public LegoActor { MxFloat m_actorTime; // 0x80 MxFloat m_lastTime; // 0x84 LegoPathBoundary* m_boundary; // 0x88 - LegoUnknown m_unk0x8c; // 0x8c + LegoSpline m_spline; // 0x8c MxU32 m_actorState; // 0xdc LegoOrientedEdge* m_destEdge; // 0xe0 MxFloat m_unk0xe4; // 0xe4 diff --git a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp index 0b1c0c2f..7233c218 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp @@ -81,7 +81,7 @@ MxResult LegoPathActor::VTable0x80(const Vector3& p_point1, Vector3& p_point2, V m_BADuration = sqrtf(m_BADuration); p2 = p_point2; p3 = p_point4; - m_unk0x8c.FUN_1009a140(p_point1, p2, p_point3, p3); + m_spline.SetSpline(p_point1, p2, p_point3, p3); m_BADuration /= 0.001; return SUCCESS; } @@ -354,10 +354,10 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform) LegoResult r; if (m_userNavFlag) { - r = m_unk0x8c.FUN_1009a1e0(m_unk0x7c / m_BADuration, p_transform, *m_boundary->GetUp(), 0); + r = m_spline.Evaluate(m_unk0x7c / m_BADuration, p_transform, *m_boundary->GetUp(), FALSE); } else { - r = m_unk0x8c.FUN_1009a1e0(m_unk0x7c / m_BADuration, p_transform, *m_boundary->GetUp(), 1); + r = m_spline.Evaluate(m_unk0x7c / m_BADuration, p_transform, *m_boundary->GetUp(), TRUE); } assert(r == 0); // SUCCESS diff --git a/LEGO1/lego/sources/misc/legospline.cpp b/LEGO1/lego/sources/misc/legospline.cpp new file mode 100644 index 00000000..25562589 --- /dev/null +++ b/LEGO1/lego/sources/misc/legospline.cpp @@ -0,0 +1,88 @@ +#include "legospline.h" + +#include "mxgeometry/mxmatrix.h" + +DECOMP_SIZE_ASSERT(LegoSpline, 0x50) + +// FUNCTION: LEGO1 0x1009a0f0 +LegoSpline::LegoSpline() +{ + for (LegoS32 i = 0; i < sizeOfArray(m_coefficents); i++) { + m_coefficents[i].Clear(); + } +} + +// FUNCTION: LEGO1 0x1009a130 +LegoSpline::~LegoSpline() +{ +} + +// FUNCTION: LEGO1 0x1009a140 +// FUNCTION: BETA10 0x10182c2f +void LegoSpline::SetSpline( + const Vector3& p_start, + const Vector3& p_tangentAtStart, + const Vector3& p_end, + const Vector3& p_tangentAtEnd +) +{ + m_coefficents[0] = p_start; + m_coefficents[1] = p_tangentAtStart; + + for (LegoS32 i = 0; i < 3; i++) { + m_coefficents[2][i] = (p_end[i] - p_start[i]) * 3.0f - p_tangentAtStart[i] * 2.0f - p_tangentAtEnd[i]; + m_coefficents[3][i] = (p_start[i] - p_end[i]) * 2.0f + p_tangentAtEnd[i] + p_tangentAtStart[i]; + } +} + +// FUNCTION: LEGO1 0x1009a1e0 +// FUNCTION: BETA10 0x10182d61 +LegoResult LegoSpline::Evaluate(float p_alpha, Matrix4& p_mat, Vector3& p_up, LegoU32 p_reverse) +{ + Vector3 position(p_mat[3]); + Vector3 right(p_mat[0]); + Vector3 up(p_mat[1]); + Vector3 dir(p_mat[2]); + + if (p_alpha <= 0.001) { + position = m_coefficents[0]; + dir = m_coefficents[1]; + } + else if (p_alpha >= 0.999) { + position = m_coefficents[0]; + position += m_coefficents[1]; + position += m_coefficents[2]; + position += m_coefficents[3]; + + for (LegoS32 i = 0; i < 3; i++) { + dir[i] = m_coefficents[1][i] + m_coefficents[2][i] * 2.0f + m_coefficents[3][i] * 3.0f; + } + } + else { + float alpha_squared = p_alpha * p_alpha; + float alpha_cubed = alpha_squared * p_alpha; + + for (LegoS32 i = 0; i < 3; i++) { + position[i] = m_coefficents[0][i] + m_coefficents[1][i] * p_alpha + m_coefficents[2][i] * alpha_squared + + m_coefficents[3][i] * alpha_cubed; + dir[i] = + m_coefficents[1][i] + m_coefficents[2][i] * p_alpha * 2.0f + m_coefficents[3][i] * alpha_squared * 3.0f; + } + } + + if (p_reverse) { + dir *= -1.0f; + } + + if (dir.Unitize() != 0) { + return FAILURE; + } + + right.EqualsCross(p_up, dir); + if (right.Unitize() != 0) { + return FAILURE; + } + + up.EqualsCross(dir, right); + return SUCCESS; +} diff --git a/LEGO1/lego/sources/misc/legospline.h b/LEGO1/lego/sources/misc/legospline.h new file mode 100644 index 00000000..b504dd7c --- /dev/null +++ b/LEGO1/lego/sources/misc/legospline.h @@ -0,0 +1,27 @@ +#ifndef __LEGOSPLINE_H +#define __LEGOSPLINE_H + +#include "legotypes.h" +#include "mxgeometry/mxgeometry3d.h" + +class Matrix4; + +// SIZE 0x50 +class LegoSpline { +public: + LegoSpline(); + ~LegoSpline(); + + void SetSpline( + const Vector3& p_start, + const Vector3& p_tangentAtStart, + const Vector3& p_end, + const Vector3& p_tangentAtEnd + ); + LegoResult Evaluate(float p_alpha, Matrix4& p_mat, Vector3& p_v, LegoU32 p_reverse); + +private: + Mx3DPointFloat m_coefficents[4]; // 0x00 +}; + +#endif // __LEGOSPLINE_H diff --git a/LEGO1/lego/sources/misc/legounknown.cpp b/LEGO1/lego/sources/misc/legounknown.cpp deleted file mode 100644 index afc22e8f..00000000 --- a/LEGO1/lego/sources/misc/legounknown.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "legounknown.h" - -#include "mxgeometry/mxmatrix.h" - -DECOMP_SIZE_ASSERT(LegoUnknown, 0x50) - -// FUNCTION: LEGO1 0x1009a0f0 -LegoUnknown::LegoUnknown() -{ - for (LegoS32 i = 0; i < sizeOfArray(m_unk0x00); i++) { - m_unk0x00[i].Clear(); - } -} - -// FUNCTION: LEGO1 0x1009a130 -LegoUnknown::~LegoUnknown() -{ -} - -// FUNCTION: LEGO1 0x1009a140 -// FUNCTION: BETA10 0x10182c2f -void LegoUnknown::FUN_1009a140( - const Vector3& p_point1, - const Vector3& p_point2, - const Vector3& p_point3, - const Vector3& p_point4 -) -{ - m_unk0x00[0] = p_point1; - m_unk0x00[1] = p_point2; - - for (LegoS32 i = 0; i < 3; i++) { - m_unk0x00[2][i] = (p_point3[i] - p_point1[i]) * 3.0f - p_point2[i] * 2.0f - p_point4[i]; - m_unk0x00[3][i] = (p_point1[i] - p_point3[i]) * 2.0f + p_point4[i] + p_point2[i]; - } -} - -// FUNCTION: LEGO1 0x1009a1e0 -// FUNCTION: BETA10 0x10182d61 -LegoResult LegoUnknown::FUN_1009a1e0(float p_f1, Matrix4& p_mat, Vector3& p_v, LegoU32 p_und) -{ - Vector3 v1(p_mat[3]); - Vector3 v2(p_mat[0]); - Vector3 v3(p_mat[1]); - Vector3 v4(p_mat[2]); - - if (p_f1 <= 0.001) { - v1 = m_unk0x00[0]; - v4 = m_unk0x00[1]; - } - else if (p_f1 >= 0.999) { - v1 = m_unk0x00[0]; - v1 += m_unk0x00[1]; - v1 += m_unk0x00[2]; - v1 += m_unk0x00[3]; - - for (LegoS32 i = 0; i < 3; i++) { - v4[i] = m_unk0x00[1][i] + m_unk0x00[2][i] * 2.0f + m_unk0x00[3][i] * 3.0f; - } - } - else { - float local30 = p_f1 * p_f1; - float local34 = local30 * p_f1; - - for (LegoS32 i = 0; i < 3; i++) { - v1[i] = m_unk0x00[0][i] + m_unk0x00[1][i] * p_f1 + m_unk0x00[2][i] * local30 + m_unk0x00[3][i] * local34; - v4[i] = m_unk0x00[1][i] + m_unk0x00[2][i] * p_f1 * 2.0f + m_unk0x00[3][i] * local30 * 3.0f; - } - } - - if (p_und) { - v4 *= -1.0f; - } - - if (v4.Unitize() != 0) { - return FAILURE; - } - - v2.EqualsCross(p_v, v4); - if (v2.Unitize() != 0) { - return FAILURE; - } - - v3.EqualsCross(v4, v2); - return SUCCESS; -} diff --git a/LEGO1/lego/sources/misc/legounknown.h b/LEGO1/lego/sources/misc/legounknown.h deleted file mode 100644 index c29bbd28..00000000 --- a/LEGO1/lego/sources/misc/legounknown.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __LEGOUNKNOWN_H -#define __LEGOUNKNOWN_H - -#include "legotypes.h" -#include "mxgeometry/mxgeometry3d.h" - -class Matrix4; - -// SIZE 0x50 -class LegoUnknown { -public: - LegoUnknown(); - ~LegoUnknown(); - - void FUN_1009a140( - const Vector3& p_point1, - const Vector3& p_point2, - const Vector3& p_point3, - const Vector3& p_point4 - ); - LegoResult FUN_1009a1e0(float p_f1, Matrix4& p_mat, Vector3& p_v, LegoU32 p_und); - -private: - Mx3DPointFloat m_unk0x00[4]; // 0x00 -}; - -#endif // __LEGOUNKNOWN_H From f52b27513024eba344e26ddece9759184313e691 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Sat, 10 Jan 2026 13:52:53 -0700 Subject: [PATCH 03/23] Add initial Kaitai formats to document LEGO Island file formats (#1712) * Add initial Kaitai formats * Update README with installation and command examples Added installation instructions for Kaitai Struct Visualizer and updated ksdump command examples. * Update README.md * Update link to Kaitai Struct documentation * Update installation link for Kaitai Struct Visualizer --- docs/README.md | 55 +++++++++++++++++ docs/history.ksy | 125 +++++++++++++++++++++++++++++++++++++++ docs/players.ksy | 48 +++++++++++++++ docs/samples/History.gsi | Bin 0 -> 184 bytes docs/samples/Players.gsi | Bin 0 -> 44 bytes 5 files changed, 228 insertions(+) create mode 100644 docs/README.md create mode 100644 docs/history.ksy create mode 100644 docs/players.ksy create mode 100755 docs/samples/History.gsi create mode 100755 docs/samples/Players.gsi diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..297f7ce3 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,55 @@ +# LEGO Island File Format Documentation + +This folder contains documentation for LEGO Island's custom binary file formats using [Kaitai Struct](https://kaitai.io/), a declarative language for describing binary data structures. + +## What is Kaitai Struct? + +Kaitai Struct allows you to define binary formats in a YAML-based `.ksy` file, which can then be: +- Compiled into parser libraries for [many programming languages](https://kaitai.io/#quick-start) (C++, Python, JavaScript, etc.) +- Visualized interactively using the [Kaitai Struct Visualizer](https://github.com/kaitai-io/kaitai_struct_visualizer) +- Dumped to human-readable formats using `ksdump` + +image + +## Documented Formats + +| File | Extension | Description | +|------|-----------|-------------| +| [`players.ksy`](/docs/players.ksy) | `.gsi` | Player profile save data (usernames) | +| [`history.ksy`](/docs/history.ksy) | `.gsi` | Score history and high scores | + +## Using the Tools + +### Installation + +See the [Kaitai Struct Visualizer installation instructions](https://github.com/kaitai-io/kaitai_struct_visualizer?tab=readme-ov-file#downloading-and-installing) for setup details. + +### Kaitai Struct Visualizer (ksv) + +The [Kaitai Struct Visualizer](https://github.com/kaitai-io/kaitai_struct_visualizer) (`ksv`) provides an interactive terminal UI for exploring binary files. + +```bash +# View a Players.gsi file +ksv samples/Players.gsi players.ksy + +# View a History.gsi file +ksv samples/History.gsi history.ksy +``` + +### Kaitai Struct Dump (ksdump) + +`ksdump` outputs the parsed structure as JSON or YAML for scripting and inspection. + +```bash +# Dump Players.gsi to JSON +ksdump --format json samples/Players.gsi players.ksy + +# Dump History.gsi to YAML +ksdump --format yaml samples/History.gsi history.ksy +``` + +## Sample Files + +The [`samples/`](/docs/samples/) directory contains example save files for testing: +- `Players.gsi` - Sample player profile data +- `History.gsi` - Sample score history data diff --git a/docs/history.ksy b/docs/history.ksy new file mode 100644 index 00000000..f60bb2af --- /dev/null +++ b/docs/history.ksy @@ -0,0 +1,125 @@ +meta: + id: history + title: Score History Save File + application: LEGO Island + file-extension: gsi + license: CC0-1.0 + endian: le +doc: | + Score history save data for LEGO Island (1997). Stores up to 20 player + score entries, tracking high scores across all missions and characters. + + The file is located at `/History.gsi` where save_path is + typically the game's installation directory. + +seq: + - id: next_player_id + type: s2 + doc: | + The next player ID to be assigned when a new player profile is created. + Increments each time a new player is added, ensuring unique IDs. + - id: count + type: s2 + doc: Number of score entries in the history (0-20 max). + - id: entries + type: score_entry + repeat: expr + repeat-expr: count + doc: Array of score history entries, sorted by total score descending. + +types: + score_entry: + doc: | + A single score history entry containing a player's high scores across + all minigames and characters. Total serialized size is 45 bytes + (2 for index + 43 for score_item data). + seq: + - id: index + type: s2 + doc: Array index of this entry (0 to count-1). Stored redundantly in file. + - id: total_score + type: s2 + doc: Sum of all individual high scores across all missions and actors. + - id: scores + type: mission_scores + doc: High scores organized by mission type, each containing scores per actor. + - id: name + type: username + doc: The player's username associated with these scores. + - id: player_id + type: s2 + doc: Unique player identifier matching the player's profile. + + mission_scores: + doc: | + High scores for all 5 missions. Each mission contains scores for all + 5 playable actors. + seq: + - id: car_race + type: actor_scores + doc: Car Race mission high scores. + - id: jetski_race + type: actor_scores + doc: Jetski Race mission high scores. + - id: pizza_delivery + type: actor_scores + doc: Pizza Delivery mission high scores. + - id: tow_track + type: actor_scores + doc: Tow Track mission high scores. + - id: ambulance + type: actor_scores + doc: Ambulance mission high scores. + + actor_scores: + doc: | + High scores for a single mission across all 5 playable actors. + seq: + - id: pepper + type: u1 + enum: score_color + doc: High score for Pepper. + - id: mama + type: u1 + enum: score_color + doc: High score for Mama. + - id: papa + type: u1 + enum: score_color + doc: High score for Papa. + - id: nick + type: u1 + enum: score_color + doc: High score for Nick. + - id: laura + type: u1 + enum: score_color + doc: High score for Laura. + + username: + doc: | + A player username consisting of up to 7 letters. Each letter is stored + as a signed 16-bit index. The struct is always 14 bytes (0x0e). + seq: + - id: letters + type: s2 + repeat: expr + repeat-expr: 7 + doc: | + Letter indices for the username characters: + - 0-25: Standard alphabet (0=A, 1=B, ..., 25=Z) + - 29: International ä, å, or ñ (language-dependent) + - 30: International ö or æ (language-dependent) + - 31: International ß or ø (language-dependent) + - 32: International ü + - -1 (0xFFFF): Empty/unused position + + Unused positions are filled with -1. A name shorter than 7 + characters will have trailing -1 values. + +enums: + score_color: + 0: grey + 1: yellow + 2: blue + 3: red diff --git a/docs/players.ksy b/docs/players.ksy new file mode 100644 index 00000000..84136ed2 --- /dev/null +++ b/docs/players.ksy @@ -0,0 +1,48 @@ +meta: + id: players + title: Players Save File + application: LEGO Island + file-extension: gsi + license: CC0-1.0 + endian: le +doc: | + Player profile save data for LEGO Island (1997). Stores up to 9 player + profiles, each identified by a 7-character username. Usernames are stored + as letter indices rather than ASCII characters. + + The file is located at `/Players.gsi` where save_path is + typically the game's installation directory. + +seq: + - id: count + type: s2 + doc: | + Number of saved player profiles. The game supports a maximum of 9 + players; when a 10th player is added, the oldest profile is deleted. + - id: entries + type: username + repeat: expr + repeat-expr: count + doc: Array of player username entries, ordered by most recently played. + +types: + username: + doc: | + A player username consisting of up to 7 letters. Each letter is stored + as a signed 16-bit index. The struct is always 14 bytes (0x0e). + seq: + - id: letters + type: s2 + repeat: expr + repeat-expr: 7 + doc: | + Letter indices for the username characters: + - 0-25: Standard alphabet (0=A, 1=B, ..., 25=Z) + - 29: International ä, å, or ñ (language-dependent) + - 30: International ö or æ (language-dependent) + - 31: International ß or ø (language-dependent) + - 32: International ü + - -1 (0xFFFF): Empty/unused position + + Unused positions are filled with -1. A name shorter than 7 + characters will have trailing -1 values. diff --git a/docs/samples/History.gsi b/docs/samples/History.gsi new file mode 100755 index 0000000000000000000000000000000000000000..f253055f399b34cf63954bdf1a0d998cf5d8ae18 GIT binary patch literal 184 zcmaKmOAf#w2n9zm?XH_9z5h-10ktMB%8PslqS1guPiCKsGMuTK>M|%vy+CX%_+-lA WLj8l$_?8|n9NuoNtDenIWULH9zzVYf literal 0 HcmV?d00001 diff --git a/docs/samples/Players.gsi b/docs/samples/Players.gsi new file mode 100755 index 0000000000000000000000000000000000000000..21c08e1d044b16a14b2be41ebd4771d38f3f1a3e GIT binary patch literal 44 gcmZQ(U`Bxq3``8dKq$t*$MF9@jK|I($iTt?04lozrvLx| literal 0 HcmV?d00001 From 4998bdaf65da2d3370bf7321a0965623bbcca7ea Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Sat, 10 Jan 2026 16:27:44 -0700 Subject: [PATCH 04/23] Savegame: kaitai format (#1713) * Add savegame.ksy * Updates * Updates --- LEGO1/lego/legoomni/src/race/legorace.cpp | 10 +- docs/README.md | 8 + docs/samples/G0.GS | Bin 0 -> 4567 bytes docs/samples/G1.GS | Bin 0 -> 17084 bytes docs/samples/G2.GS | Bin 0 -> 17156 bytes docs/savegame.ksy | 1014 +++++++++++++++++++++ 6 files changed, 1027 insertions(+), 5 deletions(-) create mode 100755 docs/samples/G0.GS create mode 100755 docs/samples/G1.GS create mode 100755 docs/samples/G2.GS create mode 100644 docs/savegame.ksy diff --git a/LEGO1/lego/legoomni/src/race/legorace.cpp b/LEGO1/lego/legoomni/src/race/legorace.cpp index ea56a692..5f869095 100644 --- a/LEGO1/lego/legoomni/src/race/legorace.cpp +++ b/LEGO1/lego/legoomni/src/race/legorace.cpp @@ -116,19 +116,19 @@ void LegoRace::Enable(MxBool p_enable) // FUNCTION: LEGO1 0x10015f30 RaceState::RaceState() { - m_entries[0].m_id = 1; + m_entries[0].m_id = LegoActor::c_pepper; m_entries[0].m_lastScore = 0; m_entries[0].m_score = 0; - m_entries[1].m_id = 2; + m_entries[1].m_id = LegoActor::c_mama; m_entries[1].m_lastScore = 0; m_entries[1].m_score = 0; - m_entries[2].m_id = 3; + m_entries[2].m_id = LegoActor::c_papa; m_entries[2].m_lastScore = 0; m_entries[2].m_score = 0; - m_entries[3].m_id = 4; + m_entries[3].m_id = LegoActor::c_nick; m_entries[3].m_lastScore = 0; m_entries[3].m_score = 0; - m_entries[4].m_id = 5; + m_entries[4].m_id = LegoActor::c_laura; m_entries[4].m_lastScore = 0; m_entries[4].m_score = 0; m_state = RaceState::e_carrace; diff --git a/docs/README.md b/docs/README.md index 297f7ce3..0ea419d7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -15,6 +15,7 @@ Kaitai Struct allows you to define binary formats in a YAML-based `.ksy` file, w | File | Extension | Description | |------|-----------|-------------| +| [`savegame.ksy`](/docs/savegame.ksy) | `.GS` | Main game save data (game state, progress, customizations) | | [`players.ksy`](/docs/players.ksy) | `.gsi` | Player profile save data (usernames) | | [`history.ksy`](/docs/history.ksy) | `.gsi` | Score history and high scores | @@ -29,6 +30,9 @@ See the [Kaitai Struct Visualizer installation instructions](https://github.com/ The [Kaitai Struct Visualizer](https://github.com/kaitai-io/kaitai_struct_visualizer) (`ksv`) provides an interactive terminal UI for exploring binary files. ```bash +# View a save game file +ksv samples/G0.GS savegame.ksy + # View a Players.gsi file ksv samples/Players.gsi players.ksy @@ -41,6 +45,9 @@ ksv samples/History.gsi history.ksy `ksdump` outputs the parsed structure as JSON or YAML for scripting and inspection. ```bash +# Dump a save game to JSON +ksdump --format json samples/G0.GS savegame.ksy + # Dump Players.gsi to JSON ksdump --format json samples/Players.gsi players.ksy @@ -51,5 +58,6 @@ ksdump --format yaml samples/History.gsi history.ksy ## Sample Files The [`samples/`](/docs/samples/) directory contains example save files for testing: +- `G0.GS`, `G1.GS`, `G2.GS` - Sample main game save files (slots 0, 1, 2) - `Players.gsi` - Sample player profile data - `History.gsi` - Sample score history data diff --git a/docs/samples/G0.GS b/docs/samples/G0.GS new file mode 100755 index 0000000000000000000000000000000000000000..205f5b8d59d1edf943da26364d2c000e13caccee GIT binary patch literal 4567 zcmeHKPly{;7=M$Q$!xZ}Y+Lo99^8vJU9-E%vU+Gt=(bjBTWu8eV3>bNCOer~-+ODC zJ#-89P|%AY^rT{sf}mwl5bN3nMX&|+pa($^Jd0pKaSQRAnasR5FG(Ar6)Cs~iM;o1#<7TZ?ecFOJMCqrAO=};T2X4BA#9a{}o zH&^>sb9K;aIiwj|nTMv2Ay(v(P^#B?pAZeUBKvF_@PZhlXgR@Zi2zZ0@s$G~_Y&3GLTGHw}7 zk5wD9Xc;awk`iKTi&(nAc+RY~h#MYBh46!o- zT@CE7dzR_DKAs{roh>fS77MdW%hRsYXwo&GIMneyX<_fmv4geahicE2pE**l99=mH z_dH&TEGtT^z%u~Ja-zZ0Ah1aA>n~MOB#Fbzf{tV!jnH&(mOBrp)4D9lGPkeFat2l$ z4k1NK>DeGUhtH~zJC~29st5(Y{>mt6yap<)cpFUy)pHf!1KeRWkCz;+JVL}cU zb1v#A&A&KLB0s@E@cfDVi}yk7m)H-HPt@;U{0xxf9$e{YjU{I|{5bL`|LL>I#7RnT z966KZoW}EZUY0ogI5MBZKjUXqy|>$*=9A_8@7j6Z?j)JKO20% zM%mMt_@ABB`)^7p2Y+Rg&Yz?@wN-TFShcWtz4UrzqqkYQ_P_@_Fa7#xY3_8jK>vJX zdr~^Lh0vMOz2CjR5J3y*^NW?gdNbww&%Ac|tGUyq;9+(4{O^~(`Ed7Q0Db4_SGOk6 z%E80=h1&A+_iw#d*#-3C)tSo|em?uzlNY`%KL1!}d-}@!Vt`(H^M@irn-6_jK}Y}i z=##hSc3%8qv-IO}y45K?eCgR&-Y5j9{nyU{3Zb927twFqna4XjFMRyVfok)82S8xuOZo6xg=o9bJ`(O4}#;DlQ)k*h?MY^?N$c8p)VHqhOn_WlY+)R@jviR zVqjSR4}}Frb3JT7sz09l(Fph)K_{Gz4I4Xpc!d~o`@#+VDTfgFVhT5zzsTb#{ccqC zJ5>yyWBh66no0Mda@$yUb9+M3edxglbbQwV;xb;?D$YOo_=fjYNh_tW&L%szchC(Kg$&yS&}E515b{lbX!C zkGFfzdFP&c?z#7U@7{Cw5e%8<2r}lI42B|eNqM}6WeRLjcE;4hTgR5i2f2A=7OR6H zuF+!9a}3WluzF)r57$`Kn`^Ri7M|WHfqa|=1)ox{u0{lw~fIoD|67`=BWx@ALM?kcd`N=r;e8*8%% zbBrS@IVCDNDJo@p2x~2{I9A&@tHWw5k!iy+7S7JknvxkgP%6Eo z3{WV%6x@ga8F71(LZ+0-1oC1U3ZXO*;wmdBPo@27g-oFkTvsU+a!P!4fKuj12e@h% z$Oov%c7Z)=l?rg3JxQ+gmsb->iNA~>SL+2W9!koD*S&)MWXN_`@?H&vzdd0hdWeV) z7ttyigsn$_h*p0iP5$#*Lm8Prtrq!TCG+opH5nl6FR^@}ob(C&rIrP_lCMUETA@&@ zy)^Zw|A?Xn3H7T2lybSCKg9hPKmtmEezijFHy)@z{b-d+JbtLOKtFY_Kkc>jyUA!2 z?&MQ0rs3~@@puyZ$2A~?{uBFOd_Rc$OWYq~f1;=Vcnpv!oODZj(tz@Ef&4)7{pt5F z>m6}2rE?&8xz}c;b0B${Kz<;3p$*^8KmE1$yXO1*(`WPd%NP3X$C@9=_!)?duaAUd zL)c&a@%?4^hn>v%aOR*vAkvJEge4BWgHd7r!knbUuXS6~*E=`poZ}kKuDX?~i+VmM ziTi45t43Dc2vq9c{NRYzBbwxFJ(hmY8JdR5m(QG^^1SY3#`;4WcYV?F{_pP}bBXR> zys6PGs!jduYHRwfcg`NqJvZa*=iR4g{^Zl@q|~Tl-ES`ZF3}}wt*dL)AY=C2cx`@i z!iLGG(y`#~@wfL*IlJPW4Z15?j>a>EZclPahySNK*@cWau4nu;9 z5UR;ThsH=@4nRcvWo1KXR6 zFsFJfo>&LO*-73EOvneu(S&$3=^mj2BBul4@xb6mfxwYKzz~|i1bQC2o&Wk8O}CwR zY&H4-wXO9iJX+!CxAhAZxjSNhhvAcDxfE2kUXWr3g1_U&oo+dhD$^kEY!x zaqGmhP#u03#=R%->wT}`pSxeg`+Hu%e(L)h2l5cRy8-f=x8dAa1!TtMDSy@TtX&lfWoUYz< zW$B>I#EBE}79EGe44SraTSC9oZ3(4eODio6ebP9WgYFg2>1NP}M?)on4iTi={Y9UY zb=P&e^EB?fTTl9(E*!w^+qZG;+BI}^bfCSx9p}!Sb0Gtc9zBZM+FI1q)L`4TZKxuM zsHms_$8lg;77W8+)v8s<&CNwtRu<;Yor_tsW+5dd1#xk4h>niNuwla>;e~`35?*|N zc=4zAI{$b%LaXHQB9dT$$BVCMK`7ycG{2DM7t;KKpI@A=vFbD<6O@w(Cum`VDFVFs zDa~aiypZrh!V3v6c)W1M6li0Wm0}7~OhJk%{4iq*48^lfkJ}NPr-`PRLUbsFuDol6 zQ&LPpia|;-NGS#>h(RjRKIYB@gNDZoDW)LpSx9>p(w+rDM4x*WYD!U)v`QW?q&*7> zFC@H>@S;Dw=!q%VA7o5H+Sh)#_qFNCflEPE(fl(aMX&}PK@&_V?kvTfrMR;ccjn{H zF1$c!_81;7gmcPCQp`$zS-IdMe(3m-JYGmKD`^cXtwE(VXn$)^7he2q zcy|Pk7sC04^gG)h-tY3MJLy%C5^J&hRgqXC*U+yY|G()$8}Oj@J!tPdy!N^Ne}QYy z`^T5&45&$b%lYrV3WZ>ib^UtAZq>VQA)n|F_XYhkR*s`r#(OTx=p8hAp}WVY{e4Fu z$5xhOr}xo?rTeNq5^2STQdVDLWWGss5Ej{3tC4YA@^7*;0t@J$Q9Ny1O)u%Ems(kq M`-+_2XP$!p0TInpWdHyG literal 0 HcmV?d00001 diff --git a/docs/samples/G2.GS b/docs/samples/G2.GS new file mode 100755 index 0000000000000000000000000000000000000000..2d941effd16d2719250e08a404ffc5836ce8e51d GIT binary patch literal 17156 zcmeI4-D@LN6u|GzB$+1L(vPi(zHI&g?e-%n`qJ3AU0JES>$VCCQsyhkq|;2jGc`>g z+FBo6Q5MCA1%(A)^g)DmDV3^AwP1bF7oQh=5_}LuT%}7_h-W65%$=L0O`&Bg-U~zS zIrrRi&;6Y$V13B`-^s z=4oX^Qf6yfW!BUBwyJLB8?||pz*<$mz6YbA+2tX2HPTc&r>jjOn=@_V`SoM4n%aW4 znXSEGdmjAAY)NmjT1hXeUc8>IDraS)vK+I9lq(OOaygbY!!S!O-Yfy+$sqD9X+*Bd z`C{XCRoSrRhAk8SAB48nkrsnGPzqUL3!2VLUTA zF$K4}*TRAj4ts+05DF3XLZUx8iClUc*IBqA?K>KP&jBWf(XqUMsa8N)Q(SsGkUyk*rEfmJFPz2 zje_y?Fmf*=_c3w=BYO8J%E;n@GVrTM105WcMTUO_2lFpN0Cc`s`&bD4QM^PPb(+7T zAPRyg)@8_Nu%ci?wEsvn912nSVDlFRgD~Y^6vRM1Kt2OQ8w-LTlo*p ztydflSK8>KP(9{wrJcUBO}BynHv0ZE66`4^C%7Nv>BoFzda52;`)nh3?d11F+q6+X z?bKL{TB6y~_am*R`$EP0VTbqcIX{T1w}5ZAzpmM+u&)z*{u$IbseGA^x99K4OdN*_qJ|j_A1@u zk=3`q{eECM{ci8wPhP)%_x7)!-@oOUe){|y>m6v~+%tp2GpV6FAAXbh>e|i*+8Evb zZFwoJjqa|$IWjf&W8Ygz#~MCUzV*suUuV$d?#7ol2DV@RZY6!^lD%F^KYsg#*WPoj z`~JC_a-jXZHG=-w3O!ZYe(8%}#-{U+CO?X4>CXE*ZUooIet@8luEmj(cYfa($m!Wt zaGQXuAFjQ1U zPJk0|2{`W*;E$^Yf2Y6;f)hAC0*moj&+&QZo;d+dfD_;ZH~~(86W|0m0ZxDucrXNN z?-U4sr|@9-^Hn(kPJk2O1ULasfD_;ZH~~)Jze6DZ@FT)1gqwhi|9>|?;O&1+U{(A8 z_K)GTNKv12Pm7!e`BgX(clhQUY&~cqJI>19s;%_i_+dYf+TUTvg@)#z`1;q09Qxl16mNy@h;p+zc5$9lbH>zr{NHs@rJWqh{xq#-L`E<{#x#z{tqJIH>BANvN literal 0 HcmV?d00001 diff --git a/docs/savegame.ksy b/docs/savegame.ksy new file mode 100644 index 00000000..f08d5c22 --- /dev/null +++ b/docs/savegame.ksy @@ -0,0 +1,1014 @@ +meta: + id: savegame + title: Main Save Game File + application: LEGO Island + file-extension: gs + license: CC0-1.0 + endian: le +doc: | + Main save game file format for LEGO Island (1997). Stores complete game + progress including customization, mission scores, and world state. + + The file is located at `/G.GS` where slot is 0-9 and + save_path is typically the game's installation directory. + + File structure: + 1. Header (version, player ID, act, actor) + 2. Variables section (vehicle colors, background color, light position) + 3. Character manager data (66 actors) + 4. Plant manager data (81 plants) + 5. Building manager data (16 buildings) + 6. Game states (mission progress, scores, etc.) + 7. Previous area (for Act 2/3 saves) + +seq: + - id: version + type: s4 + doc: | + File format version. Must be 0x1000c (65548) for valid saves. + The game rejects files with mismatched versions. + - id: player_id + type: s2 + doc: Current player's unique ID from the player profile. + - id: current_act + type: u2 + enum: act + doc: Current game act (0 = Act 1, 1 = Act 2, 2 = Act 3). + - id: actor_id + type: u1 + enum: actor + doc: Currently selected playable character. + - id: variables + type: variable + repeat: until + repeat-until: _.is_end_marker + doc: | + Vehicle customization colors and game settings. Contains 43 color + variables, background color, light position, and ends with + "END_OF_VARIABLES" marker. + - id: characters + type: character_manager + doc: Character manager data for all 66 actors in the game. + - id: plants + type: plant_entry + repeat: expr + repeat-expr: 81 + doc: Plant manager data for all 81 plants in the game world. + - id: buildings + type: building_entry + repeat: expr + repeat-expr: 16 + doc: Building manager data for all 16 buildings in the game world. + - id: building_next_variant + type: u1 + doc: Next building variant to use (cycles through variants). + - id: state_count + type: s2 + doc: Number of serialized game states that follow. + - id: states + type: game_state + repeat: expr + repeat-expr: state_count + doc: Serialized game state objects (mission progress, scores, etc.). + - id: previous_area + type: s2 + doc: | + Previous area ID for Act 2/3 saves. Set to -1 (undefined) for Act 1. + Used to restore the player's location when loading a save. + +types: + variable: + doc: | + A named variable with a string value. Used for vehicle colors and + game settings. The "END_OF_VARIABLES" marker has no value. + seq: + - id: name_length + type: u1 + doc: Length of variable name in bytes. + - id: name + type: str + size: name_length + encoding: ASCII + doc: Variable name (e.g., "c_dbbkfny0", "backgroundcolor"). + - id: value_length + type: u1 + if: not is_end_marker + doc: Length of variable value in bytes. + - id: value + type: str + size: value_length + encoding: ASCII + if: not is_end_marker + doc: | + Variable value. For colors this is a color name like "lego red". + For backgroundcolor this is "set R G B". + For lightposition this is a number "1" or "2". + instances: + is_end_marker: + value: name == "END_OF_VARIABLES" + doc: True if this is the end-of-variables marker. + + character_manager: + doc: | + All 66 character entries in the game, in the order defined by g_actorInfoInit. + Each entry is 16 bytes, for a total of 1056 bytes. + seq: + - id: pepper + type: pepper_character_entry + doc: Pepper Roni + - id: mama + type: standard_character_entry + doc: Mama Brickolini + - id: papa + type: standard_character_entry + doc: Papa Brickolini + - id: nick + type: standard_character_entry + doc: Nick Brick + - id: laura + type: standard_character_entry + doc: Laura Brick + - id: infoman + type: infoman_character_entry + doc: Infomaniac + - id: brickstr + type: standard_character_entry + doc: Brickster + - id: studs + type: standard_character_entry + doc: Studs Linkin + - id: rhoda + type: standard_character_entry + doc: Rhoda Hogg + - id: valerie + type: standard_character_entry + doc: Valerie Stubbins + - id: snap + type: standard_character_entry + doc: Snap Lockitt + - id: pt + type: standard_character_entry + - id: mg + type: standard_character_entry + doc: Margaret Patricia "Maggie" Post + - id: bu + type: standard_character_entry + - id: ml + type: standard_character_entry + - id: nu + type: standard_character_entry + - id: na + type: standard_character_entry + doc: Nancy Nubbins + - id: cl + type: standard_character_entry + - id: en + type: standard_character_entry + - id: re + type: standard_character_entry + - id: ro + type: standard_character_entry + - id: d1 + type: standard_character_entry + - id: d2 + type: standard_character_entry + - id: d3 + type: standard_character_entry + - id: d4 + type: standard_character_entry + - id: l1 + type: standard_character_entry + - id: l2 + type: standard_character_entry + - id: l3 + type: standard_character_entry + - id: l4 + type: standard_character_entry + - id: l5 + type: standard_character_entry + - id: l6 + type: standard_character_entry + - id: b1 + type: standard_character_entry + - id: b2 + type: standard_character_entry + - id: b3 + type: standard_character_entry + - id: b4 + type: standard_character_entry + - id: cm + type: standard_character_entry + - id: gd + type: standard_character_entry + - id: rd + type: standard_character_entry + - id: pg + type: standard_character_entry + doc: Polly Gone + - id: bd + type: standard_character_entry + - id: sy + type: standard_character_entry + - id: gn + type: standard_character_entry + - id: df + type: standard_character_entry + - id: bs + type: standard_character_entry + - id: lt + type: standard_character_entry + - id: st + type: standard_character_entry + - id: bm + type: standard_character_entry + - id: jk + type: standard_character_entry + - id: ghost + type: ghost_character_entry + - id: ghost01 + type: ghost_character_entry + - id: ghost02 + type: ghost_character_entry + - id: ghost03 + type: ghost_character_entry + - id: ghost04 + type: ghost_character_entry + - id: ghost05 + type: ghost_character_entry + - id: hg + type: standard_character_entry + - id: pntgy + type: standard_character_entry + - id: pep + type: pepper_character_entry + - id: cop01 + type: standard_character_entry + - id: actor_01 + type: standard_character_entry + - id: actor_02 + type: standard_character_entry + - id: actor_03 + type: standard_character_entry + - id: actor_04 + type: standard_character_entry + - id: actor_05 + type: standard_character_entry + - id: btmncycl + type: standard_character_entry + - id: cboycycl + type: standard_character_entry + - id: boatman + type: standard_character_entry + + standard_character_entry: + doc: | + Character customization and state for actors using the standard hat parts + (g_hatPartIndices). Hat index 0-19 maps directly to hat_part enum. + Total size is 16 bytes. + seq: + - id: sound + type: s4 + doc: Sound/voice variant index. + - id: move + type: s4 + doc: Movement/animation variant index. + - id: mood + type: u1 + doc: Character mood state. + - id: hat_part_name_index + type: u1 + enum: standard_hat + doc: Index into standard hat parts (0-19 = standard hats). + - id: hat_name_index + type: u1 + enum: lego_color + doc: Hat color. + - id: infogron_name_index + type: u1 + enum: lego_color + doc: Torso (infogron) color. + - id: armlft_name_index + type: u1 + enum: lego_color + doc: Left arm color. + - id: armrt_name_index + type: u1 + enum: lego_color + doc: Right arm color. + - id: leglft_name_index + type: u1 + enum: lego_color + doc: Left leg color. + - id: legrt_name_index + type: u1 + enum: lego_color + doc: Right leg color. + + pepper_character_entry: + doc: | + Character customization and state for Pepper (uses g_pepperHatPartIndices). + Hat index 0=phat, 1-20 map to standard hats 0-19. + Total size is 16 bytes. + seq: + - id: sound + type: s4 + doc: Sound/voice variant index. + - id: move + type: s4 + doc: Movement/animation variant index. + - id: mood + type: u1 + doc: Character mood state. + - id: hat_part_name_index + type: u1 + enum: pepper_hat + doc: Index into Pepper's hat parts (0=phat, 1-20=standard hats 0-19). + - id: hat_name_index + type: u1 + enum: lego_color + doc: Hat color. + - id: infogron_name_index + type: u1 + enum: lego_color + doc: Torso (infogron) color. + - id: armlft_name_index + type: u1 + enum: lego_color + doc: Left arm color. + - id: armrt_name_index + type: u1 + enum: lego_color + doc: Right arm color. + - id: leglft_name_index + type: u1 + enum: lego_color + doc: Left leg color. + - id: legrt_name_index + type: u1 + enum: lego_color + doc: Right leg color. + + infoman_character_entry: + doc: | + Character customization and state for Infoman (uses g_infomanHatPartIndices). + Hat index 0=icap (only option). + Total size is 16 bytes. + seq: + - id: sound + type: s4 + doc: Sound/voice variant index. + - id: move + type: s4 + doc: Movement/animation variant index. + - id: mood + type: u1 + doc: Character mood state. + - id: hat_part_name_index + type: u1 + enum: infoman_hat_index + doc: Index into Infoman's hat parts (0=icap only). + - id: hat_name_index + type: u1 + enum: lego_color + doc: Hat color. + - id: infogron_name_index + type: u1 + enum: lego_color + doc: Torso (infogron) color. + - id: armlft_name_index + type: u1 + enum: lego_color + doc: Left arm color. + - id: armrt_name_index + type: u1 + enum: lego_color + doc: Right arm color. + - id: leglft_name_index + type: u1 + enum: lego_color + doc: Left leg color. + - id: legrt_name_index + type: u1 + enum: lego_color + doc: Right leg color. + + ghost_character_entry: + doc: | + Character customization and state for ghosts (uses g_ghostHatPartIndices). + Hat index 0=sheet (only option). + Total size is 16 bytes. + seq: + - id: sound + type: s4 + doc: Sound/voice variant index. + - id: move + type: s4 + doc: Movement/animation variant index. + - id: mood + type: u1 + doc: Character mood state. + - id: hat_part_name_index + type: u1 + enum: ghost_hat_index + doc: Index into ghost hat parts (0=sheet only). + - id: hat_name_index + type: u1 + enum: lego_color + doc: Hat color. + - id: infogron_name_index + type: u1 + enum: lego_color + doc: Torso (infogron) color. + - id: armlft_name_index + type: u1 + enum: lego_color + doc: Left arm color. + - id: armrt_name_index + type: u1 + enum: lego_color + doc: Right arm color. + - id: leglft_name_index + type: u1 + enum: lego_color + doc: Left leg color. + - id: legrt_name_index + type: u1 + enum: lego_color + doc: Right leg color. + + plant_entry: + doc: | + Plant state data for a single plant in the game world. + Total size is 12 bytes per plant. + seq: + - id: variant + type: u1 + enum: plant_variant + doc: Plant type (flower, tree, bush, palm). + - id: sound + type: u4 + doc: Sound effect index when interacting. + - id: move + type: u4 + doc: Movement/animation state. + - id: mood + type: u1 + doc: Plant mood/state value. + - id: color + type: u1 + enum: plant_color + doc: Plant color variant. + - id: counter + type: s1 + doc: | + Growth/interaction counter. Affects plant height. + This is used in Act 2/3. + + building_entry: + doc: | + Building state data for a single building in the game world. + Total size is 10 bytes per building. + seq: + - id: sound + type: u4 + doc: Sound effect index. + - id: move + type: u4 + doc: Movement/animation state. + - id: mood + type: u1 + doc: Building mood/state value. + - id: counter + type: s1 + doc: | + Interaction counter. Affects building height adjustment. + This is used in Act 2/3. + + game_state: + doc: | + A serialized game state object. The name determines the type and + format of the data that follows. + seq: + - id: name_length + type: s2 + doc: Length of state class name. + - id: name + type: str + size: name_length + encoding: ASCII + doc: | + State class name (e.g., "Act1State", "PizzeriaState"). + Determines the format of the following data. + - id: data + type: + switch-on: name + cases: + '"PizzeriaState"': pizzeria_state_data + '"PizzaMissionState"': pizza_mission_state_data + '"TowTrackMissionState"': score_mission_state_data + '"AmbulanceMissionState"': score_mission_state_data + '"HospitalState"': hospital_state_data + '"GasStationState"': gas_station_state_data + '"PoliceState"': police_state_data + '"JetskiRaceState"': race_state_data + '"CarRaceState"': race_state_data + '"LegoJetskiBuildState"': vehicle_build_state_data + '"LegoCopterBuildState"': vehicle_build_state_data + '"LegoDuneCarBuildState"': vehicle_build_state_data + '"LegoRaceCarBuildState"': vehicle_build_state_data + '"AnimState"': anim_state_data + '"Act1State"': act1_state_data + doc: State-specific data. Format depends on state class name. + + pizzeria_state_data: + doc: | + Pizzeria state tracking playlist indices for each actor. + Total size is 10 bytes (5 x S16). + seq: + - id: pepper_playlist_index + type: s2 + doc: Pepper's next playlist index. + - id: mama_playlist_index + type: s2 + doc: Mama's next playlist index. + - id: papa_playlist_index + type: s2 + doc: Papa's next playlist index. + - id: nick_playlist_index + type: s2 + doc: Nick's next playlist index. + - id: laura_playlist_index + type: s2 + doc: Laura's next playlist index. + + pizza_mission_state_data: + doc: | + Pizza delivery mission state for all 5 actors. + Total size is 40 bytes (5 missions x 4 x S16). + seq: + - id: pepper + type: pizza_mission_entry + doc: Pepper's pizza delivery mission data. + - id: mama + type: pizza_mission_entry + doc: Mama's pizza delivery mission data. + - id: papa + type: pizza_mission_entry + doc: Papa's pizza delivery mission data. + - id: nick + type: pizza_mission_entry + doc: Nick's pizza delivery mission data. + - id: laura + type: pizza_mission_entry + doc: Laura's pizza delivery mission data. + + pizza_mission_entry: + doc: Single actor's pizza mission data (8 bytes). + seq: + - id: unk0x06 + type: s2 + doc: Unknown field at offset 0x06. + - id: counter + type: s2 + doc: Mission attempt counter. + - id: score + type: s2 + enum: score_color + doc: Current/last mission score. + - id: hi_score + type: s2 + enum: score_color + doc: High score for this mission. + + score_mission_state_data: + doc: | + Mission state with scores and high scores for all 5 actors. + Used by TowTrackMissionState and AmbulanceMissionState. + Total size is 20 bytes (10 x S16). + seq: + - id: pepper_score + type: s2 + enum: score_color + doc: Pepper's current/last score. + - id: mama_score + type: s2 + enum: score_color + doc: Mama's current/last score. + - id: papa_score + type: s2 + enum: score_color + doc: Papa's current/last score. + - id: nick_score + type: s2 + enum: score_color + doc: Nick's current/last score. + - id: laura_score + type: s2 + enum: score_color + doc: Laura's current/last score. + - id: pepper_high_score + type: s2 + enum: score_color + doc: Pepper's high score. + - id: mama_high_score + type: s2 + enum: score_color + doc: Mama's high score. + - id: papa_high_score + type: s2 + enum: score_color + doc: Papa's high score. + - id: nick_high_score + type: s2 + enum: score_color + doc: Nick's high score. + - id: laura_high_score + type: s2 + enum: score_color + doc: Laura's high score. + + hospital_state_data: + doc: | + Hospital interaction state for all actors. + Total size is 12 bytes (6 x S16). + seq: + - id: state_actor + type: s2 + doc: Current actor state. + - id: state_pepper + type: s2 + doc: Pepper's hospital interaction state. + - id: state_mama + type: s2 + doc: Mama's hospital interaction state. + - id: state_papa + type: s2 + doc: Papa's hospital interaction state. + - id: state_nick + type: s2 + doc: Nick's hospital interaction state. + - id: state_laura + type: s2 + doc: Laura's hospital interaction state. + + gas_station_state_data: + doc: | + Gas station interaction state for all actors. + Total size is 10 bytes (5 x S16). + seq: + - id: pepper_action + type: s2 + doc: Pepper's gas station action state. + - id: mama_action + type: s2 + doc: Mama's gas station action state. + - id: papa_action + type: s2 + doc: Papa's gas station action state. + - id: nick_action + type: s2 + doc: Nick's gas station action state. + - id: laura_action + type: s2 + doc: Laura's gas station action state. + + police_state_data: + doc: | + Police station state. Stores the police script ID. + Total size is 4 bytes (1 x S32). + seq: + - id: police_script + type: s4 + doc: Current police script/animation ID. + + race_state_data: + doc: | + Race state with scores for all 5 actors. + Used by JetskiRaceState and CarRaceState. + Total size is 25 bytes (5 entries x 5 bytes). + seq: + - id: pepper + type: race_entry + doc: Pepper's race scores. + - id: mama + type: race_entry + doc: Mama's race scores. + - id: papa + type: race_entry + doc: Papa's race scores. + - id: nick + type: race_entry + doc: Nick's race scores. + - id: laura + type: race_entry + doc: Laura's race scores. + + race_entry: + doc: Single actor's race score entry (5 bytes). + seq: + - id: id + type: u1 + enum: actor + doc: Actor ID. + - id: last_score + type: s2 + enum: score_color + doc: Score from last race. + - id: high_score + type: s2 + enum: score_color + doc: Best score (high score). + + vehicle_build_state_data: + doc: | + Vehicle build state tracking build progress. + Used by LegoJetskiBuildState, LegoCopterBuildState, + LegoDuneCarBuildState, and LegoRaceCarBuildState. + Total size is 4 bytes (4 x U8). + seq: + - id: introduction_counter + type: u1 + doc: Number of times intro has been shown. + - id: finished_build + type: u1 + doc: Whether vehicle build was completed (0/1). + - id: played_exit_script + type: u1 + doc: Whether exit animation has played (0/1). + - id: placed_part_count + type: u1 + doc: Number of parts placed during current build. + + anim_state_data: + doc: | + Animation manager state. Contains extra character ID and + two variable-length arrays for tracking animation states. + seq: + - id: extra_character_id + type: u4 + doc: Extra character ID. + - id: anim_count + type: u4 + doc: Number of animation entries in first array. + - id: anim_indices + type: u2 + repeat: expr + repeat-expr: anim_count + doc: Animation index values. + - id: location_flags_count + type: u4 + doc: Number of location flag entries. + - id: location_flags + type: u1 + repeat: expr + repeat-expr: location_flags_count + doc: Location flags for animation positions. + + act1_state_data: + doc: | + Act 1 state containing named plane data and textures. + Always contains exactly 7 named planes (for each vehicle type), + followed by conditional textures based on which planes have names, + and two final fields. + seq: + - id: motocycle_plane + type: named_plane + doc: Motorcycle spawn plane. + - id: bike_plane + type: named_plane + doc: Bike spawn plane. + - id: skateboard_plane + type: named_plane + doc: Skateboard spawn plane. + - id: helicopter_plane + type: named_plane + doc: Helicopter spawn plane. + - id: jetski_plane + type: named_plane + doc: Jetski spawn plane. + - id: dunebuggy_plane + type: named_plane + doc: Dune buggy spawn plane. + - id: racecar_plane + type: named_plane + doc: Racecar spawn plane. + - id: helicopter_textures + type: act1_texture + repeat: expr + repeat-expr: 3 + if: helicopter_plane.name_length > 0 + doc: Helicopter textures (windshield, left jet, right jet). + - id: jetski_textures + type: act1_texture + repeat: expr + repeat-expr: 2 + if: jetski_plane.name_length > 0 + doc: Jetski textures (front, windshield). + - id: dunebuggy_texture + type: act1_texture + if: dunebuggy_plane.name_length > 0 + doc: Dune buggy front texture. + - id: racecar_textures + type: act1_texture + repeat: expr + repeat-expr: 3 + if: racecar_plane.name_length > 0 + doc: Racecar textures (front, back, tail). + - id: cpt_click_dialogue_next_index + type: s2 + doc: Next dialogue index for Captain Click. + - id: played_exit_explanation + type: u1 + doc: Whether exit explanation has been played (0/1). + + act1_texture: + doc: | + A texture used for customizable surfaces in Act 1. + Contains filename and LegoImage bitmap data. + seq: + - id: name_length + type: s2 + doc: Length of texture filename. + - id: name + type: str + size: name_length + encoding: ASCII + doc: Texture filename (e.g., "chwind.gif"). + - id: width + type: u4 + doc: Image width in pixels. + - id: height + type: u4 + doc: Image height in pixels. + - id: palette_count + type: u4 + doc: Number of palette entries. + - id: palette + type: palette_entry + repeat: expr + repeat-expr: palette_count + doc: Palette entries (RGB values). + - id: bitmap_data + size: width * height + doc: Raw pixel data (1 byte per pixel, indexed). + + palette_entry: + doc: A single RGB palette entry. + seq: + - id: red + type: u1 + doc: Red component (0-255). + - id: green + type: u1 + doc: Green component (0-255). + - id: blue + type: u1 + doc: Blue component (0-255). + + named_plane: + doc: | + A named plane used for actor positioning in Act 1. + Total size is variable: 2 + name_length + 36 bytes. + seq: + - id: name_length + type: s2 + doc: Length of plane name (S16 format like other strings). + - id: name + type: str + size: name_length + encoding: ASCII + doc: Plane name identifier (e.g., "INT43", "EDG02_51"). + - id: position + type: f4 + repeat: expr + repeat-expr: 3 + doc: Position vector (X, Y, Z). + - id: direction + type: f4 + repeat: expr + repeat-expr: 3 + doc: Direction/forward vector (X, Y, Z). + - id: up + type: f4 + repeat: expr + repeat-expr: 3 + doc: Up vector (X, Y, Z). + +enums: + act: + 0: act1 + 1: act2 + 2: act3 + + actor: + 0: none + 1: pepper + 2: mama + 3: papa + 4: nick + 5: laura + + plant_variant: + 0: flower + 1: tree + 2: bush + 3: palm + + plant_color: + 0: white + 1: black + 2: yellow + 3: red + 4: green + + lego_color: + 0: white + 1: black + 2: yellow + 3: red + 4: blue + 5: brown + 6: lt_grey + 7: green + + hat_part: + 0: baseball + 1: chef + 2: cap + 3: cophat + 4: helmet + 5: ponytail + 6: pageboy + 7: shrthair + 8: bald + 9: flower + 10: cboyhat + 11: cuphat + 12: cathat + 13: backbcap + 14: pizhat + 15: caprc + 16: capch + 17: capdb + 18: capjs + 19: capmd + 20: sheet + 21: phat + 22: icap + + standard_hat: + 0: baseball + 1: chef + 2: cap + 3: cophat + 4: helmet + 5: ponytail + 6: pageboy + 7: shrthair + 8: bald + 9: flower + 10: cboyhat + 11: cuphat + 12: cathat + 13: backbcap + 14: pizhat + 15: caprc + 16: capch + 17: capdb + 18: capjs + 19: capmd + + pepper_hat: + 0: phat + 1: baseball + 2: chef + 3: cap + 4: cophat + 5: helmet + 6: ponytail + 7: pageboy + 8: shrthair + 9: bald + 10: flower + 11: cboyhat + 12: cuphat + 13: cathat + 14: backbcap + 15: pizhat + 16: caprc + 17: capch + 18: capdb + 19: capjs + 20: capmd + + infoman_hat_index: + 0: icap + + ghost_hat_index: + 0: sheet + + score_color: + 0: grey + 1: yellow + 2: blue + 3: red From 812202f6508222e4c752be83105fbbd8911ac675 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Sun, 11 Jan 2026 17:59:46 +0100 Subject: [PATCH 05/23] Clear unknowns in `Doors` (#1714) --- LEGO1/lego/legoomni/include/doors.h | 24 ++++--- LEGO1/lego/legoomni/src/actors/doors.cpp | 84 ++++++++++++------------ 2 files changed, 57 insertions(+), 51 deletions(-) diff --git a/LEGO1/lego/legoomni/include/doors.h b/LEGO1/lego/legoomni/include/doors.h index 5aad2dba..6f65de7f 100644 --- a/LEGO1/lego/legoomni/include/doors.h +++ b/LEGO1/lego/legoomni/include/doors.h @@ -10,7 +10,7 @@ class LegoROI; // SIZE 0x1f8 class Doors : public LegoPathActor { public: - Doors() : m_unk0x154(0), m_ltDoor(NULL), m_rtDoor(NULL), m_unk0x1f4(0) {} + Doors() : m_state(0), m_ltDoor(NULL), m_rtDoor(NULL), m_angle(0) {} // FUNCTION: LEGO1 0x1000e430 // FUNCTION: BETA10 0x100a7f20 @@ -29,19 +29,25 @@ class Doors : public LegoPathActor { void ParseAction(char* p_extra) override; // vtable+0x20 void Animate(float p_time) override; // vtable+0x70 MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 - virtual MxFloat VTable0xcc(float p_time); // vtable+0xcc + virtual MxFloat CalculateAngle(float p_time); // vtable+0xcc // SYNTHETIC: LEGO1 0x1000e580 // Doors::`scalar deleting destructor' private: - undefined4 m_unk0x154; // 0x154 - MxFloat m_unk0x158; // 0x158 - LegoROI* m_ltDoor; // 0x15c - LegoROI* m_rtDoor; // 0x160 - MxMatrix m_ltDoorLocal; // 0x164 - MxMatrix m_rtDoorLocal; // 0x1ac - MxFloat m_unk0x1f4; // 0x1f4 + enum { + e_none = 0, + e_closed = 1, + e_cycling = 2, + }; + + undefined4 m_state; // 0x154 + MxFloat m_hitTime; // 0x158 + LegoROI* m_ltDoor; // 0x15c + LegoROI* m_rtDoor; // 0x160 + MxMatrix m_ltDoorOriginalLocal; // 0x164 + MxMatrix m_rtDoorOriginalLocal; // 0x1ac + MxFloat m_angle; // 0x1f4 }; #endif // DOORS_H diff --git a/LEGO1/lego/legoomni/src/actors/doors.cpp b/LEGO1/lego/legoomni/src/actors/doors.cpp index 8fff7290..2b8da804 100644 --- a/LEGO1/lego/legoomni/src/actors/doors.cpp +++ b/LEGO1/lego/legoomni/src/actors/doors.cpp @@ -12,15 +12,15 @@ DECOMP_SIZE_ASSERT(Doors, 0x1f8) // GLOBAL: LEGO1 0x100d8e7c // GLOBAL: BETA10 0x101b954c -MxFloat g_unk0x100d8e7c = 1000.0f; +MxFloat g_timeMoving = 1000.0f; // GLOBAL: LEGO1 0x100d8e80 // GLOBAL: BETA10 0x101b9550 -MxFloat g_unk0x100d8e80 = 4000.0f; +MxFloat g_timeOpened = 4000.0f; // GLOBAL: LEGO1 0x100d8e84 // GLOBAL: BETA10 0x101b9554 -MxFloat g_unk0x100d8e84 = 6000.0f; +MxFloat g_totalTime = 6000.0f; // = g_timeMoving + g_totalTime + g_timeMoving // FUNCTION: LEGO1 0x10066100 // FUNCTION: BETA10 0x10026850 @@ -28,36 +28,36 @@ MxResult Doors::HitActor(LegoPathActor* p_actor, MxBool p_bool) { assert(m_ltDoor && m_rtDoor); - if (m_unk0x154 == 1) { - m_unk0x154 = 2; - m_unk0x158 = Timer()->GetTime(); - m_ltDoorLocal = m_ltDoor->GetLocal2World(); - m_rtDoorLocal = m_rtDoor->GetLocal2World(); + if (m_state == e_closed) { + m_state = e_cycling; + m_hitTime = Timer()->GetTime(); + m_ltDoorOriginalLocal = m_ltDoor->GetLocal2World(); + m_rtDoorOriginalLocal = m_rtDoor->GetLocal2World(); } - return m_unk0x1f4 < 0.001 ? SUCCESS : FAILURE; + return m_angle < 0.001 ? SUCCESS : FAILURE; } // FUNCTION: LEGO1 0x10066190 // FUNCTION: BETA10 0x1002696b -MxFloat Doors::VTable0xcc(float p_time) +MxFloat Doors::CalculateAngle(float p_time) { - MxFloat fVar1; + MxFloat timeSinceHit; - fVar1 = p_time - m_unk0x158; + timeSinceHit = p_time - m_hitTime; - if (fVar1 <= 0.0f) { + if (timeSinceHit <= 0.0f) { return 0.0f; } - if (fVar1 <= g_unk0x100d8e7c) { - return fVar1 * 1.570796 / g_unk0x100d8e7c; + if (timeSinceHit <= g_timeMoving) { + return timeSinceHit * 1.570796 / g_timeMoving; } - else if (fVar1 <= g_unk0x100d8e7c + g_unk0x100d8e80) { + else if (timeSinceHit <= g_timeMoving + g_timeOpened) { return 1.570796012878418; // Pi / 2 } - else if (fVar1 <= g_unk0x100d8e84) { - return (1.0 - ((fVar1 - g_unk0x100d8e80) - g_unk0x100d8e7c) / g_unk0x100d8e7c) * 1.570796; + else if (timeSinceHit <= g_totalTime) { + return (1.0 - ((timeSinceHit - g_timeOpened) - g_timeMoving) / g_timeMoving) * 1.570796; } return 0.0f; @@ -72,44 +72,44 @@ void Doors::Animate(float p_time) // TODO: Match m_roi->SetVisibility(m_boundary->GetFlag0x10()); - switch (m_unk0x154) { - case 0: - m_unk0x154 = 1; + switch (m_state) { + case e_none: + m_state = e_closed; m_actorState = c_initial; break; - case 1: + case e_closed: break; - case 2: - float local8 = VTable0xcc(p_time); + case e_cycling: + float angle = CalculateAngle(p_time); - if (local8 > 0.0f) { - MxMatrix local58(m_ltDoorLocal); - Vector3 local10(local58[3]); + if (angle > 0.0f) { + MxMatrix transform(m_ltDoorOriginalLocal); + Vector3 position(transform[3]); - local10.Clear(); - local58.RotateY(-local8); - local10 = m_ltDoorLocal[3]; - m_ltDoor->SetLocal2World(local58); + position.Clear(); + transform.RotateY(-angle); + position = m_ltDoorOriginalLocal[3]; + m_ltDoor->SetLocal2World(transform); m_ltDoor->WrappedUpdateWorldData(); - local58 = m_rtDoorLocal; - local10.Clear(); - local58.RotateY(local8); - local10 = m_rtDoorLocal[3]; - m_rtDoor->SetLocal2World(local58); + transform = m_rtDoorOriginalLocal; + position.Clear(); + transform.RotateY(angle); + position = m_rtDoorOriginalLocal[3]; + m_rtDoor->SetLocal2World(transform); m_rtDoor->WrappedUpdateWorldData(); - m_unk0x1f4 = local8; + m_angle = angle; } - if (m_unk0x158 + g_unk0x100d8e84 < p_time) { - m_ltDoor->SetLocal2World(m_ltDoorLocal); - m_rtDoor->SetLocal2World(m_rtDoorLocal); + if (m_hitTime + g_totalTime < p_time) { + m_ltDoor->SetLocal2World(m_ltDoorOriginalLocal); + m_rtDoor->SetLocal2World(m_rtDoorOriginalLocal); m_ltDoor->WrappedUpdateWorldData(); m_rtDoor->WrappedUpdateWorldData(); - m_unk0x154 = 1; + m_state = e_closed; m_actorState = c_initial; - m_unk0x1f4 = 0; + m_angle = 0; } } } From ea61077c1ba8b02d1edf7791c80b6634c4085b0a Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Mon, 12 Jan 2026 02:49:16 +0100 Subject: [PATCH 06/23] Clear unknowns in `Act3Ammo` (#1715) --- LEGO1/lego/legoomni/include/act3ammo.h | 40 ++-- LEGO1/lego/legoomni/src/actors/act3ammo.cpp | 215 ++++++++++---------- LEGO1/lego/legoomni/src/worlds/act3.cpp | 24 +-- 3 files changed, 140 insertions(+), 139 deletions(-) diff --git a/LEGO1/lego/legoomni/include/act3ammo.h b/LEGO1/lego/legoomni/include/act3ammo.h index e80aa6b0..60129a53 100644 --- a/LEGO1/lego/legoomni/include/act3ammo.h +++ b/LEGO1/lego/legoomni/include/act3ammo.h @@ -14,7 +14,7 @@ class Act3Ammo : public LegoPathActor { c_pizza = 0x01, c_donut = 0x02, c_valid = 0x04, - c_bit4 = 0x08, + c_withoutBoundary = 0x08, c_sharkFood = 0x10 }; @@ -28,10 +28,10 @@ class Act3Ammo : public LegoPathActor { MxU32 IsValid() { return m_ammoFlag & c_valid; } // FUNCTION: BETA10 0x100177b0 - Mx3DPointFloat* GetUnknown0x160() { return m_eq; } + Mx3DPointFloat* GetCoefficients() { return m_coefficients; } // FUNCTION: BETA10 0x100177e0 - MxFloat* GetUnknown0x19c() { return &m_unk0x19c; } + MxFloat* GetApexParameter() { return &m_apexParameter; } // FUNCTION: BETA10 0x1001fbd0 void SetValid(MxBool p_valid) @@ -51,18 +51,18 @@ class Act3Ammo : public LegoPathActor { MxU32 IsDonut() { return m_ammoFlag & c_donut; } // FUNCTION: BETA10 0x1001fcb0 - void SetBit4(MxBool p_bit4) + void SetShootWithoutBoundary(MxBool p_withoutBoundary) { - if (p_bit4) { - m_ammoFlag |= c_bit4; + if (p_withoutBoundary) { + m_ammoFlag |= c_withoutBoundary; } else { - m_ammoFlag &= ~c_bit4; + m_ammoFlag &= ~c_withoutBoundary; } } // FUNCTION: BETA10 0x10021d90 - MxU32 IsBit4() { return m_ammoFlag & c_bit4; } + MxU32 IsShootWithoutBoundary() { return m_ammoFlag & c_withoutBoundary; } void SetSharkFood(MxBool p_sharkFood) { @@ -76,29 +76,29 @@ class Act3Ammo : public LegoPathActor { MxU32 IsSharkFood() { return m_ammoFlag & c_sharkFood; } - MxFloat GetUnknown0x158() { return m_unk0x158; } + MxFloat GetRotateTimeout() { return m_rotateTimeout; } - void SetUnknown0x158(MxFloat p_unk0x158) { m_unk0x158 = p_unk0x158; } + void SetRotateTimeout(MxFloat p_rotateTimeout) { m_rotateTimeout = p_rotateTimeout; } MxResult Remove(); MxResult Create(Act3* p_world, MxU32 p_isPizza, MxS32 p_index); - MxResult FUN_10053b40(const Vector3& p_srcLoc, const Vector3& p_srcDir, const Vector3& p_srcUp); - MxResult FUN_10053cb0(LegoPathController* p_p, LegoPathBoundary* p_boundary, MxFloat p_unk0x19c); - MxResult FUN_10053d30(LegoPathController* p_p, MxFloat p_unk0x19c); + MxResult CalculateArc(const Vector3& p_srcLoc, const Vector3& p_srcDir, const Vector3& p_srcUp); + MxResult Shoot(LegoPathController* p_p, LegoPathBoundary* p_boundary, MxFloat p_apexParameter); + MxResult Shoot(LegoPathController* p_p, MxFloat p_apexParameter); // SYNTHETIC: LEGO1 0x10053880 // Act3Ammo::`scalar deleting destructor' private: - MxResult FUN_10053db0(float p_param1, Matrix4& p_param2); + MxResult CalculateTransform(float p_curveParameter, Matrix4& p_transform); - static Mx3DPointFloat g_unk0x10104f08; + static Mx3DPointFloat g_hitTranslation; - MxU16 m_ammoFlag; // 0x154 - MxFloat m_unk0x158; // 0x158 - Act3* m_world; // 0x15c - Mx3DPointFloat m_eq[3]; // 0x160 - MxFloat m_unk0x19c; // 0x19c + MxU16 m_ammoFlag; // 0x154 + MxFloat m_rotateTimeout; // 0x158 + Act3* m_world; // 0x15c + Mx3DPointFloat m_coefficients[3]; // 0x160 + MxFloat m_apexParameter; // 0x19c }; #endif // ACT3AMMO_H diff --git a/LEGO1/lego/legoomni/src/actors/act3ammo.cpp b/LEGO1/lego/legoomni/src/actors/act3ammo.cpp index 4ab1a27b..98980d2c 100644 --- a/LEGO1/lego/legoomni/src/actors/act3ammo.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3ammo.cpp @@ -17,7 +17,7 @@ DECOMP_SIZE_ASSERT(Act3Ammo, 0x1a0) // Initialized at LEGO1 0x100537c0 // GLOBAL: LEGO1 0x10104f08 -Mx3DPointFloat Act3Ammo::g_unk0x10104f08 = Mx3DPointFloat(0.0, 5.0, 0.0); +Mx3DPointFloat Act3Ammo::g_hitTranslation = Mx3DPointFloat(0.0, 5.0, 0.0); // FUNCTION: LEGO1 0x100537f0 // FUNCTION: BETA10 0x1001d648 @@ -111,43 +111,44 @@ MxResult Act3Ammo::Create(Act3* p_world, MxU32 p_isPizza, MxS32 p_index) // FUNCTION: LEGO1 0x10053b40 // FUNCTION: BETA10 0x1001db2a -MxResult Act3Ammo::FUN_10053b40(const Vector3& p_srcLoc, const Vector3& p_srcDir, const Vector3& p_srcUp) +MxResult Act3Ammo::CalculateArc(const Vector3& p_srcLoc, const Vector3& p_srcDir, const Vector3& p_srcUp) { assert(p_srcDir[1] != 0); - MxFloat local1c = -(p_srcLoc[1] / p_srcDir[1]); - Mx3DPointFloat local18(p_srcDir); - Mx3DPointFloat local34; + MxFloat yRatioLocDir = -(p_srcLoc[1] / p_srcDir[1]); + Mx3DPointFloat groundPoint(p_srcDir); + Mx3DPointFloat negNormalUp; - local18 *= local1c; - local18 += p_srcLoc; + groundPoint *= yRatioLocDir; + groundPoint += p_srcLoc; - local34[0] = local34[2] = 0.0f; - local34[1] = -1.0f; + negNormalUp[0] = negNormalUp[2] = 0.0f; + negNormalUp[1] = -1.0f; - m_eq[1] = p_srcUp; - m_eq[2] = p_srcLoc; + m_coefficients[1] = p_srcUp; + m_coefficients[2] = p_srcLoc; - Mx3DPointFloat local48(local34); - local48 -= m_eq[1]; + Mx3DPointFloat upRelative(negNormalUp); + upRelative -= m_coefficients[1]; for (MxS32 i = 0; i < 3; i++) { - if (local18[0] == p_srcLoc[0]) { + if (groundPoint[0] == p_srcLoc[0]) { return FAILURE; } - m_eq[0][i] = (local48[i] * local48[i] + local48[i] * m_eq[1][i] * 2.0f) / ((local18[i] - p_srcLoc[i]) * 4.0f); + m_coefficients[0][i] = (upRelative[i] * upRelative[i] + upRelative[i] * m_coefficients[1][i] * 2.0f) / + ((groundPoint[i] - p_srcLoc[i]) * 4.0f); } - assert(m_eq[0][0] > 0.000001 || m_eq[0][0] < -0.000001); + assert(m_coefficients[0][0] > 0.000001 || m_coefficients[0][0] < -0.000001); - m_unk0x19c = local48[0] / (m_eq[0][0] * 2.0f); + m_apexParameter = upRelative[0] / (m_coefficients[0][0] * 2.0f); return SUCCESS; } // FUNCTION: LEGO1 0x10053cb0 // FUNCTION: BETA10 0x1001ddf4 -MxResult Act3Ammo::FUN_10053cb0(LegoPathController* p_p, LegoPathBoundary* p_boundary, MxFloat p_unk0x19c) +MxResult Act3Ammo::Shoot(LegoPathController* p_p, LegoPathBoundary* p_boundary, MxFloat p_apexParameter) { assert(p_p); assert(IsValid()); @@ -164,7 +165,7 @@ MxResult Act3Ammo::FUN_10053cb0(LegoPathController* p_p, LegoPathBoundary* p_bou m_pathController = p_p; m_boundary = p_boundary; m_BADuration = 10000.0f; - m_unk0x19c = p_unk0x19c; + m_apexParameter = p_apexParameter; m_unk0x7c = 0.0f; m_lastTime = -1.0f; m_actorState = c_one; @@ -173,12 +174,12 @@ MxResult Act3Ammo::FUN_10053cb0(LegoPathController* p_p, LegoPathBoundary* p_bou // FUNCTION: LEGO1 0x10053d30 // FUNCTION: BETA10 0x1001df73 -MxResult Act3Ammo::FUN_10053d30(LegoPathController* p_p, MxFloat p_unk0x19c) +MxResult Act3Ammo::Shoot(LegoPathController* p_p, MxFloat p_apexParameter) { assert(p_p); assert(IsValid()); - SetBit4(TRUE); + SetShootWithoutBoundary(TRUE); if (IsPizza()) { assert(SoundManager()->GetCacheSoundManager()); @@ -191,7 +192,7 @@ MxResult Act3Ammo::FUN_10053d30(LegoPathController* p_p, MxFloat p_unk0x19c) m_pathController = p_p; m_BADuration = 10000.0f; - m_unk0x19c = p_unk0x19c; + m_apexParameter = p_apexParameter; m_unk0x7c = 0.0f; m_lastTime = -1.0f; m_actorState = c_one; @@ -200,49 +201,49 @@ MxResult Act3Ammo::FUN_10053d30(LegoPathController* p_p, MxFloat p_unk0x19c) // FUNCTION: LEGO1 0x10053db0 // FUNCTION: BETA10 0x1001e0f0 -MxResult Act3Ammo::FUN_10053db0(float p_param1, Matrix4& p_param2) +MxResult Act3Ammo::CalculateTransform(float p_curveParameter, Matrix4& p_transform) { - float local34 = p_param1 * p_param1; + float curveParameterSquare = p_curveParameter * p_curveParameter; - Vector3 local14(p_param2[0]); - Vector3 local3c(p_param2[1]); - Vector3 localc(p_param2[2]); - Vector3 local30(p_param2[3]); - Mx3DPointFloat local28; + Vector3 right(p_transform[0]); + Vector3 up(p_transform[1]); + Vector3 dir(p_transform[2]); + Vector3 pos(p_transform[3]); + Mx3DPointFloat sndCoeff; - local28 = m_eq[1]; - local28 *= p_param1; - local30 = m_eq[0]; - local30 *= local34; - local30 += local28; - local30 += m_eq[2]; - localc = m_eq[0]; - localc *= 2.0f; - localc *= p_param1; - localc += m_eq[1]; - localc *= -1.0f; + sndCoeff = m_coefficients[1]; + sndCoeff *= p_curveParameter; + pos = m_coefficients[0]; + pos *= curveParameterSquare; + pos += sndCoeff; + pos += m_coefficients[2]; + dir = m_coefficients[0]; + dir *= 2.0f; + dir *= p_curveParameter; + dir += m_coefficients[1]; + dir *= -1.0f; - if (localc.Unitize() != 0) { + if (dir.Unitize() != 0) { assert(0); return FAILURE; } - local14[1] = local14[2] = 0.0f; - local14[0] = 1.0f; - local3c.EqualsCross(localc, local14); + right[1] = right[2] = 0.0f; + right[0] = 1.0f; + up.EqualsCross(dir, right); - if (local3c.Unitize() != 0) { - local14[0] = local14[1] = 0.0f; - local14[2] = 1.0f; - local3c.EqualsCross(localc, local14); + if (up.Unitize() != 0) { + right[0] = right[1] = 0.0f; + right[2] = 1.0f; + up.EqualsCross(dir, right); - if (local3c.Unitize() != 0) { + if (up.Unitize() != 0) { assert(0); return FAILURE; } } - local14.EqualsCross(local3c, localc); + right.EqualsCross(up, dir); return SUCCESS; } @@ -257,7 +258,7 @@ void Act3Ammo::Animate(float p_time) case c_one: break; case c_two: - m_unk0x158 = p_time + 2000.0f; + m_rotateTimeout = p_time + 2000.0f; m_actorState = c_three; return; case c_three: @@ -266,7 +267,7 @@ void Act3Ammo::Animate(float p_time) transform = m_roi->GetLocal2World(); - if (m_unk0x158 > p_time) { + if (m_rotateTimeout > p_time) { Mx3DPointFloat position; position = positionRef; @@ -279,9 +280,9 @@ void Act3Ammo::Animate(float p_time) } else { m_actorState = c_initial; - m_unk0x158 = 0; + m_rotateTimeout = 0; - positionRef -= g_unk0x10104f08; + positionRef -= g_hitTranslation; m_roi->SetLocal2World(transform); m_roi->WrappedUpdateWorldData(); return; @@ -297,15 +298,15 @@ void Act3Ammo::Animate(float p_time) m_unk0x7c = 0.0f; } - MxMatrix local104; - MxMatrix local60; + MxMatrix transform; + MxMatrix additionalTransform; float f = (m_BADuration - m_unk0x7c) / m_worldSpeed + m_lastTime; - undefined4 localb4 = 0; - undefined4 localbc = 0; - MxU32 local14 = FALSE; - MxU32 localb8 = FALSE; + undefined4 unused1 = 0; + undefined4 unused2 = 0; + MxU32 annihilated = FALSE; + MxU32 reachedTarget = FALSE; if (f >= p_time) { m_actorTime = (p_time - m_lastTime) * m_worldSpeed + m_actorTime; @@ -313,69 +314,69 @@ void Act3Ammo::Animate(float p_time) m_lastTime = p_time; } else { - localb8 = TRUE; + reachedTarget = TRUE; m_unk0x7c = m_BADuration; m_lastTime = p_time; } - local104.SetIdentity(); + transform.SetIdentity(); - MxResult r = FUN_10053db0((m_unk0x7c / m_BADuration) * m_unk0x19c, local104); + MxResult r = CalculateTransform((m_unk0x7c / m_BADuration) * m_apexParameter, transform); assert(r == 0); // SUCCESS - local60.SetIdentity(); + additionalTransform.SetIdentity(); if (IsPizza()) { - local60.Scale(2.0f, 2.0f, 2.0f); + additionalTransform.Scale(2.0f, 2.0f, 2.0f); } else { - local60.Scale(5.0f, 5.0f, 5.0f); + additionalTransform.Scale(5.0f, 5.0f, 5.0f); } - if (localb8) { + if (reachedTarget) { if (m_boundary != NULL) { - Vector3 local17c(local104[0]); - Vector3 local184(local104[1]); - Vector3 local174(local104[2]); + Vector3 right(transform[0]); + Vector3 up(transform[1]); + Vector3 dir(transform[2]); if (IsPizza()) { - local184 = *m_boundary->GetUp(); - local17c[0] = 1.0f; - local17c[1] = local17c[2] = 0.0f; - local174.EqualsCross(local17c, local184); - local174.Unitize(); - local17c.EqualsCross(local184, local174); + up = *m_boundary->GetUp(); + right[0] = 1.0f; + right[1] = right[2] = 0.0f; + dir.EqualsCross(right, up); + dir.Unitize(); + right.EqualsCross(up, dir); } else { - local17c = *m_boundary->GetUp(); - local184[0] = 1.0f; - local184[1] = local184[2] = 0.0f; - local174.EqualsCross(local17c, local184); - local174.Unitize(); - local184.EqualsCross(local174, local17c); + right = *m_boundary->GetUp(); + up[0] = 1.0f; + up[1] = up[2] = 0.0f; + dir.EqualsCross(right, up); + dir.Unitize(); + up.EqualsCross(dir, right); } } m_actorState = c_initial; } else { - local60.RotateX(m_actorTime / 10.0f); - local60.RotateY(m_actorTime / 6.0f); + additionalTransform.RotateX(m_actorTime / 10.0f); + additionalTransform.RotateY(m_actorTime / 6.0f); } - MxMatrix localb0(local104); - local104.Product(local60, localb0); - m_roi->SetLocal2World(local104); + MxMatrix transformCopy(transform); + transform.Product(additionalTransform, transformCopy); + m_roi->SetLocal2World(transform); m_roi->WrappedUpdateWorldData(); if (m_BADuration <= m_unk0x7c) { m_worldSpeed = 0.0f; } - Vector3 local68(local104[3]); + Vector3 position(transform[3]); - if (localb8) { - if (IsBit4()) { + if (reachedTarget) { + if (IsShootWithoutBoundary()) { if (IsPizza()) { m_world->RemovePizza(*this); m_world->TriggerHitSound(2); @@ -414,16 +415,16 @@ void Act3Ammo::Animate(float p_time) assert(r); if (!strncmp(r->GetName(), "pammo", 5)) { - Mx3DPointFloat local1c8; - Mx3DPointFloat local1b4; + Mx3DPointFloat otherPosition; + Mx3DPointFloat distance; - local1c8 = r->GetLocal2World()[3]; - local1b4 = m_roi->GetLocal2World()[3]; + otherPosition = r->GetLocal2World()[3]; + distance = m_roi->GetLocal2World()[3]; - local1b4 -= local1c8; + distance -= otherPosition; float radius = r->GetWorldBoundingSphere().Radius(); - if (local1b4.LenSquared() <= radius * radius) { + if (distance.LenSquared() <= radius * radius) { MxS32 index = -1; if (sscanf(r->GetName(), "pammo%d", &index) != 1) { assert(0); @@ -444,22 +445,22 @@ void Act3Ammo::Animate(float p_time) assert(SoundManager()->GetCacheSoundManager()); SoundManager()->GetCacheSoundManager()->Play("dnhitpz", NULL, FALSE); m_world->RemoveDonut(*this); - local14 = TRUE; + annihilated = TRUE; break; } } } else if (!strncmp(r->GetName(), "dammo", 5)) { - Mx3DPointFloat local1f8; - Mx3DPointFloat local1e4; + Mx3DPointFloat otherPosition; + Mx3DPointFloat distance; - local1f8 = r->GetLocal2World()[3]; - local1e4 = m_roi->GetLocal2World()[3]; + otherPosition = r->GetLocal2World()[3]; + distance = m_roi->GetLocal2World()[3]; - local1e4 -= local1f8; + distance -= otherPosition; float radius = r->GetWorldBoundingSphere().Radius(); - if (local1e4.LenSquared() <= radius * radius) { + if (distance.LenSquared() <= radius * radius) { MxS32 index = -1; if (sscanf(r->GetName(), "dammo%d", &index) != 1) { assert(0); @@ -473,19 +474,19 @@ void Act3Ammo::Animate(float p_time) assert(SoundManager()->GetCacheSoundManager()); SoundManager()->GetCacheSoundManager()->Play("pzhitdn", NULL, FALSE); m_world->RemovePizza(*this); - local14 = TRUE; + annihilated = TRUE; break; } } } } - if (!local14) { + if (!annihilated) { if (IsPizza()) { - m_world->FUN_10073360(*this, local68); + m_world->FUN_10073360(*this, position); } else { - m_world->FUN_10073390(*this, local68); + m_world->FUN_10073390(*this, position); } m_worldSpeed = -1.0f; diff --git a/LEGO1/lego/legoomni/src/worlds/act3.cpp b/LEGO1/lego/legoomni/src/worlds/act3.cpp index 74c2b383..f7c773ed 100644 --- a/LEGO1/lego/legoomni/src/worlds/act3.cpp +++ b/LEGO1/lego/legoomni/src/worlds/act3.cpp @@ -330,15 +330,15 @@ MxResult Act3::ShootPizza(LegoPathController* p_controller, Vector3& p_location, m_pizzas[nextPizza].Create(this, TRUE, nextPizza); - if (m_pizzas[nextPizza].FUN_10053b40(p_location, p_direction, p_up) != SUCCESS) { + if (m_pizzas[nextPizza].CalculateArc(p_location, p_direction, p_up) != SUCCESS) { return FAILURE; } - MxFloat unk0x19c = *m_pizzas[nextPizza].GetUnknown0x19c(); + MxFloat unk0x19c = *m_pizzas[nextPizza].GetApexParameter(); if (p_controller->FUN_1004a380( p_location, p_direction, - m_pizzas[nextPizza].GetUnknown0x160(), + m_pizzas[nextPizza].GetCoefficients(), boundary, unk0x19c ) == SUCCESS) { @@ -353,7 +353,7 @@ MxResult Act3::ShootPizza(LegoPathController* p_controller, Vector3& p_location, direction -= m_brickster->GetROI()->GetLocal2World()[3]; local18 = FALSE; - if (m_pizzas[nextPizza].FUN_10053cb0(p_controller, boundary, unk0x19c) == SUCCESS) { + if (m_pizzas[nextPizza].Shoot(p_controller, boundary, unk0x19c) == SUCCESS) { p_controller->PlaceActor(&m_pizzas[nextPizza]); boundary->AddActor(&m_pizzas[nextPizza]); m_pizzas[nextPizza].SetWorldSpeed(10.0f); @@ -361,7 +361,7 @@ MxResult Act3::ShootPizza(LegoPathController* p_controller, Vector3& p_location, } } - if (local18 && m_pizzas[nextPizza].FUN_10053d30(p_controller, unk0x19c) == SUCCESS) { + if (local18 && m_pizzas[nextPizza].Shoot(p_controller, unk0x19c) == SUCCESS) { p_controller->PlaceActor(&m_pizzas[nextPizza]); m_pizzas[nextPizza].SetWorldSpeed(10.0f); return SUCCESS; @@ -385,26 +385,26 @@ MxResult Act3::ShootDonut(LegoPathController* p_controller, Vector3& p_location, m_donuts[nextDonut].Create(this, FALSE, nextDonut); - if (m_donuts[nextDonut].FUN_10053b40(p_location, p_direction, p_up) != SUCCESS) { + if (m_donuts[nextDonut].CalculateArc(p_location, p_direction, p_up) != SUCCESS) { return FAILURE; } - MxFloat unk0x19c = *m_donuts[nextDonut].GetUnknown0x19c(); + MxFloat unk0x19c = *m_donuts[nextDonut].GetApexParameter(); if (p_controller->FUN_1004a380( p_location, p_direction, - m_donuts[nextDonut].GetUnknown0x160(), + m_donuts[nextDonut].GetCoefficients(), boundary, unk0x19c ) == SUCCESS) { - if (m_donuts[nextDonut].FUN_10053cb0(p_controller, boundary, unk0x19c) == SUCCESS) { + if (m_donuts[nextDonut].Shoot(p_controller, boundary, unk0x19c) == SUCCESS) { p_controller->PlaceActor(&m_donuts[nextDonut]); boundary->AddActor(&m_donuts[nextDonut]); m_donuts[nextDonut].SetWorldSpeed(10.0f); return SUCCESS; } } - else if (m_donuts[nextDonut].FUN_10053d30(p_controller, unk0x19c) == SUCCESS) { + else if (m_donuts[nextDonut].Shoot(p_controller, unk0x19c) == SUCCESS) { p_controller->PlaceActor(&m_donuts[nextDonut]); m_donuts[nextDonut].SetWorldSpeed(10.0f); return SUCCESS; @@ -936,7 +936,7 @@ void Act3::Enable(MxBool p_enable) if (m_pizzas[i].IsValid()) { m_pizzas[i].SetLastTime(m_pizzas[i].GetLastTime() + delta); m_pizzas[i].SetActorTime(m_pizzas[i].GetActorTime() + delta); - m_pizzas[i].SetUnknown0x158(m_pizzas[i].GetUnknown0x158() + delta); + m_pizzas[i].SetRotateTimeout(m_pizzas[i].GetRotateTimeout() + delta); } } @@ -944,7 +944,7 @@ void Act3::Enable(MxBool p_enable) if (m_donuts[i].IsValid()) { m_donuts[i].SetLastTime(m_donuts[i].GetLastTime() + delta); m_donuts[i].SetActorTime(m_donuts[i].GetActorTime() + delta); - m_donuts[i].SetUnknown0x158(m_donuts[i].GetUnknown0x158() + delta); + m_donuts[i].SetRotateTimeout(m_donuts[i].GetRotateTimeout() + delta); } } From c31b3dcdffe594614929e41a683cdd4633ef7529 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Mon, 12 Jan 2026 23:15:21 +0100 Subject: [PATCH 07/23] Clear unknowns in `MxCompositeMediaPresenter` (#1716) --- .../include/mxcompositemediapresenter.h | 4 ++-- .../src/common/mxcompositemediapresenter.cpp | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/LEGO1/lego/legoomni/include/mxcompositemediapresenter.h b/LEGO1/lego/legoomni/include/mxcompositemediapresenter.h index 3ccc12d7..3bf92848 100644 --- a/LEGO1/lego/legoomni/include/mxcompositemediapresenter.h +++ b/LEGO1/lego/legoomni/include/mxcompositemediapresenter.h @@ -32,8 +32,8 @@ class MxCompositeMediaPresenter : public MxCompositePresenter { MxResult PutData() override; // vtable+0x4c private: - MxS16 m_unk0x4c; // 0x4c - MxBool m_unk0x4e; // 0x4e + MxS16 m_remainingChildren; // 0x4c + MxBool m_allChildrenStreaming; // 0x4e }; // SYNTHETIC: LEGO1 0x10074000 diff --git a/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp b/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp index 7c6a788d..781c76b6 100644 --- a/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp @@ -15,8 +15,8 @@ DECOMP_SIZE_ASSERT(MxCompositeMediaPresenter, 0x50) // FUNCTION: LEGO1 0x10073ea0 MxCompositeMediaPresenter::MxCompositeMediaPresenter() { - m_unk0x4c = 0; - m_unk0x4e = FALSE; + m_remainingChildren = 0; + m_allChildrenStreaming = FALSE; VideoManager()->RegisterPresenter(*this); } @@ -99,25 +99,25 @@ void MxCompositeMediaPresenter::StartingTickle() { AUTOLOCK(m_criticalSection); - if (!m_unk0x4e) { + if (!m_allChildrenStreaming) { for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { if ((*it)->GetCurrentTickleState() < e_streaming) { (*it)->Tickle(); if ((*it)->GetCurrentTickleState() == e_streaming || ((*it)->GetAction() && (*it)->GetAction()->GetStartTime())) { - m_unk0x4c++; + m_remainingChildren++; } } } - if (m_list.size() == m_unk0x4c) { - m_unk0x4e = TRUE; - m_unk0x4c = 0; + if (m_list.size() == m_remainingChildren) { + m_allChildrenStreaming = TRUE; + m_remainingChildren = 0; for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { if (!(*it)->GetAction()->GetStartTime()) { - m_unk0x4c++; + m_remainingChildren++; } } } @@ -128,11 +128,11 @@ void MxCompositeMediaPresenter::StartingTickle() !((*it)->GetAction()->GetFlags() & MxDSAction::c_bit9)) { (*it)->Tickle(); (*it)->GetAction()->SetFlags((*it)->GetAction()->GetFlags() | MxDSAction::c_bit9); - m_unk0x4c--; + m_remainingChildren--; } } - if (!m_unk0x4c) { + if (!m_remainingChildren) { ProgressTickleState(e_streaming); MxLong time = Timer()->GetTime(); m_action->SetTimeStarted(time); From faa4e45e48fe1234d9616396484e274077b5f422 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Mon, 12 Jan 2026 23:16:44 +0100 Subject: [PATCH 08/23] Clear unknowns in `MxCompositePresenter` (#1717) --- LEGO1/lego/legoomni/include/legoanimmmpresenter.h | 2 +- LEGO1/lego/legoomni/include/legoworldpresenter.h | 2 +- LEGO1/lego/legoomni/include/mxcontrolpresenter.h | 2 +- .../src/common/legoactioncontrolpresenter.cpp | 2 +- .../lego/legoomni/src/common/legoanimmmpresenter.cpp | 4 ++-- .../lego/legoomni/src/entity/legoworldpresenter.cpp | 4 ++-- LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp | 8 ++++---- .../lego/legoomni/src/video/legotexturepresenter.cpp | 2 +- LEGO1/omni/include/mxcompositepresenter.h | 10 +++++----- LEGO1/omni/src/common/mxcompositepresenter.cpp | 12 ++++++------ LEGO1/omni/src/common/mxmediapresenter.cpp | 3 ++- LEGO1/omni/src/video/mxstillpresenter.cpp | 2 +- 12 files changed, 27 insertions(+), 26 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoanimmmpresenter.h b/LEGO1/lego/legoomni/include/legoanimmmpresenter.h index 5c972176..cbd9232a 100644 --- a/LEGO1/lego/legoomni/include/legoanimmmpresenter.h +++ b/LEGO1/lego/legoomni/include/legoanimmmpresenter.h @@ -61,7 +61,7 @@ class LegoAnimMMPresenter : public MxCompositePresenter { void ParseExtra() override; // vtable+0x30 MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c void EndAction() override; // vtable+0x40 - void VTable0x60(MxPresenter* p_presenter) override; // vtable+0x60 + void AdvanceSerialAction(MxPresenter* p_presenter) override; // vtable+0x60 // SYNTHETIC: LEGO1 0x1004aa40 // LegoAnimMMPresenter::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/legoworldpresenter.h b/LEGO1/lego/legoomni/include/legoworldpresenter.h index 3e853f83..370474b0 100644 --- a/LEGO1/lego/legoomni/include/legoworldpresenter.h +++ b/LEGO1/lego/legoomni/include/legoworldpresenter.h @@ -42,7 +42,7 @@ class LegoWorldPresenter : public LegoEntityPresenter { void StartingTickle() override; // vtable+0x1c void ParseExtra() override; // vtable+0x30 MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c - void VTable0x60(MxPresenter* p_presenter) override; // vtable+0x60 + void AdvanceSerialAction(MxPresenter* p_presenter) override; // vtable+0x60 MxResult LoadWorld(char* p_worldName, LegoWorld* p_world); diff --git a/LEGO1/lego/legoomni/include/mxcontrolpresenter.h b/LEGO1/lego/legoomni/include/mxcontrolpresenter.h index d3d2a96a..8e37b186 100644 --- a/LEGO1/lego/legoomni/include/mxcontrolpresenter.h +++ b/LEGO1/lego/legoomni/include/mxcontrolpresenter.h @@ -18,7 +18,7 @@ class MxControlPresenter : public MxCompositePresenter { void RepeatingTickle() override {} // vtable+0x24 // FUNCTION: LEGO1 0x10043fe0 - MxBool VTable0x64(undefined4 p_undefined) override { return m_unk0x50; } // vtable+0x64 + MxBool GetActionEnded(undefined4 p_undefined) override { return m_unk0x50; } // vtable+0x64 // FUNCTION: LEGO1 0x10043ff0 virtual void VTable0x68(MxBool p_unk0x50) { m_unk0x50 = p_unk0x50; } // vtable+0x68 diff --git a/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp b/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp index 1afc9d64..0e22d8de 100644 --- a/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp @@ -26,7 +26,7 @@ void LegoActionControlPresenter::ReadyTickle() m_subscriber->FreeDataChunk(chunk); if (m_compositePresenter) { if (m_action->GetDuration() == -1 || m_action->GetFlags() & 1) { - m_compositePresenter->VTable0x60(this); + m_compositePresenter->AdvanceSerialAction(this); } } } diff --git a/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp b/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp index af32a238..2f54d8ff 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp @@ -225,7 +225,7 @@ MxLong LegoAnimMMPresenter::Notify(MxParam& p_param) } // FUNCTION: LEGO1 0x1004b360 -void LegoAnimMMPresenter::VTable0x60(MxPresenter* p_presenter) +void LegoAnimMMPresenter::AdvanceSerialAction(MxPresenter* p_presenter) { if (m_presenter == p_presenter && ((MxU8) p_presenter->GetCurrentTickleState() == MxPresenter::e_streaming || (MxU8) p_presenter->GetCurrentTickleState() == MxPresenter::e_done)) { @@ -403,7 +403,7 @@ MxBool LegoAnimMMPresenter::FUN_1004b610(MxLong p_time) m_action->SetTimeStarted(Timer()->GetTime()); if (m_compositePresenter != NULL) { - m_compositePresenter->VTable0x60(this); + m_compositePresenter->AdvanceSerialAction(this); } return TRUE; diff --git a/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp b/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp index 6ecba8b1..1177b0ee 100644 --- a/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp @@ -400,9 +400,9 @@ MxResult LegoWorldPresenter::LoadWorldModel(ModelDbModel& p_model, FILE* p_wdbFi } // FUNCTION: LEGO1 0x10067a70 -void LegoWorldPresenter::VTable0x60(MxPresenter* p_presenter) +void LegoWorldPresenter::AdvanceSerialAction(MxPresenter* p_presenter) { - MxCompositePresenter::VTable0x60(p_presenter); + MxCompositePresenter::AdvanceSerialAction(p_presenter); MxDSAction* action = p_presenter->GetAction(); if (action->GetDuration() != -1 && (action->GetFlags() & MxDSAction::c_looping) == 0) { diff --git a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp index 3b26b126..1ee5aba4 100644 --- a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp @@ -820,7 +820,7 @@ void LegoAnimPresenter::StartingTickle() if ((m_action->GetDuration() == -1 || ((MxDSMediaAction*) m_action)->GetSustainTime() == -1) && m_compositePresenter) { - m_compositePresenter->VTable0x60(this); + m_compositePresenter->AdvanceSerialAction(this); } else { m_action->SetTimeStarted(Timer()->GetTime()); @@ -830,7 +830,7 @@ void LegoAnimPresenter::StartingTickle() if (m_compositePresenter && m_compositePresenter->IsA("LegoAnimMMPresenter")) { m_unk0x96 = ((LegoAnimMMPresenter*) m_compositePresenter)->FUN_1004b8b0(); - m_compositePresenter->VTable0x60(this); + m_compositePresenter->AdvanceSerialAction(this); } VTable0x8c(); @@ -854,7 +854,7 @@ void LegoAnimPresenter::StreamingTickle() ProgressTickleState(e_done); if (m_compositePresenter) { if (m_compositePresenter->IsA("LegoAnimMMPresenter")) { - m_compositePresenter->VTable0x60(this); + m_compositePresenter->AdvanceSerialAction(this); } } } @@ -1235,7 +1235,7 @@ void LegoLoopingAnimPresenter::StreamingTickle() ProgressTickleState(e_done); if (m_compositePresenter) { if (m_compositePresenter->IsA("LegoAnimMMPresenter")) { - m_compositePresenter->VTable0x60(this); + m_compositePresenter->AdvanceSerialAction(this); } } } diff --git a/LEGO1/lego/legoomni/src/video/legotexturepresenter.cpp b/LEGO1/lego/legoomni/src/video/legotexturepresenter.cpp index 8b6950ac..ee41e678 100644 --- a/LEGO1/lego/legoomni/src/video/legotexturepresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legotexturepresenter.cpp @@ -139,7 +139,7 @@ MxResult LegoTexturePresenter::PutData() // FUNCTION: LEGO1 0x1004fcb0 void LegoTexturePresenter::DoneTickle() { - if (this->m_compositePresenter && !this->m_compositePresenter->VTable0x64(2)) { + if (this->m_compositePresenter && !this->m_compositePresenter->GetActionEnded(2)) { SetTickleState(e_idle); return; } diff --git a/LEGO1/omni/include/mxcompositepresenter.h b/LEGO1/omni/include/mxcompositepresenter.h index c11410dc..1f921ca4 100644 --- a/LEGO1/omni/include/mxcompositepresenter.h +++ b/LEGO1/omni/include/mxcompositepresenter.h @@ -43,15 +43,15 @@ class MxCompositePresenter : public MxPresenter { void SetTickleState(TickleState p_tickleState) override; // vtable+0x44 MxBool HasTickleStatePassed(TickleState p_tickleState) override; // vtable+0x48 void Enable(MxBool p_enable) override; // vtable+0x54 - virtual void VTable0x58(MxEndActionNotificationParam& p_param); // vtable+0x58 - virtual void VTable0x5c(MxNotificationParam& p_param); // vtable+0x5c - virtual void VTable0x60(MxPresenter* p_presenter); // vtable+0x60 + virtual void HandleEndAction(MxEndActionNotificationParam& p_param); // vtable+0x58 + virtual void HandlePresenter(MxNotificationParam& p_param); // vtable+0x5c + virtual void AdvanceSerialAction(MxPresenter* p_presenter); // vtable+0x60 // FUNCTION: LEGO1 0x1000caf0 - virtual MxBool VTable0x64(undefined4 p_undefined) + virtual MxBool GetActionEnded(undefined4 p_undefined) { if (m_compositePresenter) { - return m_compositePresenter->VTable0x64(p_undefined); + return m_compositePresenter->GetActionEnded(p_undefined); } return TRUE; } // vtable+0x64 diff --git a/LEGO1/omni/src/common/mxcompositepresenter.cpp b/LEGO1/omni/src/common/mxcompositepresenter.cpp index b3d56875..ca8f32cd 100644 --- a/LEGO1/omni/src/common/mxcompositepresenter.cpp +++ b/LEGO1/omni/src/common/mxcompositepresenter.cpp @@ -117,10 +117,10 @@ MxLong MxCompositePresenter::Notify(MxParam& p_param) switch (param.GetNotification()) { case c_notificationEndAction: - VTable0x58((MxEndActionNotificationParam&) p_param); + HandleEndAction((MxEndActionNotificationParam&) p_param); break; case c_notificationPresenter: - VTable0x5c((MxNotificationParam&) p_param); + HandlePresenter((MxNotificationParam&) p_param); break; default: assert(0); @@ -131,7 +131,7 @@ MxLong MxCompositePresenter::Notify(MxParam& p_param) } // FUNCTION: LEGO1 0x100b67f0 -void MxCompositePresenter::VTable0x58(MxEndActionNotificationParam& p_param) +void MxCompositePresenter::HandleEndAction(MxEndActionNotificationParam& p_param) { MxPresenter* presenter = (MxPresenter*) p_param.GetSender(); MxDSAction* action = p_param.GetAction(); @@ -177,7 +177,7 @@ void MxCompositePresenter::VTable0x58(MxEndActionNotificationParam& p_param) } // FUNCTION: LEGO1 0x100b69b0 -void MxCompositePresenter::VTable0x5c(MxNotificationParam& p_param) +void MxCompositePresenter::HandlePresenter(MxNotificationParam& p_param) { if (!m_list.empty()) { MxPresenter* presenter = (MxPresenter*) p_param.GetSender(); @@ -218,13 +218,13 @@ void MxCompositePresenter::VTable0x5c(MxNotificationParam& p_param) } // FUNCTION: LEGO1 0x100b6b40 -void MxCompositePresenter::VTable0x60(MxPresenter* p_presenter) +void MxCompositePresenter::AdvanceSerialAction(MxPresenter* p_presenter) { for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { if (*it == p_presenter) { if (++it == m_list.end()) { if (m_compositePresenter) { - m_compositePresenter->VTable0x60(this); + m_compositePresenter->AdvanceSerialAction(this); } } else if (m_action->IsA("MxDSSerialAction")) { diff --git a/LEGO1/omni/src/common/mxmediapresenter.cpp b/LEGO1/omni/src/common/mxmediapresenter.cpp index 11621f71..a8873866 100644 --- a/LEGO1/omni/src/common/mxmediapresenter.cpp +++ b/LEGO1/omni/src/common/mxmediapresenter.cpp @@ -142,7 +142,8 @@ void MxMediaPresenter::EndAction() m_currentChunk = NULL; - if (m_action->GetFlags() & MxDSAction::c_world && (!m_compositePresenter || !m_compositePresenter->VTable0x64(2))) { + if (m_action->GetFlags() & MxDSAction::c_world && + (!m_compositePresenter || !m_compositePresenter->GetActionEnded(2))) { MxPresenter::Enable(FALSE); SetTickleState(e_idle); } diff --git a/LEGO1/omni/src/video/mxstillpresenter.cpp b/LEGO1/omni/src/video/mxstillpresenter.cpp index 0c0b3a1b..ef09d215 100644 --- a/LEGO1/omni/src/video/mxstillpresenter.cpp +++ b/LEGO1/omni/src/video/mxstillpresenter.cpp @@ -132,7 +132,7 @@ void MxStillPresenter::StreamingTickle() ProgressTickleState(e_repeating); if (m_action->GetDuration() == -1 && m_compositePresenter) { - m_compositePresenter->VTable0x60(this); + m_compositePresenter->AdvanceSerialAction(this); } } } From dace101b85ded261435ced8912f0be098865e0d6 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Tue, 13 Jan 2026 00:39:16 +0100 Subject: [PATCH 09/23] Clear unknowns in `LegoExtraActor` (#1718) --- LEGO1/lego/legoomni/include/legoextraactor.h | 30 ++++--- .../legoomni/src/paths/legoextraactor.cpp | 86 +++++++++---------- 2 files changed, 61 insertions(+), 55 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoextraactor.h b/LEGO1/lego/legoomni/include/legoextraactor.h index 05ee8510..2db32dee 100644 --- a/LEGO1/lego/legoomni/include/legoextraactor.h +++ b/LEGO1/lego/legoomni/include/legoextraactor.h @@ -54,10 +54,10 @@ class LegoExtraActor : public virtual LegoAnimActor { void VTable0xa4(MxBool& p_und1, MxS32& p_und2) override; // vtable+0xa4 void VTable0xc4() override; // vtable+0xc4 - virtual MxResult FUN_1002aae0(); + virtual MxResult SwitchDirection(); void Restart(); - inline void FUN_1002ad8a(); + inline void InitializeReassemblyAnim(); void SetUnknown0x0c(undefined p_unk0x0c) { m_unk0x0c = p_unk0x0c; } @@ -65,16 +65,22 @@ class LegoExtraActor : public virtual LegoAnimActor { // LegoExtraActor::`scalar deleting destructor' private: - MxFloat m_scheduledTime; // 0x08 - undefined m_unk0x0c; // 0x0c - MxU8 m_axis; // 0x0d - undefined m_unk0x0e; // 0x0e - MxFloat m_prevWorldSpeed; // 0x10 - MxU8 m_whichAnim; // 0x14 - MxU8 m_unk0x15; // 0x15 - MxMatrix m_unk0x18; // 0x18 - LegoAnimActorStruct* m_assAnim; // 0x60 - LegoAnimActorStruct* m_disAnim; // 0x64 + enum { + e_none = 0, + e_disassemble = 1, + e_assemble = 2, + }; + + MxFloat m_scheduledTime; // 0x08 + undefined m_unk0x0c; // 0x0c + MxU8 m_axis; // 0x0d + MxBool m_animationAtCurrentBoundary; // 0x0e + MxFloat m_prevWorldSpeed; // 0x10 + MxU8 m_reassemblyAnimation; // 0x14 + MxU8 m_hitBlockCounter; // 0x15 + MxMatrix m_localBeforeHit; // 0x18 + LegoAnimActorStruct* m_assAnim; // 0x60 + LegoAnimActorStruct* m_disAnim; // 0x64 }; // GLOBAL: LEGO1 0x100d6be8 diff --git a/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp b/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp index 3afd211f..103728b5 100644 --- a/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp @@ -12,7 +12,7 @@ DECOMP_SIZE_ASSERT(LegoExtraActor, 0x1dc) // GLOBAL: LEGO1 0x100f31d0 -LegoWorld* g_unk0x100f31d0 = NULL; +LegoWorld* g_reassemblyAnimWorld = NULL; // GLOBAL: LEGO1 0x100f31d4 LegoLocomotionAnimPresenter* m_assAnimP = NULL; @@ -21,7 +21,7 @@ LegoLocomotionAnimPresenter* m_assAnimP = NULL; LegoLocomotionAnimPresenter* m_disAnimP = NULL; // GLOBAL: LEGO1 0x100f31dc -MxS32 g_unk0x100f31dc = 0; +MxS32 g_hitCounter = 0; // GLOBAL: LEGO1 0x10104c18 Mx3DPointFloat g_unk0x10104c18 = Mx3DPointFloat(0.0f, 2.5f, 0.0f); @@ -33,11 +33,11 @@ LegoExtraActor::LegoExtraActor() m_lastPathStruct = 0.0f; m_scheduledTime = 0; m_unk0x0c = 0; - m_unk0x0e = 0; - m_whichAnim = 0; + m_animationAtCurrentBoundary = FALSE; + m_reassemblyAnimation = e_none; m_assAnim = NULL; m_disAnim = NULL; - m_unk0x15 = 0; + m_hitBlockCounter = 0; } // FUNCTION: LEGO1 0x1002a6b0 @@ -128,7 +128,7 @@ void LegoExtraActor::VTable0xa4(MxBool& p_und1, MxS32& p_und2) } // FUNCTION: LEGO1 0x1002aae0 -MxResult LegoExtraActor::FUN_1002aae0() +MxResult LegoExtraActor::SwitchDirection() { LegoPathBoundary* oldEdge = m_boundary; Vector3 rightRef(m_unk0xec[0]); @@ -154,12 +154,12 @@ MxResult LegoExtraActor::FUN_1002aae0() return SUCCESS; } -inline void LegoExtraActor::FUN_1002ad8a() +inline void LegoExtraActor::InitializeReassemblyAnim() { LegoWorld* w = CurrentWorld(); - if (g_unk0x100f31d0 != w) { - g_unk0x100f31d0 = w; + if (g_reassemblyAnimWorld != w) { + g_reassemblyAnimWorld = w; m_assAnimP = (LegoLocomotionAnimPresenter*) w->Find("LegoAnimPresenter", "BNsAss01"); m_disAnimP = (LegoLocomotionAnimPresenter*) w->Find("LegoAnimPresenter", "BNsDis01"); } @@ -198,26 +198,26 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool) } if (p_bool) { - if (m_unk0x15 != 0) { + if (m_hitBlockCounter != 0) { return FAILURE; } - m_unk0x15 = 100; - FUN_1002aae0(); + m_hitBlockCounter = 100; + SwitchDirection(); } else { MxU32 b = FALSE; - if (++g_unk0x100f31dc % 2 == 0) { - MxMatrix matrix(p_actor->GetROI()->GetLocal2World()); - MxMatrix matrix2(m_roi->GetLocal2World()); + if (++g_hitCounter % 2 == 0) { + MxMatrix otherActorLocal(p_actor->GetROI()->GetLocal2World()); + MxMatrix local(m_roi->GetLocal2World()); - m_unk0x18 = matrix2; - Vector3 positionRef(matrix2[3]); - Mx3DPointFloat dir(matrix[2]); + m_localBeforeHit = local; + Vector3 positionRef(local[3]); + Mx3DPointFloat otherActorDir(otherActorLocal[2]); - dir *= 2.0f; - positionRef += dir; + otherActorDir *= 2.0f; + positionRef += otherActorDir; for (MxS32 i = 0; i < m_boundary->GetNumEdges(); i++) { Mx4DPointFloat* normal = m_boundary->GetEdgeNormal(i); @@ -229,9 +229,9 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool) } if (!b) { - m_roi->SetLocal2World(matrix2); + m_roi->SetLocal2World(local); m_roi->WrappedUpdateWorldData(); - FUN_1002ad8a(); + InitializeReassemblyAnim(); assert(m_roi); assert(SoundManager()->GetCacheSoundManager()); SoundManager()->GetCacheSoundManager()->Play("crash5", m_roi->GetName(), FALSE); @@ -239,7 +239,7 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool) m_prevWorldSpeed = GetWorldSpeed(); VTable0xc4(); SetWorldSpeed(0); - m_whichAnim = 1; + m_reassemblyAnimation = e_disassemble; SetActorState(c_one | c_noCollide); } } @@ -278,19 +278,19 @@ MxResult LegoExtraActor::VTable0x9c() MxResult result = LegoPathActor::VTable0x9c(); if (m_boundary != oldBoundary) { - MxU32 b = FALSE; + MxU32 foundAnimation = FALSE; LegoAnimPresenterSet& presenters = m_boundary->GetPresenters(); for (LegoAnimPresenterSet::iterator it = presenters.begin(); it != presenters.end(); it++) { MxU32 roiMapSize; if ((*it)->GetROIMap(roiMapSize)) { - b = TRUE; + foundAnimation = TRUE; break; } } - if (b) { - m_unk0x0e = 1; + if (foundAnimation) { + m_animationAtCurrentBoundary = TRUE; m_prevWorldSpeed = GetWorldSpeed(); SetWorldSpeed(0); } @@ -302,21 +302,21 @@ MxResult LegoExtraActor::VTable0x9c() // FUNCTION: LEGO1 0x1002b370 void LegoExtraActor::Restart() { - if (m_unk0x0e != 0) { - MxU32 b = FALSE; + if (m_animationAtCurrentBoundary != 0) { + MxU32 foundAnimation = FALSE; LegoAnimPresenterSet& presenters = m_boundary->GetPresenters(); for (LegoAnimPresenterSet::iterator it = presenters.begin(); it != presenters.end(); it++) { MxU32 roiMapSize; if ((*it)->GetROIMap(roiMapSize)) { - b = TRUE; + foundAnimation = TRUE; break; } } - if (!b) { + if (!foundAnimation) { SetWorldSpeed(m_prevWorldSpeed); - m_unk0x0e = 0; + m_animationAtCurrentBoundary = FALSE; } } } @@ -326,13 +326,13 @@ void LegoExtraActor::Animate(float p_time) { LegoAnimActorStruct* laas = NULL; - switch (m_whichAnim) { - case 0: + switch (m_reassemblyAnimation) { + case e_none: LegoAnimActor::Animate(p_time); break; - case 1: + case e_disassemble: if (m_scheduledTime < p_time) { - m_whichAnim = 2; + m_reassemblyAnimation = e_assemble; m_actorState = c_one | c_noCollide; m_scheduledTime = m_assAnim->GetDuration() + p_time; break; @@ -341,12 +341,12 @@ void LegoExtraActor::Animate(float p_time) laas = m_disAnim; break; } - case 2: + case e_assemble: if (m_scheduledTime < p_time) { - m_whichAnim = 0; + m_reassemblyAnimation = e_none; m_actorState = c_initial; SetWorldSpeed(m_prevWorldSpeed); - m_roi->SetLocal2World(m_unk0x18); + m_roi->SetLocal2World(m_localBeforeHit); m_lastTime = p_time; break; } @@ -381,7 +381,7 @@ void LegoExtraActor::Animate(float p_time) // FUNCTION: LEGO1 0x1002b5d0 void LegoExtraActor::VTable0x74(Matrix4& p_transform) { - if (m_whichAnim == 0) { + if (m_reassemblyAnimation == e_none) { LegoAnimActor::VTable0x74(p_transform); } } @@ -460,7 +460,7 @@ inline MxU32 LegoExtraActor::VTable0x6c( float local24 = p_v2.Dot(p_v2, local54) * 2.0f; float local20 = local54.Dot(local54, local54); - if (m_unk0x15 != 0 && local20 < 10.0f) { + if (m_hitBlockCounter != 0 && local20 < 10.0f) { return 0; } @@ -516,8 +516,8 @@ inline MxU32 LegoExtraActor::VTable0x6c( } } - if (m_unk0x15 != 0) { - m_unk0x15--; + if (m_hitBlockCounter != 0) { + m_hitBlockCounter--; } return 0; From 600079215f74f4bdf8b3343f60ebdb29f9e2df06 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Tue, 13 Jan 2026 21:54:44 +0100 Subject: [PATCH 10/23] Anim presenters (#1719) * Clear unknowns in `LegoAnimPresenter`, `LegoLocomotionAnimPresenter` and `LegoHideAnimPresenter` * Clear visibility unknowns in animation presenters --------- Co-authored-by: Florian Kaiser Co-authored-by: Christian Semmler --- .../lego/legoomni/include/legoanimpresenter.h | 118 +++--- LEGO1/lego/legoomni/src/actors/act3actors.cpp | 2 +- LEGO1/lego/legoomni/src/actors/doors.cpp | 2 +- .../src/build/legocarbuildpresenter.cpp | 4 +- .../src/common/legoanimationmanager.cpp | 12 +- .../src/common/legoanimmmpresenter.cpp | 8 +- LEGO1/lego/legoomni/src/entity/legoworld.cpp | 4 +- .../lego/legoomni/src/paths/legoanimactor.cpp | 4 +- .../legoomni/src/paths/legoextraactor.cpp | 6 +- .../lego/legoomni/src/paths/legopathactor.cpp | 2 +- .../legoomni/src/paths/legopathboundary.cpp | 12 +- .../legoomni/src/paths/legopathstruct.cpp | 2 +- LEGO1/lego/legoomni/src/race/carrace.cpp | 2 +- LEGO1/lego/legoomni/src/race/jetskirace.cpp | 4 +- .../legoomni/src/race/legoracespecial.cpp | 4 +- .../legoomni/src/video/legoanimpresenter.cpp | 388 +++++++++--------- LEGO1/lego/legoomni/src/worlds/legoact2.cpp | 8 +- LEGO1/lego/sources/anim/legoanim.h | 10 +- LEGO1/lego/sources/geom/legowegedge.h | 12 +- 19 files changed, 309 insertions(+), 295 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoanimpresenter.h b/LEGO1/lego/legoomni/include/legoanimpresenter.h index 6e983144..0cf49100 100644 --- a/LEGO1/lego/legoomni/include/legoanimpresenter.h +++ b/LEGO1/lego/legoomni/include/legoanimpresenter.h @@ -62,21 +62,27 @@ class LegoAnimPresenter : public MxVideoPresenter { return !strcmp(p_name, LegoAnimPresenter::ClassName()) || MxVideoPresenter::IsA(p_name); } - void ReadyTickle() override; // vtable+0x18 - void StartingTickle() override; // vtable+0x1c - void StreamingTickle() override; // vtable+0x20 - void DoneTickle() override; // vtable+0x2c - void ParseExtra() override; // vtable+0x30 - MxResult AddToManager() override; // vtable+0x34 - void Destroy() override; // vtable+0x38 - MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c - void EndAction() override; // vtable+0x40 - void PutFrame() override; // vtable+0x6c - virtual MxResult CreateAnim(MxStreamChunk* p_chunk); // vtable+0x88 - virtual void VTable0x8c(); // vtable+0x8c - virtual void VTable0x90(); // vtable+0x90 - virtual MxU32 VTable0x94(Vector3& p_v1, Vector3& p_v2, float p_f1, float p_f2, Vector3& p_v3); // vtable+0x94 - virtual MxResult VTable0x98(LegoPathBoundary* p_boundary); // vtable+0x98 + void ReadyTickle() override; // vtable+0x18 + void StartingTickle() override; // vtable+0x1c + void StreamingTickle() override; // vtable+0x20 + void DoneTickle() override; // vtable+0x2c + void ParseExtra() override; // vtable+0x30 + MxResult AddToManager() override; // vtable+0x34 + void Destroy() override; // vtable+0x38 + MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c + void EndAction() override; // vtable+0x40 + void PutFrame() override; // vtable+0x6c + virtual MxResult CreateAnim(MxStreamChunk* p_chunk); // vtable+0x88 + virtual void AddToWorld(); // vtable+0x8c + virtual void RemoveFromWorld(); // vtable+0x90 + virtual MxU32 Intersect( + Vector3& p_rayOrigin, + Vector3& p_rayDirection, + float p_rayLength, + float p_radius, + Vector3& p_intersectionPoint + ); // vtable+0x94 + virtual MxResult AddActors(LegoPathBoundary* p_boundary); // vtable+0x98 // FUNCTION: LEGO1 0x1000c990 virtual LegoROI** GetROIMap(MxU32& p_roiMapSize) @@ -85,47 +91,47 @@ class LegoAnimPresenter : public MxVideoPresenter { return m_roiMap; } // vtable+0x9c - virtual void VTable0xa0(Matrix4& p_matrix); // vtable+0xa0 + virtual void SetTransform(Matrix4& p_matrix); // vtable+0xa0 - MxResult FUN_1006afc0(MxMatrix*& p_matrix, float p_und); - MxResult FUN_1006b140(LegoROI* p_roi); - void FUN_1006c7a0(); + MxResult GetTransforms(MxMatrix*& p_matrix, float p_time); + MxResult CopyTransform(LegoROI* p_roi); + void ApplyFinishedTransform(); const char* GetActionObjectName(); void SetCurrentWorld(LegoWorld* p_currentWorld) { m_currentWorld = p_currentWorld; } // FUNCTION: BETA10 0x1005aad0 - void SetUnknown0x0cTo1() { m_unk0x9c = 1; } + void SetRoiTransformApplied() { m_roiTransformApplied = 1; } // FUNCTION: BETA10 0x1005ab00 - void SetUnknown0xa0(Matrix4* p_unk0xa0) { m_unk0xa0 = p_unk0xa0; } + void SetRoiTransform(Matrix4* p_roiTransform) { m_roiTransform = p_roiTransform; } LegoAnim* GetAnimation() { return m_anim; } protected: void Init(); void Destroy(MxBool p_fromDestructor); - LegoChar* FUN_10069150(const LegoChar* p_und1); - void FUN_100692b0(); - void FUN_100695c0(); + LegoChar* GetActorName(const LegoChar* p_name); + void CreateManagedActors(); + void CreateSceneROIs(); LegoChar* GetVariableOrIdentity(const LegoChar* p_varName, const LegoChar* p_prefix); - LegoBool FUN_100698b0(const CompoundObject& p_rois, const LegoChar* p_und2); + LegoBool AppendROIToScene(const CompoundObject& p_rois, const LegoChar* p_varName); LegoROI* FindROI(const LegoChar* p_name); - void FUN_10069b10(); + void BuildROIMap(); void UpdateStructMapAndROIIndex(LegoAnimStructMap& p_map, LegoTreeNode* p_node, LegoROI* p_roi); void UpdateStructMapAndROIIndexForNode( LegoAnimStructMap& p_map, LegoAnimNodeData* p_data, - const LegoChar* p_und, + const LegoChar* p_key, LegoROI* p_roi ); - void FUN_1006aa60(); - void FUN_1006ab70(); - LegoBool FUN_1006aba0(); - MxBool FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi); + void ReleaseManagedActors(); + void AppendManagedActors(); + LegoBool VerifyAnimationTree(); + MxBool VerifyAnimationNode(LegoTreeNode* p_node, LegoROI* p_roi); void SubstituteVariables(); - void FUN_1006b900(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix); - void FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix); + void ApplyTransform(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix); + void ApplyTransformWithVisibilityAndCam(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix); void SetDisabled(MxBool p_disabled); LegoAnim* m_anim; // 0x64 @@ -133,27 +139,27 @@ class LegoAnimPresenter : public MxVideoPresenter { MxU32 m_roiMapSize; // 0x6c LegoROIList* m_sceneROIs; // 0x70 LegoROIList* m_managedActors; // 0x74 - Matrix4* m_unk0x78; // 0x78 + Matrix4* m_transform; // 0x78 MxU32 m_flags; // 0x7c LegoWorld* m_currentWorld; // 0x80 MxAtomId m_worldAtom; // 0x84 MxS32 m_worldId; // 0x88 - LegoROI** m_unk0x8c; // 0x8c - char** m_unk0x90; // 0x90 - MxU8 m_unk0x94; // 0x94 - MxBool m_unk0x95; // 0x95 - MxBool m_unk0x96; // 0x96 + LegoROI** m_ptAtCamROI; // 0x8c + char** m_ptAtCamNames; // 0x90 + MxU8 m_ptAtCamCount; // 0x94 + MxBool m_animationFinished; // 0x95 + MxBool m_localActors; // 0x96 undefined m_unk0x97; // 0x97 LegoAnimSubstMap* m_substMap; // 0x98 - MxS16 m_unk0x9c; // 0x9c - Matrix4* m_unk0xa0; // 0xa0 + MxS16 m_roiTransformApplied; // 0x9c + Matrix4* m_roiTransform; // 0xa0 // SYNTHETIC: LEGO1 0x10068650 // LegoAnimPresenter::`scalar deleting destructor' public: - float m_unk0xa4; // 0xa4 - Mx3DPointFloat m_unk0xa8; // 0xa8 + float m_boundingRadius; // 0xa4 + Mx3DPointFloat m_centerPoint; // 0xa8 }; // VTABLE: LEGO1 0x100d4900 @@ -231,16 +237,16 @@ class LegoLocomotionAnimPresenter : public LegoLoopingAnimPresenter { void PutFrame() override; // vtable+0x6c MxResult CreateAnim(MxStreamChunk* p_chunk) override; // vtable+0x88 - void FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value); + void CreateROIAndBuildMap(LegoAnimActor* p_actor, MxFloat p_worldSpeed); - void DecrementUnknown0xd4() + void DecrementWorldRefCounter() { - if (m_unk0xd4) { - --m_unk0xd4; + if (m_worldRefCounter) { + --m_worldRefCounter; } } - undefined2 GetUnknown0xd4() { return m_unk0xd4; } + MxS16 GetWorldRefCounter() { return m_worldRefCounter; } // SYNTHETIC: LEGO1 0x1006cfe0 // LegoLocomotionAnimPresenter::`scalar deleting destructor' @@ -254,7 +260,7 @@ class LegoLocomotionAnimPresenter : public LegoLoopingAnimPresenter { LegoROIMapList* m_roiMapList; // 0xc8 MxS32 m_unk0xcc; // 0xcc MxS32 m_unk0xd0; // 0xd0 - undefined2 m_unk0xd4; // 0xd4 + MxS16 m_worldRefCounter; // 0xd4 }; class LegoPathBoundary; @@ -279,10 +285,10 @@ class LegoHideAnimPresenter : public LegoLoopingAnimPresenter { ~LegoHideAnimPresenter() override; // FUNCTION: LEGO1 0x1006d860 - void VTable0x8c() override {} // vtable+0x8c + void AddToWorld() override {} // vtable+0x8c // FUNCTION: LEGO1 0x1006d870 - void VTable0x90() override {} // vtable+0x90 + void RemoveFromWorld() override {} // vtable+0x90 // FUNCTION: BETA10 0x1005d4a0 static const char* HandlerClassName() @@ -311,7 +317,7 @@ class LegoHideAnimPresenter : public LegoLoopingAnimPresenter { void EndAction() override; // vtable+0x40 void PutFrame() override; // vtable+0x6c - void FUN_1006db40(LegoTime p_time); + void ApplyVisibility(LegoTime p_time); // SYNTHETIC: LEGO1 0x1006d9d0 // LegoHideAnimPresenter::`scalar deleting destructor' @@ -319,10 +325,10 @@ class LegoHideAnimPresenter : public LegoLoopingAnimPresenter { private: void Init(); void Destroy(MxBool p_fromDestructor); - void FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time); - void FUN_1006dc10(); - void FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node); - void FUN_1006e470( + void ApplyVisibility(LegoTreeNode* p_node, LegoTime p_time); + void AssignIndiciesWithMap(); + void BuildMap(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node); + void CheckedAdd( LegoHideAnimStructMap& p_map, LegoAnimNodeData* p_data, const char* p_name, diff --git a/LEGO1/lego/legoomni/src/actors/act3actors.cpp b/LEGO1/lego/legoomni/src/actors/act3actors.cpp index dc72f5e2..d4e82e40 100644 --- a/LEGO1/lego/legoomni/src/actors/act3actors.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3actors.cpp @@ -1216,7 +1216,7 @@ void Act3Shark::ParseAction(char* p_extra) token = strtok(NULL, g_parseExtraTokens); if (token != NULL) { - presenter->FUN_1006d680(this, atof(token)); + presenter->CreateROIAndBuildMap(this, atof(token)); } } diff --git a/LEGO1/lego/legoomni/src/actors/doors.cpp b/LEGO1/lego/legoomni/src/actors/doors.cpp index 2b8da804..af37219e 100644 --- a/LEGO1/lego/legoomni/src/actors/doors.cpp +++ b/LEGO1/lego/legoomni/src/actors/doors.cpp @@ -70,7 +70,7 @@ void Doors::Animate(float p_time) assert(m_ltDoor && m_rtDoor); // TODO: Match - m_roi->SetVisibility(m_boundary->GetFlag0x10()); + m_roi->SetVisibility(m_boundary->GetVisibility()); switch (m_state) { case e_none: diff --git a/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp b/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp index 591c2dcd..e097b1a5 100644 --- a/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp +++ b/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp @@ -121,7 +121,7 @@ void LegoCarBuildAnimPresenter::PutFrame() MoveShelfForward(); case e_stopped: if (m_carBuildEntity->GetROI()) { - FUN_1006b9a0(m_anim, m_shelfFrameBuffer, NULL); + ApplyTransformWithVisibilityAndCam(m_anim, m_shelfFrameBuffer, NULL); } default: break; @@ -589,7 +589,7 @@ void LegoCarBuildAnimPresenter::RotateAroundYAxis(MxFloat p_angle) m_platformAnimNodeData->GetRotationKey(0)->SetAngle(newRotation[3]); if (m_carBuildEntity->GetROI()) { - FUN_1006b9a0(&m_platformAnim, m_shelfFrameBuffer, NULL); + ApplyTransformWithVisibilityAndCam(&m_platformAnim, m_shelfFrameBuffer, NULL); } } } diff --git a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp index 6ad8cc85..b0ff001a 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp @@ -2384,7 +2384,7 @@ MxBool LegoAnimationManager::FUN_10063b90(LegoWorld* p_world, LegoExtraActor* p_ presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC); if (presenter != NULL) { - presenter->FUN_1006d680(p_actor, 1.7f); + presenter->CreateROIAndBuildMap(p_actor, 1.7f); } g_vehicles[g_characters[p_characterId].m_vehicleId].m_unk0x04 = FALSE; @@ -2397,7 +2397,7 @@ MxBool LegoAnimationManager::FUN_10063b90(LegoWorld* p_world, LegoExtraActor* p_ presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC); if (presenter != NULL) { - presenter->FUN_1006d680(p_actor, 0.7f); + presenter->CreateROIAndBuildMap(p_actor, 0.7f); } } @@ -2410,7 +2410,7 @@ MxBool LegoAnimationManager::FUN_10063b90(LegoWorld* p_world, LegoExtraActor* p_ presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC); if (presenter != NULL) { - presenter->FUN_1006d680(p_actor, 4.0f); + presenter->CreateROIAndBuildMap(p_actor, 4.0f); } } @@ -2423,7 +2423,7 @@ MxBool LegoAnimationManager::FUN_10063b90(LegoWorld* p_world, LegoExtraActor* p_ presenter = (LegoLocomotionAnimPresenter*) p_world->Find("LegoAnimPresenter", vehicleWC); if (presenter != NULL) { - presenter->FUN_1006d680(p_actor, 0.0f); + presenter->CreateROIAndBuildMap(p_actor, 0.0f); } } @@ -2712,12 +2712,12 @@ MxResult LegoAnimationManager::FUN_10064380( LegoLocomotionAnimPresenter* presenter = (LegoLocomotionAnimPresenter*) world->Find("LegoAnimPresenter", cycles[p_undIdx1]); if (presenter != NULL) { - presenter->FUN_1006d680(actor, 0.0f); + presenter->CreateROIAndBuildMap(actor, 0.0f); } presenter = (LegoLocomotionAnimPresenter*) world->Find("LegoAnimPresenter", cycles[p_undIdx2]); if (presenter != NULL) { - presenter->FUN_1006d680(actor, 4.0f); + presenter->CreateROIAndBuildMap(actor, 4.0f); } m_extras[i].m_unk0x08 = Timer()->GetTime(); diff --git a/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp b/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp index 2f54d8ff..4b6804c1 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp @@ -152,7 +152,7 @@ void LegoAnimMMPresenter::ReadyTickle() } if (m_tranInfo != NULL && m_tranInfo->m_unk0x0c != NULL) { - m_presenter->VTable0xa0(*m_tranInfo->m_unk0x0c); + m_presenter->SetTransform(*m_tranInfo->m_unk0x0c); } if (m_presenter != NULL) { @@ -168,7 +168,7 @@ void LegoAnimMMPresenter::StartingTickle() { if (m_presenter == NULL || m_presenter->GetCurrentTickleState() == e_idle) { if (m_tranInfo != NULL && m_tranInfo->m_unk0x08 != NULL) { - m_presenter->FUN_1006b140(m_tranInfo->m_unk0x08); + m_presenter->CopyTransform(m_tranInfo->m_unk0x08); } m_unk0x50 = Timer()->GetTime(); @@ -316,7 +316,7 @@ MxBool LegoAnimMMPresenter::FUN_1004b450() MxBool LegoAnimMMPresenter::FUN_1004b530(MxLong p_time) { if (m_presenter != NULL) { - m_presenter->FUN_1006afc0(m_unk0x68, 0); + m_presenter->GetTransforms(m_unk0x68, 0); m_roiMap = m_presenter->GetROIMap(m_roiMapSize); m_roiMapSize++; } @@ -498,7 +498,7 @@ void LegoAnimMMPresenter::FUN_1004b840() MxDSAction* action = m_action; if (m_presenter != NULL) { - m_presenter->FUN_1006c7a0(); + m_presenter->ApplyFinishedTransform(); } for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { diff --git a/LEGO1/lego/legoomni/src/entity/legoworld.cpp b/LEGO1/lego/legoomni/src/entity/legoworld.cpp index c9c84915..47b54d8b 100644 --- a/LEGO1/lego/legoomni/src/entity/legoworld.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoworld.cpp @@ -117,8 +117,8 @@ void LegoWorld::Destroy(MxBool p_fromDestructor) if (presenter->IsA("LegoLocomotionAnimPresenter")) { LegoLocomotionAnimPresenter* animPresenter = (LegoLocomotionAnimPresenter*) presenter; - animPresenter->DecrementUnknown0xd4(); - if (animPresenter->GetUnknown0xd4() == 0) { + animPresenter->DecrementWorldRefCounter(); + if (animPresenter->GetWorldRefCounter() == 0) { ApplyMask(action, MxDSAction::c_world, FALSE); presenter->EndAction(); } diff --git a/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp b/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp index 4fdaebc6..2fd3529f 100644 --- a/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp @@ -109,7 +109,7 @@ MxResult LegoAnimActor::AnimateWithTransform(float p_time, Matrix4& p_transform) LegoROI** roiMap = m_animMaps[m_curAnim]->m_roiMap; MxU32 numROIs = m_animMaps[m_curAnim]->m_numROIs; - if (!m_boundary->GetFlag0x10()) { + if (!m_boundary->GetVisibility()) { MxU32 i; m_roi->SetVisibility(FALSE); @@ -244,7 +244,7 @@ void LegoAnimActor::ParseAction(char* p_extra) token = strtok(NULL, g_parseExtraTokens); if (token) { - p->FUN_1006d680(this, atof(token)); + p->CreateROIAndBuildMap(this, atof(token)); } } diff --git a/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp b/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp index 103728b5..96581e9f 100644 --- a/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp @@ -166,7 +166,7 @@ inline void LegoExtraActor::InitializeReassemblyAnim() if (!m_assAnim) { MxS32 index = 0; - m_assAnimP->FUN_1006d680(this, -20.0f); + m_assAnimP->CreateROIAndBuildMap(this, -20.0f); for (MxS32 i = 0; i < m_animMaps.size(); i++) { if (m_animMaps[i]->GetWorldSpeed() == -20.0f) { @@ -178,7 +178,7 @@ inline void LegoExtraActor::InitializeReassemblyAnim() if (!m_disAnim) { MxS32 index = 0; - m_disAnimP->FUN_1006d680(this, -21.0f); + m_disAnimP->CreateROIAndBuildMap(this, -21.0f); for (MxS32 i = 0; i < m_animMaps.size(); i++) { if (m_animMaps[i]->GetWorldSpeed() == -21.0f) { @@ -434,7 +434,7 @@ inline MxU32 LegoExtraActor::VTable0x6c( LegoAnimPresenterSet& presenters = p_boundary->GetPresenters(); for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) { - if ((*itap)->VTable0x94(p_v1, p_v2, p_f1, p_f2, p_v3)) { + if ((*itap)->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3)) { return 1; } } diff --git a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp index 7233c218..803fc222 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp @@ -471,7 +471,7 @@ MxU32 LegoPathActor::VTable0x6c( LegoAnimPresenterSet& presenters = p_boundary->GetPresenters(); for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) { - if ((*itap)->VTable0x94(p_v1, p_v2, p_f1, p_f2, p_v3)) { + if ((*itap)->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3)) { return 1; } } diff --git a/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp b/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp index 8ef3c323..5504ef8d 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp @@ -341,15 +341,15 @@ MxU32 LegoPathBoundary::Intersect( // FUNCTION: BETA10 0x100b2220 MxU32 LegoPathBoundary::AddPresenterIfInRange(LegoAnimPresenter* p_presenter) { - Mx3DPointFloat unk0x30; + Mx3DPointFloat centerDistance; - unk0x30 = m_centerPoint; - unk0x30 -= p_presenter->m_unk0xa8; + centerDistance = m_centerPoint; + centerDistance -= p_presenter->m_centerPoint; - float len = unk0x30.LenSquared(); - float local20 = p_presenter->m_unk0xa4 + m_boundingRadius; + float len = centerDistance.LenSquared(); + float radiusSquared = p_presenter->m_boundingRadius + m_boundingRadius; - if (len > 0.001 && len > local20 * local20) { + if (len > 0.001 && len > radiusSquared * radiusSquared) { return 0; } diff --git a/LEGO1/lego/legoomni/src/paths/legopathstruct.cpp b/LEGO1/lego/legoomni/src/paths/legopathstruct.cpp index 15cca7c4..4f40ace4 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathstruct.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathstruct.cpp @@ -68,7 +68,7 @@ MxBool LegoPathStruct::HandleTrigger(LegoPathActor* p_actor, MxBool p_direction, case c_h: { LegoHideAnimPresenter* presenter = m_world->GetHideAnimPresenter(); if (presenter != NULL) { - presenter->FUN_1006db40(p_data * 100); + presenter->ApplyVisibility(p_data * 100); } break; } diff --git a/LEGO1/lego/legoomni/src/race/carrace.cpp b/LEGO1/lego/legoomni/src/race/carrace.cpp index 8fc3e24e..8a540154 100644 --- a/LEGO1/lego/legoomni/src/race/carrace.cpp +++ b/LEGO1/lego/legoomni/src/race/carrace.cpp @@ -117,7 +117,7 @@ void CarRace::ReadyWorld() { assert(m_hideAnim); LegoWorld::ReadyWorld(); - m_hideAnim->FUN_1006db40(0); + m_hideAnim->ApplyVisibility(0); MxDSAction action; action.SetAtomId(*g_jukeboxScript); diff --git a/LEGO1/lego/legoomni/src/race/jetskirace.cpp b/LEGO1/lego/legoomni/src/race/jetskirace.cpp index 66c2e5fa..94891925 100644 --- a/LEGO1/lego/legoomni/src/race/jetskirace.cpp +++ b/LEGO1/lego/legoomni/src/race/jetskirace.cpp @@ -81,7 +81,7 @@ void JetskiRace::ReadyWorld() { assert(m_hideAnim); LegoWorld::ReadyWorld(); - m_hideAnim->FUN_1006db40(0); + m_hideAnim->ApplyVisibility(0); MxDSAction action; action.SetAtomId(*g_jukeboxScript); @@ -213,7 +213,7 @@ MxLong JetskiRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) result = 1; } else if (m_playerLastPathStruct == 0xf) { - m_hideAnim->FUN_1006db40(m_playerLaps * 200 + 100); + m_hideAnim->ApplyVisibility(m_playerLaps * 200 + 100); result = 1; } diff --git a/LEGO1/lego/legoomni/src/race/legoracespecial.cpp b/LEGO1/lego/legoomni/src/race/legoracespecial.cpp index 72099caf..b02479b6 100644 --- a/LEGO1/lego/legoomni/src/race/legoracespecial.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracespecial.cpp @@ -432,7 +432,7 @@ inline MxU32 LegoCarRaceActor::VTable0x6c( LegoAnimPresenterSet& presenters = p_boundary->GetPresenters(); for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) { - if ((*itap)->VTable0x94(p_v1, p_v2, p_f1, p_f2, p_v3)) { + if ((*itap)->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3)) { return 1; } } @@ -516,7 +516,7 @@ inline MxU32 LegoJetskiRaceActor::VTable0x6c( LegoAnimPresenterSet& presenters = p_boundary->GetPresenters(); for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) { - if ((*itap)->VTable0x94(p_v1, p_v2, p_f1, p_f2, p_v3)) { + if ((*itap)->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3)) { return 1; } } diff --git a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp index 1ee5aba4..138fc51e 100644 --- a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp @@ -54,21 +54,21 @@ void LegoAnimPresenter::Init() m_roiMapSize = 0; m_managedActors = NULL; m_sceneROIs = NULL; - m_unk0x78 = NULL; + m_transform = NULL; m_flags = 0; - m_unk0xa8.Clear(); - m_unk0xa4 = 0; + m_centerPoint.Clear(); + m_boundingRadius = 0; m_currentWorld = NULL; - m_unk0x95 = FALSE; + m_animationFinished = FALSE; m_worldId = -1; m_substMap = NULL; m_worldAtom.Clear(); - m_unk0x9c = 0; - m_unk0x8c = NULL; - m_unk0x90 = NULL; - m_unk0x94 = 0; - m_unk0x96 = TRUE; - m_unk0xa0 = NULL; + m_roiTransformApplied = 0; + m_ptAtCamROI = NULL; + m_ptAtCamNames = NULL; + m_ptAtCamCount = 0; + m_localActors = TRUE; + m_roiTransform = NULL; } // FUNCTION: LEGO1 0x10068770 @@ -91,12 +91,12 @@ void LegoAnimPresenter::Destroy(MxBool p_fromDestructor) } if (m_managedActors != NULL) { - FUN_1006aa60(); + ReleaseManagedActors(); delete m_managedActors; } - if (m_unk0x78 != NULL) { - delete m_unk0x78; + if (m_transform != NULL) { + delete m_transform; } if (m_substMap != NULL) { @@ -112,22 +112,22 @@ void LegoAnimPresenter::Destroy(MxBool p_fromDestructor) delete m_substMap; } - if (m_unk0x90 != NULL) { - for (MxS32 i = 0; i < m_unk0x94; i++) { - if (m_unk0x90[i] != NULL) { - delete[] m_unk0x90[i]; + if (m_ptAtCamNames != NULL) { + for (MxS32 i = 0; i < m_ptAtCamCount; i++) { + if (m_ptAtCamNames[i] != NULL) { + delete[] m_ptAtCamNames[i]; } } - delete[] m_unk0x90; + delete[] m_ptAtCamNames; } - if (m_unk0x8c != NULL) { - delete[] m_unk0x8c; + if (m_ptAtCamROI != NULL) { + delete[] m_ptAtCamROI; } - if (m_unk0xa0 != NULL) { - delete m_unk0xa0; + if (m_roiTransform != NULL) { + delete m_roiTransform; } Init(); @@ -150,16 +150,16 @@ MxResult LegoAnimPresenter::CreateAnim(MxStreamChunk* p_chunk) if (storage.Read(&magicSig, sizeof(MxS32)) != SUCCESS || magicSig != 0x11) { goto done; } - if (storage.Read(&m_unk0xa4, sizeof(float)) != SUCCESS) { + if (storage.Read(&m_boundingRadius, sizeof(float)) != SUCCESS) { goto done; } - if (storage.Read(&m_unk0xa8[0], sizeof(float)) != SUCCESS) { + if (storage.Read(&m_centerPoint[0], sizeof(float)) != SUCCESS) { goto done; } - if (storage.Read(&m_unk0xa8[1], sizeof(float)) != SUCCESS) { + if (storage.Read(&m_centerPoint[1], sizeof(float)) != SUCCESS) { goto done; } - if (storage.Read(&m_unk0xa8[2], sizeof(float)) != SUCCESS) { + if (storage.Read(&m_centerPoint[2], sizeof(float)) != SUCCESS) { goto done; } if (storage.Read(&parseScene, sizeof(LegoS32)) != SUCCESS) { @@ -190,24 +190,24 @@ MxResult LegoAnimPresenter::CreateAnim(MxStreamChunk* p_chunk) } // FUNCTION: LEGO1 0x10069150 -LegoChar* LegoAnimPresenter::FUN_10069150(const LegoChar* p_und1) +LegoChar* LegoAnimPresenter::GetActorName(const LegoChar* p_name) { LegoChar* str; - if (LegoCharacterManager::IsActor(p_und1 + 1)) { - str = new LegoChar[strlen(p_und1)]; + if (LegoCharacterManager::IsActor(p_name + 1)) { + str = new LegoChar[strlen(p_name)]; if (str != NULL) { - strcpy(str, p_und1 + 1); + strcpy(str, p_name + 1); } } else { LegoChar buffer[32]; sprintf(buffer, "%d", m_action->GetUnknown24()); - str = new LegoChar[strlen(p_und1) + strlen(buffer) + strlen(GetActionObjectName()) + 1]; + str = new LegoChar[strlen(p_name) + strlen(buffer) + strlen(GetActionObjectName()) + 1]; if (str != NULL) { - strcpy(str, p_und1); + strcpy(str, p_name); strcat(str, buffer); strcat(str, GetActionObjectName()); } @@ -217,7 +217,7 @@ LegoChar* LegoAnimPresenter::FUN_10069150(const LegoChar* p_und1) } // FUNCTION: LEGO1 0x100692b0 -void LegoAnimPresenter::FUN_100692b0() +void LegoAnimPresenter::CreateManagedActors() { m_managedActors = new LegoROIList(); @@ -229,7 +229,7 @@ void LegoAnimPresenter::FUN_100692b0() LegoU32 actorType = m_anim->GetActorType(i); LegoROI* roi = NULL; - if (actorType == LegoAnimActorEntry::e_actorType2) { + if (actorType == LegoAnimActorEntry::e_managedLegoActor) { LegoChar* src; if (str[0] == '*') { src = str + 1; @@ -244,44 +244,44 @@ void LegoAnimPresenter::FUN_100692b0() roi->SetVisibility(FALSE); } } - else if (actorType == LegoAnimActorEntry::e_actorType4) { + else if (actorType == LegoAnimActorEntry::e_managedInvisibleRoi) { LegoChar* baseName = new LegoChar[strlen(str)]; strcpy(baseName, str + 1); strlwr(baseName); - LegoChar* und = FUN_10069150(str); - roi = CharacterManager()->FUN_10085a80(und, baseName, TRUE); + LegoChar* roiName = GetActorName(str); + roi = CharacterManager()->FUN_10085a80(roiName, baseName, TRUE); if (roi != NULL) { roi->SetVisibility(FALSE); } delete[] baseName; - delete[] und; + delete[] roiName; } - else if (actorType == LegoAnimActorEntry::e_actorType3) { + else if (actorType == LegoAnimActorEntry::e_managedInvisibleRoiTrimmed) { LegoChar* lodName = new LegoChar[strlen(str)]; strcpy(lodName, str + 1); - for (LegoChar* i = &lodName[strlen(lodName) - 1]; i > lodName; i--) { - if ((*i < '0' || *i > '9') && *i != '_') { + for (LegoChar* c = &lodName[strlen(lodName) - 1]; c > lodName; c--) { + if ((*c < '0' || *c > '9') && *c != '_') { break; } - *i = '\0'; + *c = '\0'; } strlwr(lodName); - LegoChar* und = FUN_10069150(str); - roi = CharacterManager()->CreateAutoROI(und, lodName, TRUE); + LegoChar* roiName = GetActorName(str); + roi = CharacterManager()->CreateAutoROI(roiName, lodName, TRUE); if (roi != NULL) { roi->SetVisibility(FALSE); } delete[] lodName; - delete[] und; + delete[] roiName; } if (roi != NULL) { @@ -295,7 +295,7 @@ void LegoAnimPresenter::FUN_100692b0() // FUNCTION: LEGO1 0x100695c0 // FUNCTION: BETA10 0x1004f359 -void LegoAnimPresenter::FUN_100695c0() +void LegoAnimPresenter::CreateSceneROIs() { m_sceneROIs = new LegoROIList(); @@ -304,10 +304,10 @@ void LegoAnimPresenter::FUN_100695c0() LegoU32 numActors = m_anim->GetNumActors(); for (LegoU32 i = 0; i < numActors; i++) { - if (FUN_100698b0(rois, m_anim->GetActorName(i)) == FALSE) { + if (AppendROIToScene(rois, m_anim->GetActorName(i)) == FALSE) { LegoU32 actorType = m_anim->GetActorType(i); - if (actorType == LegoAnimActorEntry::e_actorType5 || actorType == LegoAnimActorEntry::e_actorType6) { + if (actorType == LegoAnimActorEntry::e_sceneRoi1 || actorType == LegoAnimActorEntry::e_sceneRoi2) { LegoChar lodName[256]; const LegoChar* actorName = m_anim->GetActorName(i); @@ -321,7 +321,7 @@ void LegoAnimPresenter::FUN_100695c0() strlwr(lodName); CharacterManager()->CreateAutoROI(actorName, lodName, FALSE); - FUN_100698b0(rois, actorName); + AppendROIToScene(rois, actorName); } } } @@ -356,13 +356,13 @@ LegoChar* LegoAnimPresenter::GetVariableOrIdentity(const LegoChar* p_varName, co } // FUNCTION: LEGO1 0x100698b0 -LegoBool LegoAnimPresenter::FUN_100698b0(const CompoundObject& p_rois, const LegoChar* p_und2) +LegoBool LegoAnimPresenter::AppendROIToScene(const CompoundObject& p_rois, const LegoChar* p_varName) { LegoBool result = FALSE; LegoChar* str; - if (*(str = GetVariableOrIdentity(p_und2, NULL)) == '*') { - LegoChar* tmp = FUN_10069150(str); + if (*(str = GetVariableOrIdentity(p_varName, NULL)) == '*') { + LegoChar* tmp = GetActorName(str); delete[] str; str = tmp; } @@ -407,12 +407,12 @@ LegoROI* LegoAnimPresenter::FindROI(const LegoChar* p_name) } // FUNCTION: LEGO1 0x10069b10 -void LegoAnimPresenter::FUN_10069b10() +void LegoAnimPresenter::BuildROIMap() { LegoAnimStructMap anims; - if (m_unk0x8c != NULL) { - memset(m_unk0x8c, 0, m_unk0x94 * sizeof(*m_unk0x8c)); + if (m_ptAtCamROI != NULL) { + memset(m_ptAtCamROI, 0, m_ptAtCamCount * sizeof(*m_ptAtCamROI)); } UpdateStructMapAndROIIndex(anims, m_anim->GetRoot(), NULL); @@ -431,10 +431,10 @@ void LegoAnimPresenter::FUN_10069b10() m_roiMap[index] = (*it).second.m_roi; if (m_roiMap[index]->GetName() != NULL) { - for (MxS32 i = 0; i < m_unk0x94; i++) { - if (m_unk0x8c[i] == NULL && m_unk0x90[i] != NULL) { - if (!strcmpi(m_unk0x90[i], m_roiMap[index]->GetName())) { - m_unk0x8c[i] = m_roiMap[index]; + for (MxS32 i = 0; i < m_ptAtCamCount; i++) { + if (m_ptAtCamROI[i] == NULL && m_ptAtCamNames[i] != NULL) { + if (!strcmpi(m_ptAtCamNames[i], m_roiMap[index]->GetName())) { + m_ptAtCamROI[i] = m_roiMap[index]; break; } } @@ -458,7 +458,7 @@ void LegoAnimPresenter::UpdateStructMapAndROIIndex(LegoAnimStructMap& p_map, Leg if (name != NULL && *name != '-') { if (*name == '*') { - name = und2 = FUN_10069150(name); + name = und2 = GetActorName(name); } und = GetVariableOrIdentity(name, p_roi != NULL ? p_roi->GetName() : NULL); @@ -503,13 +503,13 @@ void LegoAnimPresenter::UpdateStructMapAndROIIndex(LegoAnimStructMap& p_map, Leg void LegoAnimPresenter::UpdateStructMapAndROIIndexForNode( LegoAnimStructMap& p_map, LegoAnimNodeData* p_data, - const LegoChar* p_und, + const LegoChar* p_key, LegoROI* p_roi ) { LegoAnimStructMap::iterator it; - it = p_map.find(p_und); + it = p_map.find(p_key); if (it == p_map.end()) { LegoAnimStruct animStruct; animStruct.m_index = p_map.size() + 1; @@ -517,10 +517,10 @@ void LegoAnimPresenter::UpdateStructMapAndROIIndexForNode( p_data->SetROIIndex(animStruct.m_index); - LegoChar* und = new LegoChar[strlen(p_und) + 1]; - strcpy(und, p_und); + LegoChar* key = new LegoChar[strlen(p_key) + 1]; + strcpy(key, p_key); - p_map[und] = animStruct; + p_map[key] = animStruct; } else { p_data->SetROIIndex((*it).second.m_index); @@ -529,7 +529,7 @@ void LegoAnimPresenter::UpdateStructMapAndROIIndexForNode( // FUNCTION: LEGO1 0x1006aa60 // FUNCTION: BETA10 0x1004feee -void LegoAnimPresenter::FUN_1006aa60() +void LegoAnimPresenter::ReleaseManagedActors() { LegoROIListCursor cursor(m_managedActors); LegoROI* roi; @@ -537,16 +537,16 @@ void LegoAnimPresenter::FUN_1006aa60() while (cursor.Next(roi)) { const char* name = roi->GetName(); - if (m_unk0x96 || !CharacterManager()->IsActor(name)) { + if (m_localActors || !CharacterManager()->IsActor(name)) { CharacterManager()->ReleaseActor(name); } } } // FUNCTION: LEGO1 0x1006ab70 -void LegoAnimPresenter::FUN_1006ab70() +void LegoAnimPresenter::AppendManagedActors() { - if (m_unk0x96) { + if (m_localActors) { AnimationManager()->FUN_10063270(m_managedActors, this); } else { @@ -555,25 +555,25 @@ void LegoAnimPresenter::FUN_1006ab70() } // FUNCTION: LEGO1 0x1006aba0 -LegoBool LegoAnimPresenter::FUN_1006aba0() +LegoBool LegoAnimPresenter::VerifyAnimationTree() { - return FUN_1006abb0(m_anim->GetRoot(), 0); + return VerifyAnimationNode(m_anim->GetRoot(), NULL); } // FUNCTION: LEGO1 0x1006abb0 -MxBool LegoAnimPresenter::FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi) +MxBool LegoAnimPresenter::VerifyAnimationNode(LegoTreeNode* p_node, LegoROI* p_roi) { MxBool result = FALSE; LegoROI* roi = p_roi; - LegoChar* und = NULL; + LegoChar* varOrName = NULL; const LegoChar* name = ((LegoAnimNodeData*) p_node->GetData())->GetName(); MxS32 i, count; if (name != NULL && *name != '-') { - und = GetVariableOrIdentity(name, p_roi != NULL ? p_roi->GetName() : NULL); + varOrName = GetVariableOrIdentity(name, p_roi != NULL ? p_roi->GetName() : NULL); if (p_roi == NULL) { - roi = FindROI(und); + roi = FindROI(varOrName); if (roi == NULL) { goto done; @@ -584,7 +584,7 @@ MxBool LegoAnimPresenter::FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi) if (child == NULL) { if (FindROI(name) != NULL) { - if (FUN_1006abb0(p_node, NULL)) { + if (VerifyAnimationNode(p_node, NULL)) { result = TRUE; } } @@ -596,7 +596,7 @@ MxBool LegoAnimPresenter::FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi) count = p_node->GetNumChildren(); for (i = 0; i < count; i++) { - if (!FUN_1006abb0(p_node->GetChild(i), roi)) { + if (!VerifyAnimationNode(p_node->GetChild(i), roi)) { goto done; } } @@ -604,8 +604,8 @@ MxBool LegoAnimPresenter::FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi) result = TRUE; done: - if (und != NULL) { - delete[] und; + if (varOrName != NULL) { + delete[] varOrName; } return result; @@ -637,12 +637,12 @@ void LegoAnimPresenter::PutFrame() time = 0; } - FUN_1006b9a0(m_anim, time, m_unk0x78); + ApplyTransformWithVisibilityAndCam(m_anim, time, m_transform); - if (m_unk0x8c != NULL && m_currentWorld != NULL && m_currentWorld->GetCameraController() != NULL) { - for (MxS32 i = 0; i < m_unk0x94; i++) { - if (m_unk0x8c[i] != NULL) { - MxMatrix mat(m_unk0x8c[i]->GetLocal2World()); + if (m_ptAtCamROI != NULL && m_currentWorld != NULL && m_currentWorld->GetCameraController() != NULL) { + for (MxS32 i = 0; i < m_ptAtCamCount; i++) { + if (m_ptAtCamROI[i] != NULL) { + MxMatrix mat(m_ptAtCamROI[i]->GetLocal2World()); Vector3 pos(mat[0]); Vector3 dir(mat[1]); @@ -664,8 +664,8 @@ void LegoAnimPresenter::PutFrame() dir *= dirsqr; up *= upsqr; - m_unk0x8c[i]->SetLocal2World(mat); - m_unk0x8c[i]->WrappedUpdateWorldData(); + m_ptAtCamROI[i]->SetLocal2World(mat); + m_ptAtCamROI[i]->WrappedUpdateWorldData(); } } } @@ -674,7 +674,7 @@ void LegoAnimPresenter::PutFrame() // FUNCTION: LEGO1 0x1006afc0 // FUNCTION: BETA10 0x1005059a -MxResult LegoAnimPresenter::FUN_1006afc0(MxMatrix*& p_matrix, float p_und) +MxResult LegoAnimPresenter::GetTransforms(MxMatrix*& p_matrix, float p_time) { MxU32 length = m_roiMapSize + 1; p_matrix = new MxMatrix[length]; @@ -686,7 +686,7 @@ MxResult LegoAnimPresenter::FUN_1006afc0(MxMatrix*& p_matrix, float p_und) } } - FUN_1006b900(m_anim, p_und, m_unk0x78); + ApplyTransform(m_anim, p_time, m_transform); for (i = 1; i < length; i++) { MxMatrix mat; @@ -703,7 +703,7 @@ MxResult LegoAnimPresenter::FUN_1006afc0(MxMatrix*& p_matrix, float p_und) // FUNCTION: LEGO1 0x1006b140 // FUNCTION: BETA10 0x100507e0 -MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi) +MxResult LegoAnimPresenter::CopyTransform(LegoROI* p_roi) { if (p_roi == NULL) { return FAILURE; @@ -717,16 +717,16 @@ MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi) MxMatrix inverse; const Matrix4& local2world = p_roi->GetLocal2World(); - MxMatrix* local5c; + MxMatrix* roiTransforms; MxU32 i; - if (FUN_1006afc0(local5c, 0.0f) != SUCCESS) { + if (GetTransforms(roiTransforms, 0.0f) != SUCCESS) { goto done; } for (i = 1; i <= m_roiMapSize; i++) { if (m_roiMap[i] == p_roi) { - if (local5c[i].Invert(inverse) != SUCCESS) { + if (roiTransforms[i].Invert(inverse) != SUCCESS) { goto done; } @@ -736,15 +736,15 @@ MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi) { mn->Product(inverse, local2world); - SetUnknown0xa0(mn); - delete[] local5c; - SetUnknown0x0cTo1(); + SetRoiTransform(mn); + delete[] roiTransforms; + SetRoiTransformApplied(); - MxMatrix local140(*m_unk0x78); - MxMatrix localf8; + MxMatrix originalTransform(*m_transform); + MxMatrix newTransform; - localf8.Product(local140, *m_unk0xa0); - *m_unk0x78 = localf8; + newTransform.Product(originalTransform, *m_roiTransform); + *m_transform = newTransform; return SUCCESS; } @@ -753,8 +753,8 @@ MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi) delete mn; } - if (local5c != NULL) { - delete[] local5c; + if (roiTransforms != NULL) { + delete[] roiTransforms; } return FAILURE; @@ -790,22 +790,22 @@ void LegoAnimPresenter::ReadyTickle() void LegoAnimPresenter::StartingTickle() { SubstituteVariables(); - FUN_100692b0(); - FUN_100695c0(); + CreateManagedActors(); + CreateSceneROIs(); - if (m_flags & c_mustSucceed && !FUN_1006aba0()) { + if (m_flags & c_mustSucceed && !VerifyAnimationTree()) { goto done; } - FUN_10069b10(); + BuildROIMap(); SetDisabled(TRUE); - if (m_unk0x78 == NULL) { + if (m_transform == NULL) { if (fabs(m_action->GetDirection()[0]) >= 0.00000047683716F || fabs(m_action->GetDirection()[1]) >= 0.00000047683716F || fabs(m_action->GetDirection()[2]) >= 0.00000047683716F) { - m_unk0x78 = new MxMatrix(); - CalcLocalTransform(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp(), *m_unk0x78); + m_transform = new MxMatrix(); + CalcLocalTransform(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp(), *m_transform); } else if (m_roiMap != NULL) { LegoROI* roi = m_roiMap[1]; @@ -813,7 +813,7 @@ void LegoAnimPresenter::StartingTickle() if (roi != NULL) { MxMatrix mat; mat = roi->GetLocal2World(); - m_unk0x78 = new MxMatrix(mat); + m_transform = new MxMatrix(mat); } } } @@ -829,11 +829,11 @@ void LegoAnimPresenter::StartingTickle() ProgressTickleState(e_streaming); if (m_compositePresenter && m_compositePresenter->IsA("LegoAnimMMPresenter")) { - m_unk0x96 = ((LegoAnimMMPresenter*) m_compositePresenter)->FUN_1004b8b0(); + m_localActors = ((LegoAnimMMPresenter*) m_compositePresenter)->FUN_1004b8b0(); m_compositePresenter->AdvanceSerialAction(this); } - VTable0x8c(); + AddToWorld(); done: if (m_sceneROIs != NULL) { @@ -850,7 +850,7 @@ void LegoAnimPresenter::StreamingTickle() m_subscriber->FreeDataChunk(chunk); } - if (m_unk0x95) { + if (m_animationFinished) { ProgressTickleState(e_done); if (m_compositePresenter) { if (m_compositePresenter->IsA("LegoAnimMMPresenter")) { @@ -860,7 +860,7 @@ void LegoAnimPresenter::StreamingTickle() } else { if (m_action->GetElapsedTime() > m_anim->GetDuration() + m_action->GetStartTime()) { - m_unk0x95 = TRUE; + m_animationFinished = TRUE; } } } @@ -891,7 +891,7 @@ const char* LegoAnimPresenter::GetActionObjectName() // FUNCTION: LEGO1 0x1006b900 // FUNCTION: BETA10 0x100510d8 -void LegoAnimPresenter::FUN_1006b900(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix) +void LegoAnimPresenter::ApplyTransform(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix) { LegoTreeNode* root = p_anim->GetRoot(); MxMatrix mat; @@ -916,7 +916,7 @@ void LegoAnimPresenter::FUN_1006b900(LegoAnim* p_anim, MxLong p_time, Matrix4* p // FUNCTION: LEGO1 0x1006b9a0 // FUNCTION: BETA10 0x1005118b -void LegoAnimPresenter::FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix) +void LegoAnimPresenter::ApplyTransformWithVisibilityAndCam(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix) { LegoTreeNode* root = p_anim->GetRoot(); MxMatrix mat; @@ -1007,43 +1007,43 @@ void LegoAnimPresenter::ParseExtra() } if (KeyValueStringParse(output, g_strPTATCAM, extraCopy)) { - list tmp; + list tokens; - if (m_unk0x90 != NULL) { - for (MxS32 i = 0; i < m_unk0x94; i++) { - if (m_unk0x90[i] != NULL) { + if (m_ptAtCamNames != NULL) { + for (MxS32 i = 0; i < m_ptAtCamCount; i++) { + if (m_ptAtCamNames[i] != NULL) { // (modernization) critical bug: wrong free - delete[] m_unk0x90; + delete[] m_ptAtCamNames; } } - delete[] m_unk0x90; - m_unk0x90 = NULL; + delete[] m_ptAtCamNames; + m_ptAtCamNames = NULL; } - if (m_unk0x8c != NULL) { - delete[] m_unk0x8c; - m_unk0x8c = NULL; + if (m_ptAtCamROI != NULL) { + delete[] m_ptAtCamROI; + m_ptAtCamROI = NULL; } char* token = strtok(output, g_parseExtraTokens); while (token != NULL) { char* valueCopy = new char[strlen(token) + 1]; strcpy(valueCopy, token); - tmp.push_back(valueCopy); + tokens.push_back(valueCopy); token = strtok(NULL, g_parseExtraTokens); } - m_unk0x94 = tmp.size(); - if (m_unk0x94 != 0) { - m_unk0x8c = new LegoROI*[m_unk0x94]; - m_unk0x90 = new char*[m_unk0x94]; - memset(m_unk0x8c, 0, sizeof(*m_unk0x8c) * m_unk0x94); - memset(m_unk0x90, 0, sizeof(*m_unk0x90) * m_unk0x94); + m_ptAtCamCount = tokens.size(); + if (m_ptAtCamCount != 0) { + m_ptAtCamROI = new LegoROI*[m_ptAtCamCount]; + m_ptAtCamNames = new char*[m_ptAtCamCount]; + memset(m_ptAtCamROI, 0, sizeof(*m_ptAtCamROI) * m_ptAtCamCount); + memset(m_ptAtCamNames, 0, sizeof(*m_ptAtCamNames) * m_ptAtCamCount); MxS32 i = 0; - for (list::iterator it = tmp.begin(); it != tmp.end(); it++, i++) { - m_unk0x90[i] = *it; + for (list::iterator it = tokens.begin(); it != tokens.end(); it++, i++) { + m_ptAtCamNames[i] = *it; } } } @@ -1052,13 +1052,13 @@ void LegoAnimPresenter::ParseExtra() // FUNCTION: LEGO1 0x1006c570 // FUNCTION: BETA10 0x10051ab3 -void LegoAnimPresenter::VTable0xa0(Matrix4& p_matrix) +void LegoAnimPresenter::SetTransform(Matrix4& p_matrix) { - if (m_unk0x78 != NULL) { - delete m_unk0x78; + if (m_transform != NULL) { + delete m_transform; } - m_unk0x78 = new MxMatrix(p_matrix); + m_transform = new MxMatrix(p_matrix); } // FUNCTION: LEGO1 0x1006c620 @@ -1087,7 +1087,7 @@ void LegoAnimPresenter::EndAction() } if (m_anim != NULL) { - FUN_1006b9a0(m_anim, m_anim->GetDuration(), m_unk0x78); + ApplyTransformWithVisibilityAndCam(m_anim, m_anim->GetDuration(), m_transform); } if (m_roiMapSize != 0 && m_roiMap != NULL && m_roiMap[1] != NULL && m_flags & c_hideOnStop) { @@ -1099,8 +1099,8 @@ void LegoAnimPresenter::EndAction() } SetDisabled(FALSE); - FUN_1006ab70(); - VTable0x90(); + AppendManagedActors(); + RemoveFromWorld(); if (m_currentWorld != NULL) { m_currentWorld->Remove(this); @@ -1111,24 +1111,24 @@ void LegoAnimPresenter::EndAction() // FUNCTION: LEGO1 0x1006c7a0 // FUNCTION: BETA10 0x10051da6 -void LegoAnimPresenter::FUN_1006c7a0() +void LegoAnimPresenter::ApplyFinishedTransform() { if (m_anim != NULL) { - FUN_1006b9a0(m_anim, m_anim->GetDuration(), m_unk0x78); + ApplyTransformWithVisibilityAndCam(m_anim, m_anim->GetDuration(), m_transform); } - m_unk0x95 = TRUE; + m_animationFinished = TRUE; } // FUNCTION: LEGO1 0x1006c7d0 // FUNCTION: BETA10 0x10051e07 -void LegoAnimPresenter::VTable0x8c() +void LegoAnimPresenter::AddToWorld() { - if (m_unk0x78) { - m_unk0xa8 += (*m_unk0x78)[3]; + if (m_transform) { + m_centerPoint += (*m_transform)[3]; } else { - m_unk0xa8 += m_action->GetLocation(); + m_centerPoint += m_action->GetLocation(); } if (m_currentWorld == NULL) { @@ -1145,7 +1145,7 @@ void LegoAnimPresenter::VTable0x8c() // FUNCTION: LEGO1 0x1006c860 // FUNCTION: BETA10 0x10051f45 -void LegoAnimPresenter::VTable0x90() +void LegoAnimPresenter::RemoveFromWorld() { if (m_currentWorld != NULL) { m_currentWorld->RemovePresenterFromBoundaries(this); @@ -1179,26 +1179,34 @@ void LegoAnimPresenter::SetDisabled(MxBool p_disabled) // FUNCTION: LEGO1 0x1006c8f0 // FUNCTION: BETA10 0x1005206c -MxU32 LegoAnimPresenter::VTable0x94(Vector3& p_v1, Vector3& p_v2, float p_f1, float p_f2, Vector3& p_v3) +MxU32 LegoAnimPresenter::Intersect( + Vector3& p_rayOrigin, + Vector3& p_rayDirection, + float p_rayLength, + float p_radius, + Vector3& p_intersectionPoint +) { - Mx3DPointFloat a, b; + Mx3DPointFloat centerToRay, rayEnd; - b = p_v2; - b *= p_f1; - b += p_v1; + rayEnd = p_rayDirection; + rayEnd *= p_rayLength; + rayEnd += p_rayOrigin; - a = b; - a -= m_unk0xa8; + centerToRay = rayEnd; + centerToRay -= m_centerPoint; - float len = a.LenSquared(); + float len = centerToRay.LenSquared(); if (len <= 0.0f) { return TRUE; } len = sqrt(len); - if (len <= m_unk0xa4 + p_f2 && m_roiMapSize != 0 && m_roiMap != NULL) { + if (len <= m_boundingRadius + p_radius && m_roiMapSize != 0 && m_roiMap != NULL) { for (MxU32 i = 1; i <= m_roiMapSize; i++) { - if (m_roiMap[i]->GetLODCount() != 0 && m_roiMap[i]->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3, FALSE)) { + if (m_roiMap[i]->GetLODCount() != 0 && + m_roiMap[i] + ->Intersect(p_rayOrigin, p_rayDirection, p_rayLength, p_radius, p_intersectionPoint, FALSE)) { return TRUE; } } @@ -1209,7 +1217,7 @@ MxU32 LegoAnimPresenter::VTable0x94(Vector3& p_v1, Vector3& p_v2, float p_f1, fl // FUNCTION: LEGO1 0x1006ca50 // FUNCTION: BETA10 0x100521d0 -MxResult LegoAnimPresenter::VTable0x98(LegoPathBoundary* p_boundary) +MxResult LegoAnimPresenter::AddActors(LegoPathBoundary* p_boundary) { for (MxU32 i = 1; i <= m_roiMapSize; i++) { LegoEntity* entity = m_roiMap[i]->GetEntity(); @@ -1231,7 +1239,7 @@ void LegoLoopingAnimPresenter::StreamingTickle() m_subscriber->FreeDataChunk(chunk); } - if (m_unk0x95) { + if (m_animationFinished) { ProgressTickleState(e_done); if (m_compositePresenter) { if (m_compositePresenter->IsA("LegoAnimMMPresenter")) { @@ -1242,7 +1250,7 @@ void LegoLoopingAnimPresenter::StreamingTickle() else { if (m_action->GetDuration() != -1) { if (m_action->GetElapsedTime() > m_action->GetDuration() + m_action->GetStartTime()) { - m_unk0x95 = TRUE; + m_animationFinished = TRUE; } } } @@ -1261,12 +1269,12 @@ void LegoLoopingAnimPresenter::PutFrame() time = 0; } - FUN_1006b9a0(m_anim, time, m_unk0x78); + ApplyTransformWithVisibilityAndCam(m_anim, time, m_transform); - if (m_unk0x8c != NULL && m_currentWorld != NULL && m_currentWorld->GetCameraController() != NULL) { - for (MxS32 i = 0; i < m_unk0x94; i++) { - if (m_unk0x8c[i] != NULL) { - MxMatrix mat(m_unk0x8c[i]->GetLocal2World()); + if (m_ptAtCamROI != NULL && m_currentWorld != NULL && m_currentWorld->GetCameraController() != NULL) { + for (MxS32 i = 0; i < m_ptAtCamCount; i++) { + if (m_ptAtCamROI[i] != NULL) { + MxMatrix mat(m_ptAtCamROI[i]->GetLocal2World()); Vector3 pos(mat[0]); Vector3 dir(mat[1]); @@ -1288,8 +1296,8 @@ void LegoLoopingAnimPresenter::PutFrame() dir *= dirsqr; up *= upsqr; - m_unk0x8c[i]->SetLocal2World(mat); - m_unk0x8c[i]->WrappedUpdateWorldData(); + m_ptAtCamROI[i]->SetLocal2World(mat); + m_ptAtCamROI[i]->WrappedUpdateWorldData(); } } } @@ -1315,7 +1323,7 @@ void LegoLocomotionAnimPresenter::Init() m_unk0xcc = -1; m_unk0xd0 = -1; m_roiMapList = NULL; - m_unk0xd4 = 0; + m_worldRefCounter = 0; } // FUNCTION: LEGO1 0x1006d0e0 @@ -1384,7 +1392,7 @@ void LegoLocomotionAnimPresenter::ReadyTickle() SendToCompositePresenter(Lego()); } - m_unk0xd4++; + m_worldRefCounter++; } } @@ -1405,7 +1413,7 @@ void LegoLocomotionAnimPresenter::StartingTickle() // FUNCTION: LEGO1 0x1006d660 void LegoLocomotionAnimPresenter::StreamingTickle() { - if (m_unk0xd4 == 0) { + if (m_worldRefCounter == 0) { EndAction(); } } @@ -1420,7 +1428,7 @@ void LegoLocomotionAnimPresenter::EndAction() // FUNCTION: LEGO1 0x1006d680 // FUNCTION: BETA10 0x10052b3d -void LegoLocomotionAnimPresenter::FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value) +void LegoLocomotionAnimPresenter::CreateROIAndBuildMap(LegoAnimActor* p_actor, MxFloat p_worldSpeed) { // This asserts that LegoLocomotionAnimPresenter is contained in legoanimpresenter.cpp AUTOLOCK(m_criticalSection); @@ -1430,12 +1438,12 @@ void LegoLocomotionAnimPresenter::FUN_1006d680(LegoAnimActor* p_actor, MxFloat p const char* key = ((LegoAnimNodeData*) m_anim->GetRoot()->GetData())->GetName(); variableTable->SetVariable(key, p_actor->GetROI()->GetName()); - FUN_100695c0(); - FUN_10069b10(); + CreateSceneROIs(); + BuildROIMap(); if (m_roiMap != NULL) { m_roiMapList->Append(m_roiMap); - p_actor->CreateAnimActorStruct(m_anim, p_value, m_roiMap, m_roiMapSize); + p_actor->CreateAnimActorStruct(m_anim, p_worldSpeed, m_roiMap, m_roiMapSize); m_roiMap = NULL; } @@ -1526,21 +1534,21 @@ void LegoHideAnimPresenter::StartingTickle() LegoLoopingAnimPresenter::StartingTickle(); if (m_currentTickleState == e_streaming) { - FUN_1006dc10(); - FUN_1006db40(0); + AssignIndiciesWithMap(); + ApplyVisibility(0); } } // FUNCTION: LEGO1 0x1006db40 // FUNCTION: BETA10 0x100531ab -void LegoHideAnimPresenter::FUN_1006db40(LegoTime p_time) +void LegoHideAnimPresenter::ApplyVisibility(LegoTime p_time) { - FUN_1006db60(m_anim->GetRoot(), p_time); + ApplyVisibility(m_anim->GetRoot(), p_time); } // FUNCTION: LEGO1 0x1006db60 // FUNCTION: BETA10 0x100531de -void LegoHideAnimPresenter::FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time) +void LegoHideAnimPresenter::ApplyVisibility(LegoTreeNode* p_node, LegoTime p_time) { LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); MxBool newB = FALSE; @@ -1561,23 +1569,23 @@ void LegoHideAnimPresenter::FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time) if (boundary != NULL) { newB = data->GetVisibility(p_time); - previousB = boundary->GetFlag0x10(); - boundary->SetFlag0x10(newB); + previousB = boundary->GetVisibility(); + boundary->SetVisibility(newB); } } for (MxS32 i = 0; i < p_node->GetNumChildren(); i++) { - FUN_1006db60(p_node->GetChild(i), p_time); + ApplyVisibility(p_node->GetChild(i), p_time); } } // FUNCTION: LEGO1 0x1006dc10 // FUNCTION: BETA10 0x100532fd -void LegoHideAnimPresenter::FUN_1006dc10() +void LegoHideAnimPresenter::AssignIndiciesWithMap() { LegoHideAnimStructMap anims; - FUN_1006e3f0(anims, m_anim->GetRoot()); + BuildMap(anims, m_anim->GetRoot()); if (m_boundaryMap != NULL) { delete[] m_boundaryMap; @@ -1594,7 +1602,7 @@ void LegoHideAnimPresenter::FUN_1006dc10() // FUNCTION: LEGO1 0x1006e3f0 // FUNCTION: BETA10 0x1005345e -void LegoHideAnimPresenter::FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node) +void LegoHideAnimPresenter::BuildMap(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node) { LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); const char* name = data->GetName(); @@ -1603,7 +1611,7 @@ void LegoHideAnimPresenter::FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeN LegoPathBoundary* boundary = m_currentWorld->FindPathBoundary(name); if (boundary != NULL) { - FUN_1006e470(p_map, data, name, boundary); + CheckedAdd(p_map, data, name, boundary); } else { data->SetBoundaryIndex(0); @@ -1612,13 +1620,13 @@ void LegoHideAnimPresenter::FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeN MxS32 count = p_node->GetNumChildren(); for (MxS32 i = 0; i < count; i++) { - FUN_1006e3f0(p_map, p_node->GetChild(i)); + BuildMap(p_map, p_node->GetChild(i)); } } // FUNCTION: LEGO1 0x1006e470 // FUNCTION: BETA10 0x10053520 -void LegoHideAnimPresenter::FUN_1006e470( +void LegoHideAnimPresenter::CheckedAdd( LegoHideAnimStructMap& p_map, LegoAnimNodeData* p_data, const char* p_name, diff --git a/LEGO1/lego/legoomni/src/worlds/legoact2.cpp b/LEGO1/lego/legoomni/src/worlds/legoact2.cpp index 63355c37..0e84566e 100644 --- a/LEGO1/lego/legoomni/src/worlds/legoact2.cpp +++ b/LEGO1/lego/legoomni/src/worlds/legoact2.cpp @@ -1208,19 +1208,19 @@ MxResult LegoAct2::InitializeShooting() ap = (LegoLocomotionAnimPresenter*) Find("LegoAnimPresenter", "Ambul_Anim0"); assert(ap); - ap->FUN_1006d680(m_unk0x1138, 0.0f); + ap->CreateROIAndBuildMap(m_unk0x1138, 0.0f); ap = (LegoLocomotionAnimPresenter*) Find("LegoAnimPresenter", "Ambul_Anim2"); assert(ap); - ap->FUN_1006d680(m_unk0x1138, 6.0f); + ap->CreateROIAndBuildMap(m_unk0x1138, 6.0f); ap = (LegoLocomotionAnimPresenter*) Find("LegoAnimPresenter", "Ambul_Anim3"); assert(ap); - ap->FUN_1006d680(m_unk0x1138, 3.0f); + ap->CreateROIAndBuildMap(m_unk0x1138, 3.0f); ap = (LegoLocomotionAnimPresenter*) Find("LegoAnimPresenter", "BrShoot"); assert(ap); - ap->FUN_1006d680(m_unk0x1138, -1.0f); + ap->CreateROIAndBuildMap(m_unk0x1138, -1.0f); actor->SetWorldSpeed(0.0f); m_unk0x1138->InitializeNextShot(); diff --git a/LEGO1/lego/sources/anim/legoanim.h b/LEGO1/lego/sources/anim/legoanim.h index 1c297c4d..3b935f85 100644 --- a/LEGO1/lego/sources/anim/legoanim.h +++ b/LEGO1/lego/sources/anim/legoanim.h @@ -290,11 +290,11 @@ class LegoAnimNodeData : public LegoTreeNodeData { // SIZE 0x08 struct LegoAnimActorEntry { enum { - e_actorType2 = 2, - e_actorType3 = 3, - e_actorType4 = 4, - e_actorType5 = 5, - e_actorType6 = 6, + e_managedLegoActor = 2, + e_managedInvisibleRoiTrimmed = 3, + e_managedInvisibleRoi = 4, + e_sceneRoi1 = 5, + e_sceneRoi2 = 6, }; LegoChar* m_name; // 0x00 diff --git a/LEGO1/lego/sources/geom/legowegedge.h b/LEGO1/lego/sources/geom/legowegedge.h index ea9fab08..fa9da58a 100644 --- a/LEGO1/lego/sources/geom/legowegedge.h +++ b/LEGO1/lego/sources/geom/legowegedge.h @@ -37,7 +37,7 @@ class LegoWEGEdge : public LegoWEEdge { c_bit1 = 0x01, c_bit2 = 0x02, c_bit3 = 0x04, - c_bit5 = 0x10 + c_visible = 0x10 }; LegoWEGEdge(); @@ -46,9 +46,9 @@ class LegoWEGEdge : public LegoWEEdge { LegoS32 LinkEdgesAndFaces() override; // vtable+0x04 // FUNCTION: BETA10 0x100270c0 - LegoU32 GetFlag0x10() + LegoU32 GetVisibility() { - if (m_flags & c_bit5) { + if (m_flags & c_visible) { return FALSE; } else { @@ -67,13 +67,13 @@ class LegoWEGEdge : public LegoWEEdge { const LegoChar* GetName() { return m_name; } // FUNCTION: BETA10 0x1005d5f0 - void SetFlag0x10(LegoU32 p_disable) + void SetVisibility(LegoU32 p_disable) { if (p_disable) { - m_flags &= ~c_bit5; + m_flags &= ~c_visible; } else { - m_flags |= c_bit5; + m_flags |= c_visible; } } From 197ae3ee10a913c0491ab2a107f54a75715f5476 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Thu, 15 Jan 2026 00:50:09 +0100 Subject: [PATCH 11/23] Clear unknowns in `LegoNavController` (#1720) --- .../lego/legoomni/include/legonavcontroller.h | 58 +++++++++---------- .../legoomni/src/entity/legonavcontroller.cpp | 50 ++++++++-------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legonavcontroller.h b/LEGO1/lego/legoomni/include/legonavcontroller.h index adbed6a1..974966c6 100644 --- a/LEGO1/lego/legoomni/include/legonavcontroller.h +++ b/LEGO1/lego/legoomni/include/legonavcontroller.h @@ -44,7 +44,7 @@ class LegoNavController : public MxCore { const Vector3& p_curDir, Vector3& p_newPos, Vector3& p_newDir, - const Vector3* p_und + const Vector3* p_up ); static void GetDefaults( @@ -126,36 +126,36 @@ class LegoNavController : public MxCore { float CalculateNewTargetVel(int p_pos, int p_center, float p_max); float CalculateNewAccel(int p_pos, int p_center, float p_max, int p_min); - MxResult ProcessJoystickInput(MxBool& p_und); + MxResult ProcessJoystickInput(MxBool& p_rotatedY); MxResult ProcessKeyboardInput(); - int m_hMax; // 0x08 - int m_vMax; // 0x0c - int m_deadZone; // 0x10 - float m_zeroThreshold; // 0x14 - float m_linearVel; // 0x18 - float m_rotationalVel; // 0x1c - float m_targetLinearVel; // 0x20 - float m_targetRotationalVel; // 0x24 - float m_maxLinearVel; // 0x28 - float m_maxRotationalVel; // 0x2c - float m_linearAccel; // 0x30 - float m_rotationalAccel; // 0x34 - float m_maxLinearAccel; // 0x38 - float m_maxRotationalAccel; // 0x3c - float m_minLinearAccel; // 0x40 - float m_minRotationalAccel; // 0x44 - float m_maxLinearDeccel; // 0x48 - float m_maxRotationalDeccel; // 0x4c - float m_rotSensitivity; // 0x50 - MxBool m_useRotationalVel; // 0x54 - MxTime m_lastTime; // 0x58 - MxBool m_trackDefault; // 0x5c - MxBool m_unk0x5d; // 0x5d - float m_unk0x60; // 0x60 - float m_unk0x64; // 0x64 - float m_unk0x68; // 0x68 - MxBool m_isAccelerating; // 0x6c + int m_hMax; // 0x08 + int m_vMax; // 0x0c + int m_deadZone; // 0x10 + float m_zeroThreshold; // 0x14 + float m_linearVel; // 0x18 + float m_rotationalVel; // 0x1c + float m_targetLinearVel; // 0x20 + float m_targetRotationalVel; // 0x24 + float m_maxLinearVel; // 0x28 + float m_maxRotationalVel; // 0x2c + float m_linearAccel; // 0x30 + float m_rotationalAccel; // 0x34 + float m_maxLinearAccel; // 0x38 + float m_maxRotationalAccel; // 0x3c + float m_minLinearAccel; // 0x40 + float m_minRotationalAccel; // 0x44 + float m_maxLinearDeccel; // 0x48 + float m_maxRotationalDeccel; // 0x4c + float m_rotSensitivity; // 0x50 + MxBool m_useRotationalVel; // 0x54 + MxTime m_lastTime; // 0x58 + MxBool m_trackDefault; // 0x5c + MxBool m_keyPressed; // 0x5d + float m_additionalHeightOffset; // 0x60 + float m_additionalScale; // 0x64 + float m_additionalRotationY; // 0x68 + MxBool m_isAccelerating; // 0x6c // one copy of defaults (these can be set by App.) static int g_defdeadZone; diff --git a/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp b/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp index 5a74d98d..20719e5d 100644 --- a/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp +++ b/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp @@ -134,11 +134,11 @@ LegoNavController::LegoNavController() m_linearAccel = 0.0f; m_rotationalAccel = 0.0f; m_trackDefault = FALSE; - m_unk0x5d = FALSE; + m_keyPressed = FALSE; m_isAccelerating = FALSE; - m_unk0x64 = 0.0f; - m_unk0x68 = 0.0f; - m_unk0x60 = 0.0f; + m_additionalScale = 0.0f; + m_additionalRotationY = 0.0f; + m_additionalHeightOffset = 0.0f; m_lastTime = Timer()->GetTime(); @@ -322,7 +322,7 @@ MxBool LegoNavController::CalculateNewPosDir( const Vector3& p_curDir, Vector3& p_newPos, Vector3& p_newDir, - const Vector3* p_und + const Vector3* p_up ) { if (!g_isWorldActive) { @@ -330,14 +330,14 @@ MxBool LegoNavController::CalculateNewPosDir( } MxBool changed = FALSE; - MxBool und = FALSE; + MxBool rotatedY = FALSE; MxTime currentTime = Timer()->GetTime(); float deltaTime = (currentTime - m_lastTime) / 1000.0; m_lastTime = currentTime; if (ProcessKeyboardInput() == FAILURE) { - ProcessJoystickInput(und); + ProcessJoystickInput(rotatedY); } if (m_useRotationalVel) { @@ -349,7 +349,7 @@ MxBool LegoNavController::CalculateNewPosDir( m_linearVel = CalculateNewVel(m_targetLinearVel, m_linearVel, m_linearAccel, deltaTime); - if (und || (Abs(m_rotationalVel) > m_zeroThreshold) || (Abs(m_linearVel) > m_zeroThreshold)) { + if (rotatedY || (Abs(m_rotationalVel) > m_zeroThreshold) || (Abs(m_linearVel) > m_zeroThreshold)) { float rot_mat[3][3]; Mx3DPointFloat delta_pos, new_dir, new_pos; @@ -368,7 +368,7 @@ MxBool LegoNavController::CalculateNewPosDir( delta_rad = DTOR(m_rotationalVel * m_rotSensitivity); } - if (p_und != NULL && (*p_und)[1] < 0.0f) { + if (p_up != NULL && (*p_up)[1] < 0.0f) { delta_rad = -delta_rad; } @@ -381,7 +381,7 @@ MxBool LegoNavController::CalculateNewPosDir( changed = TRUE; } - if (m_unk0x5d) { + if (m_keyPressed) { float rot_mat[3][3]; Mx3DPointFloat delta_pos, new_pos, new_dir; @@ -394,20 +394,20 @@ MxBool LegoNavController::CalculateNewPosDir( SET3(new_dir, p_curDir); } - if (m_unk0x64 != 0.0f) { - delta_pos[0] = new_dir[0] * m_unk0x64; - delta_pos[1] = new_dir[1] * m_unk0x64; - delta_pos[2] = new_dir[2] * m_unk0x64; + if (m_additionalScale != 0.0f) { + delta_pos[0] = new_dir[0] * m_additionalScale; + delta_pos[1] = new_dir[1] * m_additionalScale; + delta_pos[2] = new_dir[2] * m_additionalScale; } else { FILLVEC3(delta_pos, 0.0f); } - delta_pos[1] += m_unk0x60; + delta_pos[1] += m_additionalHeightOffset; VPV3(p_newPos, new_pos, delta_pos); - if (m_unk0x68 != 0.0f) { - float delta_rad = DTOR(m_unk0x68); + if (m_additionalRotationY != 0.0f) { + float delta_rad = DTOR(m_additionalRotationY); IDENTMAT3(rot_mat); rot_mat[0][0] = rot_mat[2][2] = cos(delta_rad); rot_mat[0][2] = rot_mat[2][0] = sin(delta_rad); @@ -418,8 +418,8 @@ MxBool LegoNavController::CalculateNewPosDir( SET3(p_newDir, new_dir); } - m_unk0x60 = m_unk0x64 = m_unk0x68 = 0.0f; - m_unk0x5d = FALSE; + m_additionalHeightOffset = m_additionalScale = m_additionalRotationY = 0.0f; + m_keyPressed = FALSE; changed = TRUE; } @@ -515,7 +515,7 @@ MxS32 LegoNavController::GetNumLocations() } // FUNCTION: LEGO1 0x10055750 -MxResult LegoNavController::ProcessJoystickInput(MxBool& p_und) +MxResult LegoNavController::ProcessJoystickInput(MxBool& p_rotatedY) { LegoOmni* instance = LegoOmni::GetInstance(); @@ -550,7 +550,7 @@ MxResult LegoNavController::ProcessJoystickInput(MxBool& p_und) if (world && world->GetCameraController()) { world->GetCameraController()->RotateY(DTOR(povPosition)); - p_und = TRUE; + p_rotatedY = TRUE; } } @@ -648,7 +648,7 @@ MxResult LegoNavController::ProcessKeyboardInput() MxLong LegoNavController::Notify(MxParam& p_param) { if (((MxNotificationParam&) p_param).GetNotification() == c_notificationKeyPress) { - m_unk0x5d = TRUE; + m_keyPressed = TRUE; MxU8 key = ((LegoEventNotificationParam&) p_param).GetKey(); switch (key) { @@ -767,7 +767,7 @@ MxLong LegoNavController::Notify(MxParam& p_param) g_fpsEnabled = TRUE; } default: - m_unk0x5d = FALSE; + m_keyPressed = FALSE; break; case '0': case '1': @@ -914,7 +914,7 @@ MxLong LegoNavController::Notify(MxParam& p_param) g_locationCalcStep = 1; break; case 'D': - m_unk0x60 = -1.0; + m_additionalHeightOffset = -1.0; break; case 'F': RealtimeView::SetUserMaxLOD(0.0); @@ -980,7 +980,7 @@ MxLong LegoNavController::Notify(MxParam& p_param) BackgroundAudioManager()->Enable(g_enableMusic); break; case 'U': - m_unk0x60 = 1.0; + m_additionalHeightOffset = 1.0; break; case 'V': if (g_nextAnimation > 0 && g_animationCalcStep == 0) { From d26acdfae9f3ad9dbec8590bb7d0bca2cfc3ad0e Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Thu, 15 Jan 2026 00:50:49 +0100 Subject: [PATCH 12/23] Clear unknown in `MxVideoManager` (#1721) --- LEGO1/omni/include/mxvideomanager.h | 2 +- LEGO1/omni/src/video/mxvideomanager.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/LEGO1/omni/include/mxvideomanager.h b/LEGO1/omni/include/mxvideomanager.h index 63c38977..2e40ed19 100644 --- a/LEGO1/omni/include/mxvideomanager.h +++ b/LEGO1/omni/include/mxvideomanager.h @@ -58,7 +58,7 @@ class MxVideoManager : public MxPresentationManager { LPDIRECT3D2 m_pDirect3D; // 0x54 MxDisplaySurface* m_displaySurface; // 0x58 MxRegion* m_region; // 0x5c - MxBool m_unk0x60; // 0x60 + MxBool m_created; // 0x60 }; #endif // MXVIDEOMANAGER_H diff --git a/LEGO1/omni/src/video/mxvideomanager.cpp b/LEGO1/omni/src/video/mxvideomanager.cpp index 7194e453..75de16b2 100644 --- a/LEGO1/omni/src/video/mxvideomanager.cpp +++ b/LEGO1/omni/src/video/mxvideomanager.cpp @@ -41,7 +41,7 @@ MxResult MxVideoManager::Init() m_displaySurface = NULL; m_region = NULL; m_videoParam.SetPalette(NULL); - m_unk0x60 = FALSE; + m_created = FALSE; return SUCCESS; } @@ -71,7 +71,7 @@ void MxVideoManager::Destroy(MxBool p_fromDestructor) delete m_videoParam.GetPalette(); } - if (m_unk0x60) { + if (m_created) { if (m_pDirectDraw) { m_pDirectDraw->Release(); } @@ -152,7 +152,7 @@ MxResult MxVideoManager::VTable0x28( MxBool locked = FALSE; MxResult status = FAILURE; - m_unk0x60 = FALSE; + m_created = FALSE; if (MxPresentationManager::Create() != SUCCESS) { goto done; @@ -226,7 +226,7 @@ MxResult MxVideoManager::Create(MxVideoParam& p_videoParam, MxU32 p_frequencyMS, MxBool locked = FALSE; MxResult status = FAILURE; - m_unk0x60 = TRUE; + m_created = TRUE; if (MxPresentationManager::Create() != SUCCESS) { goto done; From 8b0b6d90821030ebf4b2057235bff518703e3e92 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Thu, 15 Jan 2026 00:51:42 +0100 Subject: [PATCH 13/23] Clear unknowns in `LegoActionControlPresenter` (#1722) --- .../include/legoactioncontrolpresenter.h | 8 ++++---- .../src/common/legoactioncontrolpresenter.cpp | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoactioncontrolpresenter.h b/LEGO1/lego/legoomni/include/legoactioncontrolpresenter.h index 3b3193bf..ec142d22 100644 --- a/LEGO1/lego/legoomni/include/legoactioncontrolpresenter.h +++ b/LEGO1/lego/legoomni/include/legoactioncontrolpresenter.h @@ -10,7 +10,7 @@ // SIZE 0x68 class LegoActionControlPresenter : public MxMediaPresenter { public: - LegoActionControlPresenter() : m_unk0x50(Extra::ActionType::e_none) {} + LegoActionControlPresenter() : m_actionType(Extra::ActionType::e_none) {} ~LegoActionControlPresenter() override { Destroy(TRUE); } // vtable+0x00 // FUNCTION: BETA10 0x100a7840 @@ -40,9 +40,9 @@ class LegoActionControlPresenter : public MxMediaPresenter { virtual void Destroy(MxBool p_fromDestructor); // vtable+0x5c private: - Extra::ActionType m_unk0x50; // 0x50 - MxString m_unk0x54; // 0x54 - undefined4 m_unk0x64; // 0x64 + Extra::ActionType m_actionType; // 0x50 + MxString m_sourceName; // 0x54 + undefined4 m_streamId; // 0x64 }; // SYNTHETIC: LEGO1 0x1000d1d0 diff --git a/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp b/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp index 0e22d8de..266078ac 100644 --- a/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp @@ -36,11 +36,11 @@ void LegoActionControlPresenter::ReadyTickle() void LegoActionControlPresenter::RepeatingTickle() { if (IsEnabled()) { - if (m_unk0x50 == 0) { + if (m_actionType == 0) { ParseExtra(); } - InvokeAction(m_unk0x50, MxAtomId(m_unk0x54.GetData(), e_lowerCase2), m_unk0x64, NULL); + InvokeAction(m_actionType, MxAtomId(m_sourceName.GetData(), e_lowerCase2), m_streamId, NULL); ProgressTickleState(e_done); } } @@ -84,15 +84,15 @@ void LegoActionControlPresenter::ParseExtra() char output[1024]; if (KeyValueStringParse(output, g_strACTION, extraCopy)) { - m_unk0x50 = MatchActionString(strtok(output, g_parseExtraTokens)); + m_actionType = MatchActionString(strtok(output, g_parseExtraTokens)); - if (m_unk0x50 != Extra::ActionType::e_exit) { + if (m_actionType != Extra::ActionType::e_exit) { MakeSourceName(extraCopy, strtok(NULL, g_parseExtraTokens)); - m_unk0x54 = extraCopy; - m_unk0x54.ToLowerCase(); - if (m_unk0x50 != Extra::ActionType::e_run) { - m_unk0x64 = atoi(strtok(NULL, g_parseExtraTokens)); + m_sourceName = extraCopy; + m_sourceName.ToLowerCase(); + if (m_actionType != Extra::ActionType::e_run) { + m_streamId = atoi(strtok(NULL, g_parseExtraTokens)); } } } From 01c92d1966b3826c11c5e4ad7c9d86264682011e Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Sun, 18 Jan 2026 15:50:17 +0100 Subject: [PATCH 14/23] Clear unknowns in `LegoPathEdgeContainer` and `LegoBEWithFloat` (#1723) Renames `LegoBEWithFloat` also to `LegoBEWithMidpoint` to be more specific. --- .../legoomni/include/legopathcontroller.h | 38 ++++++++-------- .../legoomni/include/legopathedgecontainer.h | 45 ++++++++++--------- LEGO1/lego/legoomni/src/actors/act2actor.cpp | 2 +- LEGO1/lego/legoomni/src/actors/act3actors.cpp | 4 +- .../lego/legoomni/src/paths/legopathactor.cpp | 2 +- .../legoomni/src/paths/legopathcontroller.cpp | 40 +++++++++-------- 6 files changed, 69 insertions(+), 62 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legopathcontroller.h b/LEGO1/lego/legoomni/include/legopathcontroller.h index 4632c6b1..89b11074 100644 --- a/LEGO1/lego/legoomni/include/legopathcontroller.h +++ b/LEGO1/lego/legoomni/include/legopathcontroller.h @@ -291,58 +291,58 @@ class LegoPathController : public MxCore { // _Tree >::_Kfn,LegoPathCtrlEdgeCompare,allocator >::_Ubound // TEMPLATE: LEGO1 0x100493a0 -// list >::~list > +// list >::~list > // TEMPLATE: LEGO1 0x10049410 -// list >::insert +// list >::insert // TEMPLATE: LEGO1 0x10049470 -// list >::_Buynode +// list >::_Buynode // TEMPLATE: LEGO1 0x100494a0 -// _Tree >::_Kfn,LegoBEWithFloatComparator,allocator >::iterator::_Inc +// _Tree >::_Kfn,LegoBEWithMidpointComparator,allocator >::iterator::_Inc // TEMPLATE: LEGO1 0x100494e0 -// _Tree >::_Kfn,LegoBEWithFloatComparator,allocator >::~_Tree >::_Kfn,LegoBEWithMidpointComparator,allocator >::~_Tree >::_Kfn,LegoBEWithFloatComparator,allocator >::insert +// _Tree >::_Kfn,LegoBEWithMidpointComparator,allocator >::insert // TEMPLATE: LEGO1 0x10049840 -// _Tree >::_Kfn,LegoBEWithFloatComparator,allocator >::iterator::_Dec +// _Tree >::_Kfn,LegoBEWithMidpointComparator,allocator >::iterator::_Dec // TEMPLATE: LEGO1 0x10049890 -// _Tree >::_Kfn,LegoBEWithFloatComparator,allocator >::erase +// _Tree >::_Kfn,LegoBEWithMidpointComparator,allocator >::erase // TEMPLATE: LEGO1 0x10049cf0 -// _Tree >::_Kfn,LegoBEWithFloatComparator,allocator >::_Buynode +// _Tree >::_Kfn,LegoBEWithMidpointComparator,allocator >::_Buynode // TEMPLATE: LEGO1 0x10049d50 -// _Tree >::_Kfn,LegoBEWithFloatComparator,allocator >::_Init +// _Tree >::_Kfn,LegoBEWithMidpointComparator,allocator >::_Init // TEMPLATE: LEGO1 0x10049e00 -// _Tree >::_Kfn,LegoBEWithFloatComparator,allocator >::_Insert +// _Tree >::_Kfn,LegoBEWithMidpointComparator,allocator >::_Insert // TEMPLATE: LEGO1 0x10049d10 -// _Tree >::_Kfn,LegoBEWithFloatComparator,allocator >::_Erase +// _Tree >::_Kfn,LegoBEWithMidpointComparator,allocator >::_Erase // TEMPLATE: LEGO1 0x1004a090 -// _Tree >::_Kfn,LegoBEWithFloatComparator,allocator >::_Lrotate +// _Tree >::_Kfn,LegoBEWithMidpointComparator,allocator >::_Lrotate // TEMPLATE: LEGO1 0x1004a0f0 -// _Tree >::_Kfn,LegoBEWithFloatComparator,allocator >::_Rrotate +// _Tree >::_Kfn,LegoBEWithMidpointComparator,allocator >::_Rrotate // TEMPLATE: LEGO1 0x1004a150 -// List::~List +// List::~List // TEMPLATE: LEGO1 0x1004a1a0 -// Multiset::~Multiset +// Multiset::~Multiset // TEMPLATE: LEGO1 0x1004a1f0 -// multiset >::~multiset > +// multiset >::~multiset > // TEMPLATE: LEGO1 0x1004a760 -// ?_Construct@@YAXPAPAULegoBEWithFloat@@ABQAU1@@Z +// ?_Construct@@YAXPAPAULegoBEWithMidpoint@@ABQAU1@@Z // TEMPLATE: LEGO1 0x1004a780 // ?_Construct@@YAXPAPAULegoPathCtrlEdge@@ABQAU1@@Z @@ -351,7 +351,7 @@ class LegoPathController : public MxCore { // _Tree >::_Kfn,LegoPathCtrlEdgeCompare,allocator >::_Nil // GLOBAL: LEGO1 0x100f4364 -// _Tree >::_Kfn,LegoBEWithFloatComparator,allocator >::_Nil +// _Tree >::_Kfn,LegoBEWithMidpointComparator,allocator >::_Nil // clang-format on #endif // LEGOPATHCONTROLLER_H diff --git a/LEGO1/lego/legoomni/include/legopathedgecontainer.h b/LEGO1/lego/legoomni/include/legopathedgecontainer.h index bba8547b..5998f842 100644 --- a/LEGO1/lego/legoomni/include/legopathedgecontainer.h +++ b/LEGO1/lego/legoomni/include/legopathedgecontainer.h @@ -27,56 +27,61 @@ struct LegoBoundaryEdge { }; // SIZE 0x10 -struct LegoBEWithFloat { - LegoBEWithFloat() +struct LegoBEWithMidpoint { + LegoBEWithMidpoint() { m_edge = NULL; m_boundary = NULL; m_next = NULL; - m_unk0x0c = 0.0f; + m_distanceToMidpoint = 0.0f; } // FUNCTION: BETA10 0x100bd9a0 - LegoBEWithFloat(LegoPathCtrlEdge* p_edge, LegoPathBoundary* p_boundary, MxFloat p_unk0x0c) + LegoBEWithMidpoint(LegoPathCtrlEdge* p_edge, LegoPathBoundary* p_boundary, MxFloat p_distanceToMidpoint) { m_edge = p_edge; m_boundary = p_boundary; m_next = NULL; - m_unk0x0c = p_unk0x0c; + m_distanceToMidpoint = p_distanceToMidpoint; } // FUNCTION: BETA10 0x100bd9f0 - LegoBEWithFloat(LegoPathCtrlEdge* p_edge, LegoPathBoundary* p_boundary, LegoBEWithFloat* p_next, MxFloat p_unk0x0c) + LegoBEWithMidpoint( + LegoPathCtrlEdge* p_edge, + LegoPathBoundary* p_boundary, + LegoBEWithMidpoint* p_next, + MxFloat p_distanceToMidpoint + ) { m_edge = p_edge; m_boundary = p_boundary; m_next = p_next; - m_unk0x0c = p_unk0x0c; + m_distanceToMidpoint = p_distanceToMidpoint; } LegoPathCtrlEdge* m_edge; // 0x00 LegoPathBoundary* m_boundary; // 0x04 - LegoBEWithFloat* m_next; // 0x08 - MxFloat m_unk0x0c; // 0x0c + LegoBEWithMidpoint* m_next; // 0x08 + MxFloat m_distanceToMidpoint; // 0x0c - int operator==(LegoBEWithFloat) const { return 0; } - int operator<(LegoBEWithFloat) const { return 0; } + int operator==(LegoBEWithMidpoint) const { return 0; } + int operator<(LegoBEWithMidpoint) const { return 0; } }; -struct LegoBEWithFloatComparator { +struct LegoBEWithMidpointComparator { // FUNCTION: BETA10 0x100bef80 - bool operator()(LegoBEWithFloat* const& p_a, LegoBEWithFloat* const& p_b) const + bool operator()(LegoBEWithMidpoint* const& p_a, LegoBEWithMidpoint* const& p_b) const { - return p_a->m_unk0x0c < p_b->m_unk0x0c; + return p_a->m_distanceToMidpoint < p_b->m_distanceToMidpoint; } }; -typedef multiset LegoBEWithFloatSet; +typedef multiset LegoBEWithMidpointSet; // SIZE 0x3c struct LegoPathEdgeContainer : public list { enum { - c_bit1 = 0x01 + c_hasPath = 0x01 }; // FUNCTION: BETA10 0x100118e0 @@ -87,18 +92,18 @@ struct LegoPathEdgeContainer : public list { } // FUNCTION: BETA10 0x100bd660 - void SetBit1(MxU32 p_set) + void SetPath(MxU32 p_set) { if (p_set) { - m_flags |= c_bit1; + m_flags |= c_hasPath; } else { - m_flags &= ~c_bit1; + m_flags &= ~c_hasPath; } } // FUNCTION: BETA10 0x1001cb50 - MxU32 GetBit1() { return m_flags & c_bit1; } + MxU32 HasPath() { return m_flags & c_hasPath; } Mx3DPointFloat m_position; // 0x0c Mx3DPointFloat m_direction; // 0x20 diff --git a/LEGO1/lego/legoomni/src/actors/act2actor.cpp b/LEGO1/lego/legoomni/src/actors/act2actor.cpp index dcd7cb40..187931b5 100644 --- a/LEGO1/lego/legoomni/src/actors/act2actor.cpp +++ b/LEGO1/lego/legoomni/src/actors/act2actor.cpp @@ -181,7 +181,7 @@ MxResult Act2Actor::HitActor(LegoPathActor*, MxBool) // FUNCTION: LEGO1 0x10018a20 MxResult Act2Actor::VTable0x9c() { - if (m_grec && !m_grec->GetBit1()) { + if (m_grec && !m_grec->HasPath()) { delete m_grec; m_grec = NULL; return SUCCESS; diff --git a/LEGO1/lego/legoomni/src/actors/act3actors.cpp b/LEGO1/lego/legoomni/src/actors/act3actors.cpp index d4e82e40..af36e119 100644 --- a/LEGO1/lego/legoomni/src/actors/act3actors.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3actors.cpp @@ -510,7 +510,7 @@ MxResult Act3Cop::FUN_10040360() // FUNCTION: BETA10 0x1001942c MxResult Act3Cop::VTable0x9c() { - if (m_grec && !m_grec->GetBit1()) { + if (m_grec && !m_grec->HasPath()) { delete m_grec; m_grec = NULL; m_lastTime = Timer()->GetTime(); @@ -1120,7 +1120,7 @@ void Act3Brickster::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOrientedEd // FUNCTION: BETA10 0x1001b75b MxResult Act3Brickster::VTable0x9c() { - if (m_grec && !m_grec->GetBit1()) { + if (m_grec && !m_grec->HasPath()) { delete m_grec; m_grec = NULL; m_lastTime = Timer()->GetTime(); diff --git a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp index 803fc222..85e29f7e 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp @@ -630,7 +630,7 @@ MxResult LegoPathActor::VTable0x9c() MxU32 local20 = 1; if (m_grec != NULL) { - if (m_grec->GetBit1()) { + if (m_grec->HasPath()) { local1c = 0; local20 = 0; diff --git a/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp b/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp index abf16351..27c9fc2a 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp @@ -775,22 +775,22 @@ MxResult LegoPathController::FUN_10048310( p_grec->m_boundary = p_newBoundary; if (p_newBoundary == p_oldBoundary) { - p_grec->SetBit1(TRUE); + p_grec->SetPath(TRUE); return SUCCESS; } - list boundaryList; - list::iterator boundaryListIt; + list boundaryList; + list::iterator boundaryListIt; - LegoBEWithFloatSet boundarySet; - LegoBEWithFloatSet::iterator boundarySetItA; - LegoBEWithFloatSet::iterator boundarySetItB; + LegoBEWithMidpointSet boundarySet; + LegoBEWithMidpointSet::iterator boundarySetItA; + LegoBEWithMidpointSet::iterator boundarySetItB; LegoPathCtrlEdgeSet pathCtrlEdgeSet(m_pfsE); MxFloat local14 = 999999.0f; - p_grec->SetBit1(FALSE); + p_grec->SetPath(FALSE); for (MxS32 i = 0; i < p_oldBoundary->GetNumEdges(); i++) { LegoPathCtrlEdge* edge = (LegoPathCtrlEdge*) p_oldBoundary->GetEdges()[i]; @@ -805,12 +805,13 @@ MxResult LegoPathController::FUN_10048310( local14) { local14 = dist; p_grec->erase(p_grec->begin(), p_grec->end()); - p_grec->SetBit1(TRUE); + p_grec->SetPath(TRUE); p_grec->push_back(LegoBoundaryEdge(edge, p_oldBoundary)); } } else { - boundaryList.push_back(LegoBEWithFloat(edge, p_oldBoundary, edge->DistanceToMidpoint(p_oldPosition)) + boundaryList.push_back( + LegoBEWithMidpoint(edge, p_oldBoundary, edge->DistanceToMidpoint(p_oldPosition)) ); boundarySet.insert(&boundaryList.back()); } @@ -820,9 +821,9 @@ MxResult LegoPathController::FUN_10048310( pathCtrlEdgeSet.erase(edge); } - if (!p_grec->GetBit1()) { + if (!p_grec->HasPath()) { while (pathCtrlEdgeSet.size() > 0) { - LegoBEWithFloat edgeWithFloat; + LegoBEWithMidpoint edgeWithFloat; MxFloat local70 = 999999.0f; boundarySetItA = boundarySetItB = boundarySet.begin(); @@ -848,11 +849,12 @@ MxResult LegoPathController::FUN_10048310( if (bOther == p_newBoundary) { shouldRemove = FALSE; - LegoBEWithFloat* pfs = *boundarySetItA; + LegoBEWithMidpoint* pfs = *boundarySetItA; assert(pfs); float dist; - if ((dist = pfs->m_edge->DistanceToMidpoint(p_newPosition) + pfs->m_unk0x0c) < local70) { + if ((dist = pfs->m_edge->DistanceToMidpoint(p_newPosition) + pfs->m_distanceToMidpoint) < + local70) { edgeWithFloat.m_edge = NULL; local70 = dist; @@ -860,7 +862,7 @@ MxResult LegoPathController::FUN_10048310( if (dist < local14) { local14 = dist; p_grec->erase(p_grec->begin(), p_grec->end()); - p_grec->SetBit1(TRUE); + p_grec->SetPath(TRUE); do { p_grec->push_front(LegoBoundaryEdge(pfs->m_edge, pfs->m_boundary)); @@ -878,10 +880,10 @@ MxResult LegoPathController::FUN_10048310( shouldRemove = FALSE; float dist; - if ((dist = edge->DistanceBetweenMidpoints(*e) + (*boundarySetItA)->m_unk0x0c) < - local70) { + if ((dist = edge->DistanceBetweenMidpoints(*e) + + (*boundarySetItA)->m_distanceToMidpoint) < local70) { local70 = dist; - edgeWithFloat = LegoBEWithFloat(edge, bOther, *boundarySetItA, dist); + edgeWithFloat = LegoBEWithMidpoint(edge, bOther, *boundarySetItA, dist); } } } @@ -913,7 +915,7 @@ MxResult LegoPathController::FUN_10048310( } } - if (p_grec->GetBit1()) { + if (p_grec->HasPath()) { if (p_grec->size() > 0) { LegoPathCtrlEdge* edge = p_grec->front().m_edge; @@ -959,7 +961,7 @@ MxS32 LegoPathController::FUN_1004a240( p_v1 = p_grec.m_position; p_v2 = p_grec.m_direction; p_boundary = p_grec.m_boundary; - p_grec.SetBit1(FALSE); + p_grec.SetPath(FALSE); return 1; } From e05cb05983088d70e3baf84cc62757c330da83d6 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Sun, 18 Jan 2026 21:31:56 +0100 Subject: [PATCH 15/23] Clear unknowns in `LegoPathController` (#1724) --- .../legoomni/include/legopathcontroller.h | 26 +-- LEGO1/lego/legoomni/src/actors/act2actor.cpp | 2 +- LEGO1/lego/legoomni/src/actors/act3actors.cpp | 10 +- LEGO1/lego/legoomni/src/entity/legoworld.cpp | 6 +- .../lego/legoomni/src/paths/legopathactor.cpp | 2 +- .../legoomni/src/paths/legopathcontroller.cpp | 181 +++++++++--------- LEGO1/lego/legoomni/src/worlds/act3.cpp | 4 +- 7 files changed, 116 insertions(+), 115 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legopathcontroller.h b/LEGO1/lego/legoomni/include/legopathcontroller.h index 89b11074..32c483a8 100644 --- a/LEGO1/lego/legoomni/include/legopathcontroller.h +++ b/LEGO1/lego/legoomni/include/legopathcontroller.h @@ -104,13 +104,13 @@ class LegoPathController : public MxCore { ); MxResult PlaceActor(LegoPathActor* p_actor); MxResult RemoveActor(LegoPathActor* p_actor); - void FUN_100468f0(LegoAnimPresenter* p_presenter); + void AddPresenterIfInRange(LegoAnimPresenter* p_presenter); void RemovePresenterFromBoundaries(LegoAnimPresenter* p_presenter); - MxResult FUN_10046b30(LegoPathBoundary*& p_boundaries, MxS32& p_numL); + MxResult GetBoundaries(LegoPathBoundary*& p_boundaries, MxS32& p_numL); LegoPathBoundary* GetPathBoundary(const char* p_name); void Enable(MxBool p_enable); - void FUN_10046bb0(LegoWorld* p_world); - MxResult FUN_10048310( + void SetWorld(LegoWorld* p_world); + MxResult FindPath( LegoPathEdgeContainer* p_grec, const Vector3& p_oldPosition, const Vector3& p_oldDirection, @@ -119,17 +119,17 @@ class LegoPathController : public MxCore { const Vector3& p_newDirection, LegoPathBoundary* p_newBoundary, LegoU8 p_mask, - MxFloat* p_param9 + MxFloat* p_distance ); - MxS32 FUN_1004a240( + MxS32 GetNextPathEdge( LegoPathEdgeContainer& p_grec, - Vector3& p_v1, - Vector3& p_v2, + Vector3& p_position, + Vector3& p_direction, float p_f1, LegoOrientedEdge*& p_edge, LegoPathBoundary*& p_boundary ); - MxResult FUN_1004a380( + MxResult FindIntersectionBoundary( Vector3& p_param1, Vector3& p_param2, Mx3DPointFloat* p_param3, @@ -154,7 +154,7 @@ class LegoPathController : public MxCore { static LegoPathBoundary* GetControlBoundaryB(MxS32 p_index) { return g_ctrlBoundariesB[p_index].m_boundary; } private: - void FUN_10046970(); + void AnimateActors(); MxResult Read(LegoStorage* p_storage); MxResult ReadStructs(LegoStorage* p_storage); MxResult ReadEdges(LegoStorage* p_storage); @@ -174,7 +174,7 @@ class LegoPathController : public MxCore { } // FUNCTION: BETA10 0x100c17a0 - static MxU32 FUN_100c17a0(MxFloat p_v1, MxFloat p_v2, MxFloat p_a, MxFloat p_b) + static MxU32 BothSameComparison(MxFloat p_v1, MxFloat p_v2, MxFloat p_a, MxFloat p_b) { assert(IsBetween(p_v1, p_a, p_b)); assert(IsBetween(p_v2, p_a, p_b)); @@ -202,8 +202,8 @@ class LegoPathController : public MxCore { static CtrlBoundary* g_ctrlBoundariesA; static CtrlEdge* g_ctrlEdgesA; - static const char* g_unk0x100f42f0[]; - static const char* g_unk0x100f4330[]; + static const char* g_ctrlBoundariesNamesA[]; + static const char* g_ctrlBoundariesNamesB[]; static CtrlBoundary* g_ctrlBoundariesB; static CtrlEdge* g_ctrlEdgesB; }; diff --git a/LEGO1/lego/legoomni/src/actors/act2actor.cpp b/LEGO1/lego/legoomni/src/actors/act2actor.cpp index 187931b5..18b099ee 100644 --- a/LEGO1/lego/legoomni/src/actors/act2actor.cpp +++ b/LEGO1/lego/legoomni/src/actors/act2actor.cpp @@ -410,7 +410,7 @@ void Act2Actor::FindPath(MxU32 p_location) newDirection = g_brickstrLocations[p_location].m_direction; LegoPathBoundary* newBoundary = m_pathController->GetPathBoundary(g_brickstrLocations[p_location].m_boundary); - MxResult sts = m_pathController->FUN_10048310( + MxResult sts = m_pathController->FindPath( m_grec, m_roi->GetWorldPosition(), m_roi->GetWorldDirection(), diff --git a/LEGO1/lego/legoomni/src/actors/act3actors.cpp b/LEGO1/lego/legoomni/src/actors/act3actors.cpp index af36e119..8a0c1383 100644 --- a/LEGO1/lego/legoomni/src/actors/act3actors.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3actors.cpp @@ -345,7 +345,7 @@ MxResult Act3Cop::FUN_10040360() assert(grec); MxFloat local34; - if (m_pathController->FUN_10048310( + if (m_pathController->FindPath( grec, local2c, local20, @@ -383,7 +383,7 @@ MxResult Act3Cop::FUN_10040360() MxFloat locald8; LegoPathEdgeContainer *local138, *local134, *local140, *local13c; // unused - if (m_pathController->FUN_10048310( + if (m_pathController->FindPath( r2, local2c, local20, @@ -423,7 +423,7 @@ MxResult Act3Cop::FUN_10040360() MxFloat local100; LegoPathEdgeContainer *local150, *local14c; // unused - if (m_pathController->FUN_10048310( + if (m_pathController->FindPath( grec, local2c, local20, @@ -823,7 +823,7 @@ MxResult Act3Brickster::FUN_100417c0() MxFloat locald8; LegoPathEdgeContainer *local16c, *local168, *local174, *local170; // unused - if (m_pathController->FUN_10048310( + if (m_pathController->FindPath( r2, local28, local20, @@ -907,7 +907,7 @@ MxResult Act3Brickster::FUN_100417c0() MxFloat local13c; LegoPathEdgeContainer *local1c0, *local1bc; // unused - if (m_pathController->FUN_10048310( + if (m_pathController->FindPath( grec, local28, local20, diff --git a/LEGO1/lego/legoomni/src/entity/legoworld.cpp b/LEGO1/lego/legoomni/src/entity/legoworld.cpp index 47b54d8b..8cdff940 100644 --- a/LEGO1/lego/legoomni/src/entity/legoworld.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoworld.cpp @@ -358,7 +358,7 @@ void LegoWorld::AddPresenterIfInRange(LegoAnimPresenter* p_presenter) LegoPathController* controller; while (cursor.Next(controller)) { - controller->FUN_100468f0(p_presenter); + controller->AddPresenterIfInRange(p_presenter); } } @@ -377,7 +377,7 @@ void LegoWorld::RemovePresenterFromBoundaries(LegoAnimPresenter* p_presenter) // FUNCTION: LEGO1 0x1001ff80 void LegoWorld::AddPath(LegoPathController* p_controller) { - p_controller->FUN_10046bb0(this); + p_controller->SetWorld(this); m_pathControllerList.Append(p_controller); } @@ -411,7 +411,7 @@ MxResult LegoWorld::GetCurrPathInfo(LegoPathBoundary** p_boundaries, MxS32& p_nu return FAILURE; } - return controller->FUN_10046b30(*p_boundaries, p_numL); + return controller->GetBoundaries(*p_boundaries, p_numL); } // FUNCTION: LEGO1 0x10020220 diff --git a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp index 85e29f7e..40e312dd 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp @@ -635,7 +635,7 @@ MxResult LegoPathActor::VTable0x9c() local20 = 0; Mx3DPointFloat vec; - switch (m_pathController->FUN_1004a240(*m_grec, local34, local48, m_unk0xe4, m_destEdge, m_boundary)) { + switch (m_pathController->GetNextPathEdge(*m_grec, local34, local48, m_unk0xe4, m_destEdge, m_boundary)) { case 0: case 1: break; diff --git a/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp b/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp index 27c9fc2a..38367bb2 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp @@ -12,10 +12,10 @@ DECOMP_SIZE_ASSERT(LegoPathController::CtrlBoundary, 0x08) DECOMP_SIZE_ASSERT(LegoPathController::CtrlEdge, 0x08) // GLOBAL: LEGO1 0x100d7cc8 -MxU32 g_unk0x100d7cc8[] = {2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0}; +MxU32 g_ctrlEdgesNamesA[] = {2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0}; // GLOBAL: LEGO1 0x100d7d08 -MxU32 g_unk0x100d7d08[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +MxU32 g_ctrlEdgesNamesB[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // GLOBAL: LEGO1 0x100f42e8 // GLOBAL: BETA10 0x101f25f0 @@ -26,7 +26,7 @@ LegoPathController::CtrlBoundary* LegoPathController::g_ctrlBoundariesA = NULL; LegoPathController::CtrlEdge* LegoPathController::g_ctrlEdgesA = NULL; // GLOBAL: LEGO1 0x100f42f0 -const char* LegoPathController::g_unk0x100f42f0[] = { +const char* LegoPathController::g_ctrlBoundariesNamesA[] = { "edg03_21", "edg03_23", "edg03_30", @@ -46,7 +46,7 @@ const char* LegoPathController::g_unk0x100f42f0[] = { }; // GLOBAL: LEGO1 0x100f4330 -const char* LegoPathController::g_unk0x100f4330[] = { +const char* LegoPathController::g_ctrlBoundariesNamesB[] = { "edg03_06", "edg03_21", "edg03_30", @@ -101,23 +101,23 @@ MxResult LegoPathController::Create(MxU8* p_data, const Vector3& p_location, con LegoPathBoundary& boundary = m_boundaries[i]; MxS32 j; - for (j = 0; j < sizeOfArray(g_unk0x100f42f0); j++) { - if (!strcmpi(g_unk0x100f42f0[j], boundary.GetName())) { + for (j = 0; j < sizeOfArray(g_ctrlBoundariesNamesA); j++) { + if (!strcmpi(g_ctrlBoundariesNamesA[j], boundary.GetName())) { g_ctrlBoundariesA[j].m_controller = this; g_ctrlBoundariesA[j].m_boundary = &boundary; - MxU32 edge = g_unk0x100d7cc8[j]; + MxU32 edge = g_ctrlEdgesNamesA[j]; g_ctrlEdgesA[j].m_controller = this; g_ctrlEdgesA[j].m_edge = boundary.GetEdges()[edge]; } } - for (j = 0; j < sizeOfArray(g_unk0x100f4330); j++) { - if (!strcmpi(g_unk0x100f4330[j], boundary.GetName())) { + for (j = 0; j < sizeOfArray(g_ctrlBoundariesNamesB); j++) { + if (!strcmpi(g_ctrlBoundariesNamesB[j], boundary.GetName())) { g_ctrlBoundariesB[j].m_controller = this; g_ctrlBoundariesB[j].m_boundary = &boundary; g_ctrlEdgesB[j].m_controller = this; - g_ctrlEdgesB[j].m_edge = boundary.GetEdges()[g_unk0x100d7d08[j]]; + g_ctrlEdgesB[j].m_edge = boundary.GetEdges()[g_ctrlEdgesNamesB[j]]; } } } @@ -163,7 +163,7 @@ void LegoPathController::Destroy() m_numE = 0; MxS32 j; - for (j = 0; j < sizeOfArray(g_unk0x100f42f0); j++) { + for (j = 0; j < sizeOfArray(g_ctrlBoundariesNamesA); j++) { if (g_ctrlBoundariesA[j].m_controller == this) { g_ctrlBoundariesA[j].m_controller = NULL; g_ctrlBoundariesA[j].m_boundary = NULL; @@ -175,7 +175,7 @@ void LegoPathController::Destroy() } } - for (j = 0; j < sizeOfArray(g_unk0x100f4330); j++) { + for (j = 0; j < sizeOfArray(g_ctrlBoundariesNamesB); j++) { if (g_ctrlBoundariesB[j].m_controller == this) { g_ctrlBoundariesB[j].m_controller = NULL; g_ctrlBoundariesB[j].m_boundary = NULL; @@ -192,7 +192,7 @@ void LegoPathController::Destroy() // FUNCTION: BETA10 0x100b6d60 MxResult LegoPathController::Tickle() { - FUN_10046970(); + AnimateActors(); return SUCCESS; } @@ -343,7 +343,7 @@ MxResult LegoPathController::RemoveActor(LegoPathActor* p_actor) // FUNCTION: LEGO1 0x100468f0 // FUNCTION: BETA10 0x100b72f7 -void LegoPathController::FUN_100468f0(LegoAnimPresenter* p_presenter) +void LegoPathController::AddPresenterIfInRange(LegoAnimPresenter* p_presenter) { for (MxS32 i = 0; i < m_numL; i++) { if (!(m_boundaries[i].m_flags & LegoWEGEdge::c_bit3)) { @@ -363,7 +363,7 @@ void LegoPathController::RemovePresenterFromBoundaries(LegoAnimPresenter* p_pres // FUNCTION: LEGO1 0x10046970 // FUNCTION: BETA10 0x100b73d8 -void LegoPathController::FUN_10046970() +void LegoPathController::AnimateActors() { float time = Timer()->GetTime(); @@ -381,7 +381,7 @@ void LegoPathController::FUN_10046970() } // FUNCTION: LEGO1 0x10046b30 -MxResult LegoPathController::FUN_10046b30(LegoPathBoundary*& p_boundaries, MxS32& p_numL) +MxResult LegoPathController::GetBoundaries(LegoPathBoundary*& p_boundaries, MxS32& p_numL) { p_boundaries = m_boundaries; p_numL = m_numL; @@ -403,7 +403,7 @@ LegoPathBoundary* LegoPathController::GetPathBoundary(const char* p_name) // FUNCTION: LEGO1 0x10046bb0 // FUNCTION: BETA10 0x100b75bc -void LegoPathController::FUN_10046bb0(LegoWorld* p_world) +void LegoPathController::SetWorld(LegoWorld* p_world) { for (MxS32 i = 0; i < m_numT; i++) { m_structs[i].SetWorld(p_world); @@ -430,10 +430,10 @@ MxResult LegoPathController::Init() return FAILURE; } - g_ctrlBoundariesA = new CtrlBoundary[sizeOfArray(g_unk0x100f42f0)]; - g_ctrlEdgesA = new CtrlEdge[sizeOfArray(g_unk0x100f42f0)]; - g_ctrlBoundariesB = new CtrlBoundary[sizeOfArray(g_unk0x100f4330)]; - g_ctrlEdgesB = new CtrlEdge[sizeOfArray(g_unk0x100f4330)]; + g_ctrlBoundariesA = new CtrlBoundary[sizeOfArray(g_ctrlBoundariesNamesA)]; + g_ctrlEdgesA = new CtrlEdge[sizeOfArray(g_ctrlBoundariesNamesA)]; + g_ctrlBoundariesB = new CtrlBoundary[sizeOfArray(g_ctrlBoundariesNamesB)]; + g_ctrlEdgesB = new CtrlEdge[sizeOfArray(g_ctrlBoundariesNamesB)]; return SUCCESS; } @@ -758,7 +758,7 @@ MxResult LegoPathController::ReadVector(LegoStorage* p_storage, Mx4DPointFloat& // FUNCTION: LEGO1 0x10048310 // FUNCTION: BETA10 0x100b8911 -MxResult LegoPathController::FUN_10048310( +MxResult LegoPathController::FindPath( LegoPathEdgeContainer* p_grec, const Vector3& p_oldPosition, const Vector3& p_oldDirection, @@ -767,7 +767,7 @@ MxResult LegoPathController::FUN_10048310( const Vector3& p_newDirection, LegoPathBoundary* p_newBoundary, LegoU8 p_mask, - MxFloat* p_param9 + MxFloat* p_distance ) { p_grec->m_position = p_newPosition; @@ -788,7 +788,7 @@ MxResult LegoPathController::FUN_10048310( LegoPathCtrlEdgeSet pathCtrlEdgeSet(m_pfsE); - MxFloat local14 = 999999.0f; + MxFloat minDistance = 999999.0f; p_grec->SetPath(FALSE); @@ -802,8 +802,8 @@ MxResult LegoPathController::FUN_10048310( if (p_newBoundary == otherFace) { float dist; if ((dist = edge->DistanceToMidpoint(p_oldPosition) + edge->DistanceToMidpoint(p_newPosition)) < - local14) { - local14 = dist; + minDistance) { + minDistance = dist; p_grec->erase(p_grec->begin(), p_grec->end()); p_grec->SetPath(TRUE); p_grec->push_back(LegoBoundaryEdge(edge, p_oldBoundary)); @@ -823,8 +823,8 @@ MxResult LegoPathController::FUN_10048310( if (!p_grec->HasPath()) { while (pathCtrlEdgeSet.size() > 0) { - LegoBEWithMidpoint edgeWithFloat; - MxFloat local70 = 999999.0f; + LegoBEWithMidpoint edgeWithMidpoint; + MxFloat minDist = 999999.0f; boundarySetItA = boundarySetItB = boundarySet.begin(); @@ -854,13 +854,13 @@ MxResult LegoPathController::FUN_10048310( float dist; if ((dist = pfs->m_edge->DistanceToMidpoint(p_newPosition) + pfs->m_distanceToMidpoint) < - local70) { - edgeWithFloat.m_edge = NULL; - local70 = dist; + minDist) { + edgeWithMidpoint.m_edge = NULL; + minDist = dist; // TODO: Match - if (dist < local14) { - local14 = dist; + if (dist < minDistance) { + minDistance = dist; p_grec->erase(p_grec->begin(), p_grec->end()); p_grec->SetPath(TRUE); @@ -881,9 +881,9 @@ MxResult LegoPathController::FUN_10048310( float dist; if ((dist = edge->DistanceBetweenMidpoints(*e) + - (*boundarySetItA)->m_distanceToMidpoint) < local70) { - local70 = dist; - edgeWithFloat = LegoBEWithMidpoint(edge, bOther, *boundarySetItA, dist); + (*boundarySetItA)->m_distanceToMidpoint) < minDist) { + minDist = dist; + edgeWithMidpoint = LegoBEWithMidpoint(edge, bOther, *boundarySetItA, dist); } } } @@ -904,9 +904,9 @@ MxResult LegoPathController::FUN_10048310( } } - if (edgeWithFloat.m_edge != NULL) { - pathCtrlEdgeSet.erase(edgeWithFloat.m_edge); - boundaryList.push_back(edgeWithFloat); + if (edgeWithMidpoint.m_edge != NULL) { + pathCtrlEdgeSet.erase(edgeWithMidpoint.m_edge); + boundaryList.push_back(edgeWithMidpoint); boundarySet.insert(&boundaryList.back()); } else { @@ -936,8 +936,8 @@ MxResult LegoPathController::FUN_10048310( } } - if (p_param9 != NULL) { - *p_param9 = local14; + if (p_distance != NULL) { + *p_distance = minDistance; } return SUCCESS; @@ -948,18 +948,18 @@ MxResult LegoPathController::FUN_10048310( // FUNCTION: LEGO1 0x1004a240 // FUNCTION: BETA10 0x100b9160 -MxS32 LegoPathController::FUN_1004a240( +MxS32 LegoPathController::GetNextPathEdge( LegoPathEdgeContainer& p_grec, - Vector3& p_v1, - Vector3& p_v2, + Vector3& p_position, + Vector3& p_direction, float p_f1, LegoOrientedEdge*& p_edge, LegoPathBoundary*& p_boundary ) { if (p_grec.size() == 0) { - p_v1 = p_grec.m_position; - p_v2 = p_grec.m_direction; + p_position = p_grec.m_position; + p_direction = p_grec.m_direction; p_boundary = p_grec.m_boundary; p_grec.SetPath(FALSE); return 1; @@ -970,28 +970,28 @@ MxS32 LegoPathController::FUN_1004a240( p_grec.pop_front(); Mx3DPointFloat vec; - p_v1 = *p_edge->CCWVertex(*p_boundary); - p_v1 -= *p_edge->CWVertex(*p_boundary); - p_v1 *= p_f1; - p_v1 += *p_edge->CWVertex(*p_boundary); + p_position = *p_edge->CCWVertex(*p_boundary); + p_position -= *p_edge->CWVertex(*p_boundary); + p_position *= p_f1; + p_position += *p_edge->CWVertex(*p_boundary); p_edge->GetFaceNormal(*p_boundary, vec); - p_v2.EqualsCross(*p_boundary->GetUp(), vec); + p_direction.EqualsCross(*p_boundary->GetUp(), vec); return 0; } // FUNCTION: LEGO1 0x1004a380 // FUNCTION: BETA10 0x100b957f -MxResult LegoPathController::FUN_1004a380( - Vector3& p_param1, - Vector3& p_param2, - Mx3DPointFloat* p_param3, +MxResult LegoPathController::FindIntersectionBoundary( + Vector3& p_location, + Vector3& p_direction, + Mx3DPointFloat* p_coefficients, LegoPathBoundary*& p_boundary, - MxFloat& p_param5 + MxFloat& p_apexParameter ) { - MxFloat param5 = p_param5; - Mx3DPointFloat local24; - MxU32 local8 = TRUE; + MxFloat originalApexParameter = p_apexParameter; + Mx3DPointFloat intersectionPoint; + MxU32 solutionNotFound = TRUE; for (MxS32 i = 0; i < m_numL; i++) { if (m_boundaries[i].m_flags & LegoPathBoundary::c_bit3) { @@ -999,75 +999,76 @@ MxResult LegoPathController::FUN_1004a380( } LegoPathBoundary* b = &m_boundaries[i]; - Mx4DPointFloat* unk0x14 = b->GetUp(); - float local28 = p_param3[0].Dot(p_param3[0], *unk0x14); + Mx4DPointFloat* up = b->GetUp(); + float coeffADotUp = p_coefficients[0].Dot(p_coefficients[0], *up); - if (local28 < 0.001 && local28 > -0.001) { + if (coeffADotUp < 0.001 && coeffADotUp > -0.001) { continue; } - float local2c = p_param3[1].Dot(p_param3[1], *unk0x14); - float local34 = p_param3[2].Dot(p_param3[2], *unk0x14) + unk0x14->index_operator(3); - float local3c = local2c * local2c - local34 * local28 * 4.0f; + float coeffBDotUp = p_coefficients[1].Dot(p_coefficients[1], *up); + float coeffCDotUp = p_coefficients[2].Dot(p_coefficients[2], *up) + up->index_operator(3); + float quadraticDiscriminant = coeffBDotUp * coeffBDotUp - coeffCDotUp * coeffADotUp * 4.0f; - if (local3c < -0.001) { + if (quadraticDiscriminant < -0.001) { continue; } - if (local3c < 0.0f) { - local3c = 0.0f; + if (quadraticDiscriminant < 0.0f) { + quadraticDiscriminant = 0.0f; } else { - local3c = sqrt(local3c); + quadraticDiscriminant = sqrt(quadraticDiscriminant); } - float local38 = (local3c - local2c) / (local28 * 2.0f); - float local44 = (-local3c - local2c) / (local28 * 2.0f); + float intersectionParameter = (quadraticDiscriminant - coeffBDotUp) / (coeffADotUp * 2.0f); + float alternativeIntersectionParameter = (-quadraticDiscriminant - coeffBDotUp) / (coeffADotUp * 2.0f); - if (!IsBetween(local38, 0.0f, param5)) { - if (IsBetween(local44, 0.0f, param5)) { - local38 = local44; + if (!IsBetween(intersectionParameter, 0.0f, originalApexParameter)) { + if (IsBetween(alternativeIntersectionParameter, 0.0f, originalApexParameter)) { + intersectionParameter = alternativeIntersectionParameter; } else { continue; } } - if (local8 || FUN_100c17a0(local38, p_param5, 0.0f, param5)) { - Mx3DPointFloat local58(p_param3[0]); + if (solutionNotFound || + BothSameComparison(intersectionParameter, p_apexParameter, 0.0f, originalApexParameter)) { + Mx3DPointFloat tSqrA(p_coefficients[0]); - local58 *= local38 * local38; - local24 = p_param3[1]; - local24 *= local38; - local24 += p_param3[2]; - local24 += local58; + tSqrA *= intersectionParameter * intersectionParameter; + intersectionPoint = p_coefficients[1]; + intersectionPoint *= intersectionParameter; + intersectionPoint += p_coefficients[2]; + intersectionPoint += tSqrA; assert(b->GetNumEdges() > 1); MxS32 j; for (j = b->GetNumEdges() - 1; j >= 0; j--) { - Mx4DPointFloat* local60 = b->GetEdgeNormal(j); + Mx4DPointFloat* edgeNormal = b->GetEdgeNormal(j); - if (local24.Dot(*local60, local24) + local60->index_operator(3) < -0.001) { + if (intersectionPoint.Dot(*edgeNormal, intersectionPoint) + edgeNormal->index_operator(3) < -0.001) { break; } } if (j < 0) { - Mx3DPointFloat local74(p_param1); - local74 -= local24; + Mx3DPointFloat direction(p_location); + direction -= intersectionPoint; - if (local74.Dot(local74, *unk0x14) >= 0.0f) { - p_param5 = local38; + if (direction.Dot(direction, *up) >= 0.0f) { + p_apexParameter = intersectionParameter; p_boundary = b; - local8 = FALSE; + solutionNotFound = FALSE; } } } } - if (local8) { - p_param5 = param5; + if (solutionNotFound) { + p_apexParameter = originalApexParameter; return FAILURE; } diff --git a/LEGO1/lego/legoomni/src/worlds/act3.cpp b/LEGO1/lego/legoomni/src/worlds/act3.cpp index f7c773ed..bedbf451 100644 --- a/LEGO1/lego/legoomni/src/worlds/act3.cpp +++ b/LEGO1/lego/legoomni/src/worlds/act3.cpp @@ -335,7 +335,7 @@ MxResult Act3::ShootPizza(LegoPathController* p_controller, Vector3& p_location, } MxFloat unk0x19c = *m_pizzas[nextPizza].GetApexParameter(); - if (p_controller->FUN_1004a380( + if (p_controller->FindIntersectionBoundary( p_location, p_direction, m_pizzas[nextPizza].GetCoefficients(), @@ -390,7 +390,7 @@ MxResult Act3::ShootDonut(LegoPathController* p_controller, Vector3& p_location, } MxFloat unk0x19c = *m_donuts[nextDonut].GetApexParameter(); - if (p_controller->FUN_1004a380( + if (p_controller->FindIntersectionBoundary( p_location, p_direction, m_donuts[nextDonut].GetCoefficients(), From e094e381475423ed18dc24d3611a543eb45fbdaa Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Mon, 19 Jan 2026 23:13:01 +0100 Subject: [PATCH 16/23] Clear unknowns in `IslePathActor` (#1725) --- LEGO1/lego/legoomni/include/islepathactor.h | 10 +++++----- .../lego/legoomni/src/actors/islepathactor.cpp | 18 +++++++++--------- LEGO1/lego/legoomni/src/worlds/isle.cpp | 2 +- LEGO1/lego/legoomni/src/worlds/legoact2.cpp | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/LEGO1/lego/legoomni/include/islepathactor.h b/LEGO1/lego/legoomni/include/islepathactor.h index 46630e29..d1966b9c 100644 --- a/LEGO1/lego/legoomni/include/islepathactor.h +++ b/LEGO1/lego/legoomni/include/islepathactor.h @@ -102,10 +102,10 @@ class IslePathActor : public LegoPathActor { // FUNCTION: LEGO1 0x10002e00 virtual MxLong HandlePathStruct(LegoPathStructNotificationParam&) { return 0; } // vtable+0xdc - virtual void Enter(); // vtable+0xe0 - virtual void Exit(); // vtable+0xe4 - virtual void SpawnPlayer(LegoGameState::Area p_area, MxBool p_enter, MxU8 p_flags); // vtable+0xe8 - virtual void VTable0xec(MxMatrix p_transform, LegoPathBoundary* p_boundary, MxBool p_reset); // vtable+0xec + virtual void Enter(); // vtable+0xe0 + virtual void Exit(); // vtable+0xe4 + virtual void SpawnPlayer(LegoGameState::Area p_area, MxBool p_enter, MxU8 p_flags); // vtable+0xe8 + virtual void UpdateWorld(MxMatrix p_transform, LegoPathBoundary* p_boundary, MxBool p_reset); // vtable+0xec // FUNCTION: LEGO1 0x10002e10 ~IslePathActor() override { IslePathActor::Destroy(TRUE); } @@ -129,7 +129,7 @@ class IslePathActor : public LegoPathActor { MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 void Destroy(MxBool p_fromDestructor) override; // vtable+0x1c - void FUN_1001b660(); + void TurnAround(); void SetWorld(LegoWorld* p_world) { m_world = p_world; } diff --git a/LEGO1/lego/legoomni/src/actors/islepathactor.cpp b/LEGO1/lego/legoomni/src/actors/islepathactor.cpp index 7d7776a2..df7c3634 100644 --- a/LEGO1/lego/legoomni/src/actors/islepathactor.cpp +++ b/LEGO1/lego/legoomni/src/actors/islepathactor.cpp @@ -92,7 +92,7 @@ void IslePathActor::Enter() NavController()->ResetMaxLinearVel(m_maxLinearVel); SetUserActor(this); - FUN_1001b660(); + TurnAround(); TransformPointOfView(); } } @@ -151,7 +151,7 @@ void IslePathActor::Exit() GameState()->m_currentArea = LegoGameState::Area::e_vehicleExited; } - FUN_1001b660(); + TurnAround(); TransformPointOfView(); ResetViewVelocity(); } @@ -611,7 +611,7 @@ void IslePathActor::SpawnPlayer(LegoGameState::Area p_area, MxBool p_enter, MxU8 } // FUNCTION: LEGO1 0x1001b5b0 -void IslePathActor::VTable0xec(MxMatrix p_transform, LegoPathBoundary* p_boundary, MxBool p_reset) +void IslePathActor::UpdateWorld(MxMatrix p_transform, LegoPathBoundary* p_boundary, MxBool p_reset) { if (m_world) { m_world->RemoveActor(this); @@ -639,15 +639,15 @@ void IslePathActor::VTable0xec(MxMatrix p_transform, LegoPathBoundary* p_boundar // FUNCTION: LEGO1 0x1001b660 // FUNCTION: BETA10 0x10036ea2 -void IslePathActor::FUN_1001b660() +void IslePathActor::TurnAround() { MxMatrix transform(m_roi->GetLocal2World()); - Vector3 position(transform[0]); - Vector3 direction(transform[1]); - Vector3 up(transform[2]); + Vector3 right(transform[0]); + Vector3 up(transform[1]); + Vector3 direction(transform[2]); - up *= -1.0f; - position.EqualsCross(direction, up); + direction *= -1.0f; + right.EqualsCross(up, direction); m_roi->SetLocal2World(transform); m_roi->WrappedUpdateWorldData(); } diff --git a/LEGO1/lego/legoomni/src/worlds/isle.cpp b/LEGO1/lego/legoomni/src/worlds/isle.cpp index 54c91475..373befa0 100644 --- a/LEGO1/lego/legoomni/src/worlds/isle.cpp +++ b/LEGO1/lego/legoomni/src/worlds/isle.cpp @@ -867,7 +867,7 @@ void Isle::CheckAreaExiting() case LegoGameState::e_vehicleExited: { MxMatrix mat(UserActor()->GetROI()->GetLocal2World()); LegoPathBoundary* boundary = UserActor()->GetBoundary(); - ((IslePathActor*) UserActor())->VTable0xec(mat, boundary, TRUE); + ((IslePathActor*) UserActor())->UpdateWorld(mat, boundary, TRUE); break; } case LegoGameState::e_infocenterExited: diff --git a/LEGO1/lego/legoomni/src/worlds/legoact2.cpp b/LEGO1/lego/legoomni/src/worlds/legoact2.cpp index 0e84566e..3fe704c6 100644 --- a/LEGO1/lego/legoomni/src/worlds/legoact2.cpp +++ b/LEGO1/lego/legoomni/src/worlds/legoact2.cpp @@ -534,7 +534,7 @@ void LegoAct2::Enable(MxBool p_enable) GameState()->SetActor(LegoActor::c_pepper); m_pepper = FindROI("pepper"); - ((IslePathActor*) m_pepper->GetEntity())->VTable0xec(m_transformOnDisable, m_boundaryOnDisable, TRUE); + ((IslePathActor*) m_pepper->GetEntity())->UpdateWorld(m_transformOnDisable, m_boundaryOnDisable, TRUE); if (GameState()->m_previousArea == LegoGameState::e_infomain) { GameState()->StopArea(LegoGameState::e_infomain); From 92d602db7dba0529b154302a1f349559d6dc74ad Mon Sep 17 00:00:00 2001 From: ps1-startup Date: Sat, 24 Jan 2026 20:28:50 -0500 Subject: [PATCH 17/23] Make Ghidra server instructions clearer (#1727) I've made it so that "Request Anonymous Access" is enabled if they didn't get permission to edit. --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d50be904..e6bb082a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,6 +15,8 @@ To access the Ghidra repository, use the following details: - Address: `server.mattkc.com` - Port: `13100` +Make sure that you enabled "Request Anonymous Request" if you didn't get permission to edit. + ## General Guidelines If you feel fit to contribute, feel free to create a pull request! Someone will review and merge it (or provide feedback) as soon as possible. From d69a381a18b9ca60d9a5962a8716871cdbc4a2ce Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Sun, 25 Jan 2026 16:38:39 +0100 Subject: [PATCH 18/23] Remove pylintrc, clean up tools README (#1728) Co-authored-by: jonschz --- .pylintrc | 635 ------------------------------------------------ tools/README.md | 22 +- 2 files changed, 14 insertions(+), 643 deletions(-) delete mode 100644 .pylintrc diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index 976b3764..00000000 --- a/.pylintrc +++ /dev/null @@ -1,635 +0,0 @@ -[MAIN] - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - -# Clear in-memory caches upon conclusion of linting. Useful if running pylint -# in a server-like mode. -clear-cache-post-run=no - -# Load and enable all available extensions. Use --list-extensions to see a list -# all available extensions. -#enable-all-extensions= - -# In error mode, messages with a category besides ERROR or FATAL are -# suppressed, and no reports are done by default. Error mode is compatible with -# disabling specific errors. -#errors-only= - -# Always return a 0 (non-error) status code, even if lint errors are found. -# This is primarily useful in continuous integration scripts. -#exit-zero= - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code. -extension-pkg-allow-list= - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code. (This is an alternative name to extension-pkg-allow-list -# for backward compatibility.) -extension-pkg-whitelist= - -# Return non-zero exit code if any of these messages/categories are detected, -# even if score is above --fail-under value. Syntax same as enable. Messages -# specified are enabled, while categories only check already-enabled messages. -fail-on= - -# Specify a score threshold under which the program will exit with error. -fail-under=10 - -# Interpret the stdin as a python script, whose filename needs to be passed as -# the module_or_package argument. -#from-stdin= - -# Files or directories to be skipped. They should be base names, not paths. -ignore=CVS - -# Add files or directories matching the regular expressions patterns to the -# ignore-list. The regex matches against paths and can be in Posix or Windows -# format. Because '\\' represents the directory delimiter on Windows systems, -# it can't be used as an escape character. -ignore-paths= - -# Files or directories matching the regular expression patterns are skipped. -# The regex matches against base names, not paths. The default value ignores -# Emacs file locks -ignore-patterns=^\.# - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis). It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules=ghidra - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -init-hook='import sys; sys.path.append("tools/isledecomp"); sys.path.append("tools/ghidra_scripts")' - -# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the -# number of processors available to use, and will cap the count on Windows to -# avoid hangs. -jobs=1 - -# Control the amount of potential inferred values when inferring a single -# object. This can help the performance when dealing with large functions or -# complex, nested conditions. -limit-inference-results=100 - -# List of plugins (as comma separated values of python module names) to load, -# usually to register additional checkers. -load-plugins= - -# Pickle collected data for later comparisons. -persistent=yes - -# Minimum Python version to use for version dependent checks. Will default to -# the version used to run pylint. -py-version=3.11 - -# Discover python modules and packages in the file system subtree. -recursive=no - -# Add paths to the list of the source roots. Supports globbing patterns. The -# source root is an absolute path or a path relative to the current working -# directory used to determine a package namespace for modules located under the -# source root. -source-roots= - -# When enabled, pylint would attempt to guess common misconfiguration and emit -# user-friendly hints instead of false-positive error messages. -suggestion-mode=yes - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - -# In verbose mode, extra non-checker-related info will be displayed. -#verbose= - - -[BASIC] - -# Naming style matching correct argument names. -argument-naming-style=snake_case - -# Regular expression matching correct argument names. Overrides argument- -# naming-style. If left empty, argument names will be checked with the set -# naming style. -#argument-rgx= - -# Naming style matching correct attribute names. -attr-naming-style=snake_case - -# Regular expression matching correct attribute names. Overrides attr-naming- -# style. If left empty, attribute names will be checked with the set naming -# style. -#attr-rgx= - -# Bad variable names which should always be refused, separated by a comma. -bad-names=foo, - bar, - baz, - toto, - tutu, - tata - -# Bad variable names regexes, separated by a comma. If names match any regex, -# they will always be refused -bad-names-rgxs= - -# Naming style matching correct class attribute names. -class-attribute-naming-style=any - -# Regular expression matching correct class attribute names. Overrides class- -# attribute-naming-style. If left empty, class attribute names will be checked -# with the set naming style. -#class-attribute-rgx= - -# Naming style matching correct class constant names. -class-const-naming-style=UPPER_CASE - -# Regular expression matching correct class constant names. Overrides class- -# const-naming-style. If left empty, class constant names will be checked with -# the set naming style. -#class-const-rgx= - -# Naming style matching correct class names. -class-naming-style=PascalCase - -# Regular expression matching correct class names. Overrides class-naming- -# style. If left empty, class names will be checked with the set naming style. -#class-rgx= - -# Naming style matching correct constant names. -const-naming-style=UPPER_CASE - -# Regular expression matching correct constant names. Overrides const-naming- -# style. If left empty, constant names will be checked with the set naming -# style. -#const-rgx= - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Naming style matching correct function names. -function-naming-style=snake_case - -# Regular expression matching correct function names. Overrides function- -# naming-style. If left empty, function names will be checked with the set -# naming style. -#function-rgx= - -# Good variable names which should always be accepted, separated by a comma. -good-names=i, - j, - k, - ex, - Run, - _ - -# Good variable names regexes, separated by a comma. If names match any regex, -# they will always be accepted -good-names-rgxs= - -# Include a hint for the correct naming format with invalid-name. -include-naming-hint=no - -# Naming style matching correct inline iteration names. -inlinevar-naming-style=any - -# Regular expression matching correct inline iteration names. Overrides -# inlinevar-naming-style. If left empty, inline iteration names will be checked -# with the set naming style. -#inlinevar-rgx= - -# Naming style matching correct method names. -method-naming-style=snake_case - -# Regular expression matching correct method names. Overrides method-naming- -# style. If left empty, method names will be checked with the set naming style. -#method-rgx= - -# Naming style matching correct module names. -module-naming-style=snake_case - -# Regular expression matching correct module names. Overrides module-naming- -# style. If left empty, module names will be checked with the set naming style. -#module-rgx= - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_ - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -# These decorators are taken in consideration only for invalid-name. -property-classes=abc.abstractproperty - -# Regular expression matching correct type alias names. If left empty, type -# alias names will be checked with the set naming style. -#typealias-rgx= - -# Regular expression matching correct type variable names. If left empty, type -# variable names will be checked with the set naming style. -#typevar-rgx= - -# Naming style matching correct variable names. -variable-naming-style=snake_case - -# Regular expression matching correct variable names. Overrides variable- -# naming-style. If left empty, variable names will be checked with the set -# naming style. -#variable-rgx= - - -[CLASSES] - -# Warn about protected attribute access inside special methods -check-protected-access-in-special-methods=no - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__, - __new__, - setUp, - asyncSetUp, - __post_init__ - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make,os._exit - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - - -[DESIGN] - -# List of regular expressions of class ancestor names to ignore when counting -# public methods (see R0903) -exclude-too-few-public-methods= - -# List of qualified class names to ignore when counting class parents (see -# R0901) -ignored-parents= - -# Maximum number of arguments for function / method. -max-args=6 - -# Maximum number of attributes for a class (see R0902). -max-attributes=7 - -# Maximum number of boolean expressions in an if statement (see R0916). -max-bool-expr=5 - -# Maximum number of branch for function / method body. -max-branches=30 - -# Maximum number of locals for function / method body. -max-locals=30 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of return / yield for function / method body. -max-returns=6 - -# Maximum number of statements in function / method body. -max-statements=75 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=0 - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when caught. -overgeneral-exceptions=builtins.BaseException,builtins.Exception - - -[FORMAT] - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format= - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=2 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Maximum number of characters on a single line. -max-line-length=200 - -# Maximum number of lines in a module. -max-module-lines=1000 - -# Allow the body of a class to be on the same line as the declaration if body -# contains single statement. -single-line-class-stmt=no - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - - -[IMPORTS] - -# List of modules that can be imported at any level, not just the top level -# one. -allow-any-import-level= - -# Allow explicit reexports by alias from a package __init__. -allow-reexport-from-package=no - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# Deprecated modules which should not be used, separated by a comma. -deprecated-modules= - -# Output a graph (.gv or any supported image format) of external dependencies -# to the given file (report RP0402 must not be disabled). -ext-import-graph= - -# Output a graph (.gv or any supported image format) of all (i.e. internal and -# external) dependencies to the given file (report RP0402 must not be -# disabled). -import-graph= - -# Output a graph (.gv or any supported image format) of internal dependencies -# to the given file (report RP0402 must not be disabled). -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - -# Couples of modules and preferred modules, separated by a comma. -preferred-modules= - - -[LOGGING] - -# The type of string formatting that logging methods do. `old` means using % -# formatting, `new` is for `{}` formatting. -logging-format-style=old - -# Logging modules to check that the string format arguments are in logging -# function parameter format. -logging-modules=logging - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, -# UNDEFINED. -confidence=HIGH, - CONTROL_FLOW, - INFERENCE, - INFERENCE_FAILURE, - UNDEFINED - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once). You can also use "--disable=all" to -# disable everything first and then re-enable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use "--disable=all --enable=classes -# --disable=W". -disable=raw-checker-failed, - bad-inline-option, - locally-disabled, - file-ignored, - suppressed-message, - useless-suppression, - deprecated-pragma, - use-symbolic-message-instead, - missing-class-docstring, - missing-function-docstring, - missing-module-docstring, - fixme - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -enable=c-extension-no-member - - -[METHOD_ARGS] - -# List of qualified names (i.e., library.method) which require a timeout -# parameter e.g. 'requests.api.get,requests.api.post' -timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME, - XXX, - TODO - -# Regular expression of note tags to take in consideration. -notes-rgx= - - -[REFACTORING] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - -# Complete name of functions that never returns. When checking for -# inconsistent-return-statements if a never returning function is called then -# it will be considered as an explicit return statement and no message will be -# printed. -never-returning-functions=sys.exit,argparse.parse_error - - -[REPORTS] - -# Python expression which should return a score less than or equal to 10. You -# have access to the variables 'fatal', 'error', 'warning', 'refactor', -# 'convention', and 'info' which contain the number of messages in each -# category, as well as 'statement' which is the total number of statements -# analyzed. This score is used by the global evaluation report (RP0004). -evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details. -msg-template= - -# Set the output format. Available formats are text, parseable, colorized, json -# and msvs (visual studio). You can also give a reporter class, e.g. -# mypackage.mymodule.MyReporterClass. -#output-format= - -# Tells whether to display a full report or only the messages. -reports=no - -# Activate the evaluation score. -score=yes - - -[SIMILARITIES] - -# Comments are removed from the similarity computation -ignore-comments=yes - -# Docstrings are removed from the similarity computation -ignore-docstrings=yes - -# Imports are removed from the similarity computation -ignore-imports=yes - -# Signatures are removed from the similarity computation -ignore-signatures=yes - -# Minimum lines number of a similarity. -min-similarity-lines=16 - - -[SPELLING] - -# Limits count of emitted suggestions for spelling mistakes. -max-spelling-suggestions=4 - -# Spelling dictionary name. No available dictionaries : You need to install -# both the python package and the system dependency for enchant to work.. -spelling-dict= - -# List of comma separated words that should be considered directives if they -# appear at the beginning of a comment and should not be checked. -spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains the private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to the private dictionary (see the -# --spelling-private-dict-file option) instead of raising a message. -spelling-store-unknown-words=no - - -[STRING] - -# This flag controls whether inconsistent-quotes generates a warning when the -# character used as a quote delimiter is used inconsistently within a module. -check-quote-consistency=no - -# This flag controls whether the implicit-str-concat should generate a warning -# on implicit string concatenation in sequences defined over several lines. -check-str-concat-over-line-jumps=no - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members= - -# Tells whether to warn about missing members when the owner of the attribute -# is inferred to be None. -ignore-none=yes - -# This flag controls whether pylint should warn about no-member and similar -# checks whenever an opaque object is returned when inferring. The inference -# can return multiple potential results while evaluating a Python object, but -# some branches might not be evaluated, which results in partial inference. In -# that case, it might be useful to still emit no-member and other checks for -# the rest of the inferred objects. -ignore-on-opaque-inference=yes - -# List of symbolic message names to ignore for Mixin members. -ignored-checks-for-mixins=no-member, - not-async-context-manager, - not-context-manager, - attribute-defined-outside-init - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace - -# Show a hint with possible names when a member name was not found. The aspect -# of finding the hint is based on edit distance. -missing-member-hint=yes - -# The minimum edit distance a name should have in order to be considered a -# similar match for a missing member name. -missing-member-hint-distance=1 - -# The total number of similar names that should be taken in consideration when -# showing a hint for a missing member. -missing-member-max-choices=1 - -# Regex pattern to define which classes are considered mixins. -mixin-class-rgx=.*[Mm]ixin - -# List of decorators that change the signature of a decorated function. -signature-mutators= - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid defining new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# List of names allowed to shadow builtins -allowed-redefined-builtins= - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_, - _cb - -# A regular expression matching the name of dummy variables (i.e. expected to -# not be used). -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ - -# Argument names that match this expression will be ignored. -ignored-argument-names=_.*|^ignored_|^unused_ - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io diff --git a/tools/README.md b/tools/README.md index 0d443780..ab63b036 100644 --- a/tools/README.md +++ b/tools/README.md @@ -3,28 +3,33 @@ Accuracy to the game's original code is the main goal of this project. To facilitate the decompilation effort and maintain overall quality, we have devised a set of annotations, to be embedded in the source code, which allow us to automatically verify the accuracy of re-compiled functions' assembly, virtual tables, variable offsets and more. The tooling we have developed has been moved to the [reccmp](https://github.com/isledecomp/reccmp) repo to facilitate its use in other decompilation projects. + * See the [README](https://github.com/isledecomp/reccmp?tab=readme-ov-file#getting-started) on how to get started. * Familiarize yourself with the available [annotations](https://github.com/isledecomp/reccmp/blob/master/docs/annotations.md) and the [best practices](https://github.com/isledecomp/reccmp/blob/master/docs/recommendations.md) we have established. The following scripts are specific to LEGO Island and have thus remained here: + * [`patch_c2.py`](/tools/patch_c2.py): Patches `C2.EXE` (part of MSVC 4.20) to get rid of a bugged warning. -# Modules +## Modules + The following is a list of all the modules found in the annotations (e.g. `// FUNCTION: [module] [address]`) and which binaries they refer to. See also [this list of all known versions of the game](https://www.legoisland.org/wiki/LEGO_Island#Download). -## Retail v1.1.0.0 (v1.1) +### Retail v1.1.0.0 (v1.1) + * `LEGO1` -> `LEGO1.DLL` * `CONFIG`-> `CONFIG.EXE` * `ISLE` -> `ISLE.EXE` These modules are the most important ones and refer to the English retail version 1.1.0.0 (often shortened to v1.1), which is the most widely released one. These are the ones we attempt to decompile and match as best as possible. -## BETA v1.0 +### BETA v1.0 * `BETA10` -> `LEGO1D.DLL` * `CONFIGD` -> `CONFIG.EXE` The Beta 1.0 version contains a debug build of the game. While it does not have debug symbols, it still has a number of benefits: + * It is built with less or no optimisation, leading to better decompilations in Ghidra * Far fewer functions are inlined by the compiler, so it can be used to recognise inlined functions * It contains assertions that tell us original variable names and code file paths @@ -35,17 +40,17 @@ Unfortunately, some code has been changed after this beta version was created. T The beta version of the `CONFIG` application has provided some help with matching [MFC handler functions](https://en.wikipedia.org/wiki/Microsoft_Foundation_Class_Library) that are similar to the final version. -## Pre-Alpha +### Pre-Alpha * `ALPHA` -> `LEGO1D.DLL` This debug build is hardly used since it has little benefit over `BETA10`. - -# Re-compiling a beta build +## Re-compiling a beta build If you want to match the code against `BETA10`, use the following `cmake` setup to create a debug build: -``` + +```bash cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_BUILD_TYPE=Debug -DISLE_USE_SMARTHEAP=OFF -DISLE_BUILD_BETA10=ON -DISLE_BUILD_LEGO1=OFF ``` @@ -53,9 +58,10 @@ If you can figure out how to make a debug build with SmartHeap enabled, please a If you want to run scripts to compare your debug build to `BETA10` (e.g. `reccmp-reccmp`), it is advisable to add a copy of `LEGO1D.DLL` from Beta 1.0 to `/legobin` and rename it to `BETA10.DLL`. Analogously, you can add `LEGO1D.DLL` from the Pre-Alpha and rename it to `ALPHA.DLL`. -# Finding matching functions +## Finding matching functions This is not a recipe, but rather a list of things you can try. + * If you are working on a virtual function in a class, try to find the class' vtable. Many (but not all) classes implement `ClassName()`. These functions are usually easy to find by searching the memory for the string consisting of the class name. Keep in mind that not all child classes overwrite this function, so if the function you found is used in multiple vtables (or if you found multiple `ClassName()`-like functions), make sure you actually have the parent's vtable. * If that does not help, you can try to walk up the call tree and try to locate a function that calls the function you are interested in. * Assertions can also help you - most `.cpp` file names have already been matched based on `BETA10`, so you can search for the name of your `.cpp` file and check all the assertions in that file. While that does not find all functions in a given source file, it usually finds the more complex ones. From a251424b10488f6c9f1d23b0f3e8684e964451db Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Sun, 25 Jan 2026 20:45:58 +0100 Subject: [PATCH 19/23] Clear unknowns in `legoracers.h` (#1729) --- LEGO1/lego/legoomni/include/legoracers.h | 12 ++++---- LEGO1/lego/legoomni/src/race/legoracers.cpp | 32 ++++++++++----------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoracers.h b/LEGO1/lego/legoomni/include/legoracers.h index 3c8ffe07..53db5f20 100644 --- a/LEGO1/lego/legoomni/include/legoracers.h +++ b/LEGO1/lego/legoomni/include/legoracers.h @@ -6,9 +6,11 @@ // clang-format on #include "legoracemap.h" -#define LEGORACECAR_UNKNOWN_0 0 -#define LEGORACECAR_UNKNOWN_1 1 +#define LEGORACECAR_NONE 0 +#define LEGORACECAR_NEAR_SKELETON 1 +// kick to the left #define LEGORACECAR_KICK1 2 // name guessed +// kick to the right #define LEGORACECAR_KICK2 4 // name validated by BETA10 0x100cb659 // SIZE 0x08 @@ -23,7 +25,7 @@ struct SkeletonKickPhase { EdgeReference* m_edgeRef; // 0x00 float m_lower; // 0x04 float m_upper; // 0x08 - MxU8 m_userState; // 0x0c + MxU8 m_kickState; // 0x0c }; // VTABLE: LEGO1 0x100d5a08 LegoCarRaceActor @@ -80,7 +82,7 @@ class LegoJetski : public LegoJetskiRaceActor, public LegoRaceMap { // FUNCTION: LEGO1 0x10014210 MxResult VTable0x9c() override { return LegoJetskiRaceActor::VTable0x9c(); } // vtable+0x9c - virtual void FUN_100136f0(float p_worldSpeed); + virtual void SetMaxLinearVelocity(float p_worldSpeed); static void InitSoundIndices(); @@ -154,7 +156,7 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { // LegoRaceCar::`scalar deleting destructor' private: - undefined m_userState; // 0x54 + MxU8 m_kickState; // 0x54 float m_kickStart; // 0x58 Mx3DPointFloat m_unk0x5c; // 0x5c diff --git a/LEGO1/lego/legoomni/src/race/legoracers.cpp b/LEGO1/lego/legoomni/src/race/legoracers.cpp index d338c861..de1d7608 100644 --- a/LEGO1/lego/legoomni/src/race/legoracers.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracers.cpp @@ -171,7 +171,7 @@ MxLong g_timeLastJetskiSoundPlayed = 0; // FUNCTION: BETA10 0x100cad10 LegoRaceCar::LegoRaceCar() { - m_userState = 0; + m_kickState = LEGORACECAR_NONE; m_skelKick1Anim = 0; m_skelKick2Anim = 0; m_unk0x5c.Clear(); @@ -301,11 +301,11 @@ void LegoRaceCar::KickCamera(float p_param) LegoAnimActorStruct* a; // called `a` in BETA10 float deltaTime; - if (m_userState == LEGORACECAR_KICK1) { + if (m_kickState == LEGORACECAR_KICK1) { a = m_skelKick1Anim; } else { - assert(m_userState == LEGORACECAR_KICK2); + assert(m_kickState == LEGORACECAR_KICK2); a = m_skelKick2Anim; } @@ -315,7 +315,7 @@ void LegoRaceCar::KickCamera(float p_param) deltaTime = p_param - m_kickStart; if (a->GetDuration() <= deltaTime || deltaTime < 0.0) { - if (m_userState == LEGORACECAR_KICK1) { + if (m_kickState == LEGORACECAR_KICK1) { LegoOrientedEdge** edges = m_kick1B->GetEdges(); m_destEdge = edges[2]; m_boundary = m_kick1B; @@ -326,7 +326,7 @@ void LegoRaceCar::KickCamera(float p_param) m_boundary = m_kick2B; } - m_userState = LEGORACECAR_UNKNOWN_0; + m_kickState = LEGORACECAR_NONE; } else if (a->GetAnimTreePtr()->GetCamAnim()) { MxMatrix transformationMatrix; @@ -370,12 +370,12 @@ MxU32 LegoRaceCar::HandleSkeletonKicks(float p_param1) for (MxS32 i = 0; i < sizeOfArray(g_skeletonKickPhases); i++) { if (m_boundary == current->m_edgeRef->m_b && current->m_lower <= skeletonCurAnimPhase && skeletonCurAnimPhase <= current->m_upper) { - m_userState = current->m_userState; + m_kickState = current->m_kickState; } current = ¤t[1]; } - if (m_userState != LEGORACECAR_KICK1 && m_userState != LEGORACECAR_KICK2) { + if (m_kickState != LEGORACECAR_KICK1 && m_kickState != LEGORACECAR_KICK2) { MxTrace( // STRING: BETA10 0x101f64c8 "Got kicked in boundary %s %d %g:%g %g\n", @@ -397,14 +397,14 @@ MxU32 LegoRaceCar::HandleSkeletonKicks(float p_param1) // FUNCTION: BETA10 0x100cb88a void LegoRaceCar::Animate(float p_time) { - if (m_userNavFlag && (m_userState == LEGORACECAR_KICK1 || m_userState == LEGORACECAR_KICK2)) { + if (m_userNavFlag && (m_kickState == LEGORACECAR_KICK1 || m_kickState == LEGORACECAR_KICK2)) { KickCamera(p_time); return; } LegoCarRaceActor::Animate(p_time); - if (m_userNavFlag && m_userState == LEGORACECAR_UNKNOWN_1) { + if (m_userNavFlag && m_kickState == LEGORACECAR_NEAR_SKELETON) { if (HandleSkeletonKicks(p_time)) { return; } @@ -539,23 +539,23 @@ MxResult LegoRaceCar::VTable0x9c() result = LegoCarRaceActor::VTable0x9c(); if (m_boundary) { - MxS32 bVar2 = 0; + MxS32 onSkeletonBoundary = FALSE; for (MxS32 i = 0; i < sizeOfArray(g_skBMap); i++) { assert(g_skBMap[i].m_b); if (m_boundary == g_skBMap[i].m_b) { - bVar2 = 1; + onSkeletonBoundary = TRUE; break; } } - if (m_userState == LEGORACECAR_UNKNOWN_1) { - if (!bVar2) { - m_userState = LEGORACECAR_UNKNOWN_0; + if (m_kickState == LEGORACECAR_NEAR_SKELETON) { + if (!onSkeletonBoundary) { + m_kickState = LEGORACECAR_NONE; } } else { - m_userState = LEGORACECAR_UNKNOWN_1; + m_kickState = LEGORACECAR_NEAR_SKELETON; } } } @@ -591,7 +591,7 @@ void LegoJetski::SetWorldSpeed(MxFloat p_worldSpeed) // FUNCTION: LEGO1 0x100136f0 // FUNCTION: BETA10 0x100cc01a -void LegoJetski::FUN_100136f0(float p_worldSpeed) +void LegoJetski::SetMaxLinearVelocity(float p_worldSpeed) { if (p_worldSpeed < 0) { LegoCarRaceActor::m_animState = 2; From 5e7a787af0054099673d1192e77c86583d76df67 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Sun, 25 Jan 2026 20:48:36 +0100 Subject: [PATCH 20/23] Clear unknowns in `LegoPathBoundary` (#1730) --- .../lego/legoomni/include/legopathboundary.h | 10 +- .../legoomni/src/paths/legopathboundary.cpp | 177 +++++++++--------- 2 files changed, 97 insertions(+), 90 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legopathboundary.h b/LEGO1/lego/legoomni/include/legopathboundary.h index d3c1c4e7..e29cff24 100644 --- a/LEGO1/lego/legoomni/include/legopathboundary.h +++ b/LEGO1/lego/legoomni/include/legopathboundary.h @@ -45,9 +45,15 @@ class LegoPathBoundary : public LegoWEGEdge { LegoPathActor* p_actor, LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, - float& p_unk0xe4 + float& p_scale + ); + MxU32 Intersect( + float p_scale, + Vector3& p_oldPos, + Vector3& p_newPos, + Vector3& p_intersectionPoint, + LegoOrientedEdge*& p_edge ); - MxU32 Intersect(float p_scale, Vector3& p_point1, Vector3& p_point2, Vector3& p_point3, LegoOrientedEdge*& p_edge); MxU32 AddPresenterIfInRange(LegoAnimPresenter* p_presenter); MxU32 RemovePresenter(LegoAnimPresenter* p_presenter); diff --git a/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp b/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp index 5504ef8d..8710b5ac 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp @@ -87,7 +87,7 @@ void LegoPathBoundary::SwitchBoundary( LegoPathActor* p_actor, LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, - float& p_unk0xe4 + float& p_scale ) { LegoOrientedEdge* e = p_edge; @@ -99,7 +99,7 @@ void LegoPathBoundary::SwitchBoundary( newBoundary = p_boundary; } - MxS32 local10 = 0; + MxS32 availableEdgeCount = 0; MxU8 userNavFlag; if (e->BETA_1004a830(*newBoundary, 1)) { @@ -111,38 +111,38 @@ void LegoPathBoundary::SwitchBoundary( do { p_edge = (LegoOrientedEdge*) p_edge->GetCounterclockwiseEdge(*newBoundary); - LegoPathBoundary* local20 = (LegoPathBoundary*) p_edge->OtherFace(newBoundary); + LegoPathBoundary* otherBoundary = (LegoPathBoundary*) p_edge->OtherFace(newBoundary); - if (p_edge->GetMask0x03() && (userNavFlag || p_edge->BETA_1004a830(*local20, 1))) { - local10++; + if (p_edge->GetMask0x03() && (userNavFlag || p_edge->BETA_1004a830(*otherBoundary, 1))) { + availableEdgeCount++; } } while (p_edge != e); - MxBool localc = TRUE; - MxS32 local8 = local10 - 1; + MxBool countCounterclockwise = TRUE; + MxS32 selectedEdgeIndex = availableEdgeCount - 1; - if (local10 <= 1) { - local8 = 0; + if (availableEdgeCount <= 1) { + selectedEdgeIndex = 0; } - else if (local10 == 2) { - local8 = 1; + else if (availableEdgeCount == 2) { + selectedEdgeIndex = 1; } else { - p_actor->VTable0xa4(localc, local8); + p_actor->VTable0xa4(countCounterclockwise, selectedEdgeIndex); } - while (local8 > 0) { - if (localc) { + while (selectedEdgeIndex > 0) { + if (countCounterclockwise) { p_edge = (LegoOrientedEdge*) p_edge->GetCounterclockwiseEdge(*newBoundary); } else { p_edge = (LegoOrientedEdge*) p_edge->GetClockwiseEdge(*newBoundary); } - LegoPathBoundary* local20 = (LegoPathBoundary*) p_edge->OtherFace(newBoundary); + LegoPathBoundary* otherBoundary = (LegoPathBoundary*) p_edge->OtherFace(newBoundary); - if (p_edge->GetMask0x03() && (userNavFlag || p_edge->BETA_1004a830(*local20, 1))) { - local8--; + if (p_edge->GetMask0x03() && (userNavFlag || p_edge->BETA_1004a830(*otherBoundary, 1))) { + selectedEdgeIndex--; } } @@ -157,7 +157,7 @@ void LegoPathBoundary::SwitchBoundary( p_boundary->AddActor(p_actor); } else { - p_unk0xe4 = 1.0 - p_unk0xe4; + p_scale = 1.0 - p_scale; } } else { @@ -174,7 +174,7 @@ void LegoPathBoundary::SwitchBoundary( p_edge = (LegoOrientedEdge*) p_edge->GetCounterclockwiseEdge(*p_boundary); } - p_unk0xe4 = 1.0 - p_unk0xe4; + p_scale = 1.0 - p_scale; } } @@ -182,127 +182,128 @@ void LegoPathBoundary::SwitchBoundary( // FUNCTION: BETA10 0x100b1adc MxU32 LegoPathBoundary::Intersect( float p_scale, - Vector3& p_point1, - Vector3& p_point2, - Vector3& p_point3, + Vector3& p_oldPos, + Vector3& p_newPos, + Vector3& p_intersectionPoint, LegoOrientedEdge*& p_edge ) { LegoOrientedEdge* e = NULL; - float localc; - MxU32 local10 = 0; + float minHitDistance; + MxU32 normalizedCalculated = 0; float len = 0.0f; - Mx3DPointFloat vec; + Mx3DPointFloat direction; for (MxS32 i = 0; i < m_numEdges; i++) { LegoOrientedEdge* edge = (LegoOrientedEdge*) m_edges[i]; - if (p_point2.Dot(m_edgeNormals[i], p_point2) + m_edgeNormals[i][3] <= -1e-07) { - if (local10 == 0) { - local10 = 1; - vec = p_point2; - vec -= p_point1; + if (p_newPos.Dot(m_edgeNormals[i], p_newPos) + m_edgeNormals[i][3] <= -1e-07) { + if (normalizedCalculated == FALSE) { + normalizedCalculated = TRUE; + direction = p_newPos; + direction -= p_oldPos; - len = vec.LenSquared(); + len = direction.LenSquared(); if (len <= 0.0f) { return 0; } len = sqrt(len); - vec /= len; + direction /= len; } - float dot = vec.Dot(vec, m_edgeNormals[i]); + float dot = direction.Dot(direction, m_edgeNormals[i]); if (dot != 0.0f) { - float local34 = (-m_edgeNormals[i][3] - p_point1.Dot(p_point1, m_edgeNormals[i])) / dot; + float hitDistance = (-m_edgeNormals[i][3] - p_oldPos.Dot(p_oldPos, m_edgeNormals[i])) / dot; - if (local34 >= -0.001 && local34 <= len && (e == NULL || local34 < localc)) { + if (hitDistance >= -0.001 && hitDistance <= len && (e == NULL || hitDistance < minHitDistance)) { e = edge; - localc = local34; + minHitDistance = hitDistance; } } } } if (e != NULL) { - if (localc < 0.0f) { - localc = 0.0f; + if (minHitDistance < 0.0f) { + minHitDistance = 0.0f; } - Mx3DPointFloat local50; - Mx3DPointFloat local70; - Vector3* local5c = e->CWVertex(*this); + Mx3DPointFloat startToPosition; + Mx3DPointFloat edgeNormal; + Vector3* start = e->CWVertex(*this); - p_point3 = vec; - p_point3 *= localc; - p_point3 += p_point1; + p_intersectionPoint = direction; + p_intersectionPoint *= minHitDistance; + p_intersectionPoint += p_oldPos; - local50 = p_point2; - local50 -= *local5c; + startToPosition = p_newPos; + startToPosition -= *start; - e->GetFaceNormal(*this, local70); + e->GetFaceNormal(*this, edgeNormal); - float local58 = local50.Dot(local50, local70); - LegoOrientedEdge* local54 = NULL; + float projection = startToPosition.Dot(startToPosition, edgeNormal); + LegoOrientedEdge* candidateEdge = NULL; - if (local58 < 0.0f) { - Mx3DPointFloat local84; + if (projection < 0.0f) { + Mx3DPointFloat candidateEdgeNormal; - for (LegoOrientedEdge* local88 = (LegoOrientedEdge*) e->GetClockwiseEdge(*this); e != local88; - local88 = (LegoOrientedEdge*) local88->GetClockwiseEdge(*this)) { - local88->GetFaceNormal(*this, local84); + for (LegoOrientedEdge* cwEdge = (LegoOrientedEdge*) e->GetClockwiseEdge(*this); e != cwEdge; + cwEdge = (LegoOrientedEdge*) cwEdge->GetClockwiseEdge(*this)) { + cwEdge->GetFaceNormal(*this, candidateEdgeNormal); - if (local84.Dot(local84, local70) <= 0.9) { + if (candidateEdgeNormal.Dot(candidateEdgeNormal, edgeNormal) <= 0.9) { break; } - Vector3* local90 = local88->CWVertex(*this); - Mx3DPointFloat locala4(p_point3); - locala4 -= *local90; + Vector3* candidateStart = cwEdge->CWVertex(*this); + Mx3DPointFloat candidateToIntersection(p_intersectionPoint); + candidateToIntersection -= *candidateStart; - float local8c = locala4.Dot(locala4, local84); + float candidateProjection = candidateToIntersection.Dot(candidateToIntersection, candidateEdgeNormal); - if (local8c > local58 && local8c < local88->m_length) { - local54 = local88; - local58 = local8c; - local70 = local84; - local5c = local90; + if (candidateProjection > projection && candidateProjection < cwEdge->m_length) { + candidateEdge = cwEdge; + projection = candidateProjection; + edgeNormal = candidateEdgeNormal; + start = candidateStart; } } } else { - if (e->m_length < local58) { - Mx3DPointFloat localbc; + if (e->m_length < projection) { + Mx3DPointFloat candidateEdgeNormal; - for (LegoOrientedEdge* locala8 = (LegoOrientedEdge*) e->GetCounterclockwiseEdge(*this); e != locala8; - locala8 = (LegoOrientedEdge*) locala8->GetCounterclockwiseEdge(*this)) { - locala8->GetFaceNormal(*this, localbc); + for (LegoOrientedEdge* ccwEdge = (LegoOrientedEdge*) e->GetCounterclockwiseEdge(*this); e != ccwEdge; + ccwEdge = (LegoOrientedEdge*) ccwEdge->GetCounterclockwiseEdge(*this)) { + ccwEdge->GetFaceNormal(*this, candidateEdgeNormal); - if (localbc.Dot(localbc, local70) <= 0.9) { + if (candidateEdgeNormal.Dot(candidateEdgeNormal, edgeNormal) <= 0.9) { break; } - Vector3* localc4 = locala8->CWVertex(*this); - Mx3DPointFloat locald8(p_point3); - locald8 -= *localc4; + Vector3* candidateStart = ccwEdge->CWVertex(*this); + Mx3DPointFloat candidateToIntersection(p_intersectionPoint); + candidateToIntersection -= *candidateStart; - float localc0 = locald8.Dot(locald8, localbc); + float candidateProjection = + candidateToIntersection.Dot(candidateToIntersection, candidateEdgeNormal); - if (localc0 < local58 && localc0 >= 0.0f) { - local54 = locala8; - local58 = localc0; - local70 = localbc; - local5c = localc4; + if (candidateProjection < projection && candidateProjection >= 0.0f) { + candidateEdge = ccwEdge; + projection = candidateProjection; + edgeNormal = candidateEdgeNormal; + start = candidateStart; } } } } - if (local54 != NULL) { - e = local54; + if (candidateEdge != NULL) { + e = candidateEdge; } - if (local58 <= 0.0f) { + if (projection <= 0.0f) { if (!e->GetMask0x03()) { p_edge = (LegoOrientedEdge*) e->GetClockwiseEdge(*this); } @@ -310,18 +311,18 @@ MxU32 LegoPathBoundary::Intersect( p_edge = e; } - p_point3 = *local5c; + p_intersectionPoint = *start; return 2; } - else if (local58 > 0.0f && e->m_length > local58) { - p_point3 = local70; - p_point3 *= local58; - p_point3 += *local5c; + else if (projection > 0.0f && e->m_length > projection) { + p_intersectionPoint = edgeNormal; + p_intersectionPoint *= projection; + p_intersectionPoint += *start; p_edge = e; return 1; } else { - p_point3 = *e->CCWVertex(*this); + p_intersectionPoint = *e->CCWVertex(*this); if (!e->GetMask0x03()) { p_edge = (LegoOrientedEdge*) e->GetCounterclockwiseEdge(*this); From 99a0c3964e3c865cc97687573969acdf63c79246 Mon Sep 17 00:00:00 2001 From: MS Date: Tue, 27 Jan 2026 13:21:39 -0500 Subject: [PATCH 21/23] Add color to `clang-format` diffs (#1733) * Add color to clang-format diffs * Demo * Fix --- .github/workflows/format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 74424665..a58e8fc8 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -16,4 +16,4 @@ jobs: pipx run "clang-format>=17,<18" \ --style=file \ -i - git diff --exit-code + git diff --color --exit-code From 935be9de553db36a1fc2c7726e86816ca5c32671 Mon Sep 17 00:00:00 2001 From: MS Date: Tue, 27 Jan 2026 13:21:56 -0500 Subject: [PATCH 22/23] Implement `LegoTestTimer` (#1732) * Implement LegoTestTimer * Fix variable name * Use override --- CMakeLists.txt | 1 + .../include/legoeventnotificationparam.h | 5 + LEGO1/lego/legoomni/include/legotesttimer.h | 44 +++++ .../legoomni/src/common/legotesttimer.cpp | 156 ++++++++++++++++++ 4 files changed, 206 insertions(+) create mode 100644 LEGO1/lego/legoomni/include/legotesttimer.h create mode 100644 LEGO1/lego/legoomni/src/common/legotesttimer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b7cbf0e..519f26c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -371,6 +371,7 @@ function(add_lego_libraries NAME) LEGO1/lego/legoomni/src/worlds/police.cpp LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp LEGO1/lego/legoomni/src/entity/legopovcontroller.cpp + LEGO1/lego/legoomni/src/common/legotesttimer.cpp LEGO1/lego/legoomni/src/common/legotextureinfo.cpp LEGO1/lego/legoomni/src/actors/doors.cpp LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp diff --git a/LEGO1/lego/legoomni/include/legoeventnotificationparam.h b/LEGO1/lego/legoomni/include/legoeventnotificationparam.h index 7cfa28f9..a12c5afd 100644 --- a/LEGO1/lego/legoomni/include/legoeventnotificationparam.h +++ b/LEGO1/lego/legoomni/include/legoeventnotificationparam.h @@ -41,8 +41,13 @@ class LegoEventNotificationParam : public MxNotificationParam { { } + // FUNCTION: BETA10 0x10026070 LegoROI* GetROI() { return m_roi; } + + // FUNCTION: BETA10 0x1006aab0 MxU8 GetModifier() { return m_modifier; } + + // FUNCTION: BETA10 0x100179a0 MxU8 GetKey() const { return m_key; } // FUNCTION: LEGO1 0x10012190 diff --git a/LEGO1/lego/legoomni/include/legotesttimer.h b/LEGO1/lego/legoomni/include/legotesttimer.h new file mode 100644 index 00000000..51d17d16 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legotesttimer.h @@ -0,0 +1,44 @@ +#ifndef LEGOTESTTIMER_H +#define LEGOTESTTIMER_H + +#include "decomp.h" +#include "misc/legotypes.h" +#include "mxcore.h" +#include "mxparam.h" + +// VTABLE: BETA10 0x101bed08 +// SIZE 0x24 +class LegoTestTimer : public MxCore { +public: + LegoTestTimer(LegoS32 p_numTimers, LegoS32 p_interval, LegoS32 p_numBins, LegoS32 p_type); + ~LegoTestTimer() override; // vtable+00 + MxLong Notify(MxParam& p_param) override; // vtable+04 + + // FUNCTION: BETA10 0x100d18e0 + static const char* HandlerClassName() { return "LegoTestTimer"; } + + // FUNCTION: BETA10 0x100d18b0 + const char* ClassName() const override // vtable+0c + { + return HandlerClassName(); + } + + void Tick(LegoS32 p_timer); + void ResetAtNextTick(); + void Print(); + + // SYNTHETIC: BETA10 0x100d1900 + // LegoTestTimer::`scalar deleting destructor' + +private: + LegoS32** m_timers; // 0x08 + LegoS32* m_lastTime; // 0x0c + LegoS32* m_totalTime; // 0x10 + LegoS32 m_numTimers; // 0x14 + LegoS32 m_numBins; // 0x18 + LegoS32 m_interval; // 0x1c + MxBool m_enable; // 0x20 + MxBool m_keyRegistered; // 0x21 +}; + +#endif // LEGOTESTTIMER_H diff --git a/LEGO1/lego/legoomni/src/common/legotesttimer.cpp b/LEGO1/lego/legoomni/src/common/legotesttimer.cpp new file mode 100644 index 00000000..e40d9a62 --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legotesttimer.cpp @@ -0,0 +1,156 @@ +#include "legotesttimer.h" + +#include "legoeventnotificationparam.h" +#include "legoinputmanager.h" +#include "misc.h" +#include "mxnotificationparam.h" + +#include + +// FUNCTION: BETA10 0x100d1030 +LegoTestTimer::LegoTestTimer(LegoS32 p_numTimers, LegoS32 p_interval, LegoS32 p_numBins, LegoS32 p_type) +{ + m_enable = FALSE; + m_keyRegistered = FALSE; + + if (p_interval > 0) { + m_numTimers = p_numTimers; + m_interval = p_interval; + m_numBins = p_numBins / m_interval; + + m_lastTime = new LegoS32[m_numTimers]; + m_totalTime = new LegoS32[m_numTimers]; + m_timers = new LegoS32*[m_numTimers]; + + for (int i = 0; i < m_numTimers; i++) { + m_lastTime[i] = -1; + m_timers[i] = new LegoS32[m_numBins]; + for (int j = 0; j < m_numBins; j++) { + m_timers[i][j] = 0; + } + } + } + else { + m_numTimers = 0; + m_interval = 0; + m_numBins = 0; + m_lastTime = NULL; + m_totalTime = NULL; + m_timers = NULL; + } +} + +// FUNCTION: BETA10 0x100d11ee +LegoTestTimer::~LegoTestTimer() +{ + if (m_keyRegistered && InputManager()) { + InputManager()->UnRegister(this); + } + + m_enable = FALSE; + if (m_numTimers != 0) { + delete[] m_lastTime; + delete[] m_totalTime; + + for (int i = 0; i < m_numTimers; i++) { + delete m_timers[i]; + } + + delete[] m_timers; + } +} + +// FUNCTION: BETA10 0x100d132c +void LegoTestTimer::Tick(LegoS32 p_timer) +{ + if (m_enable) { + MxULong time = timeGetTime(); + LegoS32 prev = p_timer ? p_timer - 1 : 0; + if (m_lastTime[p_timer] == -1) { + m_lastTime[p_timer] = time; + m_totalTime[p_timer] = 0; + + for (int i = 0; i < m_numBins; i++) { + m_timers[p_timer][i] = 0; + } + } + else { + LegoS32 dtim = time - m_lastTime[prev]; + if (dtim < 0) { + dtim = 0; + } + + m_lastTime[p_timer] = time; + LegoS32 binIndex = dtim / m_interval; + if (binIndex >= m_numBins) { + binIndex = m_numBins - 1; + } + + m_timers[p_timer][binIndex]++; + m_totalTime[p_timer] += dtim; + } + } + else if (!m_keyRegistered) { + InputManager()->Register(this); + m_keyRegistered = TRUE; + } +} + +// FUNCTION: BETA10 0x100d148f +void LegoTestTimer::Print() +{ + FILE* f = fopen("\\TEST_TIME.TXT", "w"); + if (f) { + int i; + + fprintf(f, "timer"); + for (i = 0; i < m_numTimers; i++) { + fprintf(f, "%8d ", i); + } + + fprintf(f, "\n"); + for (int k = 0; k < m_numBins; k++) { + fprintf(f, "%3d: ", m_interval * (k + 1)); + for (int j = 0; j < m_numTimers; j++) { + fprintf(f, "%8d ", m_timers[j][k]); + } + fprintf(f, "\n"); + } + + fprintf(f, "ttime"); + for (i = 0; i < m_numTimers; i++) { + fprintf(f, "%8d ", m_totalTime[i]); + } + + fclose(f); + } + + ResetAtNextTick(); +} + +// FUNCTION: BETA10 0x100d161e +void LegoTestTimer::ResetAtNextTick() +{ + for (int i = 0; i < m_numTimers; i++) { + m_lastTime[i] = -1; + } +} + +// FUNCTION: BETA10 0x100d1667 +MxLong LegoTestTimer::Notify(MxParam& p_param) +{ + if (((MxNotificationParam&) p_param).GetNotification() == c_notificationKeyPress) { + MxU8 key = ((LegoEventNotificationParam&) p_param).GetKey(); + + if (key == 's' || key == 'S') { + ResetAtNextTick(); + m_enable = TRUE; + } + else if (key == 'p' || key == 'P') { + m_enable = FALSE; + Print(); + } + } + + return 0; +} From 971fe939a63402cfc13cbca63988211a8370d177 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Sat, 31 Jan 2026 01:47:11 +0100 Subject: [PATCH 23/23] Clear unknowns in `LegoPathActor` (#1731) Co-authored-by: Christian Semmler --- LEGO1/lego/legoomni/include/act2actor.h | 6 +- LEGO1/lego/legoomni/include/act3actors.h | 8 +- LEGO1/lego/legoomni/include/act3ammo.h | 2 +- LEGO1/lego/legoomni/include/helicopter.h | 2 +- LEGO1/lego/legoomni/include/legoanimactor.h | 8 +- LEGO1/lego/legoomni/include/legoextraactor.h | 37 +- LEGO1/lego/legoomni/include/legopathactor.h | 124 ++--- .../lego/legoomni/include/legopathboundary.h | 2 +- LEGO1/lego/legoomni/include/legoraceactor.h | 10 +- LEGO1/lego/legoomni/include/legoracers.h | 42 +- LEGO1/lego/legoomni/include/legoracespecial.h | 28 +- LEGO1/lego/legoomni/src/actors/act2actor.cpp | 6 +- LEGO1/lego/legoomni/src/actors/act3actors.cpp | 92 ++-- LEGO1/lego/legoomni/src/actors/act3ammo.cpp | 44 +- LEGO1/lego/legoomni/src/actors/bike.cpp | 4 +- LEGO1/lego/legoomni/src/actors/helicopter.cpp | 2 +- LEGO1/lego/legoomni/src/actors/jetski.cpp | 4 +- LEGO1/lego/legoomni/src/actors/motorcycle.cpp | 4 +- LEGO1/lego/legoomni/src/actors/skateboard.cpp | 4 +- .../src/common/legoanimationmanager.cpp | 30 +- .../src/common/legoanimmmpresenter.cpp | 4 +- .../lego/legoomni/src/paths/legoanimactor.cpp | 12 +- .../legoomni/src/paths/legoextraactor.cpp | 106 +++-- .../lego/legoomni/src/paths/legopathactor.cpp | 437 ++++++++++-------- .../legoomni/src/paths/legopathboundary.cpp | 2 +- .../legoomni/src/paths/legopathcontroller.cpp | 13 +- .../lego/legoomni/src/race/legoraceactor.cpp | 28 +- LEGO1/lego/legoomni/src/race/legoracers.cpp | 10 +- .../legoomni/src/race/legoracespecial.cpp | 130 +++--- LEGO1/lego/legoomni/src/worlds/act3.cpp | 22 +- LEGO1/realtime/vector.h | 2 +- 31 files changed, 674 insertions(+), 551 deletions(-) diff --git a/LEGO1/lego/legoomni/include/act2actor.h b/LEGO1/lego/legoomni/include/act2actor.h index 6b39de3f..4d1ac98e 100644 --- a/LEGO1/lego/legoomni/include/act2actor.h +++ b/LEGO1/lego/legoomni/include/act2actor.h @@ -29,18 +29,18 @@ class Act2Actor : public LegoAnimActor { void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 // FUNCTION: LEGO1 0x1001a180 - MxS32 VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3) override + MxS32 CheckIntersections(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3) override { if (m_animatingHit) { return 0; } - return LegoAnimActor::VTable0x68(p_v1, p_v2, p_v3); + return LegoAnimActor::CheckIntersections(p_v1, p_v2, p_v3); } // vtable+0x68 void Animate(float p_time) override; // vtable+0x70 MxResult HitActor(LegoPathActor*, MxBool) override; // vtable+0x94 - MxResult VTable0x9c() override; // vtable+0x9c + MxResult CalculateSpline() override; // vtable+0x9c MxS32 NextTargetLocation() override; // vtable+0xa0 void InitializeNextShot(); diff --git a/LEGO1/lego/legoomni/include/act3actors.h b/LEGO1/lego/legoomni/include/act3actors.h index 99b4c80b..99c02776 100644 --- a/LEGO1/lego/legoomni/include/act3actors.h +++ b/LEGO1/lego/legoomni/include/act3actors.h @@ -57,7 +57,7 @@ class Act3Actor : public LegoAnimActor { public: Act3Actor(); - MxU32 VTable0x90(float p_time, Matrix4& p_transform) override; // vtable+0x90 + MxU32 StepState(float p_time, Matrix4& p_transform) override; // vtable+0x90 MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 // FUNCTION: LEGO1 0x100431b0 @@ -105,7 +105,7 @@ class Act3Cop : public Act3Actor { void ParseAction(char* p_extra) override; // vtable+0x20 void Animate(float p_time) override; // vtable+0x70 MxResult HitActor(LegoPathActor*, MxBool) override; // vtable+0x94 - MxResult VTable0x9c() override; // vtable+0x9c + MxResult CalculateSpline() override; // vtable+0x9c MxFloat GetUnknown0x20() { return m_unk0x20; } @@ -142,8 +142,8 @@ class Act3Brickster : public Act3Actor { LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, float& p_unk0xe4 - ) override; // vtable+0x98 - MxResult VTable0x9c() override; // vtable+0x9c + ) override; // vtable+0x98 + MxResult CalculateSpline() override; // vtable+0x9c MxFloat GetUnknown0x20() { return m_unk0x20; } MxFloat GetUnknown0x24() { return m_unk0x24; } diff --git a/LEGO1/lego/legoomni/include/act3ammo.h b/LEGO1/lego/legoomni/include/act3ammo.h index 60129a53..8312877a 100644 --- a/LEGO1/lego/legoomni/include/act3ammo.h +++ b/LEGO1/lego/legoomni/include/act3ammo.h @@ -90,7 +90,7 @@ class Act3Ammo : public LegoPathActor { // Act3Ammo::`scalar deleting destructor' private: - MxResult CalculateTransform(float p_curveParameter, Matrix4& p_transform); + MxResult CalculateTransformOnCurve(float p_curveParameter, Matrix4& p_transform); static Mx3DPointFloat g_hitTranslation; diff --git a/LEGO1/lego/legoomni/include/helicopter.h b/LEGO1/lego/legoomni/include/helicopter.h index 8496faf9..9f161c7e 100644 --- a/LEGO1/lego/legoomni/include/helicopter.h +++ b/LEGO1/lego/legoomni/include/helicopter.h @@ -69,7 +69,7 @@ class Helicopter : public IslePathActor { MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 void Animate(float p_time) override; // vtable+0x70 - void VTable0x74(Matrix4& p_transform) override; // vtable+0x74 + void ApplyTransform(Matrix4& p_transform) override; // vtable+0x74 MxLong HandleClick() override; // vtable+0xcc MxLong HandleControl(LegoControlManagerNotificationParam& p_param) override; // vtable+0xd4 MxLong HandleEndAnim(LegoEndAnimNotificationParam& p_param) override; // vtable+0xd8 diff --git a/LEGO1/lego/legoomni/include/legoanimactor.h b/LEGO1/lego/legoomni/include/legoanimactor.h index bfe03344..d774a897 100644 --- a/LEGO1/lego/legoomni/include/legoanimactor.h +++ b/LEGO1/lego/legoomni/include/legoanimactor.h @@ -42,10 +42,10 @@ class LegoAnimActor : public virtual LegoPathActor { ~LegoAnimActor() override; - void ParseAction(char* p_extra) override; // vtable+0x20 - void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 - void Animate(float p_time) override; // vtable+0x70 - void VTable0x74(Matrix4& p_transform) override; // vtable+0x74 + void ParseAction(char* p_extra) override; // vtable+0x20 + void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 + void Animate(float p_time) override; // vtable+0x70 + void ApplyTransform(Matrix4& p_transform) override; // vtable+0x74 virtual MxResult GetTimeInCycle(float& p_timeInCycle); virtual MxResult AnimateWithTransform(float p_time, Matrix4& p_transform); diff --git a/LEGO1/lego/legoomni/include/legoextraactor.h b/LEGO1/lego/legoomni/include/legoextraactor.h index 2db32dee..bebcbcec 100644 --- a/LEGO1/lego/legoomni/include/legoextraactor.h +++ b/LEGO1/lego/legoomni/include/legoextraactor.h @@ -36,30 +36,31 @@ class LegoExtraActor : public virtual LegoAnimActor { return !strcmp(p_name, LegoExtraActor::ClassName()) || LegoAnimActor::IsA(p_name); } - void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 - MxS32 VTable0x68(Vector3& p_point1, Vector3& p_point2, Vector3& p_point3) override; // vtable+0x68 - inline MxU32 VTable0x6c( + void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 + MxS32 CheckIntersections(Vector3& p_rayOrigin, Vector3& p_rayEnd, Vector3& p_intersectionPoint) + override; // vtable+0x68 + inline MxU32 CheckPresenterAndActorIntersections( LegoPathBoundary* p_boundary, - Vector3& p_v1, - Vector3& p_v2, - float p_f1, - float p_f2, - Vector3& p_v3 - ) override; // vtable+0x6c - void Animate(float p_time) override; // vtable+0x70 - void VTable0x74(Matrix4& p_transform) override; // vtable+0x74 - MxU32 VTable0x90(float p_time, Matrix4& p_matrix) override; // vtable+0x90 - MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 - MxResult VTable0x9c() override; // vtable+0x9c - void VTable0xa4(MxBool& p_und1, MxS32& p_und2) override; // vtable+0xa4 - void VTable0xc4() override; // vtable+0xc4 + Vector3& p_rayOrigin, + Vector3& p_rayDirection, + float p_rayLength, + float p_radius, + Vector3& p_intersectionPoint + ) override; // vtable+0x6c + void Animate(float p_time) override; // vtable+0x70 + void ApplyTransform(Matrix4& p_transform) override; // vtable+0x74 + MxU32 StepState(float p_time, Matrix4& p_matrix) override; // vtable+0x90 + MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 + MxResult CalculateSpline() override; // vtable+0x9c + void GetWalkingBehavior(MxBool& p_countCounterclockWise, MxS32& p_selectedEdgeIndex) override; // vtable+0xa4 + void VTable0xc4() override; // vtable+0xc4 virtual MxResult SwitchDirection(); void Restart(); inline void InitializeReassemblyAnim(); - void SetUnknown0x0c(undefined p_unk0x0c) { m_unk0x0c = p_unk0x0c; } + void SetPathWalkingMode(MxU8 p_pathWalkingMode) { m_pathWalkingMode = p_pathWalkingMode; } // SYNTHETIC: LEGO1 0x1002b760 // LegoExtraActor::`scalar deleting destructor' @@ -72,7 +73,7 @@ class LegoExtraActor : public virtual LegoAnimActor { }; MxFloat m_scheduledTime; // 0x08 - undefined m_unk0x0c; // 0x0c + MxU8 m_pathWalkingMode; // 0x0c MxU8 m_axis; // 0x0d MxBool m_animationAtCurrentBoundary; // 0x0e MxFloat m_prevWorldSpeed; // 0x10 diff --git a/LEGO1/lego/legoomni/include/legopathactor.h b/LEGO1/lego/legoomni/include/legopathactor.h index 35baafbd..491e067c 100644 --- a/LEGO1/lego/legoomni/include/legopathactor.h +++ b/LEGO1/lego/legoomni/include/legopathactor.h @@ -24,9 +24,9 @@ class LegoPathActor : public LegoActor { enum ActorState { // States c_initial = 0, - c_one = 1, - c_two = 2, - c_three = 3, + c_ready = 1, + c_hit = 2, + c_hitAnimation = 3, c_disabled = 4, c_maxState = 255, @@ -37,18 +37,22 @@ class LegoPathActor : public LegoActor { LegoPathActor(); ~LegoPathActor() override; - void ParseAction(char* p_extra) override; // vtable+0x20 - virtual MxS32 VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3); // vtable+0x68 - virtual MxU32 VTable0x6c( + void ParseAction(char* p_extra) override; // vtable+0x20 + virtual MxS32 CheckIntersections( + Vector3& p_rayOrigin, + Vector3& p_rayEnd, + Vector3& p_intersectionPoint + ); // vtable+0x68 + virtual MxU32 CheckPresenterAndActorIntersections( LegoPathBoundary* p_boundary, - Vector3& p_v1, - Vector3& p_v2, - float p_f1, - float p_f2, - Vector3& p_v3 - ); // vtable+0x6c - virtual void Animate(float p_time); // vtable+0x70 - virtual void VTable0x74(Matrix4& p_transform); // vtable+0x74 + Vector3& p_rayOrigin, + Vector3& p_rayDirection, + float p_rayLength, + float p_radius, + Vector3& p_intersectionPoint + ); // vtable+0x6c + virtual void Animate(float p_time); // vtable+0x70 + virtual void ApplyTransform(Matrix4& p_transform); // vtable+0x74 // FUNCTION: LEGO1 0x10002d20 // FUNCTION: BETA10 0x1000f500 @@ -58,33 +62,33 @@ class LegoPathActor : public LegoActor { // FUNCTION: BETA10 0x1000f530 virtual MxBool GetUserNavFlag() { return m_userNavFlag; } // vtable+0x7c - virtual MxResult VTable0x80( - const Vector3& p_point1, - Vector3& p_point2, - Vector3& p_point3, - Vector3& p_point4 + virtual MxResult SetSpline( + const Vector3& p_start, + Vector3& p_tangentAtStart, + Vector3& p_end, + Vector3& p_tangentAtEnd ); // vtable+0x80 - virtual MxResult VTable0x84( + virtual MxResult SetTransformAndDestinationFromPoints( LegoPathBoundary* p_boundary, float p_time, - Vector3& p_p1, - Vector3& p_p4, + Vector3& p_start, + Vector3& p_direction, LegoOrientedEdge* p_destEdge, float p_destScale ); // vtable+0x84 - virtual MxResult VTable0x88( + virtual MxResult SetTransformAndDestinationFromEdge( LegoPathBoundary* p_boundary, float p_time, LegoEdge& p_srcEdge, float p_srcScale, LegoOrientedEdge& p_destEdge, float p_destScale - ); // vtable+0x88 - virtual MxS32 VTable0x8c(float p_time, Matrix4& p_transform); // vtable+0x8c + ); // vtable+0x88 + virtual MxS32 CalculateTransform(float p_time, Matrix4& p_transform); // vtable+0x8c // FUNCTION: LEGO1 0x10002d40 // FUNCTION: BETA10 0x1000f560 - virtual MxU32 VTable0x90(float, Matrix4&) { return FALSE; } // vtable+0x90 + virtual MxU32 StepState(float, Matrix4&) { return FALSE; } // vtable+0x90 // FUNCTION: LEGO1 0x10002d50 // FUNCTION: BETA10 0x1000f800 @@ -93,16 +97,16 @@ class LegoPathActor : public LegoActor { virtual void SwitchBoundary( LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, - float& p_unk0xe4 - ); // vtable+0x98 - virtual MxResult VTable0x9c(); // vtable+0x9c + float& p_scale + ); // vtable+0x98 + virtual MxResult CalculateSpline(); // vtable+0x9c // FUNCTION: LEGO1 0x10002d60 // FUNCTION: BETA10 0x1000f820 virtual MxS32 NextTargetLocation() { return 0; } // vtable+0xa0 - virtual void VTable0xa4(MxBool& p_und1, MxS32& p_und2); // vtable+0xa4 - virtual void VTable0xa8(); // vtable+0xa8 + virtual void GetWalkingBehavior(MxBool& p_countCounterclockWise, MxS32& p_selectedEdgeIndex); // vtable+0xa4 + virtual void ApplyLocal2World(); // vtable+0xa8 // FUNCTION: LEGO1 0x10002d70 // FUNCTION: BETA10 0x1000f580 @@ -114,26 +118,32 @@ class LegoPathActor : public LegoActor { // FUNCTION: LEGO1 0x10002d90 // FUNCTION: BETA10 0x1000f5e0 - virtual MxFloat VTable0xb4() { return m_unk0x140; } // vtable+0xb4 + virtual MxFloat GetWallHitDirectionFactor() { return m_wallHitDirectionFactor; } // vtable+0xb4 // FUNCTION: LEGO1 0x10002da0 // FUNCTION: BETA10 0x1000f610 - virtual MxFloat VTable0xb8() { return m_unk0x144; } // vtable+0xb8 + virtual MxFloat GetWallHitDampening() { return m_wallHitDampening; } // vtable+0xb8 // FUNCTION: LEGO1 0x10002db0 // FUNCTION: BETA10 0x1000f640 - virtual void VTable0xbc(MxFloat p_unk0x140) { m_unk0x140 = p_unk0x140; } // vtable+0xbc + virtual void SetWallHitDirectionFactor(MxFloat p_wallHitDirectionFactor) + { + m_wallHitDirectionFactor = p_wallHitDirectionFactor; + } // vtable+0xbc // FUNCTION: LEGO1 0x10002dc0 // FUNCTION: BETA10 0x1000f670 - virtual void VTable0xc0(MxFloat p_unk0x144) { m_unk0x144 = p_unk0x144; } // vtable+0xc0 + virtual void SetWallHitDampening(MxFloat p_wallHitDampening) + { + m_wallHitDampening = p_wallHitDampening; + } // vtable+0xc0 // FUNCTION: LEGO1 0x10002dd0 // FUNCTION: BETA10 0x1000f6a0 virtual void VTable0xc4() {} // vtable+0xc4 // FUNCTION: LEGO1 0x10002de0 - virtual void VTable0xc8(MxU8 p_unk0x148) { m_unk0x148 = p_unk0x148; } // vtable+0xc8 + virtual void SetCanRotate(MxU8 p_canRotate) { m_canRotate = p_canRotate; } // vtable+0xc8 // FUNCTION: LEGO1 0x1000c430 // FUNCTION: BETA10 0x10012790 @@ -158,7 +168,7 @@ class LegoPathActor : public LegoActor { LegoPathController* GetController() { return m_pathController; } MxBool GetCollideBox() { return m_collideBox; } - MxFloat GetLastTime() { return m_lastTime; } + MxFloat GetTransformTime() { return m_transformTime; } MxFloat GetActorTime() { return m_actorTime; } void SetBoundary(LegoPathBoundary* p_boundary) { m_boundary = p_boundary; } @@ -167,7 +177,7 @@ class LegoPathActor : public LegoActor { void SetActorState(MxU32 p_actorState) { m_actorState = p_actorState; } void SetController(LegoPathController* p_pathController) { m_pathController = p_pathController; } - void SetLastTime(MxFloat p_lastTime) { m_lastTime = p_lastTime; } + void SetTransformTime(MxFloat p_transformTime) { m_transformTime = p_transformTime; } void SetActorTime(MxFloat p_actorTime) { m_actorTime = p_actorTime; } void UpdatePlane(LegoNamedPlane& p_namedPlane); @@ -178,42 +188,42 @@ class LegoPathActor : public LegoActor { // LegoPathActor::`scalar deleting destructor' protected: - inline MxU32 FUN_1002edd0( - list& p_boundaries, + inline MxU32 CheckIntersectionBothFaces( + list& p_checkedBoundaries, LegoPathBoundary* p_boundary, - Vector3& p_v1, - Vector3& p_v2, - float p_f1, - float p_f2, - Vector3& p_v3, - MxS32 p_und + Vector3& p_rayOrigin, + Vector3& p_rayDirection, + float p_rayLength, + float p_radius, + Vector3& p_intersectionPoint, + MxS32 p_depth ); MxFloat m_BADuration; // 0x78 - MxFloat m_unk0x7c; // 0x7c + MxFloat m_traveledDistance; // 0x7c MxFloat m_actorTime; // 0x80 - MxFloat m_lastTime; // 0x84 + MxFloat m_transformTime; // 0x84 LegoPathBoundary* m_boundary; // 0x88 LegoSpline m_spline; // 0x8c MxU32 m_actorState; // 0xdc LegoOrientedEdge* m_destEdge; // 0xe0 - MxFloat m_unk0xe4; // 0xe4 + MxFloat m_destScale; // 0xe4 MxBool m_collideBox; // 0xe8 - MxBool m_unk0xe9; // 0xe9 + MxBool m_finishedTravel; // 0xe9 MxBool m_userNavFlag; // 0xea - MxMatrix m_unk0xec; // 0xec + MxMatrix m_local2World; // 0xec LegoPathEdgeContainer* m_grec; // 0x134 LegoPathController* m_pathController; // 0x138 MxFloat m_maxLinearVel; // 0x13c - MxFloat m_unk0x140; // 0x140 - MxFloat m_unk0x144; // 0x144 - MxU8 m_unk0x148; // 0x148 - MxS32 m_unk0x14c; // 0x14c - MxFloat m_unk0x150; // 0x150 + MxFloat m_wallHitDirectionFactor; // 0x140 + MxFloat m_wallHitDampening; // 0x144 + MxU8 m_canRotate; // 0x148 + MxS32 m_lastRotationAngle; // 0x14c + MxFloat m_linearRotationRatio; // 0x150 }; // FUNCTION: LEGO1 0x1002edd0 -// LegoPathActor::FUN_1002edd0 +// LegoPathActor::CheckIntersectionBothFaces // TEMPLATE: LEGO1 0x10018b70 // List::~List diff --git a/LEGO1/lego/legoomni/include/legopathboundary.h b/LEGO1/lego/legoomni/include/legopathboundary.h index e29cff24..c2ea2504 100644 --- a/LEGO1/lego/legoomni/include/legopathboundary.h +++ b/LEGO1/lego/legoomni/include/legopathboundary.h @@ -40,7 +40,7 @@ class LegoPathBoundary : public LegoWEGEdge { MxResult AddActor(LegoPathActor* p_actor); MxResult RemoveActor(LegoPathActor* p_actor); - void CheckAndCallPathTriggers(Vector3& p_point1, Vector3& p_point2, LegoPathActor* p_actor); + void CheckAndCallPathTriggers(Vector3& p_from, Vector3& p_to, LegoPathActor* p_actor); void SwitchBoundary( LegoPathActor* p_actor, LegoPathBoundary*& p_boundary, diff --git a/LEGO1/lego/legoomni/include/legoraceactor.h b/LEGO1/lego/legoomni/include/legoraceactor.h index bc3d54dc..a9ad5fc0 100644 --- a/LEGO1/lego/legoomni/include/legoraceactor.h +++ b/LEGO1/lego/legoomni/include/legoraceactor.h @@ -30,9 +30,13 @@ class LegoRaceActor : public virtual LegoAnimActor { return !strcmp(p_name, LegoRaceActor::ClassName()) || LegoAnimActor::IsA(p_name); } - MxS32 VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3) override; // vtable+0x68 - MxU32 VTable0x90(float p_time, Matrix4& p_matrix) override; // vtable+0x90 - MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 + MxS32 CheckIntersections( + Vector3& p_rayOrigin, + Vector3& p_rayEnd, + Vector3& p_intersectionPoint + ) override; // vtable+0x68 + MxU32 StepState(float p_time, Matrix4& p_matrix) override; // vtable+0x90 + MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 virtual MxResult FUN_10014aa0(); diff --git a/LEGO1/lego/legoomni/include/legoracers.h b/LEGO1/lego/legoomni/include/legoracers.h index 53db5f20..748fb5dc 100644 --- a/LEGO1/lego/legoomni/include/legoracers.h +++ b/LEGO1/lego/legoomni/include/legoracers.h @@ -64,10 +64,23 @@ class LegoJetski : public LegoJetskiRaceActor, public LegoRaceMap { void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 // FUNCTION: LEGO1 0x10014150 - MxU32 VTable0x6c(LegoPathBoundary* p_boundary, Vector3& p_v1, Vector3& p_v2, float p_f1, float p_f2, Vector3& p_v3) - override + MxU32 CheckPresenterAndActorIntersections( + LegoPathBoundary* p_boundary, + Vector3& p_rayOrigin, + Vector3& p_rayDirection, + float p_rayLength, + float p_radius, + Vector3& p_intersectionPoint + ) override { - return LegoJetskiRaceActor::VTable0x6c(p_boundary, p_v1, p_v2, p_f1, p_f2, p_v3); + return LegoJetskiRaceActor::CheckPresenterAndActorIntersections( + p_boundary, + p_rayOrigin, + p_rayDirection, + p_rayLength, + p_radius, + p_intersectionPoint + ); } // vtable+0x6c void Animate(float p_time) override; // vtable+0x70 @@ -80,7 +93,7 @@ class LegoJetski : public LegoJetskiRaceActor, public LegoRaceMap { } // vtable+0x98 // FUNCTION: LEGO1 0x10014210 - MxResult VTable0x9c() override { return LegoJetskiRaceActor::VTable0x9c(); } // vtable+0x9c + MxResult CalculateSpline() override { return LegoJetskiRaceActor::CalculateSpline(); } // vtable+0x9c virtual void SetMaxLinearVelocity(float p_worldSpeed); @@ -127,10 +140,23 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { // FUNCTION: LEGO1 0x10014500 // FUNCTION: BETA10 0x100cd5e0 - MxU32 VTable0x6c(LegoPathBoundary* p_boundary, Vector3& p_v1, Vector3& p_v2, float p_f1, float p_f2, Vector3& p_v3) - override + MxU32 CheckPresenterAndActorIntersections( + LegoPathBoundary* p_boundary, + Vector3& p_rayOrigin, + Vector3& p_rayDirection, + float p_rayLength, + float p_radius, + Vector3& p_intersectionPoint + ) override { - return LegoCarRaceActor::VTable0x6c(p_boundary, p_v1, p_v2, p_f1, p_f2, p_v3); + return LegoCarRaceActor::CheckPresenterAndActorIntersections( + p_boundary, + p_rayOrigin, + p_rayDirection, + p_rayLength, + p_radius, + p_intersectionPoint + ); } // vtable+0x6c void Animate(float p_time) override; // vtable+0x70 @@ -143,7 +169,7 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { LegoCarRaceActor::SwitchBoundary(p_boundary, p_edge, p_unk0xe4); } // vtable+0x98 - MxResult VTable0x9c() override; // vtable+0x9c + MxResult CalculateSpline() override; // vtable+0x9c virtual void SetMaxLinearVelocity(float p_maxLinearVelocity); virtual void KickCamera(float p_param); diff --git a/LEGO1/lego/legoomni/include/legoracespecial.h b/LEGO1/lego/legoomni/include/legoracespecial.h index bfa38632..bd650863 100644 --- a/LEGO1/lego/legoomni/include/legoracespecial.h +++ b/LEGO1/lego/legoomni/include/legoracespecial.h @@ -35,21 +35,21 @@ class LegoCarRaceActor : public virtual LegoRaceActor { return !strcmp(p_name, LegoCarRaceActor::ClassName()) || LegoRaceActor::IsA(p_name); } - inline MxU32 VTable0x6c( + inline MxU32 CheckPresenterAndActorIntersections( LegoPathBoundary* p_boundary, - Vector3& p_v1, - Vector3& p_v2, - float p_f1, - float p_f2, - Vector3& p_v3 + Vector3& p_rayOrigin, + Vector3& p_rayDirection, + float p_rayLength, + float p_radius, + Vector3& p_intersectionPoint ) override; // vtable+0x6c void Animate(float p_time) override; // vtable+0x70 void SwitchBoundary( LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, float& p_unk0xe4 - ) override; // vtable+0x98 - MxResult VTable0x9c() override; // vtable+0x9c + ) override; // vtable+0x98 + MxResult CalculateSpline() override; // vtable+0x9c // LegoCarRaceActor vtable @@ -130,13 +130,13 @@ class LegoJetskiRaceActor : public virtual LegoCarRaceActor { return !strcmp(p_name, LegoJetskiRaceActor::ClassName()) || LegoCarRaceActor::IsA(p_name); } - inline MxU32 VTable0x6c( + inline MxU32 CheckPresenterAndActorIntersections( LegoPathBoundary* p_boundary, - Vector3& p_v1, - Vector3& p_v2, - float p_f1, - float p_f2, - Vector3& p_v3 + Vector3& p_rayOrigin, + Vector3& p_rayDirection, + float p_rayLength, + float p_radius, + Vector3& p_intersectionPoint ) override; // vtable+0x6c void Animate(float p_time) override; // vtable+0x70 MxS32 VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edge) override; // vtable+0x1c diff --git a/LEGO1/lego/legoomni/src/actors/act2actor.cpp b/LEGO1/lego/legoomni/src/actors/act2actor.cpp index 18b099ee..320b918b 100644 --- a/LEGO1/lego/legoomni/src/actors/act2actor.cpp +++ b/LEGO1/lego/legoomni/src/actors/act2actor.cpp @@ -179,7 +179,7 @@ MxResult Act2Actor::HitActor(LegoPathActor*, MxBool) } // FUNCTION: LEGO1 0x10018a20 -MxResult Act2Actor::VTable0x9c() +MxResult Act2Actor::CalculateSpline() { if (m_grec && !m_grec->HasPath()) { delete m_grec; @@ -198,7 +198,7 @@ MxResult Act2Actor::VTable0x9c() brickstrROI->UpdateTransformationRelativeToParent(brickstrMatrix); } - return LegoPathActor::VTable0x9c(); + return LegoPathActor::CalculateSpline(); } } @@ -607,7 +607,7 @@ MxU32 Act2Actor::UpdateShot(MxFloat p_time) return FALSE; } - m_lastTime = p_time; + m_transformTime = p_time; LegoROI* brickstrROI = FindROI("brickstr"); MxMatrix initialTransform = m_roi->GetLocal2World(); diff --git a/LEGO1/lego/legoomni/src/actors/act3actors.cpp b/LEGO1/lego/legoomni/src/actors/act3actors.cpp index 8a0c1383..e109cb54 100644 --- a/LEGO1/lego/legoomni/src/actors/act3actors.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3actors.cpp @@ -100,20 +100,20 @@ Act3Actor::Act3Actor() // FUNCTION: LEGO1 0x1003fb70 // FUNCTION: BETA10 0x100180ab -MxU32 Act3Actor::VTable0x90(float p_time, Matrix4& p_transform) +MxU32 Act3Actor::StepState(float p_time, Matrix4& p_transform) { - // Note: Code duplication with LegoExtraActor::VTable0x90 + // Note: Code duplication with LegoExtraActor::StepState switch (m_actorState & c_maxState) { case c_initial: - case c_one: + case c_ready: return TRUE; - case c_two: + case c_hit: m_unk0x1c = p_time + 2000.0f; - m_actorState = c_three; - m_actorTime += (p_time - m_lastTime) * m_worldSpeed; - m_lastTime = p_time; + m_actorState = c_hitAnimation; + m_actorTime += (p_time - m_transformTime) * m_worldSpeed; + m_transformTime = p_time; return FALSE; - case c_three: + case c_hitAnimation: assert(!m_userNavFlag); Vector3 positionRef(p_transform[3]); @@ -127,10 +127,10 @@ MxU32 Act3Actor::VTable0x90(float p_time, Matrix4& p_transform) p_transform.RotateX(0.6); positionRef = position; - m_actorTime += (p_time - m_lastTime) * m_worldSpeed; - m_lastTime = p_time; + m_actorTime += (p_time - m_transformTime) * m_worldSpeed; + m_transformTime = p_time; - VTable0x74(p_transform); + ApplyTransform(p_transform); return FALSE; } else { @@ -166,7 +166,7 @@ MxResult Act3Actor::HitActor(LegoPathActor* p_actor, MxBool p_bool) roi->SetLocal2World(local2world); roi->WrappedUpdateWorldData(); - p_actor->SetActorState(c_two | c_noCollide); + p_actor->SetActorState(c_hit | c_noCollide); } return SUCCESS; @@ -195,7 +195,7 @@ MxResult Act3Cop::HitActor(LegoPathActor* p_actor, MxBool p_bool) assert(m_world); ((Act3*) m_world)->EatDonut(index); - m_unk0x20 = m_lastTime + 2000; + m_unk0x20 = m_transformTime + 2000; SetWorldSpeed(6.0); assert(SoundManager()->GetCacheSoundManager()); @@ -284,7 +284,7 @@ void Act3Cop::Animate(float p_time) { Act3Actor::Animate(p_time); - if (m_unk0x20 > 0.0f && m_unk0x20 < m_lastTime) { + if (m_unk0x20 > 0.0f && m_unk0x20 < m_transformTime) { SetWorldSpeed(2.0f); m_unk0x20 = -1.0f; } @@ -328,7 +328,7 @@ MxResult Act3Cop::FUN_10040360() LegoPathEdgeContainer* grec = NULL; Act3* a3 = (Act3*) m_world; - MxMatrix local74(m_unk0xec); + MxMatrix local74(m_local2World); Vector3 local2c(local74[3]); Vector3 local20(local74[2]); @@ -456,7 +456,7 @@ MxResult Act3Cop::FUN_10040360() vecUnk = m_grec->m_position; m_boundary = m_grec->m_boundary; - m_grec->m_direction = m_unk0xec[3]; + m_grec->m_direction = m_local2World[3]; m_grec->m_direction -= vecUnk; } else { @@ -469,7 +469,7 @@ MxResult Act3Cop::FUN_10040360() local128 = *v2; local128 -= *v1; - local128 *= m_unk0xe4; + local128 *= m_destScale; local128 += *v1; local128 *= -1.0f; local128 += m_grec->m_position; @@ -484,14 +484,14 @@ MxResult Act3Cop::FUN_10040360() vecUnk = *v2; vecUnk -= *v1; - vecUnk *= m_unk0xe4; + vecUnk *= m_destScale; vecUnk += *v1; } - Vector3 v1(m_unk0xec[0]); - Vector3 v2(m_unk0xec[1]); - Vector3 v3(m_unk0xec[2]); - Vector3 v4(m_unk0xec[3]); + Vector3 v1(m_local2World[0]); + Vector3 v2(m_local2World[1]); + Vector3 v3(m_local2World[2]); + Vector3 v4(m_local2World[3]); v3 = v4; v3 -= vecUnk; @@ -500,7 +500,7 @@ MxResult Act3Cop::FUN_10040360() v1.Unitize(); v2.EqualsCross(v3, v1); - VTable0x9c(); + CalculateSpline(); } return SUCCESS; @@ -508,17 +508,17 @@ MxResult Act3Cop::FUN_10040360() // FUNCTION: LEGO1 0x10040d20 // FUNCTION: BETA10 0x1001942c -MxResult Act3Cop::VTable0x9c() +MxResult Act3Cop::CalculateSpline() { if (m_grec && !m_grec->HasPath()) { delete m_grec; m_grec = NULL; - m_lastTime = Timer()->GetTime(); + m_transformTime = Timer()->GetTime(); FUN_10040360(); return SUCCESS; } - return Act3Actor::VTable0x9c(); + return Act3Actor::CalculateSpline(); } // FUNCTION: LEGO1 0x10040e10 @@ -570,7 +570,7 @@ void Act3Brickster::ParseAction(char* p_extra) // FUNCTION: BETA10 0x100197d7 void Act3Brickster::Animate(float p_time) { - if (m_lastTime <= m_unk0x20 && m_unk0x20 <= p_time) { + if (m_transformTime <= m_unk0x20 && m_unk0x20 <= p_time) { SetWorldSpeed(5.0f); } @@ -618,7 +618,7 @@ void Act3Brickster::Animate(float p_time) } else { MxMatrix local70; - local70 = m_unk0xec; + local70 = m_local2World; Vector3 local14(local70[0]); Vector3 local28(local70[1]); @@ -642,7 +642,7 @@ void Act3Brickster::Animate(float p_time) } } - m_lastTime = p_time; + m_transformTime = p_time; break; case 4: assert(m_shootAnim && m_bInfo); @@ -663,7 +663,7 @@ void Act3Brickster::Animate(float p_time) } else { MxMatrix locale4; - locale4 = m_unk0xec; + locale4 = m_local2World; Vector3 local88(locale4[0]); Vector3 local9c(locale4[1]); @@ -689,7 +689,7 @@ void Act3Brickster::Animate(float p_time) } } - m_lastTime = p_time; + m_transformTime = p_time; break; case 5: if (m_grec == NULL) { @@ -793,11 +793,11 @@ MxResult Act3Brickster::FUN_100417c0() LegoPathEdgeContainer* grec = NULL; Act3* a3 = (Act3*) m_world; - MxMatrix local70(m_unk0xec); + MxMatrix local70(m_local2World); Vector3 local28(local70[3]); Vector3 local20(local70[2]); - if (m_unk0x58 < 8 && m_unk0x24 + 5000.0f < m_lastTime) { + if (m_unk0x58 < 8 && m_unk0x24 + 5000.0f < m_transformTime) { float local18; for (MxS32 i = 0; i < MAX_PIZZAS; i++) { @@ -950,7 +950,7 @@ MxResult Act3Brickster::FUN_100417c0() vecUnk = m_grec->m_position; m_boundary = m_grec->m_boundary; - m_grec->m_direction = m_unk0xec[3]; + m_grec->m_direction = m_local2World[3]; m_grec->m_direction -= vecUnk; local150 = m_grec->m_direction; @@ -964,7 +964,7 @@ MxResult Act3Brickster::FUN_100417c0() local150 = *v2; local150 -= *v1; - local150 *= m_unk0xe4; + local150 *= m_destScale; local150 += *v1; local150 *= -1.0f; local150 += m_grec->m_position; @@ -979,14 +979,14 @@ MxResult Act3Brickster::FUN_100417c0() vecUnk = *v2; vecUnk -= *v1; - vecUnk *= m_unk0xe4; + vecUnk *= m_destScale; vecUnk += *v1; } - Vector3 v1(m_unk0xec[0]); - Vector3 v2(m_unk0xec[1]); - Vector3 v3(m_unk0xec[2]); - Vector3 v4(m_unk0xec[3]); + Vector3 v1(m_local2World[0]); + Vector3 v2(m_local2World[1]); + Vector3 v3(m_local2World[2]); + Vector3 v4(m_local2World[3]); v3 = v4; v3 -= vecUnk; @@ -995,7 +995,7 @@ MxResult Act3Brickster::FUN_100417c0() v1.Unitize(); v2.EqualsCross(v3, v1); - VTable0x9c(); + CalculateSpline(); if (m_pInfo != NULL) { m_unk0x38 = 5; @@ -1098,10 +1098,10 @@ MxS32 Act3Brickster::FUN_10042300() m_destEdge = maxE; if (m_boundary != boundaries[0]) { - m_unk0xe4 = 1.0 - m_unk0xe4; + m_destScale = 1.0 - m_destScale; } - VTable0x9c(); + CalculateSpline(); } return -1; @@ -1118,16 +1118,16 @@ void Act3Brickster::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOrientedEd // FUNCTION: LEGO1 0x100429d0 // FUNCTION: BETA10 0x1001b75b -MxResult Act3Brickster::VTable0x9c() +MxResult Act3Brickster::CalculateSpline() { if (m_grec && !m_grec->HasPath()) { delete m_grec; m_grec = NULL; - m_lastTime = Timer()->GetTime(); + m_transformTime = Timer()->GetTime(); return SUCCESS; } - return Act3Actor::VTable0x9c(); + return Act3Actor::CalculateSpline(); } // FUNCTION: LEGO1 0x10042ab0 diff --git a/LEGO1/lego/legoomni/src/actors/act3ammo.cpp b/LEGO1/lego/legoomni/src/actors/act3ammo.cpp index 98980d2c..961cfb34 100644 --- a/LEGO1/lego/legoomni/src/actors/act3ammo.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3ammo.cpp @@ -166,9 +166,9 @@ MxResult Act3Ammo::Shoot(LegoPathController* p_p, LegoPathBoundary* p_boundary, m_boundary = p_boundary; m_BADuration = 10000.0f; m_apexParameter = p_apexParameter; - m_unk0x7c = 0.0f; - m_lastTime = -1.0f; - m_actorState = c_one; + m_traveledDistance = 0.0f; + m_transformTime = -1.0f; + m_actorState = c_ready; return SUCCESS; } @@ -193,15 +193,15 @@ MxResult Act3Ammo::Shoot(LegoPathController* p_p, MxFloat p_apexParameter) m_pathController = p_p; m_BADuration = 10000.0f; m_apexParameter = p_apexParameter; - m_unk0x7c = 0.0f; - m_lastTime = -1.0f; - m_actorState = c_one; + m_traveledDistance = 0.0f; + m_transformTime = -1.0f; + m_actorState = c_ready; return SUCCESS; } // FUNCTION: LEGO1 0x10053db0 // FUNCTION: BETA10 0x1001e0f0 -MxResult Act3Ammo::CalculateTransform(float p_curveParameter, Matrix4& p_transform) +MxResult Act3Ammo::CalculateTransformOnCurve(float p_curveParameter, Matrix4& p_transform) { float curveParameterSquare = p_curveParameter * p_curveParameter; @@ -255,13 +255,13 @@ void Act3Ammo::Animate(float p_time) switch (m_actorState & c_maxState) { case c_initial: - case c_one: + case c_ready: break; - case c_two: + case c_hit: m_rotateTimeout = p_time + 2000.0f; - m_actorState = c_three; + m_actorState = c_hitAnimation; return; - case c_three: + case c_hitAnimation: MxMatrix transform; Vector3 positionRef(transform[3]); @@ -293,15 +293,15 @@ void Act3Ammo::Animate(float p_time) return; } - if (m_lastTime < 0.0f) { - m_lastTime = p_time; - m_unk0x7c = 0.0f; + if (m_transformTime < 0.0f) { + m_transformTime = p_time; + m_traveledDistance = 0.0f; } MxMatrix transform; MxMatrix additionalTransform; - float f = (m_BADuration - m_unk0x7c) / m_worldSpeed + m_lastTime; + float f = (m_BADuration - m_traveledDistance) / m_worldSpeed + m_transformTime; undefined4 unused1 = 0; undefined4 unused2 = 0; @@ -309,19 +309,19 @@ void Act3Ammo::Animate(float p_time) MxU32 reachedTarget = FALSE; if (f >= p_time) { - m_actorTime = (p_time - m_lastTime) * m_worldSpeed + m_actorTime; - m_unk0x7c = (p_time - m_lastTime) * m_worldSpeed + m_unk0x7c; - m_lastTime = p_time; + m_actorTime = (p_time - m_transformTime) * m_worldSpeed + m_actorTime; + m_traveledDistance = (p_time - m_transformTime) * m_worldSpeed + m_traveledDistance; + m_transformTime = p_time; } else { reachedTarget = TRUE; - m_unk0x7c = m_BADuration; - m_lastTime = p_time; + m_traveledDistance = m_BADuration; + m_transformTime = p_time; } transform.SetIdentity(); - MxResult r = CalculateTransform((m_unk0x7c / m_BADuration) * m_apexParameter, transform); + MxResult r = CalculateTransformOnCurve((m_traveledDistance / m_BADuration) * m_apexParameter, transform); assert(r == 0); // SUCCESS additionalTransform.SetIdentity(); @@ -369,7 +369,7 @@ void Act3Ammo::Animate(float p_time) m_roi->SetLocal2World(transform); m_roi->WrappedUpdateWorldData(); - if (m_BADuration <= m_unk0x7c) { + if (m_BADuration <= m_traveledDistance) { m_worldSpeed = 0.0f; } diff --git a/LEGO1/lego/legoomni/src/actors/bike.cpp b/LEGO1/lego/legoomni/src/actors/bike.cpp index 2924a2bd..e3414254 100644 --- a/LEGO1/lego/legoomni/src/actors/bike.cpp +++ b/LEGO1/lego/legoomni/src/actors/bike.cpp @@ -19,8 +19,8 @@ DECOMP_SIZE_ASSERT(Bike, 0x164) Bike::Bike() { m_maxLinearVel = 20.0; - m_unk0x150 = 3.0; - m_unk0x148 = 1; + m_linearRotationRatio = 3.0; + m_canRotate = 1; } // FUNCTION: LEGO1 0x100768f0 diff --git a/LEGO1/lego/legoomni/src/actors/helicopter.cpp b/LEGO1/lego/legoomni/src/actors/helicopter.cpp index 0337e96a..a69430eb 100644 --- a/LEGO1/lego/legoomni/src/actors/helicopter.cpp +++ b/LEGO1/lego/legoomni/src/actors/helicopter.cpp @@ -384,7 +384,7 @@ MxLong Helicopter::HandleEndAnim(LegoEndAnimNotificationParam& p_param) } // FUNCTION: LEGO1 0x10003e90 -void Helicopter::VTable0x74(Matrix4& p_transform) +void Helicopter::ApplyTransform(Matrix4& p_transform) { if (m_userNavFlag) { m_roi->UpdateTransformationRelativeToParent(p_transform); diff --git a/LEGO1/lego/legoomni/src/actors/jetski.cpp b/LEGO1/lego/legoomni/src/actors/jetski.cpp index a0c8428b..fec78e10 100644 --- a/LEGO1/lego/legoomni/src/actors/jetski.cpp +++ b/LEGO1/lego/legoomni/src/actors/jetski.cpp @@ -33,8 +33,8 @@ const char* g_varJSWNSHY5 = "c_jswnshy5"; Jetski::Jetski() { m_maxLinearVel = 25.0; - m_unk0x150 = 2.0; - m_unk0x148 = 1; + m_linearRotationRatio = 2.0; + m_canRotate = 1; } // FUNCTION: LEGO1 0x1007e630 diff --git a/LEGO1/lego/legoomni/src/actors/motorcycle.cpp b/LEGO1/lego/legoomni/src/actors/motorcycle.cpp index 303852e6..743a0df0 100644 --- a/LEGO1/lego/legoomni/src/actors/motorcycle.cpp +++ b/LEGO1/lego/legoomni/src/actors/motorcycle.cpp @@ -22,8 +22,8 @@ DECOMP_SIZE_ASSERT(Motocycle, 0x16c) Motocycle::Motocycle() { m_maxLinearVel = 40.0; - m_unk0x150 = 1.75; - m_unk0x148 = 1; + m_linearRotationRatio = 1.75; + m_canRotate = 1; m_fuel = 1.0; } diff --git a/LEGO1/lego/legoomni/src/actors/skateboard.cpp b/LEGO1/lego/legoomni/src/actors/skateboard.cpp index 09b847f7..473bd87e 100644 --- a/LEGO1/lego/legoomni/src/actors/skateboard.cpp +++ b/LEGO1/lego/legoomni/src/actors/skateboard.cpp @@ -22,8 +22,8 @@ SkateBoard::SkateBoard() { m_pizzaVisible = FALSE; m_maxLinearVel = 15.0; - m_unk0x150 = 3.5; - m_unk0x148 = 1; + m_linearRotationRatio = 3.5; + m_canRotate = 1; NotificationManager()->Register(this); } diff --git a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp index b0ff001a..2ef2574e 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp @@ -314,7 +314,7 @@ MxS32 g_legoAnimationManagerConfig = 1; float g_unk0x100f7500 = 0.1f; // GLOBAL: LEGO1 0x100f7504 -MxS32 g_unk0x100f7504 = 0; +MxS32 g_pathWalkingModeSelector = 0; // FUNCTION: LEGO1 0x1005eb50 void LegoAnimationManager::configureLegoAnimationManager(MxS32 p_legoAnimationManagerConfig) @@ -1927,10 +1927,10 @@ void LegoAnimationManager::AddExtra(MxS32 p_location, MxBool p_und) } if (i != m_numAllowedExtras) { - MxU8 und = rand() % 2 != 0 ? 1 : 2; + MxU8 pathWalkingMode = rand() % 2 != 0 ? 1 : 2; MxBool bool1, bool2; - switch (g_unk0x100f7504 % 4) { + switch (g_pathWalkingModeSelector % 4) { case 0: bool1 = FALSE; bool2 = FALSE; @@ -1948,7 +1948,7 @@ void LegoAnimationManager::AddExtra(MxS32 p_location, MxBool p_und) if (p_location < 0) { boundary = new LegoLocation::Boundary; - if (!FUN_10064120(boundary, und == 2, bool2)) { + if (!FUN_10064120(boundary, pathWalkingMode == 2, bool2)) { delete boundary; boundary = NULL; } @@ -2002,19 +2002,19 @@ void LegoAnimationManager::AddExtra(MxS32 p_location, MxBool p_und) g_characters[m_lastExtraCharacterId].m_name ); - switch (g_unk0x100f7504++ % 4) { + switch (g_pathWalkingModeSelector++ % 4) { case 0: - actor->SetUnknown0x0c(und != 1 ? 1 : 2); + actor->SetPathWalkingMode(pathWalkingMode != 1 ? 1 : 2); break; case 1: { - actor->SetUnknown0x0c(und); + actor->SetPathWalkingMode(pathWalkingMode); MxS32 src = boundary->m_src; boundary->m_src = boundary->m_dest; boundary->m_dest = src; break; } default: - actor->SetUnknown0x0c(und); + actor->SetPathWalkingMode(pathWalkingMode); break; } @@ -2184,21 +2184,21 @@ MxBool LegoAnimationManager::FUN_10062e20(LegoROI* p_roi, LegoAnimPresenter* p_p MxResult result = 1; // Not a valid MxResult value if (!local24) { - MxU8 unk0x0c; + MxU8 pathWalkingMode; switch (rand() % 3) { case 0: - unk0x0c = 1; + pathWalkingMode = 1; break; case 1: - unk0x0c = 2; + pathWalkingMode = 2; break; case 2: - unk0x0c = 0; + pathWalkingMode = 0; break; } - actor->SetUnknown0x0c(unk0x0c); + actor->SetPathWalkingMode(pathWalkingMode); Mx3DPointFloat position; Mx3DPointFloat direction; @@ -2695,8 +2695,8 @@ MxResult LegoAnimationManager::FUN_10064380( } if (actor != NULL) { - MxU8 unk0x0c = rand() % 2 != 0 ? 1 : 2; - actor->SetUnknown0x0c(unk0x0c); + MxU8 pathWalkingMode = rand() % 2 != 0 ? 1 : 2; + actor->SetPathWalkingMode(pathWalkingMode); actor->SetWorldSpeed(0.0f); if (world->PlaceActor(actor, p_boundaryName, p_src, p_srcScale, p_dest, p_destScale) != SUCCESS) { diff --git a/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp b/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp index 4b6804c1..3512727e 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp @@ -471,10 +471,10 @@ MxBool LegoAnimMMPresenter::FUN_1004b6d0(MxLong p_time) } #ifdef BETA10 - actor->VTable0xa8(); + actor->ApplyLocal2World(); #else if (m_tranInfo->m_unk0x29) { - actor->VTable0xa8(); + actor->ApplyLocal2World(); } #endif } diff --git a/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp b/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp index 2fd3529f..9ca28921 100644 --- a/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp @@ -63,10 +63,10 @@ MxResult LegoAnimActor::GetTimeInCycle(float& p_timeInCycle) } // FUNCTION: LEGO1 0x1001c240 -void LegoAnimActor::VTable0x74(Matrix4& p_transform) +void LegoAnimActor::ApplyTransform(Matrix4& p_transform) { float timeInCycle; - LegoPathActor::VTable0x74(p_transform); + LegoPathActor::ApplyTransform(p_transform); if (m_curAnim >= 0) { GetTimeInCycle(timeInCycle); @@ -80,19 +80,19 @@ void LegoAnimActor::Animate(float p_time) { assert(m_roi); - if (m_lastTime == 0) { - m_lastTime = p_time - 1.0f; + if (m_transformTime == 0) { + m_transformTime = p_time - 1.0f; } if (m_actorState == c_initial && !m_userNavFlag && m_worldSpeed <= 0) { if (m_curAnim >= 0) { - MxMatrix transform(m_unk0xec); + MxMatrix transform(m_local2World); float timeInCycle; GetTimeInCycle(timeInCycle); AnimateWithTransform(timeInCycle, transform); } - m_lastTime = m_actorTime = p_time; + m_transformTime = m_actorTime = p_time; } else { LegoPathActor::Animate(p_time); diff --git a/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp b/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp index 96581e9f..59e692f9 100644 --- a/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp @@ -32,7 +32,7 @@ LegoExtraActor::LegoExtraActor() { m_lastPathStruct = 0.0f; m_scheduledTime = 0; - m_unk0x0c = 0; + m_pathWalkingMode = 0; m_animationAtCurrentBoundary = FALSE; m_reassemblyAnimation = e_none; m_assAnim = NULL; @@ -48,19 +48,19 @@ LegoExtraActor::~LegoExtraActor() } // FUNCTION: LEGO1 0x1002a720 -MxU32 LegoExtraActor::VTable0x90(float p_time, Matrix4& p_transform) +MxU32 LegoExtraActor::StepState(float p_time, Matrix4& p_transform) { switch (m_actorState & c_maxState) { case c_initial: - case c_one: + case c_ready: return TRUE; - case c_two: + case c_hit: m_scheduledTime = p_time + 2000.0f; - m_actorState = c_three; - m_actorTime += (p_time - m_lastTime) * m_worldSpeed; - m_lastTime = p_time; + m_actorState = c_hitAnimation; + m_actorTime += (p_time - m_transformTime) * m_worldSpeed; + m_transformTime = p_time; return FALSE; - case c_three: { + case c_hitAnimation: { Vector3 positionRef(p_transform[3]); p_transform = m_roi->GetLocal2World(); @@ -89,9 +89,9 @@ MxU32 LegoExtraActor::VTable0x90(float p_time, Matrix4& p_transform) } positionRef = position; - m_actorTime += (p_time - m_lastTime) * m_worldSpeed; - m_lastTime = p_time; - VTable0x74(p_transform); + m_actorTime += (p_time - m_transformTime) * m_worldSpeed; + m_transformTime = p_time; + ApplyTransform(p_transform); return FALSE; } else { @@ -109,20 +109,20 @@ MxU32 LegoExtraActor::VTable0x90(float p_time, Matrix4& p_transform) } // FUNCTION: LEGO1 0x1002aa90 -void LegoExtraActor::VTable0xa4(MxBool& p_und1, MxS32& p_und2) +void LegoExtraActor::GetWalkingBehavior(MxBool& p_countCounterclockWise, MxS32& p_selectedEdgeIndex) { - switch (m_unk0x0c) { + switch (m_pathWalkingMode) { case 1: - p_und1 = TRUE; - p_und2 = 1; + p_countCounterclockWise = TRUE; + p_selectedEdgeIndex = 1; break; case 2: - p_und1 = FALSE; - p_und2 = 1; + p_countCounterclockWise = FALSE; + p_selectedEdgeIndex = 1; break; default: - p_und1 = TRUE; - p_und2 = rand() % p_und2 + 1; + p_countCounterclockWise = TRUE; + p_selectedEdgeIndex = rand() % p_selectedEdgeIndex + 1; break; } } @@ -131,10 +131,10 @@ void LegoExtraActor::VTable0xa4(MxBool& p_und1, MxS32& p_und2) MxResult LegoExtraActor::SwitchDirection() { LegoPathBoundary* oldEdge = m_boundary; - Vector3 rightRef(m_unk0xec[0]); - Vector3 upRef(m_unk0xec[1]); - Vector3 dirRef(m_unk0xec[2]); - Vector3 positionRef(m_unk0xec[3]); + Vector3 rightRef(m_local2World[0]); + Vector3 upRef(m_local2World[1]); + Vector3 dirRef(m_local2World[2]); + Vector3 positionRef(m_local2World[3]); dirRef *= -1.0f; rightRef.EqualsCross(upRef, dirRef); @@ -150,7 +150,7 @@ MxResult LegoExtraActor::SwitchDirection() m_boundary = oldEdge; } - LegoPathActor::VTable0x9c(); + LegoPathActor::CalculateSpline(); return SUCCESS; } @@ -240,7 +240,7 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool) VTable0xc4(); SetWorldSpeed(0); m_reassemblyAnimation = e_disassemble; - SetActorState(c_one | c_noCollide); + SetActorState(c_ready | c_noCollide); } } @@ -249,7 +249,7 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool) assert(roi); SoundManager()->GetCacheSoundManager()->Play("crash5", m_roi->GetName(), FALSE); VTable0xc4(); - SetActorState(c_two | c_noCollide); + SetActorState(c_hit | c_noCollide); Mx3DPointFloat dir = p_actor->GetWorldDirection(); MxMatrix matrix3 = MxMatrix(roi->GetLocal2World()); Vector3 positionRef(matrix3[3]); @@ -272,10 +272,10 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool) } // FUNCTION: LEGO1 0x1002b290 -MxResult LegoExtraActor::VTable0x9c() +MxResult LegoExtraActor::CalculateSpline() { LegoPathBoundary* oldBoundary = m_boundary; - MxResult result = LegoPathActor::VTable0x9c(); + MxResult result = LegoPathActor::CalculateSpline(); if (m_boundary != oldBoundary) { MxU32 foundAnimation = FALSE; @@ -333,7 +333,7 @@ void LegoExtraActor::Animate(float p_time) case e_disassemble: if (m_scheduledTime < p_time) { m_reassemblyAnimation = e_assemble; - m_actorState = c_one | c_noCollide; + m_actorState = c_ready | c_noCollide; m_scheduledTime = m_assAnim->GetDuration() + p_time; break; } @@ -347,7 +347,7 @@ void LegoExtraActor::Animate(float p_time) m_actorState = c_initial; SetWorldSpeed(m_prevWorldSpeed); m_roi->SetLocal2World(m_localBeforeHit); - m_lastTime = p_time; + m_transformTime = p_time; break; } else { @@ -379,10 +379,10 @@ void LegoExtraActor::Animate(float p_time) } // FUNCTION: LEGO1 0x1002b5d0 -void LegoExtraActor::VTable0x74(Matrix4& p_transform) +void LegoExtraActor::ApplyTransform(Matrix4& p_transform) { if (m_reassemblyAnimation == e_none) { - LegoAnimActor::VTable0x74(p_transform); + LegoAnimActor::ApplyTransform(p_transform); } } @@ -409,32 +409,32 @@ void LegoExtraActor::VTable0xc4() if (b) { float duration = m_animMaps[m_curAnim]->GetDuration(); - MxMatrix matrix(m_unk0xec); + MxMatrix matrix(m_local2World); LegoAnimActor::AnimateWithTransform(duration, matrix); } } } // FUNCTION: LEGO1 0x1002b6f0 -MxS32 LegoExtraActor::VTable0x68(Vector3& p_point1, Vector3& p_point2, Vector3& p_point3) +MxS32 LegoExtraActor::CheckIntersections(Vector3& p_rayOrigin, Vector3& p_rayEnd, Vector3& p_intersectionPoint) { - return LegoPathActor::VTable0x68(p_point1, p_point2, p_point3); + return LegoPathActor::CheckIntersections(p_rayOrigin, p_rayEnd, p_intersectionPoint); } // FUNCTION: LEGO1 0x1002b980 -inline MxU32 LegoExtraActor::VTable0x6c( +inline MxU32 LegoExtraActor::CheckPresenterAndActorIntersections( LegoPathBoundary* p_boundary, - Vector3& p_v1, - Vector3& p_v2, - float p_f1, - float p_f2, - Vector3& p_v3 + Vector3& p_rayOrigin, + Vector3& p_rayDirection, + float p_rayLength, + float p_radius, + Vector3& p_intersectionPoint ) { LegoAnimPresenterSet& presenters = p_boundary->GetPresenters(); for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) { - if ((*itap)->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3)) { + if ((*itap)->Intersect(p_rayOrigin, p_rayDirection, p_rayLength, p_radius, p_intersectionPoint)) { return 1; } } @@ -453,11 +453,11 @@ inline MxU32 LegoExtraActor::VTable0x6c( if (actor->GetUserNavFlag()) { MxMatrix local2world = roi->GetLocal2World(); Vector3 local60(local2world[3]); - Mx3DPointFloat local54(p_v1); + Mx3DPointFloat local54(p_rayOrigin); local54 -= local60; - float local1c = p_v2.Dot(p_v2, p_v2); - float local24 = p_v2.Dot(p_v2, local54) * 2.0f; + float local1c = p_rayDirection.Dot(p_rayDirection, p_rayDirection); + float local24 = p_rayDirection.Dot(p_rayDirection, local54) * 2.0f; float local20 = local54.Dot(local54, local54); if (m_hitBlockCounter != 0 && local20 < 10.0f) { @@ -487,9 +487,10 @@ inline MxU32 LegoExtraActor::VTable0x6c( local1cX = local40; } - if ((local20X >= 0.0f && local20X <= p_f1) || (local1cX >= 0.0f && local1cX <= p_f1) || - (local20X <= -0.01 && p_f1 + 0.01 <= local1cX)) { - p_v3 = p_v1; + if ((local20X >= 0.0f && local20X <= p_rayLength) || + (local1cX >= 0.0f && local1cX <= p_rayLength) || + (local20X <= -0.01 && p_rayLength + 0.01 <= local1cX)) { + p_intersectionPoint = p_rayOrigin; if (HitActor(actor, TRUE) < 0) { return 0; @@ -502,7 +503,14 @@ inline MxU32 LegoExtraActor::VTable0x6c( } } else { - if (roi->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3, m_collideBox && actor->GetCollideBox())) { + if (roi->Intersect( + p_rayOrigin, + p_rayDirection, + p_rayLength, + p_radius, + p_intersectionPoint, + m_collideBox && actor->GetCollideBox() + )) { if (HitActor(actor, TRUE) < 0) { return 0; } diff --git a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp index 40e312dd..2fca5127 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp @@ -44,18 +44,18 @@ LegoPathActor::LegoPathActor() { m_boundary = NULL; m_actorTime = 0; - m_lastTime = 0; - m_unk0x7c = 0; + m_transformTime = 0; + m_traveledDistance = 0; m_userNavFlag = FALSE; m_actorState = c_initial; m_grec = NULL; m_pathController = NULL; m_collideBox = FALSE; - m_unk0x148 = 0; - m_unk0x14c = 0; - m_unk0x140 = 0.0099999999f; - m_unk0x144 = 0.8f; - m_unk0x150 = 2.0f; + m_canRotate = 0; + m_lastRotationAngle = 0; + m_wallHitDirectionFactor = 0.0099999999f; + m_wallHitDampening = 0.8f; + m_linearRotationRatio = 2.0f; } // FUNCTION: LEGO1 0x1002d820 @@ -69,19 +69,24 @@ LegoPathActor::~LegoPathActor() // FUNCTION: LEGO1 0x1002d8d0 // FUNCTION: BETA10 0x100ae8cd -MxResult LegoPathActor::VTable0x80(const Vector3& p_point1, Vector3& p_point2, Vector3& p_point3, Vector3& p_point4) +MxResult LegoPathActor::SetSpline( + const Vector3& p_start, + Vector3& p_tangentAtStart, + Vector3& p_end, + Vector3& p_tangentAtEnd +) { - Mx3DPointFloat p1, p2, p3; + Mx3DPointFloat length, tangentAtStart, tangentAtEnd; - p1 = p_point3; - p1 -= p_point1; - m_BADuration = p1.LenSquared(); + length = p_end; + length -= p_start; + m_BADuration = length.LenSquared(); if (m_BADuration > 0.0f) { m_BADuration = sqrtf(m_BADuration); - p2 = p_point2; - p3 = p_point4; - m_spline.SetSpline(p_point1, p2, p_point3, p3); + tangentAtStart = p_tangentAtStart; + tangentAtEnd = p_tangentAtEnd; + m_spline.SetSpline(p_start, tangentAtStart, p_end, tangentAtEnd); m_BADuration /= 0.001; return SUCCESS; } @@ -93,7 +98,7 @@ MxResult LegoPathActor::VTable0x80(const Vector3& p_point1, Vector3& p_point2, V // FUNCTION: LEGO1 0x1002d9c0 // FUNCTION: BETA10 0x100ae9da -MxResult LegoPathActor::VTable0x88( +MxResult LegoPathActor::SetTransformAndDestinationFromEdge( LegoPathBoundary* p_boundary, float p_time, LegoEdge& p_srcEdge, @@ -107,29 +112,29 @@ MxResult LegoPathActor::VTable0x88( Vector3* v3 = p_destEdge.CWVertex(*p_boundary); Vector3* v4 = p_destEdge.CCWVertex(*p_boundary); - Mx3DPointFloat p1, p2, p3, p4, p5; + Mx3DPointFloat start, end, destNormal, startDirection, endDirection; - p1 = *v2; - p1 -= *v1; - p1 *= p_srcScale; - p1 += *v1; + start = *v2; + start -= *v1; + start *= p_srcScale; + start += *v1; - p2 = *v4; - p2 -= *v3; - p2 *= p_destScale; - p2 += *v3; + end = *v4; + end -= *v3; + end *= p_destScale; + end += *v3; m_boundary = p_boundary; m_destEdge = &p_destEdge; - m_unk0xe4 = p_destScale; - m_unk0x7c = 0; - m_lastTime = p_time; + m_destScale = p_destScale; + m_traveledDistance = 0; + m_transformTime = p_time; m_actorTime = p_time; - p_destEdge.GetFaceNormal(*p_boundary, p3); + p_destEdge.GetFaceNormal(*p_boundary, destNormal); - p4 = p2; - p4 -= p1; - p4.Unitize(); + startDirection = end; + startDirection -= start; + startDirection.Unitize(); MxMatrix matrix; Vector3 pos(matrix[3]); @@ -138,8 +143,8 @@ MxResult LegoPathActor::VTable0x88( Vector3 right(matrix[0]); matrix.SetIdentity(); - pos = p1; - dir = p4; + pos = start; + dir = startDirection; up = *m_boundary->GetUp(); if (!m_cameraFlag || !m_userNavFlag) { @@ -150,10 +155,10 @@ MxResult LegoPathActor::VTable0x88( m_roi->UpdateTransformationRelativeToParent(matrix); if (!m_cameraFlag || !m_userNavFlag) { - p5.EqualsCross(*p_boundary->GetUp(), p3); - p5.Unitize(); + endDirection.EqualsCross(*p_boundary->GetUp(), destNormal); + endDirection.Unitize(); - if (VTable0x80(p1, p4, p2, p5) == SUCCESS) { + if (SetSpline(start, startDirection, end, endDirection) == SUCCESS) { m_boundary->AddActor(this); } else { @@ -165,17 +170,17 @@ MxResult LegoPathActor::VTable0x88( TransformPointOfView(); } - m_unk0xec = m_roi->GetLocal2World(); + m_local2World = m_roi->GetLocal2World(); return SUCCESS; } // FUNCTION: LEGO1 0x1002de10 // FUNCTION: BETA10 0x100aee61 -MxResult LegoPathActor::VTable0x84( +MxResult LegoPathActor::SetTransformAndDestinationFromPoints( LegoPathBoundary* p_boundary, float p_time, - Vector3& p_p1, - Vector3& p_p4, + Vector3& p_start, + Vector3& p_direction, LegoOrientedEdge* p_destEdge, float p_destScale ) @@ -187,20 +192,20 @@ MxResult LegoPathActor::VTable0x84( assert(v3 && v4); - Mx3DPointFloat p2, p3, p5; + Mx3DPointFloat end, destNormal, endDirection; - p2 = *v4; - p2 -= *v3; - p2 *= p_destScale; - p2 += *v3; + end = *v4; + end -= *v3; + end *= p_destScale; + end += *v3; m_boundary = p_boundary; m_destEdge = p_destEdge; - m_unk0xe4 = p_destScale; - m_unk0x7c = 0; - m_lastTime = p_time; + m_destScale = p_destScale; + m_traveledDistance = 0; + m_transformTime = p_time; m_actorTime = p_time; - p_destEdge->GetFaceNormal(*p_boundary, p3); + p_destEdge->GetFaceNormal(*p_boundary, destNormal); MxMatrix matrix; Vector3 pos(matrix[3]); @@ -209,8 +214,8 @@ MxResult LegoPathActor::VTable0x84( Vector3 right(matrix[0]); matrix.SetIdentity(); - pos = p_p1; - dir = p_p4; + pos = p_start; + dir = p_direction; up = *m_boundary->GetUp(); if (!m_cameraFlag || !m_userNavFlag) { @@ -225,10 +230,10 @@ MxResult LegoPathActor::VTable0x84( TransformPointOfView(); } else { - p5.EqualsCross(*p_boundary->GetUp(), p3); - p5.Unitize(); + endDirection.EqualsCross(*p_boundary->GetUp(), destNormal); + endDirection.Unitize(); - if (VTable0x80(p_p1, p_p4, p2, p5) != SUCCESS) { + if (SetSpline(p_start, p_direction, end, endDirection) != SUCCESS) { MxTrace("Warning: m_BADuration = %g, roi = %s\n", m_BADuration, m_roi->GetName()); return FAILURE; } @@ -236,57 +241,59 @@ MxResult LegoPathActor::VTable0x84( m_boundary->AddActor(this); } - m_unk0xec = m_roi->GetLocal2World(); + m_local2World = m_roi->GetLocal2World(); return SUCCESS; } // FUNCTION: LEGO1 0x1002e100 // FUNCTION: BETA10 0x100b0520 -MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform) +MxS32 LegoPathActor::CalculateTransform(float p_time, Matrix4& p_transform) { if (m_userNavFlag && m_actorState == c_initial) { - m_lastTime = p_time; + m_transformTime = p_time; - Mx3DPointFloat p1, p2, p3, p4, p5; - p5 = Vector3(m_roi->GetWorldDirection()); - p4 = Vector3(m_roi->GetWorldPosition()); + Mx3DPointFloat newDir, newPos, intersectionPoint, pos, dir; + dir = Vector3(m_roi->GetWorldDirection()); + pos = Vector3(m_roi->GetWorldPosition()); LegoNavController* nav = NavController(); assert(nav); m_worldSpeed = nav->GetLinearVel(); - if (nav->CalculateNewPosDir(p4, p5, p2, p1, m_boundary->GetUp())) { - Mx3DPointFloat p6; - p6 = p2; + if (nav->CalculateNewPosDir(pos, dir, newPos, newDir, m_boundary->GetUp())) { + Mx3DPointFloat newPosCopy; + newPosCopy = newPos; MxS32 result = 0; - m_unk0xe9 = m_boundary->Intersect(m_roi->GetWorldBoundingSphere().Radius(), p4, p2, p3, m_destEdge); - if (m_unk0xe9 == -1) { + m_finishedTravel = + m_boundary + ->Intersect(m_roi->GetWorldBoundingSphere().Radius(), pos, newPos, intersectionPoint, m_destEdge); + if (m_finishedTravel == -1) { MxTrace("Intersect returned -1\n"); return -1; } else { - if (m_unk0xe9 != 0) { - p2 = p3; + if (m_finishedTravel != FALSE) { + newPos = intersectionPoint; } } - result = VTable0x68(p4, p2, p3); + result = CheckIntersections(pos, newPos, intersectionPoint); if (result > 0) { - p2 = p4; - m_unk0xe9 = 0; + newPos = pos; + m_finishedTravel = FALSE; result = 0; } else { - m_boundary->CheckAndCallPathTriggers(p4, p2, this); + m_boundary->CheckAndCallPathTriggers(pos, newPos, this); } LegoPathBoundary* oldBoundary = m_boundary; - if (m_unk0xe9 != 0) { - VTable0x9c(); + if (m_finishedTravel != FALSE) { + CalculateSpline(); if (m_boundary == oldBoundary) { MxLong time = Timer()->GetTime(); @@ -300,15 +307,15 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform) } } - m_worldSpeed *= m_unk0x144; + m_worldSpeed *= m_wallHitDampening; nav->SetLinearVel(m_worldSpeed); - Mx3DPointFloat p7(p2); - p7 -= p6; + Mx3DPointFloat newPosDelta(newPos); + newPosDelta -= newPosCopy; - if (p7.Unitize() == 0) { - float f = sqrt(p1.LenSquared()) * m_unk0x140; - p7 *= f; - p1 += p7; + if (newPosDelta.Unitize() == 0) { + float f = sqrt(newDir.LenSquared()) * m_wallHitDirectionFactor; + newPosDelta *= f; + newDir += newPosDelta; } } } @@ -320,7 +327,7 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform) Vector3 dir(p_transform[2]); Vector3 pos(p_transform[3]); - dir = p1; + dir = newDir; up = *m_boundary->GetUp(); right.EqualsCross(up, dir); @@ -328,7 +335,7 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform) assert(res == 0); dir.EqualsCross(right, up); - pos = p2; + pos = newPos; return result; } else { @@ -336,47 +343,47 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform) } } else if (p_time >= 0 && m_worldSpeed > 0) { - float f = (m_BADuration - m_unk0x7c) / m_worldSpeed + m_lastTime; + float endTime = (m_BADuration - m_traveledDistance) / m_worldSpeed + m_transformTime; - if (f < p_time) { - m_unk0x7c = m_BADuration; - m_unk0xe9 = 1; + if (endTime < p_time) { + m_traveledDistance = m_BADuration; + m_finishedTravel = TRUE; } else { - f = p_time; - m_unk0x7c += (f - m_lastTime) * m_worldSpeed; - m_unk0xe9 = 0; + endTime = p_time; + m_traveledDistance += (endTime - m_transformTime) * m_worldSpeed; + m_finishedTravel = FALSE; } - m_actorTime += (f - m_lastTime) * m_worldSpeed; - m_lastTime = f; + m_actorTime += (endTime - m_transformTime) * m_worldSpeed; + m_transformTime = endTime; p_transform.SetIdentity(); LegoResult r; if (m_userNavFlag) { - r = m_spline.Evaluate(m_unk0x7c / m_BADuration, p_transform, *m_boundary->GetUp(), FALSE); + r = m_spline.Evaluate(m_traveledDistance / m_BADuration, p_transform, *m_boundary->GetUp(), FALSE); } else { - r = m_spline.Evaluate(m_unk0x7c / m_BADuration, p_transform, *m_boundary->GetUp(), TRUE); + r = m_spline.Evaluate(m_traveledDistance / m_BADuration, p_transform, *m_boundary->GetUp(), TRUE); } assert(r == 0); // SUCCESS - Vector3 pos1(p_transform[3]); - Vector3 pos2(m_unk0xec[3]); + Vector3 end(p_transform[3]); + Vector3 origin(m_local2World[3]); Mx3DPointFloat p1; - if (VTable0x68(pos2, pos1, p1) > 0) { - m_lastTime = p_time; + if (CheckIntersections(origin, end, p1) > 0) { + m_transformTime = p_time; return 1; } else { - m_boundary->CheckAndCallPathTriggers(pos2, pos1, this); - pos2 = pos1; + m_boundary->CheckAndCallPathTriggers(origin, end, this); + origin = end; } - if (m_unk0xe9 != 0) { - VTable0x9c(); + if (m_finishedTravel != FALSE) { + CalculateSpline(); } } else { @@ -388,7 +395,7 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform) // FUNCTION: LEGO1 0x1002e740 // FUNCTION: BETA10 0x100b0f70 -void LegoPathActor::VTable0x74(Matrix4& p_transform) +void LegoPathActor::ApplyTransform(Matrix4& p_transform) { if (m_userNavFlag) { m_roi->WrappedSetLocal2WorldWithWorldDataUpdate(p_transform); @@ -409,69 +416,70 @@ void LegoPathActor::VTable0x74(Matrix4& p_transform) void LegoPathActor::Animate(float p_time) { MxMatrix transform; - MxU32 b = FALSE; + MxU32 applyTransform = FALSE; - while (m_lastTime < p_time) { - if (m_actorState != c_initial && !VTable0x90(p_time, transform)) { + while (m_transformTime < p_time) { + if (m_actorState != c_initial && !StepState(p_time, transform)) { return; } - if (VTable0x8c(p_time, transform) != 0) { + if (CalculateTransform(p_time, transform) != 0) { break; } - m_unk0xec = transform; - b = TRUE; + m_local2World = transform; + applyTransform = TRUE; - if (m_unk0xe9 != 0) { + if (m_finishedTravel != FALSE) { break; } } - if (m_userNavFlag && m_unk0x148) { + if (m_userNavFlag && m_canRotate) { LegoNavController* nav = NavController(); - float vel = (nav->GetLinearVel() > 0) - ? -(nav->GetRotationalVel() / (nav->GetMaxLinearVel() * m_unk0x150) * nav->GetLinearVel()) - : 0; + float vel = + (nav->GetLinearVel() > 0) + ? -(nav->GetRotationalVel() / (nav->GetMaxLinearVel() * m_linearRotationRatio) * nav->GetLinearVel()) + : 0; - if ((MxS32) vel != m_unk0x14c) { - m_unk0x14c = vel; + if ((MxS32) vel != m_lastRotationAngle) { + m_lastRotationAngle = vel; LegoWorld* world = CurrentWorld(); if (world) { - world->GetCameraController()->RotateZ(DTOR(m_unk0x14c)); + world->GetCameraController()->RotateZ(DTOR(m_lastRotationAngle)); } } } - if (b) { - VTable0x74(transform); + if (applyTransform) { + ApplyTransform(transform); } } // FUNCTION: LEGO1 0x1002e8b0 // FUNCTION: BETA10 0x100af2f7 -void LegoPathActor::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, float& p_unk0xe4) +void LegoPathActor::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, float& p_scale) { assert(m_boundary); - m_boundary->SwitchBoundary(this, p_boundary, p_edge, p_unk0xe4); + m_boundary->SwitchBoundary(this, p_boundary, p_edge, p_scale); } // FUNCTION: LEGO1 0x1002e8d0 // FUNCTION: BETA10 0x100b1010 -MxU32 LegoPathActor::VTable0x6c( +MxU32 LegoPathActor::CheckPresenterAndActorIntersections( LegoPathBoundary* p_boundary, - Vector3& p_v1, - Vector3& p_v2, - float p_f1, - float p_f2, - Vector3& p_v3 + Vector3& p_rayOrigin, + Vector3& p_rayDirection, + float p_rayLength, + float p_radius, + Vector3& p_intersectionPoint ) { LegoAnimPresenterSet& presenters = p_boundary->GetPresenters(); for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) { - if ((*itap)->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3)) { + if ((*itap)->Intersect(p_rayOrigin, p_rayDirection, p_rayLength, p_radius, p_intersectionPoint)) { return 1; } } @@ -487,7 +495,14 @@ MxU32 LegoPathActor::VTable0x6c( LegoROI* roi = actor->GetROI(); if (roi != NULL && (roi->GetVisibility() || actor->GetCameraFlag())) { - if (roi->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3, m_collideBox && actor->m_collideBox)) { + if (roi->Intersect( + p_rayOrigin, + p_rayDirection, + p_rayLength, + p_radius, + p_intersectionPoint, + m_collideBox && actor->m_collideBox + )) { HitActor(actor, TRUE); actor->HitActor(this, FALSE); return 2; @@ -500,26 +515,33 @@ MxU32 LegoPathActor::VTable0x6c( return 0; } -inline MxU32 LegoPathActor::FUN_1002edd0( - list& p_boundaries, +inline MxU32 LegoPathActor::CheckIntersectionBothFaces( + list& p_checkedBoundaries, LegoPathBoundary* p_boundary, - Vector3& p_v1, - Vector3& p_v2, - float p_f1, - float p_f2, - Vector3& p_v3, - MxS32 p_und + Vector3& p_rayOrigin, + Vector3& p_rayDirection, + float p_rayLength, + float p_radius, + Vector3& p_intersectionPoint, + MxS32 p_depth ) { - MxU32 result = VTable0x6c(p_boundary, p_v1, p_v2, p_f1, p_f2, p_v3); + MxU32 result = CheckPresenterAndActorIntersections( + p_boundary, + p_rayOrigin, + p_rayDirection, + p_rayLength, + p_radius, + p_intersectionPoint + ); if (result != 0) { return result; } - p_boundaries.push_back(p_boundary); + p_checkedBoundaries.push_back(p_boundary); - if (p_und >= 2) { + if (p_depth >= 2) { return 0; } @@ -531,14 +553,23 @@ inline MxU32 LegoPathActor::FUN_1002edd0( if (boundary != NULL) { list::const_iterator it; - for (it = p_boundaries.begin(); !(it == p_boundaries.end()); it++) { + for (it = p_checkedBoundaries.begin(); !(it == p_checkedBoundaries.end()); it++) { if ((*it) == boundary) { break; } } - if (it == p_boundaries.end()) { - result = FUN_1002edd0(p_boundaries, boundary, p_v1, p_v2, p_f1, p_f2, p_v3, p_und + 1); + if (it == p_checkedBoundaries.end()) { + result = CheckIntersectionBothFaces( + p_checkedBoundaries, + boundary, + p_rayOrigin, + p_rayDirection, + p_rayLength, + p_radius, + p_intersectionPoint, + p_depth + 1 + ); if (result != 0) { return result; @@ -552,26 +583,35 @@ inline MxU32 LegoPathActor::FUN_1002edd0( // FUNCTION: LEGO1 0x1002ebe0 // FUNCTION: BETA10 0x100af35e -MxS32 LegoPathActor::VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3) +MxS32 LegoPathActor::CheckIntersections(Vector3& p_rayOrigin, Vector3& p_rayEnd, Vector3& p_intersectionPoint) { assert(m_boundary && m_roi); - Mx3DPointFloat v2(p_v2); - v2 -= p_v1; + Mx3DPointFloat rayDirection(p_rayEnd); + rayDirection -= p_rayOrigin; - float len = v2.LenSquared(); + float len = rayDirection.LenSquared(); if (len <= 0.001) { return 0; } len = sqrt((double) len); - v2 /= len; + rayDirection /= len; float radius = m_roi->GetWorldBoundingSphere().Radius(); list boundaries; - return FUN_1002edd0(boundaries, m_boundary, p_v1, v2, len, radius, p_v3, 0); + return CheckIntersectionBothFaces( + boundaries, + m_boundary, + p_rayOrigin, + rayDirection, + len, + radius, + p_intersectionPoint, + 0 + ); } // FUNCTION: LEGO1 0x1002f020 @@ -622,20 +662,21 @@ void LegoPathActor::ParseAction(char* p_extra) // FUNCTION: LEGO1 0x1002f1b0 // FUNCTION: BETA10 0x100af899 -MxResult LegoPathActor::VTable0x9c() +MxResult LegoPathActor::CalculateSpline() { - Mx3DPointFloat local34; - Mx3DPointFloat local48; - MxU32 local1c = 1; - MxU32 local20 = 1; + Mx3DPointFloat targetPosition; + Mx3DPointFloat endDirection; + MxU32 noPath1 = TRUE; + MxU32 noPath2 = TRUE; if (m_grec != NULL) { if (m_grec->HasPath()) { - local1c = 0; - local20 = 0; + noPath1 = FALSE; + noPath2 = FALSE; Mx3DPointFloat vec; - switch (m_pathController->GetNextPathEdge(*m_grec, local34, local48, m_unk0xe4, m_destEdge, m_boundary)) { + switch (m_pathController + ->GetNextPathEdge(*m_grec, targetPosition, endDirection, m_destScale, m_destEdge, m_boundary)) { case 0: case 1: break; @@ -650,30 +691,30 @@ MxResult LegoPathActor::VTable0x9c() } } - if (local1c != 0) { - SwitchBoundary(m_boundary, m_destEdge, m_unk0xe4); + if (noPath1 != FALSE) { + SwitchBoundary(m_boundary, m_destEdge, m_destScale); } - if (local20 != 0) { - Mx3DPointFloat local78; + if (noPath2 != FALSE) { + Mx3DPointFloat normal; assert(m_boundary && m_destEdge); - Vector3* v1 = m_destEdge->CWVertex(*m_boundary); - Vector3* v2 = m_destEdge->CCWVertex(*m_boundary); + Vector3* cw = m_destEdge->CWVertex(*m_boundary); + Vector3* ccw = m_destEdge->CCWVertex(*m_boundary); - assert(v1 && v2); + assert(cw && ccw); - LERP3(local34, *v1, *v2, m_unk0xe4); + LERP3(targetPosition, *cw, *ccw, m_destScale); - m_destEdge->GetFaceNormal(*m_boundary, local78); - local48.EqualsCross(*m_boundary->GetUp(), local78); - local48.Unitize(); + m_destEdge->GetFaceNormal(*m_boundary, normal); + endDirection.EqualsCross(*m_boundary->GetUp(), normal); + endDirection.Unitize(); } - Vector3 rightRef(m_unk0xec[0]); - Vector3 upRef(m_unk0xec[1]); - Vector3 dirRef(m_unk0xec[2]); + Vector3 rightRef(m_local2World[0]); + Vector3 upRef(m_local2World[1]); + Vector3 dirRef(m_local2World[2]); upRef = *m_boundary->GetUp(); @@ -683,74 +724,74 @@ MxResult LegoPathActor::VTable0x9c() dirRef.EqualsCross(rightRef, upRef); dirRef.Unitize(); - Mx3DPointFloat localc0(m_unk0xec[3]); - Mx3DPointFloat local84(m_unk0xec[2]); - Mx3DPointFloat local70(local34); + Mx3DPointFloat start(m_local2World[3]); + Mx3DPointFloat direction(m_local2World[2]); + Mx3DPointFloat startToTarget(targetPosition); - local70 -= localc0; - float len = local70.LenSquared(); + startToTarget -= start; + float len = startToTarget.LenSquared(); if (len >= 0.0f) { len = sqrt(len); - local84 *= len; - local48 *= len; + direction *= len; + endDirection *= len; } if (!m_userNavFlag) { - local84 *= -1.0f; + direction *= -1.0f; } - if (VTable0x80(localc0, local84, local34, local48) != SUCCESS) { + if (SetSpline(start, direction, targetPosition, endDirection) != SUCCESS) { MxTrace("Warning: m_BADuration = %g, roi = %s\n", m_BADuration, m_roi->GetName()); return FAILURE; } - m_unk0x7c = 0.0f; + m_traveledDistance = 0.0f; return SUCCESS; } // FUNCTION: LEGO1 0x1002f650 // FUNCTION: BETA10 0x100afd67 -void LegoPathActor::VTable0xa4(MxBool& p_und1, MxS32& p_und2) +void LegoPathActor::GetWalkingBehavior(MxBool& p_countCounterclockWise, MxS32& p_selectedEdgeIndex) { switch (GetActorId()) { case c_pepper: - p_und1 = TRUE; - p_und2 = 2; + p_countCounterclockWise = TRUE; + p_selectedEdgeIndex = 2; break; case c_mama: - p_und1 = FALSE; - p_und2 = 1; + p_countCounterclockWise = FALSE; + p_selectedEdgeIndex = 1; break; case c_papa: - p_und1 = TRUE; - p_und2 = 1; + p_countCounterclockWise = TRUE; + p_selectedEdgeIndex = 1; break; case c_nick: case c_brickster: - p_und1 = TRUE; - p_und2 = rand() % p_und2 + 1; + p_countCounterclockWise = TRUE; + p_selectedEdgeIndex = rand() % p_selectedEdgeIndex + 1; break; case c_laura: - p_und1 = FALSE; - p_und2 = 2; + p_countCounterclockWise = FALSE; + p_selectedEdgeIndex = 2; break; default: - p_und1 = TRUE; - p_und2 = 1; + p_countCounterclockWise = TRUE; + p_selectedEdgeIndex = 1; break; } } // FUNCTION: LEGO1 0x1002f700 // FUNCTION: BETA10 0x100afe4c -void LegoPathActor::VTable0xa8() +void LegoPathActor::ApplyLocal2World() { - m_lastTime = Timer()->GetTime(); - m_roi->SetLocal2World(m_unk0xec); + m_transformTime = Timer()->GetTime(); + m_roi->SetLocal2World(m_local2World); m_roi->WrappedUpdateWorldData(); if (m_userNavFlag) { - m_roi->WrappedSetLocal2WorldWithWorldDataUpdate(m_unk0xec); + m_roi->WrappedSetLocal2WorldWithWorldDataUpdate(m_local2World); TransformPointOfView(); } } diff --git a/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp b/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp index 8710b5ac..45bfd9b1 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp @@ -128,7 +128,7 @@ void LegoPathBoundary::SwitchBoundary( selectedEdgeIndex = 1; } else { - p_actor->VTable0xa4(countCounterclockwise, selectedEdgeIndex); + p_actor->GetWalkingBehavior(countCounterclockwise, selectedEdgeIndex); } while (selectedEdgeIndex > 0) { diff --git a/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp b/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp index 38367bb2..f56f7e49 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp @@ -223,8 +223,14 @@ MxResult LegoPathController::PlaceActor( assert(pSrcE && pDestE); float time = Timer()->GetTime(); - MxResult result = - p_actor->VTable0x88(pBoundary, time, *pSrcE, p_srcScale, (LegoOrientedEdge&) *pDestE, p_destScale); + MxResult result = p_actor->SetTransformAndDestinationFromEdge( + pBoundary, + time, + *pSrcE, + p_srcScale, + (LegoOrientedEdge&) *pDestE, + p_destScale + ); if (result != SUCCESS) { assert(0); @@ -298,7 +304,8 @@ MxResult LegoPathController::PlaceActor( return FAILURE; } - if (p_actor->VTable0x84(boundary, time, p_position, p_direction, edge, 0.5f) == SUCCESS) { + if (p_actor->SetTransformAndDestinationFromPoints(boundary, time, p_position, p_direction, edge, 0.5f) == + SUCCESS) { p_actor->SetController(this); m_actors.insert(p_actor); return SUCCESS; diff --git a/LEGO1/lego/legoomni/src/race/legoraceactor.cpp b/LEGO1/lego/legoomni/src/race/legoraceactor.cpp index 6019ba17..d76bc21f 100644 --- a/LEGO1/lego/legoomni/src/race/legoraceactor.cpp +++ b/LEGO1/lego/legoomni/src/race/legoraceactor.cpp @@ -25,9 +25,9 @@ LegoRaceActor::LegoRaceActor() // FUNCTION: LEGO1 0x10014750 // FUNCTION: BETA10 0x100c9bba -MxS32 LegoRaceActor::VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3) +MxS32 LegoRaceActor::CheckIntersections(Vector3& p_rayOrigin, Vector3& p_rayEnd, Vector3& p_intersectionPoint) { - MxS32 result = LegoPathActor::VTable0x68(p_v1, p_v2, p_v3); + MxS32 result = LegoPathActor::CheckIntersections(p_rayOrigin, p_rayEnd, p_intersectionPoint); if (m_userNavFlag && result) { MxLong time = Timer()->GetTime(); @@ -46,20 +46,20 @@ MxS32 LegoRaceActor::VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3) // FUNCTION: LEGO1 0x100147f0 // FUNCTION: BETA10 0x100c9c93 -MxU32 LegoRaceActor::VTable0x90(float p_time, Matrix4& p_transform) +MxU32 LegoRaceActor::StepState(float p_time, Matrix4& p_transform) { - // Note: Code duplication with LegoExtraActor::VTable0x90 + // Note: Code duplication with LegoExtraActor::StepState switch (m_actorState) { case c_initial: - case c_one: + case c_ready: return TRUE; - case c_two: + case c_hit: m_unk0x08 = p_time + 2000.0f; - m_actorState = c_three; - m_actorTime += (p_time - m_lastTime) * m_worldSpeed; - m_lastTime = p_time; + m_actorState = c_hitAnimation; + m_actorTime += (p_time - m_transformTime) * m_worldSpeed; + m_transformTime = p_time; return FALSE; - case c_three: + case c_hitAnimation: assert(!m_userNavFlag); Vector3 positionRef(p_transform[3]); @@ -73,10 +73,10 @@ MxU32 LegoRaceActor::VTable0x90(float p_time, Matrix4& p_transform) p_transform.RotateX(0.6); positionRef = position; - m_actorTime += (p_time - m_lastTime) * m_worldSpeed; - m_lastTime = p_time; + m_actorTime += (p_time - m_transformTime) * m_worldSpeed; + m_transformTime = p_time; - VTable0x74(p_transform); + ApplyTransform(p_transform); return FALSE; } else { @@ -111,7 +111,7 @@ MxResult LegoRaceActor::HitActor(LegoPathActor* p_actor, MxBool p_bool) roi->SetLocal2World(matr); - p_actor->SetActorState(c_two); + p_actor->SetActorState(c_hit); } } diff --git a/LEGO1/lego/legoomni/src/race/legoracers.cpp b/LEGO1/lego/legoomni/src/race/legoracers.cpp index de1d7608..c4658ef6 100644 --- a/LEGO1/lego/legoomni/src/race/legoracers.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracers.cpp @@ -471,7 +471,7 @@ MxResult LegoRaceCar::HitActor(LegoPathActor* p_actor, MxBool p_bool) Vector3(matr[3]) += g_hitOffset; roi->SetLocal2World(matr); - p_actor->SetActorState(c_two); + p_actor->SetActorState(c_hit); } if (m_userNavFlag) { @@ -531,12 +531,12 @@ MxResult LegoRaceCar::HitActor(LegoPathActor* p_actor, MxBool p_bool) // FUNCTION: LEGO1 0x10013600 // FUNCTION: BETA10 0x100cbe60 -MxResult LegoRaceCar::VTable0x9c() +MxResult LegoRaceCar::CalculateSpline() { MxResult result; if (m_userNavFlag) { - result = LegoCarRaceActor::VTable0x9c(); + result = LegoCarRaceActor::CalculateSpline(); if (m_boundary) { MxS32 onSkeletonBoundary = FALSE; @@ -560,7 +560,7 @@ MxResult LegoRaceCar::VTable0x9c() } } else { - result = LegoCarRaceActor::VTable0x9c(); + result = LegoCarRaceActor::CalculateSpline(); } return result; @@ -685,7 +685,7 @@ MxResult LegoJetski::HitActor(LegoPathActor* p_actor, MxBool p_bool) Vector3(matr[3]) += g_hitOffset; roi->SetLocal2World(matr); - p_actor->SetActorState(c_two); + p_actor->SetActorState(c_hit); } if (m_userNavFlag) { diff --git a/LEGO1/lego/legoomni/src/race/legoracespecial.cpp b/LEGO1/lego/legoomni/src/race/legoracespecial.cpp index b02479b6..a9d6f955 100644 --- a/LEGO1/lego/legoomni/src/race/legoracespecial.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracespecial.cpp @@ -51,9 +51,9 @@ LegoCarRaceActor::LegoCarRaceActor() m_unk0x10 = 0.65f; m_unk0x14 = 0.03f; m_unk0x18 = 0.6f; - m_unk0x140 = 0.1f; - m_unk0x150 = -5.0f; - m_unk0x148 = 1; + m_wallHitDirectionFactor = 0.1f; + m_linearRotationRatio = -5.0f; + m_canRotate = 1; VariableTable()->SetVariable(g_fuel, "0.8"); } @@ -118,7 +118,7 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg Mx3DPointFloat destEdgeUnknownVector; Mx3DPointFloat crossProduct; - if (m_actorState == c_one) { + if (m_actorState == c_ready) { m_boundary = NULL; // Not sure where the upper bound of 11 comes from, the underlying array has a size of 16 @@ -132,7 +132,7 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg assert(m_boundary); m_actorState = c_initial; - m_unk0x7c = 0; + m_traveledDistance = 0; if (m_userNavFlag) { NavController()->SetLinearVel(m_worldSpeed); @@ -145,7 +145,7 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg else { for (MxS32 i = 0; i < 11; i += 2) { if (LegoPathController::GetControlEdgeA(i) == p_edge) { - m_actorState = c_one; + m_actorState = c_ready; if (m_worldSpeed < g_unk0x100f7aec) { m_worldSpeed = g_unk0x100f7aec; @@ -157,9 +157,9 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg } } - if (m_actorState == c_one) { + if (m_actorState == c_ready) { if (m_userNavFlag) { - m_unk0xe4 = 0.5f; + m_destScale = 0.5f; } // variable names verified by BETA10 @@ -167,7 +167,7 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg Vector3* v2 = m_destEdge->CWVertex(*m_boundary); assert(v1 && v2); - LERP3(pointUnknown, *v1, *v2, m_unk0xe4); + LERP3(pointUnknown, *v1, *v2, m_destScale); m_destEdge->GetFaceNormal(*m_boundary, destEdgeUnknownVector); @@ -184,14 +184,14 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg crossProduct *= 5.0f; MxResult callResult = - VTable0x80(Vector3(m_roi->GetWorldPosition()), worldDirection, pointUnknown, crossProduct); + SetSpline(Vector3(m_roi->GetWorldPosition()), worldDirection, pointUnknown, crossProduct); if (callResult) { - m_unk0x7c = 0; + m_traveledDistance = 0; return 0; } else { - m_unk0x7c = 0; + m_traveledDistance = 0; #ifdef BETA10 assert(0); #endif @@ -216,7 +216,7 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg // FUNCTION: BETA10 0x100cdb3c void LegoCarRaceActor::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, float& p_unk0xe4) { - LegoPathActor::SwitchBoundary(m_boundary, m_destEdge, m_unk0xe4); + LegoPathActor::SwitchBoundary(m_boundary, m_destEdge, m_destScale); } // FUNCTION: LEGO1 0x10080b70 @@ -229,7 +229,7 @@ void LegoCarRaceActor::Animate(float p_time) if (strcmpi(value, g_racing) == 0) { m_animState = 1; - m_lastTime = p_time - 1.0f; + m_transformTime = p_time - 1.0f; m_unk0x1c = p_time; } } @@ -241,14 +241,14 @@ void LegoCarRaceActor::Animate(float p_time) // FUNCTION: LEGO1 0x10080be0 // FUNCTION: BETA10 0x100cdc54 -MxResult LegoCarRaceActor::VTable0x9c() +MxResult LegoCarRaceActor::CalculateSpline() { LegoOrientedEdge* d = m_destEdge; if (VTable0x1c(m_boundary, m_destEdge)) { LegoPathBoundary* b = m_boundary; - SwitchBoundary(m_boundary, m_destEdge, m_unk0xe4); + SwitchBoundary(m_boundary, m_destEdge, m_destScale); assert(m_boundary && m_destEdge); // variable names verified by BETA10 @@ -257,7 +257,7 @@ MxResult LegoCarRaceActor::VTable0x9c() assert(v1 && v2); Mx3DPointFloat point1; - LERP3(point1, *v1, *v2, m_unk0xe4); + LERP3(point1, *v1, *v2, m_destScale); Mx3DPointFloat point2; Mx3DPointFloat point3; @@ -276,7 +276,7 @@ MxResult LegoCarRaceActor::VTable0x9c() point4 *= 5.0f; point5 *= 5.0f; - MxResult res = VTable0x80(m_roi->GetWorldPosition(), point4, point1, point5); + MxResult res = SetSpline(m_roi->GetWorldPosition(), point4, point1, point5); #ifdef BETA10 if (res) { @@ -285,7 +285,7 @@ MxResult LegoCarRaceActor::VTable0x9c() } #endif - m_unk0x7c = 0; + m_traveledDistance = 0; } return SUCCESS; @@ -298,7 +298,7 @@ LegoJetskiRaceActor::LegoJetskiRaceActor() m_unk0x10 = 0.95f; m_unk0x14 = 0.04f; m_unk0x18 = 0.5f; - m_unk0x150 = 1.5f; + m_linearRotationRatio = 1.5f; } // FUNCTION: LEGO1 0x10081120 @@ -314,7 +314,7 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_ Vector3* v1 = NULL; Vector3* v2 = NULL; - if (m_actorState == c_one) { + if (m_actorState == c_ready) { if (m_destEdge == LegoPathController::GetControlEdgeA(13)) { m_boundary = (LegoPathBoundary*) m_destEdge->OtherFace(LegoPathController::GetControlBoundaryA(13)); } @@ -323,7 +323,7 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_ } m_actorState = c_initial; - m_unk0x7c = 0; + m_traveledDistance = 0; if (m_userNavFlag) { NavController()->SetLinearVel(m_worldSpeed); @@ -335,7 +335,7 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_ } else { if (p_edge == LegoPathController::GetControlEdgeA(12)) { - m_actorState = c_one; + m_actorState = c_ready; if (m_worldSpeed < g_unk0x100da044) { m_worldSpeed = g_unk0x100da044; @@ -345,7 +345,7 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_ m_boundary = LegoPathController::GetControlBoundaryA(13); } else if (p_edge == LegoPathController::GetControlEdgeA(14)) { - m_actorState = c_one; + m_actorState = c_ready; if (m_worldSpeed < g_unk0x100da044) { m_worldSpeed = g_unk0x100da044; @@ -355,16 +355,16 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_ m_boundary = LegoPathController::GetControlBoundaryA(15); } - if (m_actorState == c_one) { + if (m_actorState == c_ready) { if (m_userNavFlag) { - m_unk0xe4 = 0.5f; + m_destScale = 0.5f; } v1 = m_destEdge->CCWVertex(*m_boundary); v2 = m_destEdge->CWVertex(*m_boundary); assert(v1 && v2); - LERP3(a, *v1, *v2, m_unk0xe4); + LERP3(a, *v1, *v2, m_destScale); m_destEdge->GetFaceNormal(*m_boundary, bbb); c.EqualsCross(bbb, *m_boundary->GetUp()); @@ -376,9 +376,9 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_ worldDirection *= -1.0f; } - if (VTable0x80(m_roi->GetWorldPosition(), worldDirection, a, c)) { + if (SetSpline(m_roi->GetWorldPosition(), worldDirection, a, c)) { #ifndef BETA10 - m_unk0x7c = 0; + m_traveledDistance = 0; return 0; #else assert(0); @@ -386,7 +386,7 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_ #endif } - m_unk0x7c = 0; + m_traveledDistance = 0; return 0; } else { @@ -402,11 +402,11 @@ void LegoJetskiRaceActor::Animate(float p_time) const LegoChar* raceState = VariableTable()->GetVariable(g_raceState); if (!stricmp(raceState, g_racing)) { m_animState = 1; - m_lastTime = p_time - 1.0f; + m_transformTime = p_time - 1.0f; m_unk0x1c = p_time; } else if (!m_userNavFlag) { - LegoAnimActor::Animate(m_lastTime + 1.0f); + LegoAnimActor::Animate(m_transformTime + 1.0f); } } @@ -417,13 +417,13 @@ void LegoJetskiRaceActor::Animate(float p_time) // FUNCTION: LEGO1 0x10081840 // FUNCTION: BETA10 0x100cf680 -inline MxU32 LegoCarRaceActor::VTable0x6c( +inline MxU32 LegoCarRaceActor::CheckPresenterAndActorIntersections( LegoPathBoundary* p_boundary, - Vector3& p_v1, - Vector3& p_v2, - float p_f1, - float p_f2, - Vector3& p_v3 + Vector3& p_rayOrigin, + Vector3& p_rayDirection, + float p_rayLength, + float p_radius, + Vector3& p_intersectionPoint ) { // STRING: LEGO1 0x100f7af4 @@ -432,7 +432,7 @@ inline MxU32 LegoCarRaceActor::VTable0x6c( LegoAnimPresenterSet& presenters = p_boundary->GetPresenters(); for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) { - if ((*itap)->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3)) { + if ((*itap)->Intersect(p_rayOrigin, p_rayDirection, p_rayLength, p_radius, p_intersectionPoint)) { return 1; } } @@ -456,8 +456,14 @@ inline MxU32 LegoCarRaceActor::VTable0x6c( LegoROI* firstROI = (LegoROI*) co->front(); - if (firstROI - ->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3, m_collideBox && actor->GetCollideBox())) { + if (firstROI->Intersect( + p_rayOrigin, + p_rayDirection, + p_rayLength, + p_radius, + p_intersectionPoint, + m_collideBox && actor->GetCollideBox() + )) { HitActor(actor, TRUE); if (actor->HitActor(this, FALSE) < 0) { @@ -470,8 +476,14 @@ inline MxU32 LegoCarRaceActor::VTable0x6c( LegoROI* lastROI = (LegoROI*) co->back(); - if (lastROI - ->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3, m_collideBox && actor->GetCollideBox())) { + if (lastROI->Intersect( + p_rayOrigin, + p_rayDirection, + p_rayLength, + p_radius, + p_intersectionPoint, + m_collideBox && actor->GetCollideBox() + )) { HitActor(actor, TRUE); if (actor->HitActor(this, FALSE) < 0) { @@ -484,7 +496,14 @@ inline MxU32 LegoCarRaceActor::VTable0x6c( } } else { - if (roi->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3, m_collideBox && actor->GetCollideBox())) { + if (roi->Intersect( + p_rayOrigin, + p_rayDirection, + p_rayLength, + p_radius, + p_intersectionPoint, + m_collideBox && actor->GetCollideBox() + )) { HitActor(actor, TRUE); if (actor->HitActor(this, FALSE) < 0) { @@ -504,19 +523,19 @@ inline MxU32 LegoCarRaceActor::VTable0x6c( } // FUNCTION: LEGO1 0x10081fd0 -inline MxU32 LegoJetskiRaceActor::VTable0x6c( +inline MxU32 LegoJetskiRaceActor::CheckPresenterAndActorIntersections( LegoPathBoundary* p_boundary, - Vector3& p_v1, - Vector3& p_v2, - float p_f1, - float p_f2, - Vector3& p_v3 + Vector3& p_rayOrigin, + Vector3& p_rayDirection, + float p_rayLength, + float p_radius, + Vector3& p_intersectionPoint ) { LegoAnimPresenterSet& presenters = p_boundary->GetPresenters(); for (LegoAnimPresenterSet::iterator itap = presenters.begin(); itap != presenters.end(); itap++) { - if ((*itap)->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3)) { + if ((*itap)->Intersect(p_rayOrigin, p_rayDirection, p_rayLength, p_radius, p_intersectionPoint)) { return 1; } } @@ -532,7 +551,14 @@ inline MxU32 LegoJetskiRaceActor::VTable0x6c( LegoROI* roi = actor->GetROI(); if (roi != NULL && (roi->GetVisibility() || actor->GetCameraFlag())) { - if (roi->Intersect(p_v1, p_v2, p_f1, p_f2, p_v3, m_collideBox && actor->GetCollideBox())) { + if (roi->Intersect( + p_rayOrigin, + p_rayDirection, + p_rayLength, + p_radius, + p_intersectionPoint, + m_collideBox && actor->GetCollideBox() + )) { HitActor(actor, TRUE); if (actor->HitActor(this, FALSE) < 0) { diff --git a/LEGO1/lego/legoomni/src/worlds/act3.cpp b/LEGO1/lego/legoomni/src/worlds/act3.cpp index bedbf451..e7f5bb3e 100644 --- a/LEGO1/lego/legoomni/src/worlds/act3.cpp +++ b/LEGO1/lego/legoomni/src/worlds/act3.cpp @@ -582,13 +582,13 @@ MxLong Act3::Notify(MxParam& p_param) m_cop1->SetActorState(LegoPathActor::c_initial); m_cop1->SetWorldSpeed(2.0f); - m_cop1->VTable0xa8(); + m_cop1->ApplyLocal2World(); m_cop2->SetActorState(LegoPathActor::c_initial); m_cop2->SetWorldSpeed(2.0f); - m_cop2->VTable0xa8(); + m_cop2->ApplyLocal2World(); - m_brickster->VTable0xa8(); + m_brickster->ApplyLocal2World(); m_pizzaHitSound = 0; m_pizzaMissSound = 0; m_copDonutSound = 0; @@ -907,34 +907,34 @@ void Act3::Enable(MxBool p_enable) MxFloat delta = Timer()->GetTime() - m_time - 100.0f; m_time = -1.0f; - m_cop1->SetLastTime(m_cop1->GetLastTime() + delta); + m_cop1->SetTransformTime(m_cop1->GetTransformTime() + delta); m_cop1->SetActorTime(m_cop1->GetActorTime() + delta); m_cop1->SetUnknown0x20(m_cop1->GetUnknown0x20() + delta); m_cop1->SetUnknown0x1c(m_cop1->GetUnknown0x1c() + delta); - m_cop2->SetLastTime(m_cop2->GetLastTime() + delta); + m_cop2->SetTransformTime(m_cop2->GetTransformTime() + delta); m_cop2->SetActorTime(m_cop2->GetActorTime() + delta); m_cop2->SetUnknown0x20(m_cop2->GetUnknown0x20() + delta); m_cop2->SetUnknown0x1c(m_cop2->GetUnknown0x1c() + delta); - m_brickster->SetLastTime(m_brickster->GetLastTime() + delta); + m_brickster->SetTransformTime(m_brickster->GetTransformTime() + delta); m_brickster->SetActorTime(m_brickster->GetActorTime() + delta); m_brickster->SetUnknown0x20(m_brickster->GetUnknown0x20() + delta); m_brickster->SetUnknown0x24(m_brickster->GetUnknown0x24() + delta); m_brickster->SetUnknown0x50(m_brickster->GetUnknown0x50() + delta); m_brickster->SetUnknown0x1c(m_brickster->GetUnknown0x1c() + delta); - m_copter->SetLastTime(m_copter->GetLastTime() + delta); + m_copter->SetTransformTime(m_copter->GetTransformTime() + delta); m_copter->SetActorTime(m_copter->GetActorTime() + delta); - m_shark->SetLastTime(m_shark->GetLastTime() + delta); + m_shark->SetTransformTime(m_shark->GetTransformTime() + delta); m_shark->SetActorTime(m_shark->GetActorTime() + delta); m_shark->SetUnknown0x2c(m_shark->GetUnknown0x2c() + delta); MxS32 i; for (i = 0; i < (MxS32) sizeOfArray(m_pizzas); i++) { if (m_pizzas[i].IsValid()) { - m_pizzas[i].SetLastTime(m_pizzas[i].GetLastTime() + delta); + m_pizzas[i].SetTransformTime(m_pizzas[i].GetTransformTime() + delta); m_pizzas[i].SetActorTime(m_pizzas[i].GetActorTime() + delta); m_pizzas[i].SetRotateTimeout(m_pizzas[i].GetRotateTimeout() + delta); } @@ -942,7 +942,7 @@ void Act3::Enable(MxBool p_enable) for (i = 0; i < (MxS32) sizeOfArray(m_donuts); i++) { if (m_donuts[i].IsValid()) { - m_donuts[i].SetLastTime(m_donuts[i].GetLastTime() + delta); + m_donuts[i].SetTransformTime(m_donuts[i].GetTransformTime() + delta); m_donuts[i].SetActorTime(m_donuts[i].GetActorTime() + delta); m_donuts[i].SetRotateTimeout(m_donuts[i].GetRotateTimeout() + delta); } @@ -954,7 +954,7 @@ void Act3::Enable(MxBool p_enable) InputManager()->SetWorld(this); InputManager()->Register(this); SetUserActor(m_copter); - m_copter->VTable0xa8(); + m_copter->ApplyLocal2World(); SetAppCursor(e_cursorArrow); } } diff --git a/LEGO1/realtime/vector.h b/LEGO1/realtime/vector.h index 3841783f..2bf03b52 100644 --- a/LEGO1/realtime/vector.h +++ b/LEGO1/realtime/vector.h @@ -123,7 +123,7 @@ class Vector4 : public Vector3 { Vector4(float* p_data) : Vector3(p_data) {} // Some code initializes a Vector4 from a `const float*` source. - // Example: `LegoCarBuild::VTable0x6c` + // Example: `LegoCarBuild::CheckIntersections` // Vector4 however is a class that can mutate its underlying source, making // initialization with a const source fundamentally incompatible. // BETA10 appears to have two separate constructors for Vector4 as well,