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 1d1ee26d..1f4090d2 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 @@ -177,6 +179,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/act2brick.cpp b/LEGO1/act2brick.cpp index dde79d0b..1ec4f139 100644 --- a/LEGO1/act2brick.cpp +++ b/LEGO1/act2brick.cpp @@ -25,5 +25,5 @@ MxResult Act2Brick::Tickle() { // TODO - return 0; + return SUCCESS; } 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/jukeboxstate.cpp b/LEGO1/jukeboxstate.cpp index 25b6dc90..d4a2511f 100644 --- a/LEGO1/jukeboxstate.cpp +++ b/LEGO1/jukeboxstate.cpp @@ -1 +1,6 @@ #include "jukeboxstate.h" + +// OFFSET: LEGO1 0x1000f300 +MxBool JukeBoxState::VTable0x14() { + return FALSE; +} diff --git a/LEGO1/jukeboxstate.h b/LEGO1/jukeboxstate.h index 75640fe3..d2b37e38 100644 --- a/LEGO1/jukeboxstate.h +++ b/LEGO1/jukeboxstate.h @@ -21,6 +21,8 @@ public: return !strcmp(name, JukeBoxState::ClassName()) || LegoState::IsA(name); } + virtual MxBool VTable0x14() override; // vtable+0x14 + }; #endif // JUKEBOXSTATE_H diff --git a/LEGO1/legoanimationmanager.cpp b/LEGO1/legoanimationmanager.cpp index 20e0a0e3..bf182ef5 100644 --- a/LEGO1/legoanimationmanager.cpp +++ b/LEGO1/legoanimationmanager.cpp @@ -27,7 +27,7 @@ MxResult LegoAnimationManager::Tickle() { // TODO - return 0; + return SUCCESS; } // OFFSET: LEGO1 0x1005f130 STUB 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 a44aef32..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,12 +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 7e306af1..c02877d9 100644 --- a/LEGO1/legoomni.cpp +++ b/LEGO1/legoomni.cpp @@ -5,10 +5,15 @@ #include "legogamestate.h" #include "legoutil.h" #include "legoobjectfactory.h" +#include "legoinputmanager.h" +#include "legoworld.h" // 0x100f4588 MxAtomId *g_nocdSourceName = NULL; +// 0x100f456c +MxAtomId *g_jukeboxScript = NULL; + // 0x101020e8 void (*g_omniUserMessage)(const char *,int); @@ -24,10 +29,11 @@ LegoOmni::~LegoOmni() Destroy(); } -// OFFSET: LEGO1 0x1005b560 STUB +// OFFSET: LEGO1 0x1005b560 void LegoOmni::CreateBackgroundAudio() { - // TODO + if (m_bkgAudioManager) + m_bkgAudioManager->Create(*g_jukeboxScript, 100); } // OFFSET: LEGO1 0x1005af10 STUB @@ -205,6 +211,12 @@ LegoInputManager *InputManager() return LegoOmni::GetInstance()->GetInputManager(); } +// OFFSET: LEGO1 0x10015750 +LegoControlManager *ControlManager() +{ + return LegoOmni::GetInstance()->GetInputManager()->GetControlManager(); +} + // OFFSET: LEGO1 0x10015760 LegoGameState *GameState() { @@ -257,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; @@ -300,9 +312,10 @@ MxResult LegoOmni::Start(MxDSAction* action) return result; } -void LegoOmni::DeleteObject(MxDSAction &ds) +MxResult LegoOmni::DeleteObject(MxDSAction &ds) { // FIXME: Stub + return FAILURE; } MxBool LegoOmni::DoesEntityExist(MxDSAction &ds) @@ -322,9 +335,11 @@ int LegoOmni::vtable0x30(char*, int, MxCore*) return 0; } -void LegoOmni::NotifyCurrentEntity() +// OFFSET: LEGO1 0x1005b3a0 +void LegoOmni::NotifyCurrentEntity(MxNotificationParam *p_param) { - // FIXME: Stub + if (m_currentWorld) + NotificationManager()->Send(m_currentWorld, p_param); } // OFFSET: LEGO1 0x1005b640 @@ -346,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 37d3ef4b..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; @@ -57,11 +59,11 @@ public: virtual MxResult Create(COMPAT_CONST MxOmniCreateParam &p) override; // vtable+18 virtual void Destroy() override; // vtable+1c virtual MxResult Start(MxDSAction* action) override; - virtual void DeleteObject(MxDSAction &ds) override; + virtual MxResult DeleteObject(MxDSAction &ds) override; virtual MxBool DoesEntityExist(MxDSAction &ds) override; virtual void vtable0x2c() override; virtual int vtable0x30(char*, int, MxCore*) override; - virtual void NotifyCurrentEntity() override; + virtual void NotifyCurrentEntity(MxNotificationParam *p_param) override; virtual void StartTimer() override; virtual void StopTimer() override; @@ -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/legopathcontroller.cpp b/LEGO1/legopathcontroller.cpp index f8b64109..94a6aa1d 100644 --- a/LEGO1/legopathcontroller.cpp +++ b/LEGO1/legopathcontroller.cpp @@ -16,5 +16,5 @@ LegoPathController::~LegoPathController() MxResult LegoPathController::Tickle() { // TODO - return 0; + return SUCCESS; } diff --git a/LEGO1/legosoundmanager.cpp b/LEGO1/legosoundmanager.cpp index 01f8fee5..cec30564 100644 --- a/LEGO1/legosoundmanager.cpp +++ b/LEGO1/legosoundmanager.cpp @@ -1,20 +1,48 @@ #include "legosoundmanager.h" +#include "mxautolocker.h" -// OFFSET: LEGO1 0x100298a0 STUB +// OFFSET: LEGO1 0x100298a0 LegoSoundManager::LegoSoundManager() { - // TODO + Init(); } -// OFFSET: LEGO1 0x10029940 STUB +// OFFSET: LEGO1 0x10029940 LegoSoundManager::~LegoSoundManager() { - // TODO + Destroy(TRUE); +} + +// OFFSET: LEGO1 0x1002a390 +void LegoSoundManager::Destroy() +{ + Destroy(FALSE); +} + +// OFFSET: LEGO1 0x100299b0 STUB +void LegoSoundManager::Destroy(MxBool p_fromDestructor) +{ + +} + +// OFFSET: LEGO1 0x100299f0 STUB +MxResult LegoSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) +{ + return FAILURE; +} + +// OFFSET: LEGO1 0x100299a0 +void LegoSoundManager::Init() +{ + unk0x40 = 0; + unk0x3c = 0; } // OFFSET: LEGO1 0x1002a3a0 STUB MxResult LegoSoundManager::Tickle() { - // TODO - return 0; + MxMediaManager::Tickle(); + MxAutoLocker lock(&this->m_criticalSection); + + return 0; // TODO: call something in unk0x40 } diff --git a/LEGO1/legosoundmanager.h b/LEGO1/legosoundmanager.h index 90e23fba..1f16f497 100644 --- a/LEGO1/legosoundmanager.h +++ b/LEGO1/legosoundmanager.h @@ -10,11 +10,17 @@ class LegoSoundManager : public MxSoundManager public: LegoSoundManager(); virtual ~LegoSoundManager() override; + virtual MxResult Tickle() override; // vtable+08 + virtual void Destroy() override; // vtable+18 + virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread) override; //vtable+0x30 private: void Init(); + void Destroy(MxBool p_fromDestructor); + undefined4 unk0x3c; + undefined4 unk0x40; }; #endif // LEGOSOUNDMANAGER_H diff --git a/LEGO1/legostate.cpp b/LEGO1/legostate.cpp index 4b808624..9342f4f2 100644 --- a/LEGO1/legostate.cpp +++ b/LEGO1/legostate.cpp @@ -13,7 +13,7 @@ MxBool LegoState::VTable0x14() { } // OFFSET: LEGO1 0x10005fa0 -MxBool LegoState::VTable0x18() { +MxBool LegoState::SetFlag() { return FALSE; } diff --git a/LEGO1/legostate.h b/LEGO1/legostate.h index 457e7964..67d781d1 100644 --- a/LEGO1/legostate.h +++ b/LEGO1/legostate.h @@ -27,7 +27,7 @@ public: } virtual MxBool VTable0x14(); // vtable+0x14 - virtual MxBool VTable0x18(); // vtable+0x18 + virtual MxBool SetFlag(); // vtable+0x18 virtual MxResult VTable0x1C(LegoFileStream *p_legoFileStream); // vtable+0x1C }; 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/mxbackgroundaudiomanager.cpp b/LEGO1/mxbackgroundaudiomanager.cpp index 40891bef..cbf480fc 100644 --- a/LEGO1/mxbackgroundaudiomanager.cpp +++ b/LEGO1/mxbackgroundaudiomanager.cpp @@ -1,6 +1,8 @@ #include "mxbackgroundaudiomanager.h" #include "mxomni.h" +#include "mxstreamer.h" +#include "mxticklemanager.h" DECOMP_SIZE_ASSERT(MxBackgroundAudioManager, 0x150) @@ -20,14 +22,29 @@ MxBackgroundAudioManager::MxBackgroundAudioManager() // OFFSET: LEGO1 0x1007ec20 MxBackgroundAudioManager::~MxBackgroundAudioManager() { - // TODO + TickleManager()->UnregisterClient(this); NotificationManager()->Unregister(this); + DestroyMusic(); } // OFFSET: LEGO1 0x1007f470 void MxBackgroundAudioManager::Stop() { - // TODO + if (m_action2.GetObjectId() != -1) + DeleteObject(m_action2); + + m_unk138 = 0; + m_action2.SetAtomId(MxAtomId()); + m_action2.SetObjectId(-1); + + if (m_action1.GetObjectId() != -1) + DeleteObject(m_action1); + + m_unka0 = 0; + m_action1.SetAtomId(MxAtomId()); + m_unk148 = 0; + m_action1.SetObjectId(-1); + m_unk13c = 0; } // OFFSET: LEGO1 0x1007f5f0 @@ -47,3 +64,45 @@ void MxBackgroundAudioManager::Init() this->m_unka0 = 0; this->m_unk13c = 0; } + +// OFFSET: LEGO1 0x1007ece0 +MxResult MxBackgroundAudioManager::Create(MxAtomId &p_script, MxU32 p_frequencyMS) +{ + MxResult result = OpenMusic(p_script); + + if (result == SUCCESS) { + TickleManager()->RegisterClient(this, p_frequencyMS); + m_musicEnabled = TRUE; + } + + return result; +} + +// OFFSET: LEGO1 0x1007ed20 +MxResult MxBackgroundAudioManager::OpenMusic(MxAtomId &p_script) +{ + if (m_script.GetInternal()) + DestroyMusic(); + + MxResult result = FAILURE; + + if (Streamer()->Open(p_script.GetInternal(), 0)) { + m_script = p_script; + result = SUCCESS; + } + + return result; +} + +// OFFSET: LEGO1 0x1007ed70 +void MxBackgroundAudioManager::DestroyMusic() +{ + if (m_script.GetInternal()) { + MxDSAction ds; + ds.SetAtomId(m_script); + ds.SetUnknown24(-2); + DeleteObject(ds); + Streamer()->Close(m_script.GetInternal()); + m_musicEnabled = FALSE; + } +} \ No newline at end of file diff --git a/LEGO1/mxbackgroundaudiomanager.h b/LEGO1/mxbackgroundaudiomanager.h index a2c4cae3..f81fe854 100644 --- a/LEGO1/mxbackgroundaudiomanager.h +++ b/LEGO1/mxbackgroundaudiomanager.h @@ -28,10 +28,13 @@ public: } __declspec(dllexport) void Enable(unsigned char p); + virtual MxResult Create(MxAtomId &p_script, MxU32 p_frequencyMS); void Stop(); private: void Init(); + MxResult OpenMusic(MxAtomId &p_script); + void DestroyMusic(); MxBool m_musicEnabled; // 0x8 MxDSAction m_action1; // 0xc @@ -42,7 +45,7 @@ private: MxS32 m_unk140; MxS32 m_unk144; MxS16 m_unk148; - MxAtomId m_unk14c; + MxAtomId m_script; }; #endif // MXBACKGROUNDAUDIOMANAGER_H diff --git a/LEGO1/mxbitmap.cpp b/LEGO1/mxbitmap.cpp index 8f33fc22..1128fded 100644 --- a/LEGO1/mxbitmap.cpp +++ b/LEGO1/mxbitmap.cpp @@ -369,7 +369,7 @@ MxResult MxBitmap::SetBitDepth(MxBool p_isHighColor) MxResult MxBitmap::StretchBits(HDC p_hdc, MxS32 p_xSrc, MxS32 p_ySrc, MxS32 p_xDest, MxS32 p_yDest, MxS32 p_destWidth, MxS32 p_destHeight) { // Compression fix? - if ((this->m_bmiHeader->biCompression != 16) && (0 < this->m_bmiHeader->biHeight)) { + if ((this->m_bmiHeader->biCompression != BI_RGB_TOPDOWN) && (0 < this->m_bmiHeader->biHeight)) { p_ySrc = (this->m_bmiHeader->biHeight - p_destHeight) - p_ySrc; } diff --git a/LEGO1/mxbitmap.h b/LEGO1/mxbitmap.h index 53b01e16..6bb1c5fd 100644 --- a/LEGO1/mxbitmap.h +++ b/LEGO1/mxbitmap.h @@ -21,6 +21,13 @@ struct MxBITMAPINFO { RGBQUAD bmiColors[256]; }; +// Non-standard value for biCompression in the BITMAPINFOHEADER struct. +// By default, uncompressed bitmaps (BI_RGB) are stored in bottom-up order. +// You can specify that the bitmap has top-down order instead by providing +// a negative number for biHeight. It could be that Mindscape decided on a +// belt & suspenders approach here. +#define BI_RGB_TOPDOWN 0x10 + // SIZE 0x20 // VTABLE 0x100dc7b0 class MxBitmap : public MxCore @@ -43,6 +50,10 @@ public: virtual MxResult StretchBits(HDC p_hdc, MxS32 p_xSrc, MxS32 p_ySrc, MxS32 p_xDest, MxS32 p_yDest, MxS32 p_destWidth, MxS32 p_destHeight); // vtable+40 inline BITMAPINFOHEADER *GetBmiHeader() const { return m_bmiHeader; } + inline MxLong GetBmiWidth() const { return m_bmiHeader->biWidth; } + inline MxLong GetBmiHeight() const { return m_bmiHeader->biHeight; } + inline MxLong GetBmiHeightAbs() const { return m_bmiHeader->biHeight > 0 ? m_bmiHeader->biHeight : -m_bmiHeader->biHeight; } + inline MxU8 *GetBitmapData() const { return m_data; } private: MxResult ImportColorsToPalette(RGBQUAD*, MxPalette*); diff --git a/LEGO1/mxdiskstreamcontroller.cpp b/LEGO1/mxdiskstreamcontroller.cpp index 0c74c3a7..0c1afedf 100644 --- a/LEGO1/mxdiskstreamcontroller.cpp +++ b/LEGO1/mxdiskstreamcontroller.cpp @@ -16,7 +16,7 @@ MxDiskStreamController::~MxDiskStreamController() MxResult MxDiskStreamController::Tickle() { // TODO - return 0; + return SUCCESS; } // OFFSET: LEGO1 0x100c7790 STUB 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/mxdsbuffer.cpp b/LEGO1/mxdsbuffer.cpp index 686627a4..b01be21a 100644 --- a/LEGO1/mxdsbuffer.cpp +++ b/LEGO1/mxdsbuffer.cpp @@ -1,9 +1,21 @@ #include "mxdsbuffer.h" +DECOMP_SIZE_ASSERT(MxDSBuffer, 0x34); + // OFFSET: LEGO1 0x100c6470 MxDSBuffer::MxDSBuffer() { - // TODO + m_unk20 = 0; + m_pBuffer = NULL; + m_pIntoBuffer = NULL; + m_pIntoBuffer2 = NULL; + m_unk14 = 0; + m_unk18 = 0; + m_unk1c = 0; + m_writeOffset = 0; + m_bytesRemaining = 0; + m_mode = 2; + m_unk30 = 0; } // OFFSET: LEGO1 0x100c6530 @@ -11,3 +23,15 @@ MxDSBuffer::~MxDSBuffer() { // TODO } + +// OFFSET: LEGO1 0x100c6780 +MxResult MxDSBuffer::FUN_100c6780(void* p_buffer, MxU32 p_size) +{ + m_pBuffer = p_buffer; + m_pIntoBuffer = p_buffer; + m_pIntoBuffer2 = p_buffer; + m_bytesRemaining = p_size; + m_writeOffset = p_size; + m_mode = 2; + return SUCCESS; +} diff --git a/LEGO1/mxdsbuffer.h b/LEGO1/mxdsbuffer.h index cb962cea..a48c4727 100644 --- a/LEGO1/mxdsbuffer.h +++ b/LEGO1/mxdsbuffer.h @@ -12,9 +12,30 @@ public: MxDSBuffer(); virtual ~MxDSBuffer() override; -private: - undefined m_unk08[0x2C]; + // OFFSET: LEGO1 0x100c6500 + inline virtual const char *ClassName() const override // vtable+0x0c + { + // 0x100f0568 + return "MxDSBuffer"; + } + MxResult FUN_100c6780(void* p_buffer, MxU32 p_size); + + inline void* GetBuffer() { return m_pBuffer;} + inline MxU32 GetWriteOffset() { return m_writeOffset;} + +private: + void* m_pBuffer; + void* m_pIntoBuffer; + void* m_pIntoBuffer2; + undefined4 m_unk14; + undefined4 m_unk18; + undefined4 m_unk1c; + undefined2 m_unk20; + undefined4 m_mode; + MxU32 m_writeOffset; + MxU32 m_bytesRemaining; + undefined4 m_unk30; }; #endif // MXDSBUFFER_H diff --git a/LEGO1/mxdssource.cpp b/LEGO1/mxdssource.cpp index 0ede6402..3c725a81 100644 --- a/LEGO1/mxdssource.cpp +++ b/LEGO1/mxdssource.cpp @@ -1,10 +1,10 @@ #include "mxdssource.h" +#include "mxdsbuffer.h" // OFFSET: LEGO1 0x100bffd0 -void MxDSSource::FUN_100bffd0(void* p_unk) +void MxDSSource::ReadToBuffer(MxDSBuffer* p_buffer) { - // TODO: Calls read, reading into a buffer somewhere in p_unk. - Read(NULL, 0); + Read((unsigned char*)p_buffer->GetBuffer(), p_buffer->GetWriteOffset()); } // OFFSET: LEGO1 0x100bfff0 @@ -17,4 +17,4 @@ MxLong MxDSSource::GetLengthInDWords() MxU32 *MxDSSource::GetBuffer() { return m_pBuffer; -} \ No newline at end of file +} diff --git a/LEGO1/mxdssource.h b/LEGO1/mxdssource.h index 2891f426..9c404ad0 100644 --- a/LEGO1/mxdssource.h +++ b/LEGO1/mxdssource.h @@ -3,13 +3,15 @@ #include "mxcore.h" +class MxDSBuffer; + // VTABLE 0x100dc8c8 class MxDSSource : public MxCore { public: MxDSSource() : m_lengthInDWords(0) - , m_pBuffer(0) + , m_pBuffer(NULL) , m_position(-1) {} @@ -28,7 +30,7 @@ public: virtual MxLong Open(MxULong) = 0; virtual MxLong Close() = 0; - virtual void FUN_100bffd0(void* p_unk); + virtual void ReadToBuffer(MxDSBuffer* p_buffer); virtual MxResult Read(unsigned char *, MxULong) = 0; virtual MxLong Seek(MxLong, int) = 0; virtual MxULong GetBufferSize() = 0; 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/mxeventpresenter.cpp b/LEGO1/mxeventpresenter.cpp index 88c20ce3..3a4ff7f4 100644 --- a/LEGO1/mxeventpresenter.cpp +++ b/LEGO1/mxeventpresenter.cpp @@ -1,4 +1,6 @@ #include "mxeventpresenter.h" +#include "mxeventmanager.h" +#include "mxomni.h" #include "decomp.h" @@ -10,14 +12,31 @@ MxEventPresenter::MxEventPresenter() Init(); } -// OFFSET: LEGO1 0x100c2d40 STUB +// OFFSET: LEGO1 0x100c2d40 MxEventPresenter::~MxEventPresenter() { - // TODO + Destroy(); } // OFFSET: LEGO1 0x100c2da0 void MxEventPresenter::Init() { - m_unk50 = 0; + m_unk50 = NULL; +} + +// OFFSET: LEGO1 0x100c2de0 +void MxEventPresenter::Destroy() +{ + MxEventManager *eventManager = EventManager(); + if (eventManager) + EventManager()->RemovePresenter(*this); + + m_criticalSection.Enter(); + + if (m_unk50) + delete m_unk50; + + Init(); + + m_criticalSection.Leave(); } diff --git a/LEGO1/mxeventpresenter.h b/LEGO1/mxeventpresenter.h index 256d0c7f..358a54af 100644 --- a/LEGO1/mxeventpresenter.h +++ b/LEGO1/mxeventpresenter.h @@ -26,10 +26,12 @@ public: return !strcmp(name, MxEventPresenter::ClassName()) || MxMediaPresenter::IsA(name); } + virtual void Destroy() override; // vtable+0x38 + private: void Init(); - undefined4 m_unk50; + undefined4 *m_unk50; }; #endif // MXEVENTPRESENTER_H diff --git a/LEGO1/mxmediapresenter.cpp b/LEGO1/mxmediapresenter.cpp index 2fb6b57c..3f31bf96 100644 --- a/LEGO1/mxmediapresenter.cpp +++ b/LEGO1/mxmediapresenter.cpp @@ -12,7 +12,7 @@ MxMediaPresenter::~MxMediaPresenter() MxResult MxMediaPresenter::Tickle() { // TODO - return 0; + return SUCCESS; } // OFFSET: LEGO1 0x100b54e0 diff --git a/LEGO1/mxmediapresenter.h b/LEGO1/mxmediapresenter.h index d0a5efe4..7ef31a98 100644 --- a/LEGO1/mxmediapresenter.h +++ b/LEGO1/mxmediapresenter.h @@ -43,9 +43,8 @@ public: undefined4 m_unk44; undefined4 m_unk48; undefined4 m_unk4c; -private: - void Init(); protected: + void Init(); void Destroy(MxBool p_fromDestructor); }; diff --git a/LEGO1/mxnotificationmanager.h b/LEGO1/mxnotificationmanager.h index adcd6876..5bc7b3a4 100644 --- a/LEGO1/mxnotificationmanager.h +++ b/LEGO1/mxnotificationmanager.h @@ -50,6 +50,8 @@ public: void Unregister(MxCore *p_listener); MxResult Send(MxCore *p_listener, MxNotificationParam *p_param); + inline MxNotificationPtrList *GetQueue() { return m_queue; } + private: void FlushPending(MxCore *p_listener); }; 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 88e4bf02..167791ad 100644 --- a/LEGO1/mxomni.cpp +++ b/LEGO1/mxomni.cpp @@ -61,22 +61,28 @@ MxResult MxOmni::Start(MxDSAction* p_dsAction) MxResult result = FAILURE; if(p_dsAction->GetAtomId().GetInternal() != NULL && p_dsAction->GetObjectId() != -1 && m_streamer != NULL) { - result = m_streamer->Unknown100b99b0(p_dsAction); + result = m_streamer->FUN_100b99b0(p_dsAction); } return result; } // OFFSET: LEGO1 0x100b00c0 STUB -void MxOmni::DeleteObject(MxDSAction &ds) +MxResult MxOmni::DeleteObject(MxDSAction &p_dsAction) { // TODO + return FAILURE; } -// OFFSET: LEGO1 0x100b09a0 STUB -MxBool MxOmni::DoesEntityExist(MxDSAction &ds) +// OFFSET: LEGO1 0x100b09a0 +MxBool MxOmni::DoesEntityExist(MxDSAction &p_dsAction) { - // TODO + if (m_streamer->FUN_100b9b30(p_dsAction)) { + MxNotificationPtrList *queue = m_notificationManager->GetQueue(); + + if (!queue || queue->size() == 0) + return TRUE; + } return FALSE; } @@ -94,7 +100,7 @@ int MxOmni::vtable0x30(char*, int, MxCore*) } // OFFSET: LEGO1 0x100aefc0 -void MxOmni::NotifyCurrentEntity(MxParam *p_param) +void MxOmni::NotifyCurrentEntity(MxNotificationParam *p_param) { } @@ -226,7 +232,7 @@ MxResult MxOmni::Create(MxOmniCreateParam &p) } if (p.CreateFlags().CreateStreamer()) { - if (!(m_streamer = new MxStreamer()) || m_streamer->Create() != SUCCESS) + if (!(m_streamer = new MxStreamer()) || m_streamer->Create() != SUCCESS) goto done; } @@ -397,3 +403,23 @@ MxEventManager* EventManager() { return MxOmni::GetInstance()->GetEventManager(); } + +// OFFSET: LEGO1 0x100acf70 +MxResult DeleteObject(MxDSAction &p_dsAction) +{ + return MxOmni::GetInstance()->DeleteObject(p_dsAction); +} + +// 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 ab07d2bd..970eb4f3 100644 --- a/LEGO1/mxomni.h +++ b/LEGO1/mxomni.h @@ -5,11 +5,13 @@ #include "mxstring.h" #include "mxcriticalsection.h" +class MxAtomId; class MxAtomIdCounterSet; class MxDSAction; class MxEventManager; class MxMusicManager; class MxNotificationManager; +class MxNotificationParam; class MxObjectFactory; class MxOmniCreateParam; class MxSoundManager; @@ -41,11 +43,11 @@ public: virtual MxResult Create(COMPAT_CONST MxOmniCreateParam &p); // vtable+18 virtual void Destroy(); // vtable+1c virtual MxResult Start(MxDSAction* p_dsAction); // vtable+20 - virtual void DeleteObject(MxDSAction &ds); // vtable+24 - virtual MxBool DoesEntityExist(MxDSAction &ds); // vtable+28 + virtual MxResult DeleteObject(MxDSAction &p_dsAction); // vtable+24 + virtual MxBool DoesEntityExist(MxDSAction &p_dsAction); // vtable+28 virtual void vtable0x2c(); // vtable+2c virtual int vtable0x30(char*, int, MxCore*); // vtable+30 - virtual void NotifyCurrentEntity(MxParam *p_param); // vtable+34 + virtual void NotifyCurrentEntity(MxNotificationParam *p_param); // vtable+34 virtual void StartTimer(); // vtable+38 virtual void StopTimer(); // vtable+3c virtual MxBool IsTimerRunning(); //vtable+40 @@ -94,8 +96,11 @@ __declspec(dllexport) MxMusicManager * MusicManager(); __declspec(dllexport) MxEventManager * EventManager(); __declspec(dllexport) MxNotificationManager * NotificationManager(); +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/mxpalette.cpp b/LEGO1/mxpalette.cpp index cdd1597f..b11a1209 100644 --- a/LEGO1/mxpalette.cpp +++ b/LEGO1/mxpalette.cpp @@ -379,7 +379,7 @@ void MxPalette::Detach() MxResult MxPalette::SetEntries(LPPALETTEENTRY p_entries) { MxS32 i; - MxResult status = 0; + MxResult status = SUCCESS; if ( this->m_palette ) { @@ -423,7 +423,7 @@ MxResult MxPalette::SetEntries(LPPALETTEENTRY p_entries) this->m_entries[i].peFlags = 0x80; if ( this->m_palette->SetEntries(0, 0, 256, this->m_entries) ) - status = -1; + status = FAILURE; } return status; diff --git a/LEGO1/mxsoundmanager.cpp b/LEGO1/mxsoundmanager.cpp index 51336843..ca04580f 100644 --- a/LEGO1/mxsoundmanager.cpp +++ b/LEGO1/mxsoundmanager.cpp @@ -58,11 +58,23 @@ MxResult MxSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) // OFFSET: LEGO1 0x100aed10 STUB void MxSoundManager::vtable0x34() { - // TODO STUB + // TODO } // OFFSET: LEGO1 0x100aee10 STUB void MxSoundManager::vtable0x38() { - // TODO STUB + // TODO +} + +// OFFSET: LEGO1 0x100aeab0 +void MxSoundManager::Destroy() +{ + Destroy(FALSE); +} + +// OFFSET: LEGO1 0x100aeac0 STUB +void MxSoundManager::SetVolume(MxS32 p_volume) +{ + // TODO } diff --git a/LEGO1/mxsoundmanager.h b/LEGO1/mxsoundmanager.h index 3bd41085..9e0656f8 100644 --- a/LEGO1/mxsoundmanager.h +++ b/LEGO1/mxsoundmanager.h @@ -14,6 +14,8 @@ public: MxSoundManager(); virtual ~MxSoundManager() override; // vtable+0x0 + virtual void Destroy() override; // vtable+18 + virtual void SetVolume(MxS32 p_volume) override; // vtable+2c virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); //vtable+0x30 virtual void vtable0x34(); // vtable+0x34 virtual void vtable0x38(); // vtable+0x38 diff --git a/LEGO1/mxsoundpresenter.cpp b/LEGO1/mxsoundpresenter.cpp index 50e04ce4..8204c01c 100644 --- a/LEGO1/mxsoundpresenter.cpp +++ b/LEGO1/mxsoundpresenter.cpp @@ -1 +1,45 @@ #include "mxsoundpresenter.h" + +#include "decomp.h" +#include "mxsoundmanager.h" + +DECOMP_SIZE_ASSERT(MxSoundPresenter, 0x54) + +// OFFSET: LEGO1 0x1000d430 +MxSoundPresenter::~MxSoundPresenter() +{ + Destroy(TRUE); +} + +// OFFSET: LEGO1 0x100b1a50 +void MxSoundPresenter::Destroy(MxBool p_fromDestructor) +{ + if (MSoundManager()) + MSoundManager()->RemovePresenter(*this); + + this->m_criticalSection.Enter(); + MxMediaPresenter::Init(); + this->m_criticalSection.Leave(); + + if (!p_fromDestructor) + MxMediaPresenter::Destroy(FALSE); +} + +// OFFSET: LEGO1 0x100b1aa0 +MxResult MxSoundPresenter::AddToManager() +{ + MxResult ret = FAILURE; + + if (MSoundManager()) { + ret = SUCCESS; + MSoundManager()->AddPresenter(*this); + } + + return ret; +} + +// OFFSET: LEGO1 0x1000d490 +void MxSoundPresenter::Destroy() +{ + Destroy(FALSE); +} diff --git a/LEGO1/mxsoundpresenter.h b/LEGO1/mxsoundpresenter.h index 53d7000d..a63083af 100644 --- a/LEGO1/mxsoundpresenter.h +++ b/LEGO1/mxsoundpresenter.h @@ -2,11 +2,14 @@ #define MXSOUNDPRESENTER_H #include "mxaudiopresenter.h" +#include "mxomni.h" // VTABLE 0x100d4b08 class MxSoundPresenter : public MxAudioPresenter { public: + virtual ~MxSoundPresenter() override; + // OFFSET: LEGO1 0x1000d4a0 inline virtual const char *ClassName() const // vtable+0x0c { @@ -20,6 +23,11 @@ public: return !strcmp(name, MxSoundPresenter::ClassName()) || MxAudioPresenter::IsA(name); }; + virtual MxResult AddToManager() override; // vtable+0x34 + virtual void Destroy() override; // vtable+0x38 + +private: + void Destroy(MxBool); }; #endif // MXSOUNDPRESENTER_H diff --git a/LEGO1/mxstreamer.cpp b/LEGO1/mxstreamer.cpp index 84d1b7b9..3bb13b73 100644 --- a/LEGO1/mxstreamer.cpp +++ b/LEGO1/mxstreamer.cpp @@ -132,7 +132,7 @@ MxResult MxStreamer::AddStreamControllerToOpenList(MxStreamController *stream) } // OFFSET: LEGO1 0x100b99b0 -MxResult MxStreamer::Unknown100b99b0(MxDSAction* p_action) +MxResult MxStreamer::FUN_100b99b0(MxDSAction* p_action) { MxStreamController* controller; if (p_action != NULL && p_action->GetAtomId().GetInternal() != NULL && p_action->GetObjectId() != -1) @@ -147,6 +147,15 @@ MxResult MxStreamer::Unknown100b99b0(MxDSAction* p_action) return FAILURE; } +// OFFSET: LEGO1 0x100b9b30 +MxBool MxStreamer::FUN_100b9b30(MxDSObject &p_dsObject) +{ + MxStreamController *controller = GetOpenStream(p_dsObject.GetAtomId().GetInternal()); + if (controller) + return controller->FUN_100c20d0(p_dsObject); + return TRUE; +} + // OFFSET: LEGO1 0x100b9b60 MxLong MxStreamer::Notify(MxParam &p) { diff --git a/LEGO1/mxstreamer.h b/LEGO1/mxstreamer.h index b5d86e4d..3931b1fb 100644 --- a/LEGO1/mxstreamer.h +++ b/LEGO1/mxstreamer.h @@ -7,6 +7,7 @@ #include "mxcore.h" #include "mxnotificationparam.h" #include "mxstreamcontroller.h" +#include "mxdsobject.h" #include "mxtypes.h" // NOTE: This feels like some kind of templated class, maybe something from the @@ -92,11 +93,10 @@ public: virtual MxResult Create(); // vtable+0x14 + MxBool FUN_100b9b30(MxDSObject &p_dsObject); MxStreamController *GetOpenStream(const char *p_name); - MxResult AddStreamControllerToOpenList(MxStreamController *p_stream); - - MxResult MxStreamer::Unknown100b99b0(MxDSAction* p_action); + MxResult FUN_100b99b0(MxDSAction* p_action); private: list m_openStreams; // 0x8 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/mxvideopresenter.cpp b/LEGO1/mxvideopresenter.cpp index a22adcd4..f48a0f8b 100644 --- a/LEGO1/mxvideopresenter.cpp +++ b/LEGO1/mxvideopresenter.cpp @@ -2,7 +2,7 @@ #include "MxVideoManager.h" DECOMP_SIZE_ASSERT(MxVideoPresenter, 0x64); -DECOMP_SIZE_ASSERT(MxVideoPresenter::UnkStruct, 0xc); +DECOMP_SIZE_ASSERT(MxVideoPresenter::AlphaMask, 0xc); // OFFSET: LEGO1 0x1000c700 void MxVideoPresenter::VTable0x5c(undefined4 p_unknown1) @@ -49,28 +49,128 @@ LPDIRECTDRAWSURFACE MxVideoPresenter::VTable0x78() // OFFSET: LEGO1 0x1000c7c0 MxBool MxVideoPresenter::VTable0x7c() { - return (m_bitmap != NULL) || (m_unk54 != NULL); + return (m_bitmap != NULL) || (m_alpha != NULL); } // OFFSET: LEGO1 0x1000c7e0 MxS32 MxVideoPresenter::GetWidth() { - return m_unk54 ? m_unk54->width + return m_alpha ? m_alpha->m_width : m_bitmap->GetBmiHeader()->biWidth; } // OFFSET: LEGO1 0x1000c800 MxS32 MxVideoPresenter::GetHeight() { - return m_unk54 ? m_unk54->height + return m_alpha ? m_alpha->m_height : m_bitmap->GetBmiHeader()->biHeight; } +// OFFSET: LEGO1 0x100b24f0 +MxVideoPresenter::AlphaMask::AlphaMask(const MxBitmap &p_bitmap) +{ + m_width = p_bitmap.GetBmiWidth(); + // DECOMP: ECX becomes word-sized if these are not two separate actions. + MxLong _height = p_bitmap.GetBmiHeightAbs(); + m_height = _height; + + MxS32 size = ((m_width * m_height) / 8) + 1; + m_bitmask = new MxU8[size]; + memset(m_bitmask, 0, size); + + MxU32 biCompression = p_bitmap.GetBmiHeader()->biCompression; + MxU32 rows_before_top; + MxU8 *bitmap_src_ptr; + + // The goal here is to enable us to walk through the bitmap's rows + // in order, regardless of the orientation. We want to end up at the + // start of the first row, which is either at position 0, or at + // (image_stride * biHeight) - 1. + + // Reminder: Negative biHeight means this is a top-down DIB. + // Otherwise it is bottom-up. + + if (biCompression == BI_RGB) { + // DECOMP: I think this must be an OR. If not, the check for + // biCompression == 16 gets optimized away. + if (biCompression == BI_RGB_TOPDOWN || p_bitmap.GetBmiHeight() < 0) { + rows_before_top = 0; + } else { + rows_before_top = p_bitmap.GetBmiHeightAbs(); + rows_before_top--; + } + + goto seek_to_last_row; + } else if (biCompression == BI_RGB_TOPDOWN) { + // DECOMP: This is the only condition where we skip the + // calculation below. + bitmap_src_ptr = p_bitmap.GetBitmapData(); + } else { + if (p_bitmap.GetBmiHeight() < 0) { + rows_before_top = 0; + } else { + rows_before_top = p_bitmap.GetBmiHeightAbs(); + rows_before_top--; + } + +// TODO: would prefer not to use goto if we can figure this structure out +seek_to_last_row: + bitmap_src_ptr = ((p_bitmap.GetBmiWidth()+3)&-4) * rows_before_top + p_bitmap.GetBitmapData(); + } + + // How many bytes are there for each row of the bitmap? + // (i.e. the image stride) + // If this is a bottom-up DIB, we will walk it in reverse. + // TODO: Same rounding trick as in MxBitmap + MxS32 row_seek = ((m_height+3)&-4); + if (p_bitmap.GetBmiHeight() < 0) + row_seek = -row_seek; + + // The actual offset into the m_bitmask array. The two for-loops + // are just for counting the pixels. + MxS32 offset = 0; + + MxU8 *t_ptr = bitmap_src_ptr; + for (MxS32 j = 0; j < m_height; j++) { + for (MxS32 i = 0; i < m_width; i++) { + if (*t_ptr) { + // TODO: Second CDQ instruction for abs() should not be there. + MxU32 shift = abs(offset) & 7; + m_bitmask[offset / 8] |= (1 << abs(shift)); + } + t_ptr++; + offset++; + } + // Seek to the start of the next row + bitmap_src_ptr += row_seek; + t_ptr = bitmap_src_ptr; + } +} + +// OFFSET: LEGO1 0x100b2670 +MxVideoPresenter::AlphaMask::AlphaMask(const MxVideoPresenter::AlphaMask &p_alpha) +{ + m_width = p_alpha.m_width; + m_height = p_alpha.m_height; + + MxS32 size = ((m_width * m_height) / 8) + 1; + m_bitmask = new MxU8[size]; + memcpy(m_bitmask, p_alpha.m_bitmask, size); +} + + +// OFFSET: LEGO1 0x100b26d0 +MxVideoPresenter::AlphaMask::~AlphaMask() +{ + if (m_bitmask) + delete[] m_bitmask; +} + // OFFSET: LEGO1 0x100b2760 void MxVideoPresenter::Init() { m_bitmap = NULL; - m_unk54 = NULL; + m_alpha = NULL; m_unk5c = 1; m_unk58 = NULL; m_unk60 = -1; @@ -99,7 +199,7 @@ void MxVideoPresenter::Destroy(MxBool p_fromDestructor) m_flags = m_flags & 0xfb; } - if (MVideoManager() && (m_unk54 || m_bitmap)) { + if (MVideoManager() && (m_alpha || m_bitmap)) { MxS32 height = GetHeight(); MxS32 width = GetWidth(); @@ -112,7 +212,7 @@ void MxVideoPresenter::Destroy(MxBool p_fromDestructor) } delete m_bitmap; - delete m_unk54; + delete m_alpha; Init(); diff --git a/LEGO1/mxvideopresenter.h b/LEGO1/mxvideopresenter.h index 30a6ada7..61a1027c 100644 --- a/LEGO1/mxvideopresenter.h +++ b/LEGO1/mxvideopresenter.h @@ -49,16 +49,19 @@ public: // TODO: Not sure what this is. Seems to have size of 12 bytes // based on 0x100b9e9a. Values are copied from the bitmap header. - struct UnkStruct { - undefined unk0[4]; - MxU16 width; - MxU16 height; + // SIZE 0xc + struct AlphaMask { + MxU8 *m_bitmask; + MxU16 m_width; + MxU16 m_height; - virtual ~UnkStruct() {} + AlphaMask(const MxBitmap &); + AlphaMask(const AlphaMask &); + virtual ~AlphaMask(); }; MxBitmap *m_bitmap; - UnkStruct *m_unk54; + AlphaMask *m_alpha; LPDIRECTDRAWSURFACE m_unk58; undefined2 m_unk5c; unsigned char m_flags; // 0x5e 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.cpp b/LEGO1/scorestate.cpp index 826ab482..edfd372b 100644 --- a/LEGO1/scorestate.cpp +++ b/LEGO1/scorestate.cpp @@ -1 +1,15 @@ #include "scorestate.h" + +DECOMP_SIZE_ASSERT(ScoreState, 0x0C); + +// OFFSET: LEGO1 0x1000de20 +MxBool ScoreState::VTable0x14() { + return FALSE; +} + +// OFFSET: LEGO1 0x1000de30 +MxBool ScoreState::SetFlag() +{ + m_playCubeTutorial = TRUE; + return TRUE; +} diff --git a/LEGO1/scorestate.h b/LEGO1/scorestate.h index 4f5a8dc2..4b9e25c1 100644 --- a/LEGO1/scorestate.h +++ b/LEGO1/scorestate.h @@ -21,6 +21,14 @@ public: return !strcmp(name, ScoreState::ClassName()) || LegoState::IsA(name); }; + 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; }; #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 diff --git a/tools/reccmp/reccmp.py b/tools/reccmp/reccmp.py index f26ab764..d32b5ad0 100755 --- a/tools/reccmp/reccmp.py +++ b/tools/reccmp/reccmp.py @@ -434,7 +434,7 @@ for subdir, dirs, files in os.walk(source): line = srcfile.readline() line_no += 1 # Name comes after // comment - name = line[2:].strip() + name = line.strip()[2:].strip() recinfo = syminfo.get_recompiled_address_from_name(name) if not recinfo: