From 4cc6b9b8ec7a0e7e11accae892325c5b86395cd5 Mon Sep 17 00:00:00 2001 From: Nathan M Gilbert Date: Mon, 23 Oct 2023 07:16:21 -0400 Subject: [PATCH] Implement Score (#230) * Implement Score * Update mxomni.cpp Fix case of OFFSET comment. * Fix DeleteObjects * Apply changes (see comment) --------- Co-authored-by: Christian Semmler --- .gitignore | 1 + CMakeLists.txt | 3 + LEGO1/ambulancemissionstate.cpp | 2 + LEGO1/ambulancemissionstate.h | 19 ++ LEGO1/gifmanager.cpp | 25 +++ LEGO1/gifmanager.h | 73 +++++++ LEGO1/legocontrolmanager.cpp | 12 + LEGO1/legocontrolmanager.h | 2 + LEGO1/legoentity.cpp | 66 +++++- LEGO1/legoentity.h | 15 +- LEGO1/legogamestate.cpp | 12 + LEGO1/legogamestate.h | 9 +- LEGO1/legoinputmanager.cpp | 30 ++- LEGO1/legoinputmanager.h | 13 +- LEGO1/legoomni.cpp | 8 +- LEGO1/legoomni.h | 7 +- LEGO1/legoworld.cpp | 75 +++++++ LEGO1/legoworld.h | 22 ++ LEGO1/mxactionnotificationparam.h | 2 + LEGO1/mxappnotificationparam.cpp | 3 + LEGO1/mxappnotificationparam.h | 22 ++ LEGO1/mxdsaction.cpp | 2 +- LEGO1/mxdsaction.h | 3 +- LEGO1/mxentity.h | 1 + LEGO1/mxnotificationparam.h | 20 +- LEGO1/mxomni.cpp | 16 +- LEGO1/mxomni.h | 3 + LEGO1/mxtype17notificationparam.cpp | 3 + LEGO1/mxtype17notificationparam.h | 22 ++ LEGO1/pizzamissionstate.cpp | 12 + LEGO1/pizzamissionstate.h | 19 ++ LEGO1/racestate.cpp | 16 ++ LEGO1/racestate.h | 20 +- LEGO1/score.cpp | 328 +++++++++++++++++++++++++++- LEGO1/score.h | 36 ++- LEGO1/scorestate.h | 5 +- LEGO1/towtrackmissionstate.cpp | 2 + LEGO1/towtrackmissionstate.h | 26 ++- 38 files changed, 923 insertions(+), 32 deletions(-) create mode 100644 LEGO1/gifmanager.cpp create mode 100644 LEGO1/gifmanager.h create mode 100644 LEGO1/mxappnotificationparam.cpp create mode 100644 LEGO1/mxappnotificationparam.h create mode 100644 LEGO1/mxtype17notificationparam.cpp create mode 100644 LEGO1/mxtype17notificationparam.h diff --git a/.gitignore b/.gitignore index 8768f944..93ad1c7a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ Debug/ Release/ *.ncb /.vs +/.vscode ISLE.EXE LEGO1.DLL build/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b663cb0..5b19d06e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ add_library(lego1 SHARED LEGO1/gasstation.cpp LEGO1/gasstationentity.cpp LEGO1/gasstationstate.cpp + LEGO1/gifmanager.cpp LEGO1/helicopter.cpp LEGO1/helicopterstate.cpp LEGO1/historybook.cpp @@ -98,6 +99,7 @@ add_library(lego1 SHARED LEGO1/legoworldpresenter.cpp LEGO1/motorcycle.cpp LEGO1/mxactionnotificationparam.cpp + LEGO1/mxappnotificationparam.cpp LEGO1/mxatomid.cpp LEGO1/mxatomidcounter.cpp LEGO1/mxaudiomanager.cpp @@ -176,6 +178,7 @@ add_library(lego1 SHARED LEGO1/mxticklemanager.cpp LEGO1/mxtimer.cpp LEGO1/mxtransitionmanager.cpp + LEGO1/mxtype17notificationparam.cpp LEGO1/mxvariable.cpp LEGO1/mxvariabletable.cpp LEGO1/mxvector.cpp diff --git a/LEGO1/ambulancemissionstate.cpp b/LEGO1/ambulancemissionstate.cpp index 6b20ce3a..05f28796 100644 --- a/LEGO1/ambulancemissionstate.cpp +++ b/LEGO1/ambulancemissionstate.cpp @@ -1,5 +1,7 @@ #include "ambulancemissionstate.h" +DECOMP_SIZE_ASSERT(AmbulanceMissionState, 0x24); + // OFFSET: LEGO1 0x100373a0 STUB AmbulanceMissionState::AmbulanceMissionState() { diff --git a/LEGO1/ambulancemissionstate.h b/LEGO1/ambulancemissionstate.h index 572bba9a..4f59c5d8 100644 --- a/LEGO1/ambulancemissionstate.h +++ b/LEGO1/ambulancemissionstate.h @@ -23,6 +23,25 @@ public: return !strcmp(name, AmbulanceMissionState::ClassName()) || LegoState::IsA(name); } + inline MxU16 GetColor(MxU8 id) + { + switch (id) + { + case 1: return m_color1; + case 2: return m_color2; + case 3: return m_color3; + case 4: return m_color4; + case 5: return m_color5; + default: return 0; + } + } +protected: + undefined m_unk8[0x12]; + MxU16 m_color1; + MxU16 m_color2; + MxU16 m_color3; + MxU16 m_color4; + MxU16 m_color5; }; diff --git a/LEGO1/gifmanager.cpp b/LEGO1/gifmanager.cpp new file mode 100644 index 00000000..8327cb43 --- /dev/null +++ b/LEGO1/gifmanager.cpp @@ -0,0 +1,25 @@ +#include "gifmanager.h" + +DECOMP_SIZE_ASSERT(GifData, 0x14); +DECOMP_SIZE_ASSERT(GifMapEntry, 0x14); +DECOMP_SIZE_ASSERT(GifMap, 0x08); +DECOMP_SIZE_ASSERT(GifManagerBase, 0x14); +DECOMP_SIZE_ASSERT(GifManager, 0x30); + +GifMapEntry *DAT_100f0100; + +// OFFSET: LEGO1 0x10001cc0 +GifMapEntry *GifMap::FindNode(const char *&string) +{ + GifMapEntry *ret = m_unk4; + GifMapEntry *current = ret->m_parent; + while (current != DAT_100f0100) { + if (strcmp(current->m_key, string) <= 0) { + ret = current; + current = current->m_right; + } + else + current = current->m_left; + } + return ret; +} \ No newline at end of file diff --git a/LEGO1/gifmanager.h b/LEGO1/gifmanager.h new file mode 100644 index 00000000..357a2a9a --- /dev/null +++ b/LEGO1/gifmanager.h @@ -0,0 +1,73 @@ +#ifndef GIFMANAGER_H +#define GIFMANAGER_H + +#include "decomp.h" +#include "mxtypes.h" + +#include +#include + +struct GifData +{ +public: + const char *m_name; + LPDIRECTDRAWSURFACE m_surface; + LPDIRECTDRAWPALETTE m_palette; + LPDIRECT3DRMTEXTURE2 m_texture; + MxU8 *m_data; +}; + +struct GifMapEntry +{ +public: + GifMapEntry *m_right; + GifMapEntry *m_parent; + GifMapEntry *m_left; + const char *m_key; + GifData *m_value; +}; + +class GifMap +{ +public: + GifMapEntry *FindNode(const char *&string); + + inline GifData *Get(const char *string) { + GifData *ret = NULL; + GifMapEntry *entry = FindNode(string); + if (((m_unk4 == entry || strcmp(string, entry->m_key) > 0) ? m_unk4 : entry) != entry) + ret = entry->m_value; + return ret; + } + + undefined4 m_unk0; + GifMapEntry *m_unk4; +}; + +// VTABLE 0x100d86d4 +class GifManagerBase +{ +public: + // OFFSET: LEGO1 0x1005a310 STUB + virtual ~GifManagerBase() {} // vtable+00 + + inline GifData *Get(const char *name) { return m_unk8.Get(name); } + +protected: + undefined4 m_unk0; + undefined4 m_unk4; + GifMap m_unk8; +}; + +// VTABLE 0x100d86fc +class GifManager : public GifManagerBase +{ +public: + // OFFSET: LEGO1 0x1005a580 STUB + virtual ~GifManager() {} // vtable+00 + +protected: + undefined m_unk[0x1c]; +}; + +#endif // GIFMANAGER_H \ No newline at end of file diff --git a/LEGO1/legocontrolmanager.cpp b/LEGO1/legocontrolmanager.cpp index 91ff8c39..49d4ba83 100644 --- a/LEGO1/legocontrolmanager.cpp +++ b/LEGO1/legocontrolmanager.cpp @@ -19,3 +19,15 @@ MxResult LegoControlManager::Tickle() return 0; } + +// OFFSET: LEGO1 0x10028e10 STUB +void LegoControlManager::Register(MxCore *p_listener) +{ + // TODO +} + +// OFFSET: LEGO1 0x10028ea0 STUB +void LegoControlManager::Unregister(MxCore *p_listener) +{ + // TODO +} diff --git a/LEGO1/legocontrolmanager.h b/LEGO1/legocontrolmanager.h index 0088ac0f..b293d8a6 100644 --- a/LEGO1/legocontrolmanager.h +++ b/LEGO1/legocontrolmanager.h @@ -25,6 +25,8 @@ public: return !strcmp(name, LegoControlManager::ClassName()) || MxCore::IsA(name); } + void Register(MxCore *p_listener); + void Unregister(MxCore *p_listener); }; #endif // LEGOCONTROLMANAGER_H diff --git a/LEGO1/legoentity.cpp b/LEGO1/legoentity.cpp index c4e52dd1..99b8e849 100644 --- a/LEGO1/legoentity.cpp +++ b/LEGO1/legoentity.cpp @@ -37,10 +37,10 @@ void LegoEntity::Reset() } // OFFSET: LEGO1 0x100107e0 -MxResult LegoEntity::InitFromMxDSObject(MxDSObject& p_object) +MxResult LegoEntity::InitFromMxDSObject(MxDSObject &p_dsObject) { - m_mxEntityId = p_object.GetObjectId(); - m_atom = p_object.GetAtomId(); + m_mxEntityId = p_dsObject.GetObjectId(); + m_atom = p_dsObject.GetAtomId(); AddToCurrentWorld(); return SUCCESS; } @@ -88,3 +88,63 @@ void LegoEntity::ParseAction(char *p_extra) } } } + +// OFFSET: LEGO1 0x100108a0 STUB +void LegoEntity::VTable0x24() +{ + // TODO +} + +// OFFSET: LEGO1 0x10010790 STUB +void LegoEntity::VTable0x28() +{ + // TODO +} + +// OFFSET: LEGO1 0x10010650 STUB +void LegoEntity::VTable0x2c() +{ + // TODO +} + +// OFFSET: LEGO1 0x10010f10 STUB +void LegoEntity::VTable0x34() +{ + // TODO +} + +// OFFSET: LEGO1 0x10011070 STUB +void LegoEntity::VTable0x38() +{ + // TODO +} + +// OFFSET: LEGO1 0x10011300 STUB +void LegoEntity::VTable0x3c() +{ + // TODO +} + +// OFFSET: LEGO1 0x10011360 STUB +void LegoEntity::VTable0x40() +{ + // TODO +} + +// OFFSET: LEGO1 0x100113c0 STUB +void LegoEntity::VTable0x44() +{ + // TODO +} + +// OFFSET: LEGO1 0x10011420 STUB +void LegoEntity::VTable0x48() +{ + // TODO +} + +// OFFSET: LEGO1 0x10011470 STUB +void LegoEntity::VTable0x4c() +{ + // TODO +} \ No newline at end of file diff --git a/LEGO1/legoentity.h b/LEGO1/legoentity.h index fc5117ea..0dbbf8df 100644 --- a/LEGO1/legoentity.h +++ b/LEGO1/legoentity.h @@ -35,9 +35,21 @@ public: return !strcmp(name, LegoEntity::ClassName()) || MxEntity::IsA(name); } - virtual MxResult InitFromMxDSObject(MxDSObject& p_object); // vtable+0x18 + virtual MxResult InitFromMxDSObject(MxDSObject &p_dsObject); // vtable+0x18 virtual void Destroy(MxBool p_fromDestructor); // vtable+0x1c virtual void ParseAction(char *); // vtable+0x20 + virtual void VTable0x24(); // vtable+0x24 + virtual void VTable0x28(); // vtable+0x28 + virtual void VTable0x2c(); // vtable+0x2c + // OFFSET: LEGO1 0x10001090 + virtual void VTable0x30(undefined4 p_unk50) { m_unk50 = p_unk50; } // vtable+0x30 + virtual void VTable0x34(); // vtable+0x34 + virtual void VTable0x38(); // vtable+0x38 + virtual void VTable0x3c(); // vtable+0x3c + virtual void VTable0x40(); // vtable+0x40 + virtual void VTable0x44(); // vtable+0x44 + virtual void VTable0x48(); // vtable+0x48 + virtual void VTable0x4c(); // vtable+0x4c protected: void Reset(); @@ -57,7 +69,6 @@ protected: ExtraActionType m_actionType; // 0x5c char *m_actionArgString; // 0x60 MxS32 m_actionArgNumber; // 0x64 - }; #endif // LEGOENTITY_H diff --git a/LEGO1/legogamestate.cpp b/LEGO1/legogamestate.cpp index ca1595c7..6891bbcd 100644 --- a/LEGO1/legogamestate.cpp +++ b/LEGO1/legogamestate.cpp @@ -233,4 +233,16 @@ void LegoGameState::RegisterState(LegoState *p_state) if (m_stateArray[targetIndex]) delete m_stateArray[targetIndex]; m_stateArray[targetIndex] = p_state; +} + +// OFFSET: LEGO1 0x1003a720 STUB +void LegoGameState::FUN_1003a720(MxU32 p_unk) +{ + // TODO +} + +// OFFSET: LEGO1 0x1003b060 STUB +void LegoGameState::HandleAction(MxU32 p_unk) +{ + // TODO } \ No newline at end of file diff --git a/LEGO1/legogamestate.h b/LEGO1/legogamestate.h index 8dc0be4a..050b1100 100644 --- a/LEGO1/legogamestate.h +++ b/LEGO1/legogamestate.h @@ -33,6 +33,10 @@ public: LegoState *CreateState(char *p_stateName); void GetFileSavePath(MxString *p_outPath, MxULong p_slotn); + void FUN_1003a720(MxU32 p_unk); + void HandleAction(MxU32 p_unk); + + inline void SetUnknown424(undefined4 p_unk424) { m_unk424 = p_unk424; } private: void RegisterState(LegoState *p_state); @@ -49,7 +53,10 @@ private: LegoBackgroundColor *m_tempBackgroundColor; // 0x1c LegoFullScreenMovie *m_fullScreenMovie; // 0x20 MxU16 m_unk24; // 0x24 - undefined m_unk28[1032]; + undefined m_unk28[1020]; + undefined4 m_unk424; + undefined4 m_unk428; + undefined4 m_unk42c; }; #endif // LEGOGAMESTATE_H diff --git a/LEGO1/legoinputmanager.cpp b/LEGO1/legoinputmanager.cpp index 3aaaec76..19feff1d 100644 --- a/LEGO1/legoinputmanager.cpp +++ b/LEGO1/legoinputmanager.cpp @@ -10,8 +10,8 @@ DECOMP_SIZE_ASSERT(LegoInputManager, 0x338); LegoInputManager::LegoInputManager() { m_unk0x5c = NULL; - m_unk0x64 = 0; - m_unk0x60 = 0; + m_world = NULL; + m_camera = NULL; m_unk0x68 = NULL; m_unk0x80 = 0; m_timer = 0; @@ -184,6 +184,30 @@ void LegoInputManager::UnRegister(MxCore *) // TODO } +// OFFSET: LEGO1 0x1005c700 +void LegoInputManager::SetCamera(LegoCameraController *p_camera) +{ + m_camera = p_camera; +} + +// OFFSET: LEGO1 0x1005c710 +void LegoInputManager::ClearCamera() +{ + m_camera = NULL; +} + +// OFFSET: LEGO1 0x1005c720 +void LegoInputManager::SetWorld(LegoWorld *p_world) +{ + m_world = p_world; +} + +// OFFSET: LEGO1 0x1005c730 +void LegoInputManager::ClearWorld() +{ + m_world = NULL; +} + // OFFSET: LEGO1 0x1005c740 STUB void LegoInputManager::QueueEvent(NotificationId id, unsigned char p2, MxLong p3, MxLong p4, unsigned char p5) { @@ -205,4 +229,4 @@ void LegoInputManager::KillTimer() LegoOmni* omni = LegoOmni::GetInstance(); ::KillTimer(omni->GetWindowHandle(), m_timer); } -} +} \ No newline at end of file diff --git a/LEGO1/legoinputmanager.h b/LEGO1/legoinputmanager.h index d2fe26de..4a31221d 100644 --- a/LEGO1/legoinputmanager.h +++ b/LEGO1/legoinputmanager.h @@ -2,6 +2,7 @@ #define LEGOINPUTMANAGER_H #include "decomp.h" +#include "legoworld.h" #include "mxpresenter.h" #include "mxlist.h" @@ -40,14 +41,22 @@ public: MxResult GetJoystickState(MxU32 *joystick_x, MxU32 *joystick_y, DWORD *buttons_state, MxU32 *pov_position); void SetTimer(); void KillTimer(); + void SetCamera(LegoCameraController *p_camera); + void ClearCamera(); + void SetWorld(LegoWorld *p_world); + void ClearWorld(); + + inline void SetUnknown88(MxBool p_unk0x88) { m_unk0x88 = p_unk0x88; } + inline void SetUnknown336(MxBool p_unk0x336) { m_unk0x336 = p_unk0x336; } inline LegoControlManager *GetControlManager() { return m_controlManager; } + inline LegoWorld *GetWorld() { return m_world; } //private: MxCriticalSection m_criticalSection; MxList *m_unk0x5c; // list or hash table - undefined4 m_unk0x60; - undefined4 m_unk0x64; + LegoCameraController *m_camera; + LegoWorld *m_world; MxList *m_unk0x68; // list or hash table undefined4 m_unk0x6c; undefined4 m_unk0x70; diff --git a/LEGO1/legoomni.cpp b/LEGO1/legoomni.cpp index 8786145e..c02877d9 100644 --- a/LEGO1/legoomni.cpp +++ b/LEGO1/legoomni.cpp @@ -269,7 +269,7 @@ void LegoOmni::Init() m_unk68 = 0; m_inputMgr = NULL; m_unk6c = 0; - m_unk74 = 0; + m_gifManager = NULL; m_unk78 = 0; m_currentWorld = NULL; m_unk80 = FALSE; @@ -361,3 +361,9 @@ LegoWorld *GetCurrentWorld() { return LegoOmni::GetInstance()->GetCurrentWorld(); } + +// OFFSET: LEGO1 0x10015800 +GifManager *GetGifManager() +{ + return LegoOmni::GetInstance()->GetGifManager(); +} \ No newline at end of file diff --git a/LEGO1/legoomni.h b/LEGO1/legoomni.h index 8a61c2df..a1ee22cd 100644 --- a/LEGO1/legoomni.h +++ b/LEGO1/legoomni.h @@ -5,9 +5,11 @@ #include "mxomni.h" #include "mxdsaction.h" +class GifManager; class Isle; class LegoAnimationManager; class LegoBuildingManager; +class LegoControlManager; class LegoEntity; class LegoGameState; class LegoInputManager; @@ -76,12 +78,13 @@ public: LegoNavController *GetNavController() { return m_navController; } MxTransitionManager *GetTransitionManager() { return m_transitionManager; } LegoWorld *GetCurrentWorld() { return m_currentWorld; } + GifManager *GetGifManager() { return m_gifManager; } private: undefined4 m_unk68; undefined4 m_unk6c; LegoInputManager *m_inputMgr; // 0x70 - undefined4 m_unk74; + GifManager *m_gifManager; undefined4 m_unk78; LegoWorld *m_currentWorld; MxBool m_unk80; @@ -114,9 +117,11 @@ __declspec(dllexport) MxTransitionManager * TransitionManager(); __declspec(dllexport) LegoVideoManager * VideoManager(); LegoBuildingManager* BuildingManager(); +LegoControlManager* ControlManager(); Isle* GetIsle(); LegoPlantManager* PlantManager(); MxBool KeyValueStringParse(char *, const char *, const char *); LegoWorld *GetCurrentWorld(); +GifManager *GetGifManager(); #endif // LEGOOMNI_H diff --git a/LEGO1/legoworld.cpp b/LEGO1/legoworld.cpp index 68009d43..7f4c8c34 100644 --- a/LEGO1/legoworld.cpp +++ b/LEGO1/legoworld.cpp @@ -1,4 +1,11 @@ #include "legoworld.h" +#include "legoomni.h" +#include "legoinputmanager.h" +#include "mxticklemanager.h" + +DECOMP_SIZE_ASSERT(LegoWorld, 0xf8); + +MxBool g_isWorldActive; // OFFSET: LEGO1 0x1001ca40 STUB LegoWorld::LegoWorld() @@ -11,3 +18,71 @@ LegoWorld::~LegoWorld() { // TODO } + +// OFFSET: LEGO1 0x10022340 +void LegoWorld::Stop() +{ + TickleManager()->UnregisterClient(this); +} + +// OFFSET: LEGO1 0x1001f630 STUB +void LegoWorld::VTable0x54() +{ + // TODO +} + +// OFFSET: LEGO1 0x10020220 STUB +void LegoWorld::VTable0x58() +{ + // TODO +} + +// OFFSET: LEGO1 0x1001d670 +MxBool LegoWorld::VTable0x5c() +{ + return FALSE; +} + +// OFFSET: LEGO1 0x100010a0 +void LegoWorld::VTable0x60() +{ +} + +// OFFSET: LEGO1 0x1001d680 +MxBool LegoWorld::VTable0x64() +{ + return FALSE; +} + +// OFFSET: LEGO1 0x10021a70 STUB +void LegoWorld::VTable0x68(MxBool p_add) +{ + // TODO +} + +// OFFSET: LEGO1 0x1001e0b0 STUB +MxResult LegoWorld::SetAsCurrentWorld(MxDSObject &p_dsObject) +{ + // TODO + return SUCCESS; +} + +// OFFSET: LEGO1 0x10015820 STUB +void FUN_10015820(MxU32 p_unk1, MxU32 p_unk2) +{ + // TODO +} + +// OFFSET: LEGO1 0x10015910 STUB +void FUN_10015910(MxU32 p_unk1) +{ + // TODO +} + +// OFFSET: LEGO1 0x100159c0 +void SetIsWorldActive(MxBool p_isWorldActive) +{ + if (!p_isWorldActive) + LegoOmni::GetInstance()->GetInputManager()->SetCamera(NULL); + g_isWorldActive = p_isWorldActive; +} \ No newline at end of file diff --git a/LEGO1/legoworld.h b/LEGO1/legoworld.h index d6170bfc..5c404804 100644 --- a/LEGO1/legoworld.h +++ b/LEGO1/legoworld.h @@ -2,6 +2,7 @@ #define LEGOWORLD_H #include "legoentity.h" +#include "legocameracontroller.h" // VTABLE 0x100d6280 // SIZE 0xf8 @@ -23,6 +24,27 @@ public: { return !strcmp(name, LegoWorld::ClassName()) || LegoEntity::IsA(name); } + + virtual void Stop(); // vtable+50 + virtual void VTable0x54(); // vtable+54 + virtual void VTable0x58(); // vtable+58 + virtual MxBool VTable0x5c(); // vtable+5c + virtual void VTable0x60(); // vtable+60 + virtual MxBool VTable0x64(); // vtable+64 + virtual void VTable0x68(MxBool p_add); // vtable+68 + + MxResult SetAsCurrentWorld(MxDSObject &p_dsObject); + +protected: + undefined m_unk68[0x30]; + LegoCameraController *m_camera; + undefined m_unk9c[0x5a]; + undefined m_unkf6; + undefined m_unkf7; }; +void FUN_10015820(MxU32 p_unk1, MxU32 p_unk2); +void FUN_10015910(MxU32 p_unk1); +void SetIsWorldActive(MxBool p_isWorldActive); + #endif // LEGOWORLD_H diff --git a/LEGO1/mxactionnotificationparam.h b/LEGO1/mxactionnotificationparam.h index 4229e252..ecf70ed1 100644 --- a/LEGO1/mxactionnotificationparam.h +++ b/LEGO1/mxactionnotificationparam.h @@ -38,6 +38,8 @@ public: virtual MxNotificationParam *Clone() override; // vtable+0x4 + inline MxDSAction *GetAction() { return m_action; } + protected: MxDSAction *m_action; // 0xc MxBool m_realloc; // 0x10 diff --git a/LEGO1/mxappnotificationparam.cpp b/LEGO1/mxappnotificationparam.cpp new file mode 100644 index 00000000..fd12ba47 --- /dev/null +++ b/LEGO1/mxappnotificationparam.cpp @@ -0,0 +1,3 @@ +#include "mxappnotificationparam.h" + +DECOMP_SIZE_ASSERT(MxAppNotificationParam, 0x1c) \ No newline at end of file diff --git a/LEGO1/mxappnotificationparam.h b/LEGO1/mxappnotificationparam.h new file mode 100644 index 00000000..d248f32a --- /dev/null +++ b/LEGO1/mxappnotificationparam.h @@ -0,0 +1,22 @@ +#ifndef MXAPPNOTIFICATIONPARAM_H +#define MXAPPNOTIFICATIONPARAM_H + +#include "mxnotificationparam.h" + +#include "decomp.h" + +// VTABLE 0x100d6aa0 +class MxAppNotificationParam : public MxNotificationParam +{ +public: + inline MxAppNotificationParam() : MxNotificationParam((MxParamType) 0, NULL) {} + + virtual ~MxAppNotificationParam() override {} // vtable+0x0 (scalar deleting destructor) + inline MxU8 GetUnknown18() { return m_unk18; } + +protected: + undefined m_unkc[0xc]; + MxU8 m_unk18; +}; + +#endif // MXAPPNOTIFICATIONPARAM_H \ No newline at end of file diff --git a/LEGO1/mxdsaction.cpp b/LEGO1/mxdsaction.cpp index 3ba421e5..846149a4 100644 --- a/LEGO1/mxdsaction.cpp +++ b/LEGO1/mxdsaction.cpp @@ -26,7 +26,7 @@ MxDSAction::MxDSAction() this->m_location.Fill(FLT_MAX); this->m_direction.Fill(FLT_MAX); this->m_up.Fill(FLT_MAX); - this->m_unk84 = 0; + this->m_unk84 = NULL; this->m_unk88 = 0; this->m_omni = NULL; this->m_unkTimingField = INT_MIN; diff --git a/LEGO1/mxdsaction.h b/LEGO1/mxdsaction.h index 868ae002..dbbd1fa3 100644 --- a/LEGO1/mxdsaction.h +++ b/LEGO1/mxdsaction.h @@ -62,6 +62,7 @@ public: inline MxS32 GetLoopCount() { return m_loopCount; } inline void SetLoopCount(MxS32 p_loopCount) { m_loopCount = p_loopCount; } inline const MxVector3Data &GetLocation() const { return m_location; } + inline void SetUnknown84(MxCore *p_unk84) { m_unk84 = p_unk84; } inline void SetOmni(MxOmni *p_omni) { m_omni = p_omni; } inline MxBool IsLooping() const { return m_flags & Flag_Looping; } @@ -82,7 +83,7 @@ private: MxVector3Data m_up; char *m_extraData; MxU16 m_extraLength; - undefined4 m_unk84; + MxCore *m_unk84; undefined4 m_unk88; MxOmni *m_omni; // 0x8c diff --git a/LEGO1/mxentity.h b/LEGO1/mxentity.h index 2585f342..c897732d 100644 --- a/LEGO1/mxentity.h +++ b/LEGO1/mxentity.h @@ -28,6 +28,7 @@ public: } virtual MxResult SetEntityId(MxS32 p_id, const MxAtomId &p_atom); // vtable+0x14 + protected: MxS32 m_mxEntityId; // 0x8 MxAtomId m_atom; // 0xc diff --git a/LEGO1/mxnotificationparam.h b/LEGO1/mxnotificationparam.h index a02f33d8..a57de83b 100644 --- a/LEGO1/mxnotificationparam.h +++ b/LEGO1/mxnotificationparam.h @@ -9,9 +9,25 @@ class MxCore; enum MxParamType { - MXSTREAMER_UNKNOWN = 2, + PARAM_NONE = 0, + PAINT = 1, // 100dc210:100d8350 + MXSTREAMER_UNKNOWN = 2, // 100d8358:100d8350 + TYPE4 = 4, // 100dc208:100d8350 MXPRESENTER_NOTIFICATION = 5, - MXSTREAMER_DELETE_NOTIFY = 6, + MXSTREAMER_DELETE_NOTIFY = 6, // 100dc760 + APP_MESSAGE = 7, // 100d6aa0 + MOUSE_RELEASE = 8, // 100d6aa0 + MOUSE_PRESS = 9, // 100d6aa0 + MOUSE_MOVE = 10, // 100d6aa0 + TYPE11 = 11, // 100d6aa0 + PARAM_TIMER = 15, // 100d6aa0 + TYPE17 = 17, + TYPE18 = 18, // 100d7e80 + TYPE19 = 19, // 100d6230 + TYPE20 = 20, + TYPE21 = 21, + TYPE22 = 22, + TYPE23 = 23, MXTRANSITIONMANAGER_TRANSITIONENDED = 24 }; diff --git a/LEGO1/mxomni.cpp b/LEGO1/mxomni.cpp index 0265cc74..167791ad 100644 --- a/LEGO1/mxomni.cpp +++ b/LEGO1/mxomni.cpp @@ -408,4 +408,18 @@ MxEventManager* EventManager() MxResult DeleteObject(MxDSAction &p_dsAction) { return MxOmni::GetInstance()->DeleteObject(p_dsAction); -} \ No newline at end of file +} + +// OFFSET: LEGO1 0x100159e0 +void DeleteObjects(MxAtomId *p_id, MxS32 p_first, MxS32 p_last) +{ + MxDSAction action; + + action.SetAtomId(*p_id); + action.SetUnknown24(-2); + + for (MxS32 l_first = p_first, l_last = p_last; l_first <= l_last; l_first++) { + action.SetObjectId(l_first); + DeleteObject(action); + } +} diff --git a/LEGO1/mxomni.h b/LEGO1/mxomni.h index 430c0fe6..970eb4f3 100644 --- a/LEGO1/mxomni.h +++ b/LEGO1/mxomni.h @@ -5,6 +5,7 @@ #include "mxstring.h" #include "mxcriticalsection.h" +class MxAtomId; class MxAtomIdCounterSet; class MxDSAction; class MxEventManager; @@ -99,5 +100,7 @@ MxResult DeleteObject(MxDSAction &p_dsAction); MxVideoManager *MVideoManager(); MxAtomIdCounterSet *AtomIdCounterSet(); MxObjectFactory *ObjectFactory(); +MxResult DeleteObject(MxDSAction &p_dsAction); +void DeleteObjects(MxAtomId *p_id, MxS32 p_first, MxS32 p_last); #endif // MXOMNI_H diff --git a/LEGO1/mxtype17notificationparam.cpp b/LEGO1/mxtype17notificationparam.cpp new file mode 100644 index 00000000..50cc1294 --- /dev/null +++ b/LEGO1/mxtype17notificationparam.cpp @@ -0,0 +1,3 @@ +#include "mxtype17notificationparam.h" + +DECOMP_SIZE_ASSERT(MxType17NotificationParam, 0x2c) \ No newline at end of file diff --git a/LEGO1/mxtype17notificationparam.h b/LEGO1/mxtype17notificationparam.h new file mode 100644 index 00000000..747d602b --- /dev/null +++ b/LEGO1/mxtype17notificationparam.h @@ -0,0 +1,22 @@ +#ifndef MXTYPE17NOTIFICATIONPARAM_H +#define MXTYPE17NOTIFICATIONPARAM_H + +#include "mxnotificationparam.h" + +#include "decomp.h" + +// ??? This type is handled, but seemingly never created and no VTABLE fits +class MxType17NotificationParam : public MxNotificationParam +{ +public: + inline MxU32 GetUnknown20() { return m_unk20; } + inline MxU16 GetUnknown28() { return m_unk28; } + +protected: + undefined m_unkc[0x14]; + MxU32 m_unk20; + undefined4 m_unk24; + MxU16 m_unk28; +}; + +#endif // MXTYPE17NOTIFICATIONPARAM_H \ No newline at end of file diff --git a/LEGO1/pizzamissionstate.cpp b/LEGO1/pizzamissionstate.cpp index 5dc85dcc..4851ab93 100644 --- a/LEGO1/pizzamissionstate.cpp +++ b/LEGO1/pizzamissionstate.cpp @@ -1 +1,13 @@ #include "pizzamissionstate.h" + +DECOMP_SIZE_ASSERT(PizzaMissionStateEntry, 0x20) +DECOMP_SIZE_ASSERT(PizzaMissionState, 0xb0) + +// OFFSET: LEGO1 0x10039510 +PizzaMissionStateEntry *PizzaMissionState::GetState(MxU8 id) +{ + for (MxS16 i = 0; i < 5; i++) + if (m_state[i].m_id == id) + return m_state + i; + return NULL; +} \ No newline at end of file diff --git a/LEGO1/pizzamissionstate.h b/LEGO1/pizzamissionstate.h index 575c4972..6c6d1107 100644 --- a/LEGO1/pizzamissionstate.h +++ b/LEGO1/pizzamissionstate.h @@ -3,6 +3,16 @@ #include "legostate.h" +struct PizzaMissionStateEntry +{ +public: + undefined2 m_unk0; + MxU8 m_id; + undefined m_unk3[0x15]; + MxU16 m_color; + undefined m_unk18[6]; +}; + // VTABLE 0x100d7408 class PizzaMissionState : public LegoState { @@ -20,6 +30,15 @@ public: return !strcmp(name, PizzaMissionState::ClassName()) || LegoState::IsA(name); } + inline MxU16 GetColor(MxU8 id) { return GetState(id)->m_color; } + +private: + PizzaMissionStateEntry *GetState(MxU8 id); + +protected: + undefined4 m_unk8; + undefined4 m_unkc; + PizzaMissionStateEntry m_state[5]; }; #endif // PIZZAMISSIONSTATE_H diff --git a/LEGO1/racestate.cpp b/LEGO1/racestate.cpp index 4eeb21b7..373c4554 100644 --- a/LEGO1/racestate.cpp +++ b/LEGO1/racestate.cpp @@ -1,7 +1,23 @@ #include "racestate.h" +DECOMP_SIZE_ASSERT(RaceStateEntry, 0x06) + +// TODO: Must be 0x2c but current structure is incorrect +// DECOMP_SIZE_ASSERT(RaceState, 0x2c) + // OFFSET: LEGO1 0x10015f30 STUB RaceState::RaceState() { // TODO } + +// OFFSET: LEGO1 0x10016280 +RaceStateEntry *RaceState::GetState(MxU8 id) +{ + for (MxS16 i = 0;; i++) { + if (i >= 5) + return NULL; + if (m_state[i].m_id == id) + return m_state + i; + } +} \ No newline at end of file diff --git a/LEGO1/racestate.h b/LEGO1/racestate.h index b9415051..c5138fad 100644 --- a/LEGO1/racestate.h +++ b/LEGO1/racestate.h @@ -3,8 +3,17 @@ #include "legostate.h" +struct RaceStateEntry +{ +public: + MxU8 m_id; + undefined m_unk1[1]; + MxU16 m_unk2; + MxU16 m_color; +}; + // VTABLE 0x100d5e30 -// SIZE probably 0x2c +// SIZE 0x2c class RaceState : public LegoState { public: @@ -23,6 +32,15 @@ public: return !strcmp(name, RaceState::ClassName()) || LegoState::IsA(name); } + inline MxU16 GetColor(MxU8 id) { return GetState(id)->m_color; } + +private: + RaceStateEntry *GetState(MxU8 id); + +protected: + RaceStateEntry m_state[5]; + undefined2 m_unk26[2]; + undefined4 m_unk28; }; #endif // RACESTATE_H diff --git a/LEGO1/score.cpp b/LEGO1/score.cpp index fc4070f7..15b32820 100644 --- a/LEGO1/score.cpp +++ b/LEGO1/score.cpp @@ -1,21 +1,333 @@ #include "score.h" +#include "gifmanager.h" +#include "ambulancemissionstate.h" +#include "mxnotificationmanager.h" +#include "mxnotificationparam.h" +#include "mxtransitionmanager.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" +#include "legoinputmanager.h" +#include "legoomni.h" +#include "pizzamissionstate.h" +#include "racestate.h" +#include "towtrackmissionstate.h" -// OFFSET: LEGO1 0x10001000 STUB +DECOMP_SIZE_ASSERT(Score, 0x104) + +MxAtomId *g_infoscorScript; + +// OFFSET: LEGO1 0x10001000 Score::Score() { - // TODO + m_unkf8 = 0; + NotificationManager()->Register(this); } -// OFFSET: LEGO1 0x10001200 STUB +// OFFSET: LEGO1 0x10001200 Score::~Score() { - // TODO + if (InputManager()->GetWorld() == this) + InputManager()->ClearWorld(); + InputManager()->UnRegister(this); + ControlManager()->Unregister(this); + NotificationManager()->Unregister(this); } -// OFFSET: LEGO1 0x10001410 STUB +// OFFSET: LEGO1 0x10001410 MxLong Score::Notify(MxParam &p) { - // TODO - - return 0; + MxLong ret = 0; + LegoWorld::Notify(p); + if (m_unkf6) { + switch (((MxNotificationParam &)p).GetType()) + { + case PAINT: + ret = 1; + Paint(); + break; + case MXSTREAMER_UNKNOWN: + ret = FUN_10001510((MxEndActionNotificationParam &)p); + break; + case APP_MESSAGE: + if (((MxAppNotificationParam &)p).GetUnknown18() == 0x20) + DeleteScript(); // Shutting down + ret = 1; + break; + case TYPE17: + ret = FUN_100016d0((MxType17NotificationParam &)p); + break; + case MXTRANSITIONMANAGER_TRANSITIONENDED: + DeleteObjects(g_infoscorScript, 7, 9); + if (m_unkf8) + GameState()->HandleAction(m_unkf8); + ret = 1; + break; + default: + break; + } + } + return ret; } + +// OFFSET: LEGO1 0x100010b0 +MxBool Score::VTable0x5c() +{ + return TRUE; +} + +// OFFSET: LEGO1 0x100012a0 +MxResult Score::InitFromMxDSObject(MxDSObject &p_dsObject) +{ + MxResult result = SetAsCurrentWorld(p_dsObject); + + if (result == SUCCESS) { + InputManager()->SetWorld(this); + ControlManager()->Register(this); + InputManager()->Register(this); + SetIsWorldActive(FALSE); + LegoGameState *gs = GameState(); + ScoreState *state = (ScoreState *)gs->GetState("ScoreState"); + m_state = state ? state : (ScoreState *)gs->CreateState("ScoreState"); + GameState()->SetUnknown424(0xd); + GameState()->FUN_1003a720(0); + } + + return result; +} + +// OFFSET: LEGO1 0x10001340 +void Score::DeleteScript() +{ + if (m_state->GetTutorialFlag()) { + MxDSAction action; + action.SetObjectId(0x1f5); + action.SetAtomId(*g_infoscorScript); + action.SetUnknown24(-2); + DeleteObject(action); + m_state->SetTutorialFlag(FALSE); + } +} + +// OFFSET: LEGO1 0x10001510 +MxLong Score::FUN_10001510(MxEndActionNotificationParam &p) +{ + MxDSAction *action = p.GetAction(); + + if (m_atom == action->GetAtomId()) { + MxU32 id = action->GetObjectId(); + switch (action->GetObjectId()) { + case 10: + m_unkf8 = 0x38; + TransitionManager()->StartTransition(MxTransitionManager::PIXELATION, 0x32, 0, 0); + break; + case 0x1f5: + FUN_10015910(0xb); + m_state->SetTutorialFlag(FALSE); + } + } + + return 1; +} + +// OFFSET: LEGO1 0x10001580 +void Score::Stop() +{ + LegoWorld::Stop(); + + MxDSAction action; + action.SetObjectId(0x1f4); + action.SetAtomId(m_atom); + action.SetUnknown84(this); + Start(&action); + + if (m_state->GetTutorialFlag()) { + MxDSAction action2; + action.SetObjectId(0x1f5); + action.SetAtomId(*g_infoscorScript); + Start(&action); + } + else + FUN_10015910(0xb); + + FUN_10015820(0, 7); +} + +// OFFSET: LEGO1 0x100016d0 +MxLong Score::FUN_100016d0(MxType17NotificationParam &p) +{ + MxS16 l = p.GetUnknown28(); + + if (l == 1 || p.GetUnknown20() == 4) { + switch (p.GetUnknown20()) + { + case 1: + m_unkf8 = 2; + DeleteScript(); + TransitionManager()->StartTransition(MxTransitionManager::PIXELATION, 0x32, 0, 0); + break; + case 2: + m_unkf8 = 3; + DeleteScript(); + TransitionManager()->StartTransition(MxTransitionManager::PIXELATION, 0x32, 0, 0); + break; + case 3: + { + LegoInputManager *im = InputManager(); + im->SetUnknown88(TRUE); + im->SetUnknown336(FALSE); + DeleteScript(); + + MxDSAction action; + action.SetObjectId(10); + action.SetAtomId(*g_infoscorScript); + Start(&action); + break; + } + case 4: + { + switch (l) { + case 1: + { + MxDSAction action; + action.SetObjectId(7); + action.SetAtomId(*g_infoscorScript); + Start(&action); + break; + } + case 2: + { + MxDSAction action; + action.SetObjectId(8); + action.SetAtomId(*g_infoscorScript); + Start(&action); + break; + } + case 3: + { + MxDSAction action; + action.SetObjectId(9); + action.SetAtomId(*g_infoscorScript); + Start(&action); + break; + } + } + break; + } + } + } + + return 1; +} + +// OFFSET: LEGO1 0x10001980 +void Score::VTable0x68(MxBool p_add) +{ + LegoWorld::VTable0x68(p_add); + + if (p_add) { + InputManager()->SetWorld(this); + SetIsWorldActive(FALSE); + } + else if (InputManager()->GetWorld() == this) + InputManager()->ClearWorld(); +} + +// OFFSET: LEGO1 0x100019d0 +void Score::Paint() +{ + GifManager *gm = GetGifManager(); + GifData *gd = gm->Get("bigcube.gif"); + + if (gd) { + RaceState *l78 = (RaceState *)GameState()->GetState("JetskiRaceState"); + RaceState *l70 = (RaceState *)GameState()->GetState("CarRaceState"); + TowTrackMissionState *lesi = (TowTrackMissionState *)GameState()->GetState("TowTrackMissionState"); + PizzaMissionState *l74 = (PizzaMissionState *)GameState()->GetState("PizzaMissionState"); + AmbulanceMissionState *lebp = (AmbulanceMissionState *)GameState()->GetState("AmbulanceMissionState"); + + DDSURFACEDESC desc; + memset(&desc, 0, 0x6c); + desc.dwSize = 0x6c; + if (gd->m_surface->Lock(NULL, &desc, 0, NULL) == DD_OK) { + if (desc.lPitch != desc.dwWidth) { + gd->m_surface->Unlock(desc.lpSurface); + return; + } + + for (MxU8 id = 1; id <= 5; id++) { + m_surface = (MxU8 *)desc.lpSurface; + MxU16 color = 0; + if (l70) + color = l70->GetColor(id); + MxU32 row = id - 1; + FillArea(0, row, color); + color = 0; + if (l78) + color = l78->GetColor(id); + FillArea(1, row, color); + color = 0; + if (l74) + color = l74->GetColor(id); + FillArea(2, row, color); + color = 0; + if (lesi) + color = lesi->GetColor(id); + FillArea(3, row, color); + color = 0; + if (lebp) + color = lebp->GetColor(id); + FillArea(4, row, color); + } + + gd->m_surface->Unlock(desc.lpSurface); + gd->m_texture->Changed(TRUE, FALSE); + m_surface = NULL; + } + } +} + +// OFFSET: LEGO1 0x10001d20 +void Score::FillArea(MxU32 p_x, MxU32 p_y, MxS16 p_color) +{ + MxU32 data[24]; + data[9] = 0x2b00; + data[10] = 0x5700; + data[11] = 0x8000; + data[19] = 0x2a; + data[12] = 0xab00; + data[13] = 0xd600; + data[20] = 0x27; + data[21] = 0x29; + data[22] = 0x29; + data[23] = 0x2a; + data[4] = 0x2f; + data[5] = 0x56; + data[6] = 0x81; + data[15] = 0x29; + data[16] = 0x27; + data[7] = 0xaa; + data[8] = 0xd4; + data[14] = 0x25; + data[0] = 0x11; + data[17] = 0x28; + data[18] = 0x28; + data[1] = 0xf; + MxU32 size = data[p_x + 14]; + MxU8 *ptr = data[p_x + 4] + data[p_y + 9] + m_surface; + MxS32 count = data[p_y + 19]; + data[2] = 0x8; + data[3] = 0x5; + MxU32 value = data[p_color]; + for (; count > 0; count--) { + memset(ptr++, value, size); + ptr += 0x100; + } +} + +// OFFSET: LEGO1 0x10001e40 +MxBool Score::VTable0x64() +{ + DeleteScript(); + m_unkf8 = 2; + return TRUE; +} \ No newline at end of file diff --git a/LEGO1/score.h b/LEGO1/score.h index e103b4bc..844a4c02 100644 --- a/LEGO1/score.h +++ b/LEGO1/score.h @@ -2,6 +2,10 @@ #define SCORE_H #include "legoworld.h" +#include "scorestate.h" +#include "mxactionnotificationparam.h" +#include "mxappnotificationparam.h" +#include "mxtype17notificationparam.h" // VTABLE 0x100d4018 // SIZE 0x104 @@ -10,9 +14,39 @@ class Score : public LegoWorld public: Score(); virtual ~Score() override; // vtable+0x0 - virtual MxLong Notify(MxParam &p) override; // vtable+0x4 + + // OFFSET: LEGO1 0x100010c0 + inline virtual const char *ClassName() const override // vtable+0x0c + { + // 0x100f0058 + return "Score"; + } + // OFFSET: LEGO1 0x100010d0 + inline virtual MxBool IsA(const char *name) const override // vtable+0x10 + { + return !strcmp(name, Score::ClassName()) || LegoWorld::IsA(name); + } + + virtual MxResult InitFromMxDSObject(MxDSObject &p_dsObject) override; // vtable+18 + virtual void Stop() override; // vtable+50 + virtual MxBool VTable0x5c() override; // vtable+5c + virtual MxBool VTable0x64() override; // vtable+64 + virtual void VTable0x68(MxBool p_add) override; // vtable+68 + + void Paint(); + MxLong FUN_10001510(MxEndActionNotificationParam &p); + MxLong FUN_100016d0(MxType17NotificationParam &p); + void FillArea(MxU32 p_x, MxU32 p_y, MxS16 p_color); + +protected: + undefined4 m_unkf8; + ScoreState *m_state; + MxU8 *m_surface; + +private: + void DeleteScript(); }; #endif // SCORE_H diff --git a/LEGO1/scorestate.h b/LEGO1/scorestate.h index ac977d1f..4b9e25c1 100644 --- a/LEGO1/scorestate.h +++ b/LEGO1/scorestate.h @@ -24,8 +24,11 @@ public: virtual MxBool VTable0x14() override; // vtable+0x14 virtual MxBool SetFlag() override; // vtable+0x18 + inline MxBool GetTutorialFlag() { return m_playCubeTutorial; } + inline void SetTutorialFlag(MxBool p_playCubeTutorial) { m_playCubeTutorial = p_playCubeTutorial; } + private: - MxBool m_playCubeTutorial; + MxBool m_playCubeTutorial; }; #endif // SCORESTATE_H diff --git a/LEGO1/towtrackmissionstate.cpp b/LEGO1/towtrackmissionstate.cpp index b85c40cc..d0a9b434 100644 --- a/LEGO1/towtrackmissionstate.cpp +++ b/LEGO1/towtrackmissionstate.cpp @@ -1,5 +1,7 @@ #include "towtrackmissionstate.h" +DECOMP_SIZE_ASSERT(TowTrackMissionState, 0x28) + // OFFSET: LEGO1 0x1004dd30 STUB TowTrackMissionState::TowTrackMissionState() { diff --git a/LEGO1/towtrackmissionstate.h b/LEGO1/towtrackmissionstate.h index a335584f..ed4e8552 100644 --- a/LEGO1/towtrackmissionstate.h +++ b/LEGO1/towtrackmissionstate.h @@ -5,7 +5,7 @@ // VTABLE 0x100d7fd8 // SIZE 0x28 -class TowTrackMissionState : LegoState +class TowTrackMissionState : public LegoState { public: TowTrackMissionState(); @@ -15,14 +15,34 @@ public: { // 0x100f00bc return "TowTrackMissionState"; - }; + } // OFFSET: LEGO1 0x1004dfb0 inline virtual MxBool IsA(const char *name) const // vtable+0x10 { return !strcmp(name, TowTrackMissionState::ClassName()) || LegoState::IsA(name); - }; + } + inline MxU16 GetColor(MxU8 id) + { + switch (id) + { + case 1: return m_color1; + case 2: return m_color2; + case 3: return m_color3; + case 4: return m_color4; + case 5: return m_color5; + default: return 0; + } + } + +protected: + undefined m_unk8[0x14]; + MxU16 m_color1; + MxU16 m_color2; + MxU16 m_color3; + MxU16 m_color4; + MxU16 m_color5; }; #endif // TOWTRACKMISSIONSTATE_H