From b824ba79ce0bdc4997b14f3f77524f09789d6856 Mon Sep 17 00:00:00 2001 From: jonschz Date: Sat, 23 Nov 2024 08:23:28 +0100 Subject: [PATCH] Implement `CarRace` --- LEGO1/lego/legoomni/include/carrace.h | 14 +- LEGO1/lego/legoomni/include/jetskirace.h | 2 - LEGO1/lego/legoomni/include/legoentity.h | 9 +- .../lego/legoomni/include/legoinputmanager.h | 7 + .../lego/legoomni/include/legonavcontroller.h | 9 + LEGO1/lego/legoomni/include/legopathactor.h | 1 + LEGO1/lego/legoomni/include/legoracers.h | 1 + LEGO1/lego/legoomni/src/common/misc.cpp | 6 + LEGO1/lego/legoomni/src/entity/legoactor.cpp | 1 + LEGO1/lego/legoomni/src/entity/legoentity.cpp | 29 +- LEGO1/lego/legoomni/src/main/scripts.cpp | 1 + LEGO1/lego/legoomni/src/race/carrace.cpp | 395 +++++++++++++++++- LEGO1/lego/legoomni/src/race/jetskirace.cpp | 33 +- LEGO1/lego/legoomni/src/race/legoracers.cpp | 7 + .../legoomni/src/race/legoracespecial.cpp | 4 + LEGO1/library_msvc.h | 3 + .../omni/include/mxactionnotificationparam.h | 1 + LEGO1/omni/include/mxentity.h | 4 + reccmp-project.yml | 11 + 19 files changed, 487 insertions(+), 51 deletions(-) diff --git a/LEGO1/lego/legoomni/include/carrace.h b/LEGO1/lego/legoomni/include/carrace.h index 38a6e77a..9fc6d21c 100644 --- a/LEGO1/lego/legoomni/include/carrace.h +++ b/LEGO1/lego/legoomni/include/carrace.h @@ -66,12 +66,22 @@ class CarRace : public LegoRace { // FUNCTION: BETA10 0x100f16f0 void SetSkeleton(RaceSkel* p_skeleton) { m_skeleton = p_skeleton; } + void FUN_10017820(MxS32 p_param1, MxS16 p_param2); + // SYNTHETIC: LEGO1 0x10016c70 // CarRace::`scalar deleting destructor' private: - undefined m_unk0x144[12]; // 0x144 - RaceSkel* m_skeleton; // 0x150 + static const MxS32 g_unk0x100d5d10[]; + static const MxS32 g_unk0x100d5d30[]; + static const MxS32 g_unk0x100d5d40[]; + static const MxS32 g_unk0x100d5d50[]; + static const MxS32 g_unk0x100d5d60[]; + + MxS32 m_unk0x144; // 0x144 + MxS32 m_unk0x148; // 0x148 + MxS32 m_unk0x14c; // 0x14c + RaceSkel* m_skeleton; // 0x150 }; #endif // CARRACE_H diff --git a/LEGO1/lego/legoomni/include/jetskirace.h b/LEGO1/lego/legoomni/include/jetskirace.h index b666868f..e880086f 100644 --- a/LEGO1/lego/legoomni/include/jetskirace.h +++ b/LEGO1/lego/legoomni/include/jetskirace.h @@ -65,8 +65,6 @@ class JetskiRace : public LegoRace { void FUN_10016930(MxS32 p_param1, MxS16 p_param2); private: - inline MxS32 PossiblyGetPlaceOfPlayer(); - static MxS32 g_unk0x100f0c78; }; diff --git a/LEGO1/lego/legoomni/include/legoentity.h b/LEGO1/lego/legoomni/include/legoentity.h index c984e097..ae9aadab 100644 --- a/LEGO1/lego/legoomni/include/legoentity.h +++ b/LEGO1/lego/legoomni/include/legoentity.h @@ -10,6 +10,7 @@ class MxDSAction; class Vector3; // VTABLE: LEGO1 0x100d4858 +// VTABLE: BETA10 0x101b9388 // SIZE 0x68 class LegoEntity : public MxEntity { public: @@ -38,6 +39,7 @@ class LegoEntity : public MxEntity { MxLong Notify(MxParam& p_param) override; // vtable+0x04 // FUNCTION: LEGO1 0x1000c2f0 + // FUNCTION: BETA10 0x10012730 const char* ClassName() const override // vtable+0x0c { // STRING: LEGO1 0x100f0064 @@ -116,8 +118,11 @@ class LegoEntity : public MxEntity { // For tokens from the extra string that look like this: // "Action:openram;\lego\scripts\Race\CarRaceR;0" Extra::ActionType m_actionType; // 0x5c - char* m_filename; // 0x60 - MxS32 m_targetEntityId; // 0x64 + + // variable name verified by BETA10 0x1007eddf + char* m_siFile; // 0x60 + + MxS32 m_targetEntityId; // 0x64 }; // SYNTHETIC: LEGO1 0x1000c3b0 diff --git a/LEGO1/lego/legoomni/include/legoinputmanager.h b/LEGO1/lego/legoomni/include/legoinputmanager.h index 8f2b0693..0ba5bad7 100644 --- a/LEGO1/lego/legoomni/include/legoinputmanager.h +++ b/LEGO1/lego/legoomni/include/legoinputmanager.h @@ -132,6 +132,13 @@ class LegoInputManager : public MxPresenter { void GetKeyboardState(); MxResult GetNavigationKeyStates(MxU32& p_keyFlags); + void Reset88and336() + { + // This function is hypothesized based on LEGO1 0x100173f5 + m_unk0x88 = TRUE; + m_unk0x336 = FALSE; + } + // SYNTHETIC: LEGO1 0x1005b8d0 // LegoInputManager::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/legonavcontroller.h b/LEGO1/lego/legoomni/include/legonavcontroller.h index 216b7b89..c99ab3fe 100644 --- a/LEGO1/lego/legoomni/include/legonavcontroller.h +++ b/LEGO1/lego/legoomni/include/legonavcontroller.h @@ -82,6 +82,12 @@ class LegoNavController : public MxCore { // FUNCTION: BETA10 0x100b0f40 void SetLinearVel(MxFloat p_linearVel) { m_linearVel = p_linearVel; } + // FUNCTION: BETA10 0x100c99e0 + void SetDeadZone(MxS32 p_deadZone) { m_deadZone = p_deadZone; } + + // FUNCTION: BETA10 0x100c7880 + void SetTrackDefault(MxS32 p_trackDefault) { m_trackDefault = p_trackDefault; } + MxFloat GetLinearVel() { return m_linearVel; } MxFloat GetRotationalVel() { return m_rotationalVel; } MxFloat GetMaxLinearVel() { return m_maxLinearVel; } @@ -91,6 +97,9 @@ class LegoNavController : public MxCore { m_trackDefault = 0; } + // FUNCTION: BETA10 0x100c9a10 + int GetDefaultDeadZone() { return g_defdeadZone; } + // SYNTHETIC: LEGO1 0x10054c10 // LegoNavController::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/legopathactor.h b/LEGO1/lego/legoomni/include/legopathactor.h index c4d5cd8d..d82e771c 100644 --- a/LEGO1/lego/legoomni/include/legopathactor.h +++ b/LEGO1/lego/legoomni/include/legopathactor.h @@ -15,6 +15,7 @@ struct LegoUnknown100db7f4; class LegoWEEdge; extern MxLong g_unk0x100f3308; +extern const char* g_strHIT_WALL_SOUND; // VTABLE: LEGO1 0x100d6e28 // SIZE 0x154 diff --git a/LEGO1/lego/legoomni/include/legoracers.h b/LEGO1/lego/legoomni/include/legoracers.h index 3648987f..3ccfc06f 100644 --- a/LEGO1/lego/legoomni/include/legoracers.h +++ b/LEGO1/lego/legoomni/include/legoracers.h @@ -77,6 +77,7 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { virtual MxU32 HandleSkeletonKicks(float p_param1); static void FUN_10012de0(); + static void FUN_10012e00(); static void FUN_10013670(); // SYNTHETIC: LEGO1 0x10014240 diff --git a/LEGO1/lego/legoomni/src/common/misc.cpp b/LEGO1/lego/legoomni/src/common/misc.cpp index 61399b00..a0ff5d0a 100644 --- a/LEGO1/lego/legoomni/src/common/misc.cpp +++ b/LEGO1/lego/legoomni/src/common/misc.cpp @@ -41,8 +41,10 @@ MxBackgroundAudioManager* BackgroundAudioManager() } // FUNCTION: LEGO1 0x10015740 +// FUNCTION: BETA10 0x100e4895 LegoInputManager* InputManager() { + assert(LegoOmni::GetInstance()); return LegoOmni::GetInstance()->GetInputManager(); } @@ -95,8 +97,10 @@ LegoWorld* CurrentWorld() } // FUNCTION: LEGO1 0x100157b0 +// FUNCTION: BETA10 0x100e4a8d LegoCharacterManager* CharacterManager() { + assert(LegoOmni::GetInstance()); return LegoOmni::GetInstance()->GetCharacterManager(); } @@ -131,8 +135,10 @@ ViewLODListManager* GetViewLODListManager() } // FUNCTION: LEGO1 0x10015820 +// FUNCTION: BETA10 0x100e4c92 void FUN_10015820(MxBool p_disable, MxU16 p_flags) { + assert(LegoOmni::GetInstance()); LegoOmni::GetInstance()->FUN_1005b4f0(p_disable, p_flags); } diff --git a/LEGO1/lego/legoomni/src/entity/legoactor.cpp b/LEGO1/lego/legoomni/src/entity/legoactor.cpp index 2377302e..927ad4a4 100644 --- a/LEGO1/lego/legoomni/src/entity/legoactor.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoactor.cpp @@ -140,6 +140,7 @@ void LegoActor::SetROI(LegoROI* p_roi, MxBool p_bool1, MxBool p_bool2) } // FUNCTION: LEGO1 0x1002d6e0 +// FUNCTION: BETA10 0x1003d6f2 void LegoActor::Mute(MxBool p_muted) { if (m_sound != NULL) { diff --git a/LEGO1/lego/legoomni/src/entity/legoentity.cpp b/LEGO1/lego/legoomni/src/entity/legoentity.cpp index 81cb3fe3..7442d189 100644 --- a/LEGO1/lego/legoomni/src/entity/legoentity.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoentity.cpp @@ -28,7 +28,7 @@ void LegoEntity::Init() m_worldSpeed = 0; m_roi = NULL; m_cameraFlag = FALSE; - m_filename = NULL; + m_siFile = NULL; m_unk0x10 = 0; m_flags = 0; m_actionType = Extra::ActionType::e_unknown; @@ -37,6 +37,7 @@ void LegoEntity::Init() } // FUNCTION: LEGO1 0x10010650 +// FUNCTION: BETA10 0x1007e39a void LegoEntity::ResetWorldTransform(MxBool p_cameraFlag) { LegoWorld* world = CurrentWorld(); @@ -66,6 +67,7 @@ void LegoEntity::ResetWorldTransform(MxBool p_cameraFlag) } // FUNCTION: LEGO1 0x10010790 +// FUNCTION: BETA10 0x1007e4f6 void LegoEntity::SetWorldTransform(const Vector3& p_location, const Vector3& p_direction, const Vector3& p_up) { LegoWorld* world = CurrentWorld(); @@ -78,6 +80,7 @@ void LegoEntity::SetWorldTransform(const Vector3& p_location, const Vector3& p_d } // FUNCTION: LEGO1 0x100107e0 +// FUNCTION: BETA10 0x1007e572 MxResult LegoEntity::Create(MxDSAction& p_dsAction) { m_entityId = p_dsAction.GetObjectId(); @@ -87,6 +90,7 @@ MxResult LegoEntity::Create(MxDSAction& p_dsAction) } // FUNCTION: LEGO1 0x10010810 +// FUNCTION: BETA10 0x1007e5b9 void LegoEntity::Destroy(MxBool p_fromDestructor) { if (m_roi) { @@ -103,11 +107,12 @@ void LegoEntity::Destroy(MxBool p_fromDestructor) } } - delete[] m_filename; + delete[] m_siFile; Init(); } // FUNCTION: LEGO1 0x10010880 +// FUNCTION: BETA10 0x1007e6e1 void LegoEntity::SetWorld() { LegoWorld* world = CurrentWorld(); @@ -118,6 +123,7 @@ void LegoEntity::SetWorld() } // FUNCTION: LEGO1 0x100108a0 +// FUNCTION: BETA10 0x1007e724 void LegoEntity::SetROI(LegoROI* p_roi, MxBool p_bool1, MxBool p_bool2) { m_roi = p_roi; @@ -225,6 +231,7 @@ Mx3DPointFloat LegoEntity::GetWorldPosition() } // FUNCTION: LEGO1 0x10010e10 +// FUNCTION: BETA10 0x1007ec97 void LegoEntity::ParseAction(char* p_extra) { char copy[1024]; @@ -232,16 +239,22 @@ void LegoEntity::ParseAction(char* p_extra) strcpy(copy, p_extra); if (KeyValueStringParse(actionValue, g_strACTION, copy)) { - m_actionType = MatchActionString(strtok(actionValue, g_parseExtraTokens)); + char* token = strtok(actionValue, g_parseExtraTokens); + assert(token); + m_actionType = MatchActionString(token); if (m_actionType != Extra::ActionType::e_exit) { - char* token = strtok(NULL, g_parseExtraTokens); + token = strtok(NULL, g_parseExtraTokens); + assert(token); - m_filename = new char[strlen(token) + 1]; - strcpy(m_filename, token); + m_siFile = new char[strlen(token) + 1]; + assert(m_siFile); + strcpy(m_siFile, token); if (m_actionType != Extra::ActionType::e_run) { - m_targetEntityId = atoi(strtok(NULL, g_parseExtraTokens)); + token = strtok(NULL, g_parseExtraTokens); + assert(token); + m_targetEntityId = atoi(token); } } } @@ -458,7 +471,7 @@ MxLong LegoEntity::Notify(MxParam& p_param) } if (m_actionType != Extra::e_unknown) { - InvokeAction(m_actionType, MxAtomId(m_filename, e_lowerCase2), m_targetEntityId, this); + InvokeAction(m_actionType, MxAtomId(m_siFile, e_lowerCase2), m_targetEntityId, this); } else { switch (GameState()->GetActorId()) { diff --git a/LEGO1/lego/legoomni/src/main/scripts.cpp b/LEGO1/lego/legoomni/src/main/scripts.cpp index b5b8f9fe..ce3956cb 100644 --- a/LEGO1/lego/legoomni/src/main/scripts.cpp +++ b/LEGO1/lego/legoomni/src/main/scripts.cpp @@ -15,6 +15,7 @@ MxAtomId* g_jetskiScript = NULL; MxAtomId* g_racecarScript = NULL; // GLOBAL: LEGO1 0x100f452c +// GLOBAL: BETA10 0x10211514 MxAtomId* g_carraceScript = NULL; // GLOBAL: LEGO1 0x100f4530 diff --git a/LEGO1/lego/legoomni/src/race/carrace.cpp b/LEGO1/lego/legoomni/src/race/carrace.cpp index 6ffb2ebd..0831f523 100644 --- a/LEGO1/lego/legoomni/src/race/carrace.cpp +++ b/LEGO1/lego/legoomni/src/race/carrace.cpp @@ -1,9 +1,63 @@ #include "carrace.h" +#include "actions/carrace_actions.h" +#include "dunebuggy.h" +#include "isle.h" +#include "legoanimationmanager.h" +#include "legobackgroundcolor.h" +#include "legocontrolmanager.h" +#include "legohideanimpresenter.h" +#include "legonavcontroller.h" +#include "legopathstruct.h" +#include "legoracers.h" +#include "legoutils.h" +#include "misc.h" #include "mxactionnotificationparam.h" +#include "mxbackgroundaudiomanager.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxstillpresenter.h" +#include "mxtransitionmanager.h" +#include "mxvariabletable.h" +#include "scripts.h" DECOMP_SIZE_ASSERT(CarRace, 0x154) +// GLOBAL: LEGO1 0x100d5d10 +const MxS32 CarRace::g_unk0x100d5d10[] = { + CarraceScript::c_srt001sl_RunAnim, + CarraceScript::c_srt002sl_RunAnim, + CarraceScript::c_srt003sl_RunAnim, + CarraceScript::c_srt004sl_RunAnim, + CarraceScript::c_srt005sl_RunAnim, + CarraceScript::c_srt001rh_RunAnim, + CarraceScript::c_srt002rh_RunAnim, + CarraceScript::c_srt003rh_RunAnim +}; + +// GLOBAL: LEGO1 0x100d5d30 +const MxS32 CarRace::g_unk0x100d5d30[] = {202, 204, 205, 206}; + +// GLOBAL: LEGO1 0x100d5d40 +const MxS32 CarRace::g_unk0x100d5d40[] = {207, 208, 209}; + +// GLOBAL: LEGO1 0x100d5d50 +const MxS32 CarRace::g_unk0x100d5d50[] = {509, 510, 511}; + +// GLOBAL: LEGO1 0x100d5d60 +const MxS32 CarRace::g_unk0x100d5d60[] = {200, 201, 203}; + +// GLOBAL: LEGO1 0x100f0c70 +// STRING: LEGO1 0x100f0c48 +const LegoChar* g_CRCFRNTY6 = "C_RCFRNTY6"; + +// GLOBAL: LEGO1 0x100f0c74 +// STRING: LEGO1 0x100f0c3c +const LegoChar* g_CRCEDGEY0 = "C_RCEDGEY0"; + +// GLOBAL: LEGO1 0x100f0c7c +static MxS32 g_unk0x100f0c7c = 2; + // FUNCTION: LEGO1 0x10016a90 CarRace::CarRace() { @@ -11,50 +65,349 @@ CarRace::CarRace() this->m_unk0x130 = MxRect32(0x16c, 0x154, 0x1ec, 0x15e); } -// STUB: LEGO1 0x10016ce0 +// FUNCTION: LEGO1 0x10016ce0 +// FUNCTION: BETA10 0x100c8364 MxResult CarRace::Create(MxDSAction& p_dsAction) { + MxResult result = LegoRace::Create(p_dsAction); + + NavController()->SetDeadZone(1); + NavController()->SetTrackDefault(0); + GameState()->m_currentArea = LegoGameState::e_carrace; + GameState()->StopArea(LegoGameState::e_undefined); + + LegoGameState* state = GameState(); + + RaceState* raceState = (RaceState*) state->GetState("CarRaceState"); + + if (!raceState) { + raceState = (RaceState*) state->CreateState("CarRaceState"); + } + + m_raceState = raceState; + + m_act1State->m_unk0x018 = 6; + m_unk0x144 = -1; + m_unk0x148 = -1; + m_unk0x14c = -1; + + LegoRaceCar::FUN_10012e00(); + + InvokeAction( + Extra::e_start, + m_atomId, + DuneBuggy::GetColorOffset(g_CRCEDGEY0) + (DuneBuggy::GetColorOffset(g_CRCFRNTY6) * 5 + 15) * 2, + NULL + ); + InvokeAction(Extra::e_start, m_atomId, CarraceScript::c_RaceCarDashboard, NULL); + // TODO return SUCCESS; } -// STUB: LEGO1 0x10016dd0 +// FUNCTION: LEGO1 0x10016dd0 +// FUNCTION: BETA10 0x100c8490 void CarRace::ReadyWorld() { - // TODO + assert(m_hideAnim); + LegoWorld::ReadyWorld(); + m_hideAnim->FUN_1006db40(0); + MxDSAction local_ac; + + local_ac.SetAtomId(*g_jukeboxScript); + local_ac.SetObjectId(16); + + BackgroundAudioManager()->PlayMusic(local_ac, 5, MxPresenter::e_repeating); + AnimationManager()->Resume(); + FUN_10015820(FALSE, 7); + + m_unk0x144 = g_unk0x100d5d10[rand() & 7]; + + AnimationManager()->FUN_10060dc0(m_unk0x144, NULL, TRUE, FALSE, NULL, FALSE, TRUE, FALSE, TRUE); + + m_unk0x128 = (MxStillPresenter*) Find("MxPresenter", "CarLocator2"); + m_unk0x128->SetPosition(m_unk0x130.GetLeft(), m_unk0x130.GetTop()); + + m_unk0x12c = (MxStillPresenter*) Find("MxPresenter", "CarLocator3"); + m_unk0x12c->SetPosition(m_unk0x130.GetLeft(), m_unk0x130.GetTop()); + VariableTable()->SetVariable("DISTANCE", "0.036"); } -// STUB: LEGO1 0x10016f60 -MxLong CarRace::HandleEndAction(MxEndActionNotificationParam&) +// FUNCTION: LEGO1 0x10016f60 +// FUNCTION: BETA10 0x100c85eb +MxLong CarRace::HandleEndAction(MxEndActionNotificationParam& p_param) { - // TODO - return 0; + MxLong result = 0; + + if (p_param.GetAction()) { + MxDSAction* action = p_param.GetAction(); + MxU32 objectId = action->GetObjectId(); + + if (m_unk0x144 == objectId) { + InvokeAction(Extra::e_start, *g_carraceScript, CarraceScript::c_irtx08ra_PlayWav, NULL); + result = 1; + } + else if (objectId == CarraceScript::c_irtx08ra_PlayWav && m_destLocation == LegoGameState::e_undefined) { + m_unk0x110[0]->Mute(FALSE); + m_unk0x110[1]->Mute(FALSE); + m_unk0x110[2]->Mute(FALSE); + + VariableTable()->SetVariable(g_raceState, g_racing); + result = 1; + } + else if (m_unk0x148 == objectId) { + AnimationManager()->FUN_10060dc0(m_unk0x14c, NULL, TRUE, FALSE, NULL, FALSE, TRUE, FALSE, TRUE); + } + else if (m_unk0x14c == objectId) { + NotificationManager()->Send(this, MxNotificationParam()); + } + } + + return result; } -// STUB: LEGO1 0x100170e0 -MxLong CarRace::HandlePathStruct(LegoPathStructNotificationParam&) +// FUNCTION: LEGO1 0x100170e0 +// FUNCTION: BETA10 0x100c87ac +MxLong CarRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) { - // TODO - return 0; + MxLong result = 0; + + if (p_param.GetTrigger() == 68) { + MxEntity* sender = (MxEntity*) p_param.GetSender(); + MxS32 paramData = p_param.GetData(); + + switch (sender->GetEntityId()) { + case 10: + if (paramData <= m_unk0x104 || paramData >= m_unk0x104 + 5) { + break; + } + + m_unk0x104 = paramData; + LegoChar buffer[20]; + sprintf(buffer, "%g", 0.036 + 0.928 * (m_unk0xf8 * 20.0 + m_unk0x104) / (g_unk0x100f0c7c * 20.0)); + VariableTable()->SetVariable("DISTANCE", buffer); + + if (m_unk0x104 == 0x14) { + m_unk0x104 = 0; + m_unk0xf8++; + + if (g_unk0x100f0c7c == m_unk0xf8) { + VariableTable()->SetVariable(g_raceState, ""); + + m_unk0x110[0]->Mute(TRUE); + m_unk0x110[1]->Mute(TRUE); + m_unk0x110[2]->Mute(TRUE); + + m_unk0x110[0]->SetMaxLinearVel(-1.0); + m_unk0x110[1]->SetMaxLinearVel(-1.0); + m_unk0x110[2]->SetMaxLinearVel(-1.0); + + RemoveActor(m_unk0x110[1]); + m_unk0x110[1]->ClearMaps(); + + RemoveActor(m_unk0x110[2]); + m_unk0x110[2]->ClearMaps(); + + MxS32 position; + + if (m_unk0xfc < m_unk0xf8 && m_unk0x100 < m_unk0xf8) { + position = 3; + m_unk0x148 = g_unk0x100d5d40[rand() % 3]; + m_unk0x14c = g_unk0x100d5d60[rand() % 3]; + } + else if (m_unk0xfc < m_unk0xf8 || m_unk0x100 < m_unk0xf8) { + position = 2; + if (m_unk0xfc == g_unk0x100f0c7c) { + m_unk0x148 = g_unk0x100d5d30[rand() % 4]; + m_unk0x14c = g_unk0x100d5d60[rand() % 3]; + } + else { + m_unk0x148 = g_unk0x100d5d50[rand() % 3]; + m_unk0x14c = g_unk0x100d5d40[rand() % 3]; + } + } + else { + position = 1; + m_unk0x148 = g_unk0x100d5d30[rand() % 4]; + m_unk0x14c = g_unk0x100d5d50[rand() % 3]; + } + + InputManager()->Reset88and336(); + InputManager()->SetUnknown336(TRUE); + VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); + NavController()->SetDeadZone(NavController()->GetDefaultDeadZone()); + NavController()->SetTrackDefault(1); + LegoRaceCar::FUN_10012de0(); + m_raceState->m_unk0x28 = 2; + + RaceState::Entry* raceState = m_raceState->GetState(GameState()->GetActorId()); + raceState->m_unk0x02 = position; + + if (raceState->m_score < (MxS16) position) { + raceState->m_score = position; + } + + AnimationManager()->FUN_10060dc0(m_unk0x148, NULL, TRUE, FALSE, NULL, FALSE, TRUE, FALSE, TRUE); + } + + result = 1; + } + + break; + case 11: + if (paramData <= m_unk0x108 || paramData >= m_unk0x108 + 5) { + break; + } + + FUN_10017820(0xb, paramData); + m_unk0x108 = paramData; + + if (m_unk0x108 == 0x14) { + m_unk0x108 = 0; + m_unk0xfc++; + + if (g_unk0x100f0c7c == m_unk0xfc) { + m_unk0x110[1]->SetMaxLinearVel(-1.0); + RemoveActor(m_unk0x110[1]); + m_unk0x110[1]->ClearMaps(); + m_unk0x110[1]->GetROI()->SetVisibility(FALSE); + + LegoROI* roi = FindROI("rcblack"); + + if (roi) { + roi->SetVisibility(FALSE); + } + } + } + + break; + case 12: + if (paramData <= m_unk0x10c || paramData >= m_unk0x10c + 5) { + break; + } + + FUN_10017820(0xc, paramData); + + m_unk0x10c = paramData; + + if (m_unk0x10c == 0x14) { + m_unk0x10c = 0; + m_unk0x100++; + + if (g_unk0x100f0c7c == m_unk0x100) { + m_unk0x110[2]->SetMaxLinearVel(-1.0); + RemoveActor(m_unk0x110[2]); + m_unk0x110[2]->ClearMaps(); + m_unk0x110[2]->GetROI()->SetVisibility(FALSE); + + LegoROI* roi = FindROI("rcgreen"); + + if (roi) { + roi->SetVisibility(FALSE); + } + } + } + + break; + } + } + + return result; } -// STUB: LEGO1 0x10017650 -MxLong CarRace::HandleClick(LegoEventNotificationParam&) +// FUNCTION: LEGO1 0x10017650 +MxLong CarRace::HandleClick(LegoEventNotificationParam& p_param) { - // TODO - return 0; + LegoControlManagerNotificationParam* param = (LegoControlManagerNotificationParam*) &p_param; + + if (param->m_unk0x28 == 1) { + switch (param->m_clickedObjectId) { + case 3: + InvokeAction(Extra::e_stop, *g_carraceScript, CarraceScript::c_irtx08ra_PlayWav, NULL); + m_act1State->m_unk0x018 = 0; + VariableTable()->SetVariable(g_raceState, ""); + VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); + NavController()->SetDeadZone(NavController()->GetDefaultDeadZone()); + NavController()->SetTrackDefault(1); + LegoRaceCar::FUN_10012de0(); + m_destLocation = LegoGameState::e_infomain; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + GameState()->GetBackgroundColor()->SetValue("reset"); + break; + case 98: + InvokeAction(Extra::e_stop, *g_carraceScript, CarraceScript::c_irtx08ra_PlayWav, NULL); + m_act1State->m_unk0x018 = 0; + VariableTable()->SetVariable(g_raceState, ""); + VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); + NavController()->SetDeadZone(NavController()->GetDefaultDeadZone()); + NavController()->SetTrackDefault(1); + LegoRaceCar::FUN_10012de0(); + m_destLocation = LegoGameState::e_carraceExterior; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + GameState()->GetBackgroundColor()->SetValue("reset"); + break; + default: + break; + } + } + return 1; } -// STUB: LEGO1 0x100177e0 +// FUNCTION: LEGO1 0x100177e0 +// FUNCTION: BETA10 0x100c8f59 MxLong CarRace::HandleType0Notification(MxNotificationParam&) { - // TODO - return 0; + if (m_raceState->m_unk0x28 == 2) { + m_destLocation = LegoGameState::e_unk21; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + + return 1; } -// STUB: LEGO1 0x10017900 +// FUNCTION: LEGO1 0x10017820 +void CarRace::FUN_10017820(MxS32 p_param1, MxS16 p_param2) +{ + MxS32 local4; + MxStillPresenter* presenter; + MxS32 x, y; + + if (p_param1 == 11) { + presenter = m_unk0x128; + local4 = m_unk0xfc; + } + else if (p_param1 == 12) { + presenter = m_unk0x12c; + local4 = m_unk0x100; + } + + if (presenter) { + x = m_unk0x130.GetLeft() + 0.5 + + (m_unk0x130.GetRight() - m_unk0x130.GetLeft() + 1) * (local4 * 20.0 + p_param2) / (g_unk0x100f0c7c * 20.0); + y = m_unk0x130.GetTop() + 0.5 + + (m_unk0x130.GetBottom() - m_unk0x130.GetTop() + 1) * (local4 * 20.0 + p_param2) / (g_unk0x100f0c7c * 20.0); + + presenter->SetPosition(x, y); + } +} + +// FUNCTION: LEGO1 0x10017900 MxBool CarRace::Escape() { - // TODO - return FALSE; + InvokeAction(Extra::e_stop, *g_carraceScript, CarraceScript::c_irtx08ra_PlayWav, NULL); + + AnimationManager()->FUN_10061010(FALSE); + DeleteObjects(&m_atomId, 500, 999); + m_act1State->m_unk0x018 = 0; + VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); + + VariableTable()->SetVariable(g_raceState, ""); + NavController()->SetDeadZone(NavController()->GetDefaultDeadZone()); + + NavController()->SetTrackDefault(1); + LegoRaceCar::FUN_10012de0(); + + GameState()->GetBackgroundColor()->SetValue("reset"); + m_destLocation = LegoGameState::e_infomain; + return TRUE; } diff --git a/LEGO1/lego/legoomni/src/race/jetskirace.cpp b/LEGO1/lego/legoomni/src/race/jetskirace.cpp index b4ffa03e..757aba08 100644 --- a/LEGO1/lego/legoomni/src/race/jetskirace.cpp +++ b/LEGO1/lego/legoomni/src/race/jetskirace.cpp @@ -152,18 +152,6 @@ MxLong JetskiRace::HandleClick(LegoEventNotificationParam& p_param) return result; } -inline MxS32 JetskiRace::PossiblyGetPlaceOfPlayer() -{ - if (m_unk0xfc < m_unk0xf8 && m_unk0x100 < m_unk0xf8) { - return 3; - } - else if (m_unk0xfc < m_unk0xf8 || m_unk0x100 < m_unk0xf8) { - return 2; - } - - return 1; -} - // FUNCTION: LEGO1 0x100166a0 // FUNCTION: BETA10 0x100c8085 MxLong JetskiRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) @@ -190,7 +178,17 @@ MxLong JetskiRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) m_unk0xf8++; if (g_unk0x100f0c78 == m_unk0xf8) { - MxS16 sVar6 = PossiblyGetPlaceOfPlayer(); + MxS32 position; + + if (m_unk0xfc < m_unk0xf8 && m_unk0x100 < m_unk0xf8) { + position = 3; + } + else if (m_unk0xfc < m_unk0xf8 || m_unk0x100 < m_unk0xf8) { + position = 2; + } + else { + position = 1; + } VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); @@ -198,10 +196,10 @@ MxLong JetskiRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) m_raceState->m_unk0x28 = 2; RaceState::Entry* raceStateEntry = m_raceState->GetState(GameState()->GetActorId()); - raceStateEntry->m_unk0x02 = sVar6; + raceStateEntry->m_unk0x02 = position; - if (raceStateEntry->m_score < sVar6) { - raceStateEntry->m_score = sVar6; + if (raceStateEntry->m_score < (MxS16) position) { + raceStateEntry->m_score = position; } m_destLocation = LegoGameState::e_jetrace2; @@ -215,6 +213,7 @@ MxLong JetskiRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) m_hideAnim->FUN_1006db40(m_unk0xf8 * 200 + 100); result = 1; } + break; case 11: if (paramData <= m_unk0x108 || paramData >= m_unk0x108 + 5) { @@ -232,6 +231,7 @@ MxLong JetskiRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) ((LegoPathActor*) p_param.GetSender())->SetMaxLinearVel(0.1); } } + break; case 12: if (paramData <= m_unk0x10c || paramData >= m_unk0x10c + 5) { @@ -250,6 +250,7 @@ MxLong JetskiRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) ((LegoPathActor*) p_param.GetSender())->SetMaxLinearVel(0.1); } } + break; } } diff --git a/LEGO1/lego/legoomni/src/race/legoracers.cpp b/LEGO1/lego/legoomni/src/race/legoracers.cpp index 73a070cd..705b3eb2 100644 --- a/LEGO1/lego/legoomni/src/race/legoracers.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracers.cpp @@ -180,6 +180,13 @@ void LegoRaceCar::FUN_10012de0() g_unk0x100f0b88 = 0; } +// STUB: LEGO1 0x10012e00 +// STUB: BETA10 0x100cb129 +void LegoRaceCar::FUN_10012e00() +{ + // TODO +} + // FUNCTION: LEGO1 0x10012e60 // FUNCTION: BETA10 0x100cb191 void LegoRaceCar::SetWorldSpeed(MxFloat p_worldSpeed) diff --git a/LEGO1/lego/legoomni/src/race/legoracespecial.cpp b/LEGO1/lego/legoomni/src/race/legoracespecial.cpp index 6bfb2565..e81bf457 100644 --- a/LEGO1/lego/legoomni/src/race/legoracespecial.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracespecial.cpp @@ -16,6 +16,8 @@ DECOMP_SIZE_ASSERT(LegoCarRaceActor, 0x1a0) // GLOBAL: LEGO1 0x100f0c68 // STRING: LEGO1 0x100f0c5c +// GLOBAL: BETA10 0x101f5b04 +// STRING: BETA10 0x101f5b14 const char* g_raceState = "RACE_STATE"; // GLOBAL: LEGO1 0x100f7af0 @@ -24,6 +26,8 @@ const char* g_fuel = "FUEL"; // GLOBAL: LEGO1 0x100f0c6c // STRING: LEGO1 0x100f0c54 +// GLOBAL: BETA10 0x101f5b08 +// STRING: BETA10 0x101f5b20 const char* g_racing = "RACING"; // GLOBAL: LEGO1 0x100f7aec diff --git a/LEGO1/library_msvc.h b/LEGO1/library_msvc.h index f50de490..179f4222 100644 --- a/LEGO1/library_msvc.h +++ b/LEGO1/library_msvc.h @@ -744,4 +744,7 @@ // LIBRARY: BETA10 0x100f8ad0 // strcmp +// LIBRARY: BETA10 0x100f9610 +// rand + #endif diff --git a/LEGO1/omni/include/mxactionnotificationparam.h b/LEGO1/omni/include/mxactionnotificationparam.h index e110888e..79c18ee0 100644 --- a/LEGO1/omni/include/mxactionnotificationparam.h +++ b/LEGO1/omni/include/mxactionnotificationparam.h @@ -47,6 +47,7 @@ class MxActionNotificationParam : public MxNotificationParam { return new MxActionNotificationParam(m_type, m_sender, m_action, m_realloc); } // vtable+0x04 + // FUNCTION: BETA10 0x10017970 MxDSAction* GetAction() { return m_action; } protected: diff --git a/LEGO1/omni/include/mxentity.h b/LEGO1/omni/include/mxentity.h index 96348a65..7ca2c8b7 100644 --- a/LEGO1/omni/include/mxentity.h +++ b/LEGO1/omni/include/mxentity.h @@ -8,6 +8,7 @@ #include "mxtypes.h" // VTABLE: LEGO1 0x100d5390 +// VTABLE: BETA10 0x101b93e8 // SIZE 0x10 class MxEntity : public MxCore { public: @@ -33,6 +34,7 @@ class MxEntity : public MxCore { } // FUNCTION: LEGO1 0x10001070 + // FUNCTION: BETA10 0x1000f3a0 virtual MxResult Create(MxS32 p_entityId, const MxAtomId& p_atomId) { m_entityId = p_entityId; @@ -47,7 +49,9 @@ class MxEntity : public MxCore { return SUCCESS; } + // FUNCTION: BETA10 0x10031c60 MxS32 GetEntityId() { return m_entityId; } + MxAtomId& GetAtomId() { return m_atomId; } void SetEntityId(MxS32 p_entityId) { m_entityId = p_entityId; } diff --git a/reccmp-project.yml b/reccmp-project.yml index c4213582..e91334c8 100644 --- a/reccmp-project.yml +++ b/reccmp-project.yml @@ -19,3 +19,14 @@ targets: source-root: LEGO1 hash: sha256: d91435a40fa31f405fba33b03bd3bd40dcd4ca36ccf8ef6162c6c5ca0d7190e7 + ghidra: + ignore-types: + # these classes have been changed by hand to account for changes between LEGO1 and BETA10 + - LegoCarBuild + - LegoCarBuildAnimPresenter + - LegoRace + - LegoWorld + ignore-functions: + # strcpy, strlen, ... (arguments are imported incorrectly) + - 0x100fa200 + - 0x100f9780