diff --git a/LEGO1/lego/legoomni/include/jukebox.h b/LEGO1/lego/legoomni/include/jukebox.h index f760641d..9879a446 100644 --- a/LEGO1/lego/legoomni/include/jukebox.h +++ b/LEGO1/lego/legoomni/include/jukebox.h @@ -34,6 +34,7 @@ public: // SYNTHETIC: LEGO1 0x1005d810 // JukeBox::`scalar deleting destructor' + enum JukeBoxScript { e_mamaPapaBrickolini, e_jailUnused, @@ -65,29 +66,18 @@ public: e_legoRadioReminder2, e_legoRadioRacingAd, - e_legoRadioNews1, e_legoRadioNews2, - e_legoRadioPizzaAd1, - e_legoRadioBricksterPSA, - e_legoRadioSports1, - e_legoRadioIntermission1, e_legoRadioIntermission2, - e_legoRadioPizzaAd2, - e_legoRadioWeatherReport, - e_legoRadioSports2, - e_legoRadioPizzaAd3, - e_legoRadioIntermission3, - e_legoRadioSuperStoreAd, e_legoRadioLuckyYou, diff --git a/LEGO1/lego/legoomni/include/legostate.h b/LEGO1/lego/legoomni/include/legostate.h index 41942312..de66cdc6 100644 --- a/LEGO1/lego/legoomni/include/legostate.h +++ b/LEGO1/lego/legoomni/include/legostate.h @@ -43,6 +43,19 @@ public: // SYNTHETIC: LEGO1 0x10006160 // LegoState::`scalar deleting destructor' + + // SIZE 0x0c + struct StateStruct { + void* m_unk0x00; // 0x00 + undefined2 m_unk0x04; // 0x04 + undefined2 m_unk0x06; // 0x06 + MxU16 m_unk0x08; // 0x08 + + StateStruct(); + + MxU32 FUN_10014d00(); + MxBool FUN_10014de0(MxU32 p_objectId); + }; }; #endif // LEGOSTATE_H diff --git a/LEGO1/lego/legoomni/include/legovehiclebuildstate.h b/LEGO1/lego/legoomni/include/legovehiclebuildstate.h index b0463448..7a78b4ed 100644 --- a/LEGO1/lego/legoomni/include/legovehiclebuildstate.h +++ b/LEGO1/lego/legoomni/include/legovehiclebuildstate.h @@ -28,18 +28,8 @@ public: // SYNTHETIC: LEGO1 0x100260a0 // LegoVehicleBuildState::`scalar deleting destructor' -public: - struct UnkStruct { - undefined4 m_unk0x00; // 0x00 - undefined2 m_unk0x04; // 0x04 - undefined2 m_unk0x06; // 0x06 - undefined2 m_unk0x08; // 0x08 - - UnkStruct(); - }; - private: - UnkStruct m_unk0x08[4]; // 0x08 + StateStruct m_unk0x08[4]; // 0x08 // This can be one of the following: // * LegoRaceCarBuildState diff --git a/LEGO1/lego/legoomni/include/mxbackgroundaudiomanager.h b/LEGO1/lego/legoomni/include/mxbackgroundaudiomanager.h index 787484b0..cb2e3435 100644 --- a/LEGO1/lego/legoomni/include/mxbackgroundaudiomanager.h +++ b/LEGO1/lego/legoomni/include/mxbackgroundaudiomanager.h @@ -31,6 +31,8 @@ public: return !strcmp(p_name, MxBackgroundAudioManager::ClassName()) || MxCore::IsA(p_name); } + inline MxBool GetMusicEnabled() { return m_musicEnabled; } + void StartAction(MxParam& p_param); void StopAction(MxParam& p_param); MxResult PlayMusic(MxDSAction& p_action, undefined4 p_unk0x140, undefined4 p_unk0x13c); diff --git a/LEGO1/lego/legoomni/include/mxcontrolpresenter.h b/LEGO1/lego/legoomni/include/mxcontrolpresenter.h index 0903f557..1ead16da 100644 --- a/LEGO1/lego/legoomni/include/mxcontrolpresenter.h +++ b/LEGO1/lego/legoomni/include/mxcontrolpresenter.h @@ -43,7 +43,6 @@ public: private: MxBool FUN_10044270(MxS32 p_x, MxS32 p_y, MxVideoPresenter* p_presenter); - void FUN_10044540(undefined2); undefined2 m_unk0x4c; // 0x4c MxS16 m_unk0x4e; // 0x4e diff --git a/LEGO1/lego/legoomni/include/radio.h b/LEGO1/lego/legoomni/include/radio.h index 4edf734f..347a22d1 100644 --- a/LEGO1/lego/legoomni/include/radio.h +++ b/LEGO1/lego/legoomni/include/radio.h @@ -1,10 +1,13 @@ #ifndef RADIO_H #define RADIO_H +#include "legocontrolmanager.h" +#include "mxactionnotificationparam.h" #include "mxcore.h" #include "radiostate.h" // VTABLE: LEGO1 0x100d6d10 +// SIZE 0x10 class Radio : public MxCore { public: Radio(); @@ -31,10 +34,15 @@ public: // Radio::`scalar deleting destructor' private: - RadioState* m_state; // 0x08 - MxBool m_unk0x0c; // 0x0c + RadioState* m_state; // 0x08 + MxBool m_unk0x0c; // 0x0c + MxBool m_bgAudioPreviouslyEnabled; // 0x0d void CreateRadioState(); + void Play(); + void Stop(); + MxLong HandleEndAction(MxEndActionNotificationParam& p_param); + MxLong HandleNotification17(LegoControlManagerEvent& p_param); }; #endif // RADIO_H diff --git a/LEGO1/lego/legoomni/include/radiostate.h b/LEGO1/lego/legoomni/include/radiostate.h index 68dc154a..adfbe623 100644 --- a/LEGO1/lego/legoomni/include/radiostate.h +++ b/LEGO1/lego/legoomni/include/radiostate.h @@ -2,6 +2,7 @@ #define RADIOSTATE_H #include "legostate.h" +#include "mxdsaction.h" // VTABLE: LEGO1 0x100d6d28 // SIZE 0x30 @@ -26,6 +27,18 @@ public: // SYNTHETIC: LEGO1 0x1002d020 // RadioState::`scalar deleting destructor' + + inline MxBool IsActive() { return m_active; } + + inline void SetActive(MxBool p_active) { m_active = p_active; } + + undefined4 FUN_1002d090(); + MxBool FUN_1002d0c0(const MxAtomId& p_atom, MxU32 p_objectId); + +private: + StateStruct m_unk0x08[3]; // 0x08 + MxS16 m_unk0x2c; // 0x2c + MxBool m_active; // 0x2e }; #endif // RADIOSTATE_H diff --git a/LEGO1/lego/legoomni/src/build/legovehiclebuildstate.cpp b/LEGO1/lego/legoomni/src/build/legovehiclebuildstate.cpp index f950c429..8cf60edd 100644 --- a/LEGO1/lego/legoomni/src/build/legovehiclebuildstate.cpp +++ b/LEGO1/lego/legoomni/src/build/legovehiclebuildstate.cpp @@ -2,17 +2,7 @@ #include "decomp.h" -DECOMP_SIZE_ASSERT(LegoVehicleBuildState, 0x50); // 1000acd7 -DECOMP_SIZE_ASSERT(LegoVehicleBuildState::UnkStruct, 0x0c); - -// FUNCTION: LEGO1 0x10017c00 -LegoVehicleBuildState::UnkStruct::UnkStruct() -{ - m_unk0x04 = 0; - m_unk0x00 = 0; - m_unk0x06 = 0; - m_unk0x08 = 0; -} +DECOMP_SIZE_ASSERT(LegoVehicleBuildState, 0x50) // FUNCTION: LEGO1 0x10025f30 LegoVehicleBuildState::LegoVehicleBuildState(char* p_classType) diff --git a/LEGO1/lego/legoomni/src/common/legostate.cpp b/LEGO1/lego/legoomni/src/common/legostate.cpp index c9946492..5d3bcf4e 100644 --- a/LEGO1/lego/legoomni/src/common/legostate.cpp +++ b/LEGO1/lego/legoomni/src/common/legostate.cpp @@ -1,3 +1,27 @@ #include "legostate.h" DECOMP_SIZE_ASSERT(LegoState, 0x08) +DECOMP_SIZE_ASSERT(LegoState::StateStruct, 0x0c) + +// STUB: LEGO1 0x10014d00 +MxU32 LegoState::StateStruct::FUN_10014d00() +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10014de0 +MxBool LegoState::StateStruct::FUN_10014de0(MxU32 p_objectId) +{ + // TODO + return FALSE; +} + +// FUNCTION: LEGO1 0x10017c00 +LegoState::StateStruct::StateStruct() +{ + m_unk0x04 = 0; + m_unk0x00 = 0; + m_unk0x06 = 0; + m_unk0x08 = 0; +} diff --git a/LEGO1/lego/legoomni/src/isle/radio.cpp b/LEGO1/lego/legoomni/src/isle/radio.cpp index c0182a1c..ad5d96b7 100644 --- a/LEGO1/lego/legoomni/src/isle/radio.cpp +++ b/LEGO1/lego/legoomni/src/isle/radio.cpp @@ -3,6 +3,8 @@ #include "legocontrolmanager.h" #include "legogamestate.h" #include "legoomni.h" +#include "mxbackgroundaudiomanager.h" +#include "mxcontrolpresenter.h" #include "mxnotificationmanager.h" DECOMP_SIZE_ASSERT(Radio, 0x10); @@ -17,16 +19,119 @@ Radio::Radio() CreateRadioState(); } -// STUB: LEGO1 0x1002c990 +// FUNCTION: LEGO1 0x1002c990 Radio::~Radio() { - // TODO + if (m_state->IsActive()) { + BackgroundAudioManager()->Stop(); + m_state->SetActive(FALSE); + } + + ControlManager()->Unregister(this); + NotificationManager()->Unregister(this); } -// STUB: LEGO1 0x1002ca30 +// FUNCTION: LEGO1 0x1002ca30 MxLong Radio::Notify(MxParam& p_param) { - // TODO + MxLong result = 0; + + if (m_unk0x0c) { + switch (((MxNotificationParam&) p_param).GetType()) { + case c_notificationEndAction: + result = HandleEndAction((MxEndActionNotificationParam&) p_param); + break; + case c_notificationType17: + result = HandleNotification17((LegoControlManagerEvent&) p_param); + break; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x1002ca70 +void Radio::Play() +{ + if (!m_state->IsActive()) { + GetCurrentWorld(); + + MxDSAction action; + action.SetObjectId(m_state->FUN_1002d090()); + action.SetAtomId(*g_jukeboxScript); + action.SetLoopCount(1); + + m_bgAudioPreviouslyEnabled = BackgroundAudioManager()->GetMusicEnabled(); + if (!m_bgAudioPreviouslyEnabled) { + BackgroundAudioManager()->Enable(TRUE); + } + + BackgroundAudioManager()->PlayMusic(action, 3, 4); + m_state->SetActive(TRUE); + } +} + +// FUNCTION: LEGO1 0x1002cb70 +void Radio::Stop() +{ + if (m_state->IsActive()) { + LegoWorld* world = GetCurrentWorld(); + + MxControlPresenter* presenter = (MxControlPresenter*) world->Find(world->GetAtom(), 18); + + if (presenter) + presenter->VTable0x6c(0); + + BackgroundAudioManager()->Stop(); + BackgroundAudioManager()->Enable(m_bgAudioPreviouslyEnabled); + m_state->SetActive(FALSE); + } +} + +// FUNCTION: LEGO1 0x1002cbc0 +MxLong Radio::HandleNotification17(LegoControlManagerEvent& p_param) +{ + MxDSAction action; // Unused + MxS32 objectId = p_param.GetClickedObjectId(); + + if (objectId == 18) { + if (m_state->IsActive()) { + Stop(); + } + else { + Play(); + } + + if (GetCurrentWorld()) { +#ifdef COMPAT_MODE + MxNotificationParam param(c_notificationEndAction, this); + GetCurrentWorld()->Notify(param); +#else + GetCurrentWorld()->Notify(MxNotificationParam(c_notificationType0, this)); +#endif + } + + return 1; + } + + return 0; +} + +// FUNCTION: LEGO1 0x1002ccc0 +MxLong Radio::HandleEndAction(MxEndActionNotificationParam& p_param) +{ + if (m_state->IsActive() && + m_state->FUN_1002d0c0(p_param.GetAction()->GetAtomId(), p_param.GetAction()->GetObjectId())) { + + MxDSAction action; + action.SetAtomId(*g_jukeboxScript); + action.SetObjectId(m_state->FUN_1002d090()); + action.SetLoopCount(1); + + BackgroundAudioManager()->PlayMusic(action, 3, 4); + return 1; + } + return 0; } diff --git a/LEGO1/lego/legoomni/src/isle/radiostate.cpp b/LEGO1/lego/legoomni/src/isle/radiostate.cpp index 08aa91fa..cb692fcf 100644 --- a/LEGO1/lego/legoomni/src/isle/radiostate.cpp +++ b/LEGO1/lego/legoomni/src/isle/radiostate.cpp @@ -1,14 +1,115 @@ #include "radiostate.h" -// STUB: LEGO1 0x1002ce10 +#include "jukebox.h" +#include "legoomni.h" +#include "mxtimer.h" + +// GLOBAL: LEGO1 0x100f3218 +JukeBox::JukeBoxScript g_unk0x100f3218[6] = { + JukeBox::e_legoRadioReminder1, + JukeBox::e_legoRadioJingle1, + JukeBox::e_legoRadioJingle2, + JukeBox::e_legoRadioJingle3, + JukeBox::e_legoRadioJingle4, + JukeBox::e_legoRadioReminder2 +}; + +// GLOBAL: LEGO1 0x100f3230 +JukeBox::JukeBoxScript g_unk0x100f3230[14] = { + JukeBox::e_legoRadioRacingAd, + JukeBox::e_legoRadioNews1, + JukeBox::e_legoRadioNews2, + JukeBox::e_legoRadioPizzaAd1, + JukeBox::e_legoRadioBricksterPSA, + JukeBox::e_legoRadioSports1, + JukeBox::e_legoRadioIntermission1, + JukeBox::e_legoRadioIntermission2, + JukeBox::e_legoRadioPizzaAd2, + JukeBox::e_legoRadioWeatherReport, + JukeBox::e_legoRadioSports2, + JukeBox::e_legoRadioPizzaAd3, + JukeBox::e_legoRadioIntermission3, + JukeBox::e_legoRadioSuperStoreAd, +}; + +// GLOBAL: LEGO1 0x100f3268 +JukeBox::JukeBoxScript g_unk0x100f3268[9] = { + JukeBox::e_centralRoads, + JukeBox::e_beachBlvd, + JukeBox::e_residentialArea, + JukeBox::e_legoRadioLuckyYou, + JukeBox::e_legoRadioJazzInterlude, + JukeBox::e_legoRadioPianoInterlude1, + JukeBox::e_legoRadioPoliceStation, + JukeBox::e_legoRadioPianoInterlude2, + JukeBox::e_legoRadioCredits, +}; + +// FUNCTION: LEGO1 0x1002ce10 RadioState::RadioState() { - // TODO + srand(Timer()->GetTime()); + + MxS32 random = rand(); + m_unk0x2c = random % 3; + + // TODO: Most likely inline function + + m_unk0x08[0].m_unk0x04 = sizeof(g_unk0x100f3218) / sizeof(g_unk0x100f3218[0]); + m_unk0x08[0].m_unk0x00 = g_unk0x100f3218; + m_unk0x08[0].m_unk0x08 = 0; + m_unk0x08[0].m_unk0x06 = 0; + + random = rand(); + + m_unk0x08[1].m_unk0x08 = 0; + m_unk0x08[1].m_unk0x06 = 0; + m_unk0x08[1].m_unk0x04 = sizeof(g_unk0x100f3230) / sizeof(g_unk0x100f3230[0]); + m_unk0x08[1].m_unk0x00 = g_unk0x100f3230; + + m_unk0x08[0].m_unk0x08 = (MxU32) random % (sizeof(g_unk0x100f3218) / sizeof(g_unk0x100f3218[0])); + random = rand(); + + m_unk0x08[2].m_unk0x08 = 0; + m_unk0x08[2].m_unk0x06 = 0; + m_unk0x08[2].m_unk0x04 = sizeof(g_unk0x100f3268) / sizeof(g_unk0x100f3268[0]); + m_unk0x08[2].m_unk0x00 = g_unk0x100f3268; + + m_unk0x08[1].m_unk0x08 = (MxU32) random % (sizeof(g_unk0x100f3230) / sizeof(g_unk0x100f3230[0])); + random = rand(); + + m_unk0x08[2].m_unk0x08 = (MxU32) random % (sizeof(g_unk0x100f3268) / sizeof(g_unk0x100f3268[0])); + + m_active = FALSE; } -// STUB: LEGO1 0x1002cf50 +// FUNCTION: LEGO1 0x1002cf50 MxBool RadioState::VTable0x14() { - // TODO + return FALSE; +} + +// FUNCTION: LEGO1 0x1002d090 +MxU32 RadioState::FUN_1002d090() +{ + if (m_unk0x2c == 2) { + m_unk0x2c = 0; + } + else { + m_unk0x2c++; + } + + return m_unk0x08[m_unk0x2c].FUN_10014d00(); +} + +// FUNCTION: LEGO1 0x1002d0c0 +MxBool RadioState::FUN_1002d0c0(const MxAtomId& p_atom, MxU32 p_objectId) +{ + if (*g_jukeboxScript == p_atom) { + for (MxS16 i = 0; i < 3; i++) + if (m_unk0x08[i].FUN_10014de0(p_objectId)) + return TRUE; + } + return FALSE; }