From 6497cb42b7b6873584a2a272077b8e1f62889716 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Fri, 11 Jul 2025 03:58:53 +0200 Subject: [PATCH 01/25] Clear unknowns in `Matrix` (#1615) --- .../legoomni/src/video/legoanimpresenter.cpp | 6 +- LEGO1/realtime/matrix.h | 2 +- LEGO1/realtime/matrix4d.inl.h | 60 +++++++++---------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp index 82c76aa6..033525f4 100644 --- a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp @@ -707,7 +707,7 @@ MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi) Matrix4* mn = new MxMatrix(); assert(mn); - MxMatrix local58; + MxMatrix inverse; const Matrix4& local2world = p_roi->GetLocal2World(); MxMatrix* local5c; MxU32 i; @@ -718,7 +718,7 @@ MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi) for (i = 1; i <= m_roiMapSize; i++) { if (m_roiMap[i] == p_roi) { - if (local5c[i].BETA_1005a590(local58) != SUCCESS) { + if (local5c[i].Invert(inverse) != SUCCESS) { goto done; } @@ -727,7 +727,7 @@ MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi) } { - mn->Product(local58, local2world); + mn->Product(inverse, local2world); SetUnknown0xa0(mn); delete[] local5c; SetUnknown0x0cTo1(); diff --git a/LEGO1/realtime/matrix.h b/LEGO1/realtime/matrix.h index bbadcdf2..c799d88f 100644 --- a/LEGO1/realtime/matrix.h +++ b/LEGO1/realtime/matrix.h @@ -45,7 +45,7 @@ class Matrix4 { inline void RotateX(const float& p_angle); inline void RotateY(const float& p_angle); inline void RotateZ(const float& p_angle); - inline int BETA_1005a590(Matrix4& p_mat); + inline int Invert(Matrix4& p_mat); inline void Swap(int p_d1, int p_d2); // FUNCTION: BETA10 0x1001c670 diff --git a/LEGO1/realtime/matrix4d.inl.h b/LEGO1/realtime/matrix4d.inl.h index b8bba5a3..b15e6135 100644 --- a/LEGO1/realtime/matrix4d.inl.h +++ b/LEGO1/realtime/matrix4d.inl.h @@ -288,62 +288,62 @@ void Matrix4::RotateZ(const float& p_angle) } // FUNCTION: BETA10 0x1005a590 -int Matrix4::BETA_1005a590(Matrix4& p_mat) +int Matrix4::Invert(Matrix4& p_mat) { - float local5c[4][4]; - Matrix4 localc(local5c); - localc = *this; + float copyData[4][4]; + Matrix4 copy(copyData); + copy = *this; p_mat.SetIdentity(); for (int i = 0; i < 4; i++) { - int local1c = i; - int local10; + int pivotColumn = i; + int column; - for (local10 = i + 1; local10 < 4; local10++) { - if (fabs(localc[local1c][i]) < fabs(localc[local10][i])) { - local1c = local10; + for (column = i + 1; column < 4; column++) { + if (fabs(copy[pivotColumn][i]) < fabs(copy[column][i])) { + pivotColumn = column; } } - if (local1c != i) { - localc.Swap(local1c, i); - p_mat.Swap(local1c, i); + if (pivotColumn != i) { + copy.Swap(pivotColumn, i); + p_mat.Swap(pivotColumn, i); } - if (localc[i][i] < 0.001f && localc[i][i] > -0.001f) { + if (copy[i][i] < 0.001f && copy[i][i] > -0.001f) { return -1; } - float local60 = localc[i][i]; - int local18; + float pivotValue = copy[i][i]; + int k; - for (local18 = 0; local18 < 4; local18++) { - p_mat[i][local18] /= local60; + for (k = 0; k < 4; k++) { + p_mat[i][k] /= pivotValue; } - for (local18 = 0; local18 < 4; local18++) { - localc[i][local18] /= local60; + for (k = 0; k < 4; k++) { + copy[i][k] /= pivotValue; } - for (local10 = 0; local10 < 4; local10++) { - if (i != local10) { - float afStack70[4]; + for (column = 0; column < 4; column++) { + if (i != column) { + float tempColumn[4]; - for (local18 = 0; local18 < 4; local18++) { - afStack70[local18] = p_mat[i][local18] * localc[local10][i]; + for (k = 0; k < 4; k++) { + tempColumn[k] = p_mat[i][k] * copy[column][i]; } - for (local18 = 0; local18 < 4; local18++) { - p_mat[local10][local18] -= afStack70[local18]; + for (k = 0; k < 4; k++) { + p_mat[column][k] -= tempColumn[k]; } - for (local18 = 0; local18 < 4; local18++) { - afStack70[local18] = localc[i][local18] * localc[local10][i]; + for (k = 0; k < 4; k++) { + tempColumn[k] = copy[i][k] * copy[column][i]; } - for (local18 = 0; local18 < 4; local18++) { - localc[local10][local18] -= afStack70[local18]; + for (k = 0; k < 4; k++) { + copy[column][k] -= tempColumn[k]; } } } From a34c293177c3326dc0d3fd22ffab0ac9263ac91d Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Sat, 12 Jul 2025 02:10:36 +0200 Subject: [PATCH 02/25] Name Disable function in `LegoOmni` and `misc` (#1616) --- LEGO1/lego/legoomni/include/legomain.h | 2 +- LEGO1/lego/legoomni/include/misc.h | 2 +- LEGO1/lego/legoomni/src/actors/ambulance.cpp | 2 +- LEGO1/lego/legoomni/src/actors/bike.cpp | 2 +- LEGO1/lego/legoomni/src/actors/dunebuggy.cpp | 2 +- LEGO1/lego/legoomni/src/actors/helicopter.cpp | 2 +- LEGO1/lego/legoomni/src/actors/jetski.cpp | 2 +- LEGO1/lego/legoomni/src/actors/motorcycle.cpp | 2 +- LEGO1/lego/legoomni/src/actors/skateboard.cpp | 2 +- LEGO1/lego/legoomni/src/actors/towtrack.cpp | 2 +- .../lego/legoomni/src/build/legocarbuild.cpp | 2 +- .../legoomni/src/common/legogamestate.cpp | 2 +- LEGO1/lego/legoomni/src/common/misc.cpp | 4 ++-- .../src/entity/legoworldpresenter.cpp | 2 +- LEGO1/lego/legoomni/src/main/legomain.cpp | 2 +- LEGO1/lego/legoomni/src/race/carrace.cpp | 2 +- LEGO1/lego/legoomni/src/race/jetskirace.cpp | 2 +- LEGO1/lego/legoomni/src/worlds/act3.cpp | 8 ++++---- .../legoomni/src/worlds/elevatorbottom.cpp | 2 +- LEGO1/lego/legoomni/src/worlds/gasstation.cpp | 2 +- LEGO1/lego/legoomni/src/worlds/hospital.cpp | 2 +- LEGO1/lego/legoomni/src/worlds/infocenter.cpp | 20 +++++++++---------- .../legoomni/src/worlds/infocenterdoor.cpp | 2 +- LEGO1/lego/legoomni/src/worlds/isle.cpp | 10 +++++----- LEGO1/lego/legoomni/src/worlds/jukebox.cpp | 2 +- LEGO1/lego/legoomni/src/worlds/legoact2.cpp | 6 +++--- LEGO1/lego/legoomni/src/worlds/police.cpp | 2 +- LEGO1/lego/legoomni/src/worlds/score.cpp | 2 +- 28 files changed, 47 insertions(+), 47 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legomain.h b/LEGO1/lego/legoomni/include/legomain.h index 6f2b1e21..423d715c 100644 --- a/LEGO1/lego/legoomni/include/legomain.h +++ b/LEGO1/lego/legoomni/include/legomain.h @@ -129,7 +129,7 @@ class LegoOmni : public MxOmni { LegoROI* FindROI(const char* p_name); void AddWorld(LegoWorld* p_world); void DeleteWorld(LegoWorld* p_world); - void FUN_1005b4f0(MxBool p_disable, MxU16 p_flags); + void Disable(MxBool p_disable, MxU16 p_flags); void CreateBackgroundAudio(); void RemoveWorld(const MxAtomId& p_atom, MxLong p_objectId); MxResult RegisterWorlds(); diff --git a/LEGO1/lego/legoomni/include/misc.h b/LEGO1/lego/legoomni/include/misc.h index 374b83f2..f9a26e8b 100644 --- a/LEGO1/lego/legoomni/include/misc.h +++ b/LEGO1/lego/legoomni/include/misc.h @@ -48,7 +48,7 @@ LegoPlantManager* PlantManager(); LegoBuildingManager* BuildingManager(); LegoTextureContainer* TextureContainer(); ViewLODListManager* GetViewLODListManager(); -void FUN_10015820(MxBool p_disable, MxU16 p_flags); +void Disable(MxBool p_disable, MxU16 p_flags); LegoROI* FindROI(const char* p_name); void SetROIVisible(const char* p_name, MxBool p_visible); void SetUserActor(LegoPathActor* p_userActor); diff --git a/LEGO1/lego/legoomni/src/actors/ambulance.cpp b/LEGO1/lego/legoomni/src/actors/ambulance.cpp index 95ca6975..b439db66 100644 --- a/LEGO1/lego/legoomni/src/actors/ambulance.cpp +++ b/LEGO1/lego/legoomni/src/actors/ambulance.cpp @@ -372,7 +372,7 @@ MxLong Ambulance::HandleClick() return 1; } - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::e_ambulance); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); diff --git a/LEGO1/lego/legoomni/src/actors/bike.cpp b/LEGO1/lego/legoomni/src/actors/bike.cpp index 6c82cb0d..fa9bedcb 100644 --- a/LEGO1/lego/legoomni/src/actors/bike.cpp +++ b/LEGO1/lego/legoomni/src/actors/bike.cpp @@ -54,7 +54,7 @@ MxLong Bike::HandleClick() { if (CanExit()) { Act1State* state = (Act1State*) GameState()->GetState("Act1State"); - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_bike); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE); diff --git a/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp b/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp index e9ec7817..562edfd9 100644 --- a/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp +++ b/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp @@ -92,7 +92,7 @@ MxLong DuneBuggy::HandleClick() return 1; } - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_dunecar); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE); diff --git a/LEGO1/lego/legoomni/src/actors/helicopter.cpp b/LEGO1/lego/legoomni/src/actors/helicopter.cpp index c8c465f7..622fe71e 100644 --- a/LEGO1/lego/legoomni/src/actors/helicopter.cpp +++ b/LEGO1/lego/legoomni/src/actors/helicopter.cpp @@ -148,7 +148,7 @@ MxLong Helicopter::HandleClick() IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 ); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::e_copter); - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE); SetActorState(c_disabled); PlayMusic(JukeboxScript::c_Jail_Music); diff --git a/LEGO1/lego/legoomni/src/actors/jetski.cpp b/LEGO1/lego/legoomni/src/actors/jetski.cpp index 11ff7d18..caf3d1f8 100644 --- a/LEGO1/lego/legoomni/src/actors/jetski.cpp +++ b/LEGO1/lego/legoomni/src/actors/jetski.cpp @@ -85,7 +85,7 @@ MxLong Jetski::HandleClick() return 1; } - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_jetski); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE); diff --git a/LEGO1/lego/legoomni/src/actors/motorcycle.cpp b/LEGO1/lego/legoomni/src/actors/motorcycle.cpp index 5819598e..99810420 100644 --- a/LEGO1/lego/legoomni/src/actors/motorcycle.cpp +++ b/LEGO1/lego/legoomni/src/actors/motorcycle.cpp @@ -88,7 +88,7 @@ MxLong Motocycle::HandleClick() return 1; } - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_motocycle); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE); diff --git a/LEGO1/lego/legoomni/src/actors/skateboard.cpp b/LEGO1/lego/legoomni/src/actors/skateboard.cpp index 0998ba58..12524111 100644 --- a/LEGO1/lego/legoomni/src/actors/skateboard.cpp +++ b/LEGO1/lego/legoomni/src/actors/skateboard.cpp @@ -79,7 +79,7 @@ MxLong SkateBoard::HandleClick() return 1; } - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_skateboard); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE); diff --git a/LEGO1/lego/legoomni/src/actors/towtrack.cpp b/LEGO1/lego/legoomni/src/actors/towtrack.cpp index 7d8a8975..bb117e5f 100644 --- a/LEGO1/lego/legoomni/src/actors/towtrack.cpp +++ b/LEGO1/lego/legoomni/src/actors/towtrack.cpp @@ -411,7 +411,7 @@ MxLong TowTrack::HandleClick() return 1; } - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::e_towtrack); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); diff --git a/LEGO1/lego/legoomni/src/build/legocarbuild.cpp b/LEGO1/lego/legoomni/src/build/legocarbuild.cpp index 5f99393e..8809cd5c 100644 --- a/LEGO1/lego/legoomni/src/build/legocarbuild.cpp +++ b/LEGO1/lego/legoomni/src/build/legocarbuild.cpp @@ -1253,7 +1253,7 @@ void LegoCarBuild::FUN_10024ef0() m_buildState->m_animationState = LegoVehicleBuildState::e_cutscene; FUN_10025720(FUN_10025d70()); m_buildState->m_unk0x4c += 1; - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x10024f30 diff --git a/LEGO1/lego/legoomni/src/common/legogamestate.cpp b/LEGO1/lego/legoomni/src/common/legogamestate.cpp index 1e53cb4f..3dbe88bc 100644 --- a/LEGO1/lego/legoomni/src/common/legogamestate.cpp +++ b/LEGO1/lego/legoomni/src/common/legogamestate.cpp @@ -851,7 +851,7 @@ void LegoGameState::SwitchArea(Area p_area) m_previousArea = m_currentArea; m_currentArea = p_area; - FUN_10015820(TRUE, LegoOmni::c_disableInput | LegoOmni::c_disable3d); + Disable(TRUE, LegoOmni::c_disableInput | LegoOmni::c_disable3d); BackgroundAudioManager()->Stop(); AnimationManager()->Suspend(); VideoManager()->SetUnk0x554(FALSE); diff --git a/LEGO1/lego/legoomni/src/common/misc.cpp b/LEGO1/lego/legoomni/src/common/misc.cpp index 08072b7c..6b231b56 100644 --- a/LEGO1/lego/legoomni/src/common/misc.cpp +++ b/LEGO1/lego/legoomni/src/common/misc.cpp @@ -140,10 +140,10 @@ ViewLODListManager* GetViewLODListManager() // FUNCTION: LEGO1 0x10015820 // FUNCTION: BETA10 0x100e4c92 -void FUN_10015820(MxBool p_disable, MxU16 p_flags) +void Disable(MxBool p_disable, MxU16 p_flags) { assert(LegoOmni::GetInstance()); - LegoOmni::GetInstance()->FUN_1005b4f0(p_disable, p_flags); + LegoOmni::GetInstance()->Disable(p_disable, p_flags); } // FUNCTION: LEGO1 0x10015840 diff --git a/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp b/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp index 6bd3ca51..397a4a77 100644 --- a/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp @@ -62,7 +62,7 @@ LegoWorldPresenter::~LegoWorldPresenter() } if (result == FALSE) { - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } if (m_entity) { diff --git a/LEGO1/lego/legoomni/src/main/legomain.cpp b/LEGO1/lego/legoomni/src/main/legomain.cpp index 632b2943..548cc427 100644 --- a/LEGO1/lego/legoomni/src/main/legomain.cpp +++ b/LEGO1/lego/legoomni/src/main/legomain.cpp @@ -518,7 +518,7 @@ LegoOmni::World LegoOmni::GetWorldId(const char* p_key) } // FUNCTION: LEGO1 0x1005b4f0 -void LegoOmni::FUN_1005b4f0(MxBool p_disable, MxU16 p_flags) +void LegoOmni::Disable(MxBool p_disable, MxU16 p_flags) { if (p_disable) { if (p_flags & c_disableInput) { diff --git a/LEGO1/lego/legoomni/src/race/carrace.cpp b/LEGO1/lego/legoomni/src/race/carrace.cpp index 0c3c3a51..fb4cc192 100644 --- a/LEGO1/lego/legoomni/src/race/carrace.cpp +++ b/LEGO1/lego/legoomni/src/race/carrace.cpp @@ -124,7 +124,7 @@ void CarRace::ReadyWorld() BackgroundAudioManager()->PlayMusic(action, 5, MxPresenter::e_repeating); AnimationManager()->Resume(); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); m_unk0x144 = g_unk0x100d5d10[rand() & 7]; diff --git a/LEGO1/lego/legoomni/src/race/jetskirace.cpp b/LEGO1/lego/legoomni/src/race/jetskirace.cpp index 1297ed36..eddb7266 100644 --- a/LEGO1/lego/legoomni/src/race/jetskirace.cpp +++ b/LEGO1/lego/legoomni/src/race/jetskirace.cpp @@ -95,7 +95,7 @@ void JetskiRace::ReadyWorld() m_unk0x12c = (MxStillPresenter*) Find("MxPresenter", "JetskiLocator3"); m_unk0x12c->SetPosition(m_unk0x130.GetLeft(), m_unk0x130.GetTop()); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); VariableTable()->SetVariable("DISTANCE", "0.036"); diff --git a/LEGO1/lego/legoomni/src/worlds/act3.cpp b/LEGO1/lego/legoomni/src/worlds/act3.cpp index 10bf69cf..ecef0c51 100644 --- a/LEGO1/lego/legoomni/src/worlds/act3.cpp +++ b/LEGO1/lego/legoomni/src/worlds/act3.cpp @@ -552,7 +552,7 @@ MxLong Act3::Notify(MxParam& p_param) if (param.GetAction() != NULL && param.GetAction()->GetAtomId() == *g_act3Script) { if (param.GetAction()->GetObjectId() == Act3Script::c_HelicopterDashboard) { MxDSAction action; - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); SetAppCursor(e_cursorArrow); VideoManager()->Get3DManager()->SetFrustrum(45.0f, 0.1f, 125.0f); @@ -634,7 +634,7 @@ MxLong Act3::Notify(MxParam& p_param) assert(m_copter && m_brickster && m_cop1 && m_cop2); m_unk0x4220.FUN_100720d0(0); m_state->m_unk0x08 = 0; - FUN_10015820(TRUE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(TRUE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); m_copter->HandleClick(); m_copter->m_state->m_unk0x08 = 1; m_copter->HandleEndAnim((LegoEndAnimNotificationParam&) param); @@ -685,7 +685,7 @@ MxResult Act3::Tickle() if (m_unk0x426c != (Act3Script::Script) 0) { if (AnimationManager()->FUN_10064ee0(m_unk0x426c)) { - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); TickleManager()->UnregisterClient(this); m_unk0x426c = (Act3Script::Script) 0; } @@ -880,7 +880,7 @@ void Act3::Enable(MxBool p_enable) GameState()->StopArea(LegoGameState::e_infomain); } - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); PlayMusic(JukeboxScript::c_Act3Music); GameState()->m_isDirty = TRUE; diff --git a/LEGO1/lego/legoomni/src/worlds/elevatorbottom.cpp b/LEGO1/lego/legoomni/src/worlds/elevatorbottom.cpp index 7affe1c8..2a9c0772 100644 --- a/LEGO1/lego/legoomni/src/worlds/elevatorbottom.cpp +++ b/LEGO1/lego/legoomni/src/worlds/elevatorbottom.cpp @@ -79,7 +79,7 @@ void ElevatorBottom::ReadyWorld() { LegoWorld::ReadyWorld(); PlayMusic(JukeboxScript::c_InformationCenter_Music); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x100181d0 diff --git a/LEGO1/lego/legoomni/src/worlds/gasstation.cpp b/LEGO1/lego/legoomni/src/worlds/gasstation.cpp index 024683b3..40e757c7 100644 --- a/LEGO1/lego/legoomni/src/worlds/gasstation.cpp +++ b/LEGO1/lego/legoomni/src/worlds/gasstation.cpp @@ -265,7 +265,7 @@ void GasStation::ReadyWorld() break; } - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x10005590 diff --git a/LEGO1/lego/legoomni/src/worlds/hospital.cpp b/LEGO1/lego/legoomni/src/worlds/hospital.cpp index dbb1c00c..74d15678 100644 --- a/LEGO1/lego/legoomni/src/worlds/hospital.cpp +++ b/LEGO1/lego/legoomni/src/worlds/hospital.cpp @@ -214,7 +214,7 @@ void Hospital::ReadyWorld() m_setWithCurrentAction = 1; } - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x10074dd0 diff --git a/LEGO1/lego/legoomni/src/worlds/infocenter.cpp b/LEGO1/lego/legoomni/src/worlds/infocenter.cpp index 0a8d5f1c..19957ac8 100644 --- a/LEGO1/lego/legoomni/src/worlds/infocenter.cpp +++ b/LEGO1/lego/legoomni/src/worlds/infocenter.cpp @@ -465,7 +465,7 @@ void Infocenter::ReadyWorld() PlayAction(InfomainScript::c_iicx18in_RunAnim); PlayMusic(JukeboxScript::c_InformationCenter_Music); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); return; case 5: default: { @@ -478,7 +478,7 @@ void Infocenter::ReadyWorld() m_bigInfoBlinkTimer = 1; } - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); if (!m_infocenterState->HasRegistered()) { m_bookAnimationTimer = 1; @@ -489,7 +489,7 @@ void Infocenter::ReadyWorld() case 8: PlayMusic(JukeboxScript::c_InformationCenter_Music); PlayAction(InfomainScript::c_iic043in_RunAnim); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); return; case 0xf: m_infocenterState->m_unk0x74 = 2; @@ -499,7 +499,7 @@ void Infocenter::ReadyWorld() PlayAction(InfomainScript::c_iicx17in_RunAnim); PlayMusic(JukeboxScript::c_InformationCenter_Music); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); return; } break; @@ -508,7 +508,7 @@ void Infocenter::ReadyWorld() PlayMusic(JukeboxScript::c_InformationCenter_Music); bgRed->Enable(TRUE); PlayAction(InfomainScript::c_iic043in_RunAnim); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); return; } @@ -538,7 +538,7 @@ void Infocenter::ReadyWorld() PlayAction(script); InputManager()->DisableInputProcessing(); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); return; } @@ -553,7 +553,7 @@ void Infocenter::ReadyWorld() PlayMusic(JukeboxScript::c_InformationCenter_Music); bgRed->Enable(TRUE); PlayAction(InfomainScript::c_iic043in_RunAnim); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); return; } @@ -590,7 +590,7 @@ void Infocenter::ReadyWorld() PlayAction(script); InputManager()->DisableInputProcessing(); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); return; } @@ -603,7 +603,7 @@ void Infocenter::ReadyWorld() } m_infocenterState->m_unk0x74 = 11; - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x1006f9a0 @@ -1284,7 +1284,7 @@ void Infocenter::StopCutscene() VideoManager()->EnableFullScreenMovie(FALSE); InputManager()->SetUnknown335(FALSE); SetAppCursor(e_cursorArrow); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x10070d00 diff --git a/LEGO1/lego/legoomni/src/worlds/infocenterdoor.cpp b/LEGO1/lego/legoomni/src/worlds/infocenterdoor.cpp index c546744a..8f92a323 100644 --- a/LEGO1/lego/legoomni/src/worlds/infocenterdoor.cpp +++ b/LEGO1/lego/legoomni/src/worlds/infocenterdoor.cpp @@ -88,7 +88,7 @@ void InfocenterDoor::ReadyWorld() { LegoWorld::ReadyWorld(); PlayMusic(JukeboxScript::c_InformationCenter_Music); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x10037a90 diff --git a/LEGO1/lego/legoomni/src/worlds/isle.cpp b/LEGO1/lego/legoomni/src/worlds/isle.cpp index 7865969b..2b630be4 100644 --- a/LEGO1/lego/legoomni/src/worlds/isle.cpp +++ b/LEGO1/lego/legoomni/src/worlds/isle.cpp @@ -277,7 +277,7 @@ void Isle::ReadyWorld() EnableAnimations(TRUE); FUN_10032620(); m_act1state->PlaceActors(); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } } @@ -839,7 +839,7 @@ void Isle::Enable(MxBool p_enable) (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_jetski) && (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_skateboard) && (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_jetrace2)) { - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } SetROIVisible("stretch", FALSE); @@ -961,7 +961,7 @@ MxLong Isle::HandleTransitionEnd() m_destLocation = LegoGameState::e_undefined; VariableTable()->SetVariable("VISIBILITY", "Show Gas"); AnimationManager()->Resume(); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); SetAppCursor(e_cursorArrow); SetIsWorldActive(TRUE); break; @@ -971,7 +971,7 @@ MxLong Isle::HandleTransitionEnd() m_destLocation = LegoGameState::e_undefined; VariableTable()->SetVariable("VISIBILITY", "Show Policsta"); AnimationManager()->Resume(); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); SetAppCursor(e_cursorArrow); SetIsWorldActive(TRUE); break; @@ -1082,7 +1082,7 @@ void Isle::FUN_10032d30( VariableTable()->SetVariable(g_varCAMERALOCATION, p_cameraLocation); } - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); SetAppCursor(e_cursorArrow); m_destLocation = LegoGameState::e_undefined; m_act1state->m_unk0x01f = FALSE; diff --git a/LEGO1/lego/legoomni/src/worlds/jukebox.cpp b/LEGO1/lego/legoomni/src/worlds/jukebox.cpp index a92f493d..d09b7e62 100644 --- a/LEGO1/lego/legoomni/src/worlds/jukebox.cpp +++ b/LEGO1/lego/legoomni/src/worlds/jukebox.cpp @@ -247,7 +247,7 @@ MxResult JukeBox::Tickle() if (m_unk0x100 == 1) { m_unk0x100 = 0; - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } return SUCCESS; diff --git a/LEGO1/lego/legoomni/src/worlds/legoact2.cpp b/LEGO1/lego/legoomni/src/worlds/legoact2.cpp index ddc97f1c..49936b28 100644 --- a/LEGO1/lego/legoomni/src/worlds/legoact2.cpp +++ b/LEGO1/lego/legoomni/src/worlds/legoact2.cpp @@ -192,7 +192,7 @@ MxResult LegoAct2::Tickle() case 2: if (g_unk0x100f4474) { if (AnimationManager()->FUN_10064ee0(g_unk0x100f4474)) { - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); g_unk0x100f4474 = (Act2mainScript::Script) 0; } } @@ -200,7 +200,7 @@ MxResult LegoAct2::Tickle() m_unk0x10d0 += 50; break; case 3: - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); m_unk0x10d0 = 0; m_unk0x10c4 = 4; FUN_10052560(Act2mainScript::c_tja009ni_RunAnim, TRUE, TRUE, NULL, NULL, NULL); @@ -540,7 +540,7 @@ void LegoAct2::Enable(MxBool p_enable) GameState()->StopArea(LegoGameState::e_infomain); } - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); if (m_unk0x10c4 != 6 && m_unk0x10c4 != 12) { PlayMusic(m_music); diff --git a/LEGO1/lego/legoomni/src/worlds/police.cpp b/LEGO1/lego/legoomni/src/worlds/police.cpp index f1936ead..1c3bccd7 100644 --- a/LEGO1/lego/legoomni/src/worlds/police.cpp +++ b/LEGO1/lego/legoomni/src/worlds/police.cpp @@ -95,7 +95,7 @@ void Police::ReadyWorld() { LegoWorld::ReadyWorld(); PlayMusic(JukeboxScript::c_PoliceStation_Music); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x1005e550 diff --git a/LEGO1/lego/legoomni/src/worlds/score.cpp b/LEGO1/lego/legoomni/src/worlds/score.cpp index 76f987e2..edc2d991 100644 --- a/LEGO1/lego/legoomni/src/worlds/score.cpp +++ b/LEGO1/lego/legoomni/src/worlds/score.cpp @@ -159,7 +159,7 @@ void Score::ReadyWorld() PlayMusic(JukeboxScript::c_InformationCenter_Music); } - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x100016d0 From d9d9880d8b37c0cf10128575e1a9684fdfe1c64a Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Sat, 12 Jul 2025 02:11:12 +0200 Subject: [PATCH 03/25] Clear unknowns in `LegoAnimNodeData` (#1617) --- LEGO1/lego/legoomni/src/video/legohideanimpresenter.cpp | 8 ++++---- LEGO1/lego/sources/anim/legoanim.cpp | 2 +- LEGO1/lego/sources/anim/legoanim.h | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/LEGO1/lego/legoomni/src/video/legohideanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legohideanimpresenter.cpp index 89768b3e..60f8dce5 100644 --- a/LEGO1/lego/legoomni/src/video/legohideanimpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legohideanimpresenter.cpp @@ -114,7 +114,7 @@ void LegoHideAnimPresenter::FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time) } if (m_boundaryMap != NULL) { - LegoPathBoundary* boundary = m_boundaryMap[data->GetUnknown0x22()]; + LegoPathBoundary* boundary = m_boundaryMap[data->GetBoundaryIndex()]; if (boundary != NULL) { newB = data->GetVisibility(p_time); @@ -163,7 +163,7 @@ void LegoHideAnimPresenter::FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeN FUN_1006e470(p_map, data, name, boundary); } else { - data->SetUnknown0x22(0); + data->SetBoundaryIndex(0); } } @@ -190,7 +190,7 @@ void LegoHideAnimPresenter::FUN_1006e470( animStruct.m_index = p_map.size() + 1; animStruct.m_boundary = p_boundary; - p_data->SetUnknown0x22(animStruct.m_index); + p_data->SetBoundaryIndex(animStruct.m_index); char* name = new char[strlen(p_name) + 1]; strcpy(name, p_name); @@ -198,7 +198,7 @@ void LegoHideAnimPresenter::FUN_1006e470( p_map[name] = animStruct; } else { - p_data->SetUnknown0x22((*it).second.m_index); + p_data->SetBoundaryIndex((*it).second.m_index); } } diff --git a/LEGO1/lego/sources/anim/legoanim.cpp b/LEGO1/lego/sources/anim/legoanim.cpp index 8ec3ee2d..9026c245 100644 --- a/LEGO1/lego/sources/anim/legoanim.cpp +++ b/LEGO1/lego/sources/anim/legoanim.cpp @@ -524,7 +524,7 @@ LegoAnimNodeData::LegoAnimNodeData() m_translationKeys = NULL; m_roiIndex = 0; m_rotationKeys = NULL; - m_unk0x22 = 0; + m_boundaryIndex = 0; m_scaleKeys = NULL; m_morphKeys = NULL; m_translationIndex = 0; diff --git a/LEGO1/lego/sources/anim/legoanim.h b/LEGO1/lego/sources/anim/legoanim.h index 372128b5..7a03d99c 100644 --- a/LEGO1/lego/sources/anim/legoanim.h +++ b/LEGO1/lego/sources/anim/legoanim.h @@ -190,7 +190,7 @@ class LegoAnimNodeData : public LegoTreeNodeData { LegoU16 GetROIIndex() { return m_roiIndex; } // FUNCTION: BETA10 0x1005d5c0 - LegoU16 GetUnknown0x22() { return m_unk0x22; } + LegoU16 GetBoundaryIndex() { return m_boundaryIndex; } // FUNCTION: BETA10 0x10073b80 LegoRotationKey* GetRotationKey(MxS32 index) { return &m_rotationKeys[index]; } @@ -217,7 +217,7 @@ class LegoAnimNodeData : public LegoTreeNodeData { void SetROIIndex(LegoU16 p_roiIndex) { m_roiIndex = p_roiIndex; } // FUNCTION: BETA10 0x1005f2e0 - void SetUnknown0x22(LegoU16 p_unk0x22) { m_unk0x22 = p_unk0x22; } + void SetBoundaryIndex(LegoU16 p_boundaryIndex) { m_boundaryIndex = p_boundaryIndex; } LegoResult CreateLocalTransform(LegoTime p_time, Matrix4& p_matrix) { @@ -280,7 +280,7 @@ class LegoAnimNodeData : public LegoTreeNodeData { LegoScaleKey* m_scaleKeys; // 0x18 LegoMorphKey* m_morphKeys; // 0x1c LegoU16 m_roiIndex; // 0x20 - LegoU16 m_unk0x22; // 0x22 + LegoU16 m_boundaryIndex; // 0x22 LegoU32 m_translationIndex; // 0x24 LegoU32 m_rotationIndex; // 0x28 LegoU32 m_scaleIndex; // 0x2c From 10986376cb543ca1eb76b117b6c220caef78f931 Mon Sep 17 00:00:00 2001 From: MS Date: Fri, 11 Jul 2025 23:26:21 -0400 Subject: [PATCH 04/25] Fix #1575 (#1618) --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 064a207e..c9fe6030 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -592,6 +592,10 @@ if (MSVC_FOR_DECOMP) set_property(TARGET isle ${lego1_targets} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") endif() + if (ISLE_BUILD_CONFIG) + target_link_libraries(config PRIVATE mfc42) + endif() + if (ISLE_INCLUDE_ENTROPY) message(STATUS "Using entropy file: ${ISLE_ENTROPY_FILENAME}") foreach(tgt IN LISTS lego1_targets beta10_targets) From ac4653759958a437c042060632d9ebb08aeffe54 Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Sat, 12 Jul 2025 17:05:29 +0200 Subject: [PATCH 05/25] Interpret Act3List properties, minor fixes (#1619) Co-authored-by: jonschz --- LEGO1/lego/legoomni/include/act3.h | 16 ++-- .../lego/legoomni/include/legoinputmanager.h | 1 + .../lego/legoomni/include/legovideomanager.h | 2 + LEGO1/lego/legoomni/src/main/legomain.cpp | 38 +++++---- LEGO1/lego/legoomni/src/worlds/act3.cpp | 81 ++++++++++--------- LEGO1/omni/include/mxvideomanager.h | 3 + LEGO1/omni/src/video/mxdisplaysurface.cpp | 12 +-- 7 files changed, 89 insertions(+), 64 deletions(-) diff --git a/LEGO1/lego/legoomni/include/act3.h b/LEGO1/lego/legoomni/include/act3.h index 38e2876e..040da125 100644 --- a/LEGO1/lego/legoomni/include/act3.h +++ b/LEGO1/lego/legoomni/include/act3.h @@ -20,12 +20,12 @@ class MxQuaternionTransformer; struct Act3ListElement { MxU32 m_objectId; // 0x00 undefined4 m_unk0x04; // 0x04 - undefined m_unk0x08; // 0x08 + MxBool m_hasStarted; // 0x08 Act3ListElement() {} - Act3ListElement(MxU32 p_objectId, undefined4 p_unk0x04, undefined p_unk0x08) - : m_objectId(p_objectId), m_unk0x04(p_unk0x04), m_unk0x08(p_unk0x08) + Act3ListElement(MxU32 p_objectId, undefined4 p_unk0x04, MxBool p_hasStarted) + : m_objectId(p_objectId), m_unk0x04(p_unk0x04), m_hasStarted(p_hasStarted) { } @@ -36,10 +36,16 @@ struct Act3ListElement { // SIZE 0x10 class Act3List : private list { public: + enum InsertMode { + e_replaceAction = 1, + e_queueAction = 2, + e_onlyIfEmpty = 3 + }; + Act3List() { m_unk0x0c = 0; } - void Insert(MxS32 p_objectId, MxS32 p_option); - void FUN_10071fa0(); + void Insert(MxS32 p_objectId, InsertMode p_option); + void DeleteActionWrapper(); void Clear(); void FUN_100720d0(MxU32 p_objectId); diff --git a/LEGO1/lego/legoomni/include/legoinputmanager.h b/LEGO1/lego/legoomni/include/legoinputmanager.h index 27e53fcb..0013bcde 100644 --- a/LEGO1/lego/legoomni/include/legoinputmanager.h +++ b/LEGO1/lego/legoomni/include/legoinputmanager.h @@ -117,6 +117,7 @@ class LegoInputManager : public MxPresenter { void SetUseJoystick(MxBool p_useJoystick) { m_useJoystick = p_useJoystick; } void SetJoystickIndex(MxS32 p_joystickIndex) { m_joystickIndex = p_joystickIndex; } + // FUNCTION: BETA10 0x1002e290 void DisableInputProcessing() { m_unk0x88 = TRUE; diff --git a/LEGO1/lego/legoomni/include/legovideomanager.h b/LEGO1/lego/legoomni/include/legovideomanager.h index e7848c02..52a760fe 100644 --- a/LEGO1/lego/legoomni/include/legovideomanager.h +++ b/LEGO1/lego/legoomni/include/legovideomanager.h @@ -62,7 +62,9 @@ class LegoVideoManager : public MxVideoManager { MxBool GetRender3D() { return m_render3d; } double GetElapsedSeconds() { return m_elapsedSeconds; } + // FUNCTION: BETA10 0x1002e290 void SetRender3D(MxBool p_render3d) { m_render3d = p_render3d; } + void SetUnk0x554(MxBool p_unk0x554) { m_unk0x554 = p_unk0x554; } private: diff --git a/LEGO1/lego/legoomni/src/main/legomain.cpp b/LEGO1/lego/legoomni/src/main/legomain.cpp index 548cc427..0da66855 100644 --- a/LEGO1/lego/legoomni/src/main/legomain.cpp +++ b/LEGO1/lego/legoomni/src/main/legomain.cpp @@ -518,26 +518,36 @@ LegoOmni::World LegoOmni::GetWorldId(const char* p_key) } // FUNCTION: LEGO1 0x1005b4f0 +// FUNCTION: BETA10 0x1008eeec void LegoOmni::Disable(MxBool p_disable, MxU16 p_flags) { - if (p_disable) { - if (p_flags & c_disableInput) { - m_inputManager->DisableInputProcessing(); - } +#ifdef BETA10 + if (this->m_paused != p_disable) { + // This is probably a different variable, but this code was mostly added for structural matching + m_paused = p_disable; +#endif - if (p_flags & c_disable3d) { - ((LegoVideoManager*) m_videoManager)->SetRender3D(FALSE); - } + if (p_disable) { + if (p_flags & c_disableInput) { + m_inputManager->DisableInputProcessing(); + } - if (p_flags & c_clearScreen) { - m_videoManager->GetDisplaySurface()->ClearScreen(); + if (p_flags & c_disable3d) { + ((LegoVideoManager*) m_videoManager)->SetRender3D(FALSE); + } + + if (p_flags & c_clearScreen) { + m_videoManager->GetDisplaySurface()->ClearScreen(); + } } + else { + m_inputManager->EnableInputProcessing(); + ((LegoVideoManager*) m_videoManager)->SetRender3D(TRUE); + ((LegoVideoManager*) m_videoManager)->UpdateView(0, 0, 0, 0); + } +#ifdef BETA10 } - else { - m_inputManager->EnableInputProcessing(); - ((LegoVideoManager*) m_videoManager)->SetRender3D(TRUE); - ((LegoVideoManager*) m_videoManager)->UpdateView(0, 0, 0, 0); - } +#endif } // FUNCTION: LEGO1 0x1005b560 diff --git a/LEGO1/lego/legoomni/src/worlds/act3.cpp b/LEGO1/lego/legoomni/src/worlds/act3.cpp index ecef0c51..8bfaacd4 100644 --- a/LEGO1/lego/legoomni/src/worlds/act3.cpp +++ b/LEGO1/lego/legoomni/src/worlds/act3.cpp @@ -109,16 +109,16 @@ Act3Script::Script g_unk0x100d95e8[] = {Act3Script::c_tlp053in_RunAnim, Act3Script::c_tlp064la_RunAnim, Act3Script::c_tlp068in_RunAnim}; // FUNCTION: LEGO1 0x10071d40 -void Act3List::Insert(MxS32 p_objectId, MxS32 p_option) +void Act3List::Insert(MxS32 p_objectId, InsertMode p_option) { if (m_unk0x0c) { return; } switch (p_option) { - case 1: + case InsertMode::e_replaceAction: if (!empty()) { - FUN_10071fa0(); + DeleteActionWrapper(); push_back(Act3ListElement(p_objectId, p_option, FALSE)); } else { @@ -126,7 +126,7 @@ void Act3List::Insert(MxS32 p_objectId, MxS32 p_option) push_back(Act3ListElement(p_objectId, p_option, TRUE)); } break; - case 2: + case InsertMode::e_queueAction: if (empty()) { push_back(Act3ListElement(p_objectId, p_option, TRUE)); InvokeAction(Extra::e_start, *g_act3Script, p_objectId, NULL); @@ -135,7 +135,7 @@ void Act3List::Insert(MxS32 p_objectId, MxS32 p_option) push_back(Act3ListElement(p_objectId, p_option, FALSE)); } break; - case 3: + case InsertMode::e_onlyIfEmpty: if (empty()) { push_back(Act3ListElement(p_objectId, p_option, TRUE)); InvokeAction(Extra::e_start, *g_act3Script, p_objectId, NULL); @@ -145,7 +145,7 @@ void Act3List::Insert(MxS32 p_objectId, MxS32 p_option) } // FUNCTION: LEGO1 0x10071fa0 -void Act3List::FUN_10071fa0() +void Act3List::DeleteActionWrapper() { DeleteAction(); } @@ -161,7 +161,7 @@ void Act3List::Clear() } for (Act3List::iterator it = begin(); it != end();) { - if ((*it).m_unk0x08) { + if ((*it).m_hasStarted) { MxDSAction ds; ds.SetAtomId(*g_act3Script); ds.SetObjectId((*it).m_objectId); @@ -175,46 +175,47 @@ void Act3List::Clear() // FUNCTION: LEGO1 0x100720d0 void Act3List::FUN_100720d0(MxU32 p_objectId) { - if (m_unk0x0c == 0) { - MxU32 removed = FALSE; + if (m_unk0x0c) { + return; + } - if (!empty()) { - if (p_objectId != 0) { - for (Act3List::iterator it = begin(); it != end(); it++) { - if ((*it).m_unk0x08 && (*it).m_objectId == p_objectId) { - erase(it); - removed = TRUE; - break; - } + MxU32 removed = FALSE; + + if (!empty()) { + if (p_objectId != 0) { + for (Act3List::iterator it = begin(); it != end(); it++) { + if ((*it).m_hasStarted && (*it).m_objectId == p_objectId) { + erase(it); + removed = TRUE; + break; } } - else { - pop_front(); - removed = TRUE; - } + } + else { + pop_front(); + removed = TRUE; + } - if (removed && size() > 0) { - // TODO: Match - Act3List::iterator it = begin(); - Act3ListElement& item = *(it++); + if (removed && size() > 0) { + Act3List::iterator it = begin(); + Act3ListElement& firstItem = *(it++); - for (; it != end(); it++) { - if ((*it).m_unk0x04 == 1) { - for (Act3List::iterator it2 = begin(); it2 != it;) { - if ((*it2).m_unk0x08) { - FUN_10071fa0(); - return; - } - - it2 = erase(it2); + for (; it != end(); it++) { + if ((*it).m_unk0x04 == 1) { + for (Act3List::iterator it2 = begin(); it2 != it;) { + if ((*it2).m_hasStarted) { + DeleteActionWrapper(); + return; } + + it2 = erase(it2); } } + } - if (!item.m_unk0x08) { - item.m_unk0x08 = TRUE; - InvokeAction(Extra::e_start, *g_act3Script, item.m_objectId, NULL); - } + if (!firstItem.m_hasStarted) { + firstItem.m_hasStarted = TRUE; + InvokeAction(Extra::e_start, *g_act3Script, firstItem.m_objectId, NULL); } } } @@ -454,14 +455,14 @@ void Act3::TriggerHitSound(undefined4 p_param1) m_bricksterDonutSound = 0; } - m_unk0x4220.Insert(g_bricksterDonutSounds[m_bricksterDonutSound++], 1); + m_unk0x4220.Insert(g_bricksterDonutSounds[m_bricksterDonutSound++], Act3List::e_replaceAction); return; } default: return; } - m_unk0x4220.Insert(objectId, 3); + m_unk0x4220.Insert(objectId, Act3List::e_onlyIfEmpty); } // FUNCTION: LEGO1 0x10072c30 diff --git a/LEGO1/omni/include/mxvideomanager.h b/LEGO1/omni/include/mxvideomanager.h index 78411dcb..2ecab25d 100644 --- a/LEGO1/omni/include/mxvideomanager.h +++ b/LEGO1/omni/include/mxvideomanager.h @@ -41,7 +41,10 @@ class MxVideoManager : public MxMediaManager { MxVideoParam& GetVideoParam() { return this->m_videoParam; } LPDIRECTDRAW GetDirectDraw() { return this->m_pDirectDraw; } + + // FUNCTION: BETA10 0x1002e290 MxDisplaySurface* GetDisplaySurface() { return this->m_displaySurface; } + MxRegion* GetRegion() { return this->m_region; } // SYNTHETIC: LEGO1 0x100be280 diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index bd751a57..ff46b5f4 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -42,20 +42,22 @@ void MxDisplaySurface::Init() } // FUNCTION: LEGO1 0x100ba640 +// FUNCTION: BETA10 0x1013f506 void MxDisplaySurface::ClearScreen() { + MxS32 i; MxS32 backBuffers; DDSURFACEDESC desc; HRESULT hr; - if (!m_videoParam.Flags().GetFlipSurfaces()) { - backBuffers = 1; - } - else { + if (m_videoParam.Flags().GetFlipSurfaces()) { backBuffers = m_videoParam.GetBackBuffers() + 1; } + else { + backBuffers = 1; + } - for (MxS32 i = 0; i < backBuffers; i++) { + for (i = 0; i < backBuffers; i++) { memset(&desc, 0, sizeof(DDSURFACEDESC)); desc.dwSize = sizeof(DDSURFACEDESC); From 00a4861914f409b195623bf7c113882e2da68997 Mon Sep 17 00:00:00 2001 From: MS Date: Sat, 12 Jul 2025 12:39:16 -0400 Subject: [PATCH 06/25] Beta matching `CConfigApp` (#1620) * Beta matching CConfigApp * Docs --- CONFIG/config.cpp | 134 ++++++++++++++++++++++++++++++--------------- CONFIG/config.h | 6 ++ reccmp-project.yml | 5 ++ tools/README.md | 3 + 4 files changed, 105 insertions(+), 43 deletions(-) diff --git a/CONFIG/config.cpp b/CONFIG/config.cpp index 13a80e7f..54b16ee9 100644 --- a/CONFIG/config.cpp +++ b/CONFIG/config.cpp @@ -4,6 +4,7 @@ #include "MainDlg.h" #include "detectdx5.h" +#include #include // _chdir #include #include @@ -19,6 +20,7 @@ ON_COMMAND(ID_HELP, OnHelp) END_MESSAGE_MAP() // FUNCTION: CONFIG 0x00402c40 +// FUNCTION: CONFIGD 0x00406900 CConfigApp::CConfigApp() { } @@ -26,11 +28,13 @@ CConfigApp::CConfigApp() #define MiB (1024 * 1024) // FUNCTION: CONFIG 0x00402dc0 +// FUNCTION: CONFIGD 0x004069dc BOOL CConfigApp::InitInstance() { if (!IsLegoNotRunning()) { return FALSE; } + if (!DetectDirectX5()) { AfxMessageBox( "\"LEGO\xae Island\" is not detecting DirectX 5 or later. Please quit all other applications and try " @@ -38,20 +42,25 @@ BOOL CConfigApp::InitInstance() ); return FALSE; } + #ifdef _AFXDLL Enable3dControls(); #else Enable3dControlsStatic(); #endif + CConfigCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); if (_stricmp(afxCurrentAppName, "config") == 0) { m_run_config_dialog = TRUE; } + m_device_enumerator = new LegoDeviceEnumerate; if (m_device_enumerator->DoEnumerate()) { + assert("Could not build device list." == NULL); return FALSE; } + m_driver = NULL; m_device = NULL; m_full_screen = TRUE; @@ -76,11 +85,17 @@ BOOL CConfigApp::InitInstance() m_texture_quality = 1; } else { - m_model_quality = 2; m_3d_sound = TRUE; + m_model_quality = 2; m_texture_quality = 1; } - if (!m_run_config_dialog) { + + if (m_run_config_dialog) { + CMainDialog main_dialog(NULL); + m_pMainWnd = &main_dialog; + main_dialog.DoModal(); + } + else { ReadRegisterSettings(); ValidateSettings(); WriteRegisterSettings(); @@ -89,17 +104,17 @@ BOOL CConfigApp::InitInstance() m_driver = NULL; m_device = NULL; char password[256]; - ReadReg("password", password, sizeof(password)); + BOOL read = ReadReg("password", password, sizeof(password)); const char* exe = _stricmp("ogel", password) == 0 ? "isled.exe" : "isle.exe"; char diskpath[1024]; - if (ReadReg("diskpath", diskpath, sizeof(diskpath))) { + read = ReadReg("diskpath", diskpath, sizeof(diskpath)); + if (read) { _chdir(diskpath); } + _spawnl(_P_NOWAIT, exe, exe, "/diskstream", "/script", "\\lego\\scripts\\isle\\isle.si", NULL); - return FALSE; } - CMainDialog main_dialog(NULL); - main_dialog.DoModal(); + return FALSE; } @@ -117,35 +132,40 @@ BOOL CConfigApp::IsLegoNotRunning() } // FUNCTION: CONFIG 0x004031b0 +// FUNCTION: CONFIGD 0x00406dc3 BOOL CConfigApp::WriteReg(const char* p_key, const char* p_value) const { HKEY hKey; DWORD pos; + BOOL success = FALSE; + BOOL created = RegCreateKeyEx( + HKEY_LOCAL_MACHINE, + "SOFTWARE\\Mindscape\\LEGO Island", + 0, + "string", + 0, + KEY_READ | KEY_WRITE, + NULL, + &hKey, + &pos + ); - if (RegCreateKeyEx( - HKEY_LOCAL_MACHINE, - "SOFTWARE\\Mindscape\\LEGO Island", - 0, - "string", - 0, - KEY_READ | KEY_WRITE, - NULL, - &hKey, - &pos - ) == ERROR_SUCCESS) { - if (RegSetValueEx(hKey, p_key, 0, REG_SZ, (LPBYTE) p_value, strlen(p_value)) == ERROR_SUCCESS) { + if (created == ERROR_SUCCESS) { + if (RegSetValueEx(hKey, p_key, 0, REG_SZ, (LPBYTE) p_value, strlen(p_value) + 1) == ERROR_SUCCESS) { if (RegCloseKey(hKey) == ERROR_SUCCESS) { - return TRUE; + success = TRUE; } } else { RegCloseKey(hKey); } } - return FALSE; + + return success; } // FUNCTION: CONFIG 0x00403240 +// FUNCTION: CONFIGD 0x00406e6e BOOL CConfigApp::ReadReg(LPCSTR p_key, LPCSTR p_value, DWORD p_size) const { HKEY hKey; @@ -164,28 +184,30 @@ BOOL CConfigApp::ReadReg(LPCSTR p_key, LPCSTR p_value, DWORD p_size) const } // FUNCTION: CONFIG 0x004032b0 +// FUNCTION: CONFIGD 0x00406ef6 BOOL CConfigApp::ReadRegBool(LPCSTR p_key, BOOL* p_bool) const { char buffer[256]; + BOOL read = TRUE; - BOOL read = ReadReg(p_key, buffer, sizeof(buffer)); + read = ReadReg(p_key, buffer, sizeof(buffer)); if (read) { if (strcmp("YES", buffer) == 0) { *p_bool = TRUE; - return read; } - - if (strcmp("NO", buffer) == 0) { + else if (strcmp("NO", buffer) == 0) { *p_bool = FALSE; - return read; } - - read = FALSE; + else { + read = FALSE; + } } + return read; } // FUNCTION: CONFIG 0x00403380 +// FUNCTION: CONFIGD 0x00406fa1 BOOL CConfigApp::ReadRegInt(LPCSTR p_key, int* p_value) const { char buffer[256]; @@ -199,46 +221,63 @@ BOOL CConfigApp::ReadRegInt(LPCSTR p_key, int* p_value) const } // FUNCTION: CONFIG 0x004033d0 +// FUNCTION: CONFIGD 0x00407080 BOOL CConfigApp::IsDeviceInBasicRGBMode() const { /* * BUG: should be: * return !GetHardwareDeviceColorModel() && (m_device->m_HELDesc.dcmColorModel & D3DCOLOR_RGB); */ + assert(m_device); return !GetHardwareDeviceColorModel() && m_device->m_HELDesc.dcmColorModel == D3DCOLOR_RGB; } // FUNCTION: CONFIG 0x00403400 +// FUNCTION: CONFIGD 0x004070fa D3DCOLORMODEL CConfigApp::GetHardwareDeviceColorModel() const { + assert(m_device); return m_device->m_HWDesc.dcmColorModel; } // FUNCTION: CONFIG 0x00403410 +// FUNCTION: CONFIGD 0x0040714e BOOL CConfigApp::IsPrimaryDriver() const { + assert(m_driver && m_device_enumerator); return m_driver == &m_device_enumerator->GetDriverList().front(); } // FUNCTION: CONFIG 0x00403430 +// FUNCTION: CONFIGD 0x004071d2 BOOL CConfigApp::ReadRegisterSettings() { char buffer[256]; BOOL is_modified = FALSE; - int tmp = -1; - if (ReadReg("3D Device ID", buffer, sizeof(buffer))) { - tmp = m_device_enumerator->ParseDeviceName(buffer); - if (tmp >= 0) { - tmp = m_device_enumerator->GetDevice(tmp, m_driver, m_device); + BOOL read = ReadReg("3D Device ID", buffer, sizeof(buffer)); + int r = -1; + + if (read) { + r = m_device_enumerator->ParseDeviceName(buffer); + if (r >= 0) { + r = m_device_enumerator->GetDevice(r, m_driver, m_device); + if (r) { + r = -1; + } } } - if (tmp != 0) { - is_modified = TRUE; + + if (r < 0) { m_device_enumerator->FUN_1009d210(); - tmp = m_device_enumerator->GetBestDevice(); - m_device_enumerator->GetDevice(tmp, m_driver, m_device); + r = m_device_enumerator->GetBestDevice(); + is_modified = TRUE; + assert(r >= 0); + r = m_device_enumerator->GetDevice(r, m_driver, m_device); } + + assert(r == 0 && m_driver && m_device); + if (!ReadRegInt("Display Bit Depth", &m_display_bit_depth)) { is_modified = TRUE; } @@ -279,6 +318,7 @@ BOOL CConfigApp::ReadRegisterSettings() } // FUNCTION: CONFIG 0x00403630 +// FUNCTION: CONFIGD 0x00407547 BOOL CConfigApp::ValidateSettings() { BOOL is_modified = FALSE; @@ -301,11 +341,7 @@ BOOL CConfigApp::ValidateSettings() is_modified = TRUE; } } - if (!GetHardwareDeviceColorModel()) { - m_draw_cursor = FALSE; - is_modified = TRUE; - } - else { + if (GetHardwareDeviceColorModel()) { if (!m_3d_video_ram) { m_3d_video_ram = TRUE; is_modified = TRUE; @@ -315,6 +351,10 @@ BOOL CConfigApp::ValidateSettings() is_modified = TRUE; } } + else { + m_draw_cursor = FALSE; + is_modified = TRUE; + } if (m_flip_surfaces) { if (!m_3d_video_ram) { m_3d_video_ram = TRUE; @@ -341,8 +381,10 @@ BOOL CConfigApp::ValidateSettings() } // FUNCTION: CONFIG 0x004037a0 +// FUNCTION: CONFIGD 0x00407793 DWORD CConfigApp::GetConditionalDeviceRenderBitDepth() const { + assert(m_device); if (IsDeviceInBasicRGBMode()) { return 0; } @@ -353,8 +395,10 @@ DWORD CConfigApp::GetConditionalDeviceRenderBitDepth() const } // FUNCTION: CONFIG 0x004037e0 +// FUNCTION: CONFIGD 0x00407822 DWORD CConfigApp::GetDeviceRenderBitStatus() const { + assert(m_device); if (GetHardwareDeviceColorModel()) { return m_device->m_HWDesc.dwDeviceRenderBitDepth & DDBD_16; } @@ -364,6 +408,7 @@ DWORD CConfigApp::GetDeviceRenderBitStatus() const } // FUNCTION: CONFIG 0x00403810 +// FUNCTION: CONFIGD 0x004078ac BOOL CConfigApp::AdjustDisplayBitDepthBasedOnRenderStatus() { if (m_display_bit_depth == 8) { @@ -388,7 +433,8 @@ BOOL CConfigApp::AdjustDisplayBitDepthBasedOnRenderStatus() return TRUE; } -// FUNCTION: CONFIG 00403890 +// FUNCTION: CONFIG 0x00403890 +// FUNCTION: CONFIGD 0x00407966 void CConfigApp::WriteRegisterSettings() const { @@ -401,6 +447,7 @@ void CConfigApp::WriteRegisterSettings() const WriteReg(NAME, buffer); \ } while (0) + assert(m_device_enumerator && m_driver && m_device); m_device_enumerator->FormatDeviceName(buffer, m_driver, m_device); WriteReg("3D Device ID", buffer); WriteReg("3D Device Name", m_device->m_deviceName); @@ -422,6 +469,7 @@ void CConfigApp::WriteRegisterSettings() const } // FUNCTION: CONFIG 0x00403a90 +// FUNCTION: CONFIGD 0x00407c44 int CConfigApp::ExitInstance() { if (m_device_enumerator) { diff --git a/CONFIG/config.h b/CONFIG/config.h index c3282769..02366100 100644 --- a/CONFIG/config.h +++ b/CONFIG/config.h @@ -14,6 +14,7 @@ struct MxDriver; #define currentConfigApp ((CConfigApp*) afxCurrentWinApp) // VTABLE: CONFIG 0x00406040 +// VTABLE: CONFIGD 0x0040c0a0 // SIZE 0x108 class CConfigApp : public CWinApp { public: @@ -74,18 +75,23 @@ class CConfigApp : public CWinApp { }; // SYNTHETIC: CONFIG 0x00402cd0 +// SYNTHETIC: CONFIGD 0x00408330 // CConfigApp::`scalar deleting destructor' // FUNCTION: CONFIG 0x402c20 +// FUNCTION: CONFIGD 0x4068d0 // CConfigApp::_GetBaseMessageMap // FUNCTION: CONFIG 0x402c30 +// FUNCTION: CONFIGD 0x4068e5 // CConfigApp::GetMessageMap // GLOBAL: CONFIG 0x406008 +// GLOBAL: CONFIGD 0x40c058 // CConfigApp::messageMap // GLOBAL: CONFIG 0x406010 +// GLOBAL: CONFIGD 0x40c060 // CConfigApp::_messageEntries #endif // !defined(AFX_CONFIG_H) diff --git a/reccmp-project.yml b/reccmp-project.yml index fd9a2ef1..c0a1c907 100644 --- a/reccmp-project.yml +++ b/reccmp-project.yml @@ -43,3 +43,8 @@ targets: source-root: LEGO1 hash: sha256: dc7e5ed8ec9d96851126a40c4d23755f1783a8df61def44c667dfaa992ac509e + CONFIGD: + filename: CONFIGD.EXE + source-root: . + hash: + sha256: 9d2b7de2e53eee99cce24a64777a08a7f919a0401a393d9494bce27ef2e24c39 diff --git a/tools/README.md b/tools/README.md index 0d75e48e..0d443780 100644 --- a/tools/README.md +++ b/tools/README.md @@ -22,6 +22,7 @@ These modules are the most important ones and refer to the English retail versio ## BETA v1.0 * `BETA10` -> `LEGO1D.DLL` +* `CONFIGD` -> `CONFIG.EXE` The Beta 1.0 version contains a debug build of the game. While it does not have debug symbols, it still has a number of benefits: * It is built with less or no optimisation, leading to better decompilations in Ghidra @@ -32,6 +33,8 @@ It is therefore advisable to search for the corresponding function in `BETA10` w Unfortunately, some code has been changed after this beta version was created. Therefore, we are not aiming for a perfect binary match of `BETA10`. In case of discrepancies, `LEGO1` (as defined above) is our "gold standard" for matching. +The beta version of the `CONFIG` application has provided some help with matching [MFC handler functions](https://en.wikipedia.org/wiki/Microsoft_Foundation_Class_Library) that are similar to the final version. + ## Pre-Alpha * `ALPHA` -> `LEGO1D.DLL` From 657720c825490007ede73b7364ae13b17603abcc Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Sun, 13 Jul 2025 16:50:20 +0200 Subject: [PATCH 07/25] Match `Act3List::FUN_100720d0` (#1622) --- LEGO1/lego/legoomni/include/act3.h | 2 +- LEGO1/lego/legoomni/src/worlds/act3.cpp | 75 +++++++++++++++---------- 2 files changed, 45 insertions(+), 32 deletions(-) diff --git a/LEGO1/lego/legoomni/include/act3.h b/LEGO1/lego/legoomni/include/act3.h index 040da125..28129b4b 100644 --- a/LEGO1/lego/legoomni/include/act3.h +++ b/LEGO1/lego/legoomni/include/act3.h @@ -47,7 +47,7 @@ class Act3List : private list { void Insert(MxS32 p_objectId, InsertMode p_option); void DeleteActionWrapper(); void Clear(); - void FUN_100720d0(MxU32 p_objectId); + void RemoveByObjectIdOrFirst(MxU32 p_objectId); private: undefined4 m_unk0x0c; // 0x0c diff --git a/LEGO1/lego/legoomni/src/worlds/act3.cpp b/LEGO1/lego/legoomni/src/worlds/act3.cpp index 8bfaacd4..d48a3980 100644 --- a/LEGO1/lego/legoomni/src/worlds/act3.cpp +++ b/LEGO1/lego/legoomni/src/worlds/act3.cpp @@ -172,51 +172,64 @@ void Act3List::Clear() } } +// Removes the element with the given objectId from the list, or the first if `p_objectId` is zero. // FUNCTION: LEGO1 0x100720d0 -void Act3List::FUN_100720d0(MxU32 p_objectId) +void Act3List::RemoveByObjectIdOrFirst(MxU32 p_objectId) { if (m_unk0x0c) { return; } MxU32 removed = FALSE; + Act3List::iterator it; + // This iterator appears to be unnecessary - maybe left in by accident, or it was used for assertions. + // Removing it decreases the match percentage. + Act3List::iterator unusedIterator; - if (!empty()) { - if (p_objectId != 0) { - for (Act3List::iterator it = begin(); it != end(); it++) { - if ((*it).m_hasStarted && (*it).m_objectId == p_objectId) { - erase(it); - removed = TRUE; - break; - } + if (empty()) { + return; + } + + if (!p_objectId) { + pop_front(); + removed = TRUE; + } + else { + for (it = begin(); it != end(); it++) { + // Removing this variable decreases the match, but replacing `*it` by `unused` below also does. + Act3ListElement& unused = *it; + + if ((*it).m_hasStarted && (*it).m_objectId == p_objectId) { + erase(it); + removed = TRUE; + break; } } - else { - pop_front(); - removed = TRUE; - } + } - if (removed && size() > 0) { - Act3List::iterator it = begin(); - Act3ListElement& firstItem = *(it++); + if (removed && size() > 0) { + it = begin(); + unusedIterator = it; + Act3ListElement& firstItem = front(); + it++; - for (; it != end(); it++) { - if ((*it).m_unk0x04 == 1) { - for (Act3List::iterator it2 = begin(); it2 != it;) { - if ((*it2).m_hasStarted) { - DeleteActionWrapper(); - return; - } - - it2 = erase(it2); + while (it != end()) { + if ((*it).m_unk0x04 == 1) { + for (Act3List::iterator it2 = begin(); it2 != it; erase(it2++)) { + if ((*it2).m_hasStarted) { + DeleteActionWrapper(); + return; } } } - if (!firstItem.m_hasStarted) { - firstItem.m_hasStarted = TRUE; - InvokeAction(Extra::e_start, *g_act3Script, firstItem.m_objectId, NULL); - } + it++; + unusedIterator++; + } + + if (!firstItem.m_hasStarted) { + firstItem.m_hasStarted = TRUE; + InvokeAction(Extra::e_start, *g_act3Script, firstItem.m_objectId, NULL); } } } @@ -613,7 +626,7 @@ MxLong Act3::Notify(MxParam& p_param) } while (length < (MxS32) sizeOfArray(m_helicopterDots)); } else { - m_unk0x4220.FUN_100720d0(param.GetAction()->GetObjectId()); + m_unk0x4220.RemoveByObjectIdOrFirst(param.GetAction()->GetObjectId()); } } break; @@ -633,7 +646,7 @@ MxLong Act3::Notify(MxParam& p_param) case c_notificationEndAnim: if (m_state->m_unk0x08 == 1) { assert(m_copter && m_brickster && m_cop1 && m_cop2); - m_unk0x4220.FUN_100720d0(0); + m_unk0x4220.RemoveByObjectIdOrFirst(0); m_state->m_unk0x08 = 0; Disable(TRUE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); m_copter->HandleClick(); From 40c1a40d2b1580563bff8d575bb1b2c9959775d2 Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Sun, 13 Jul 2025 16:50:51 +0200 Subject: [PATCH 08/25] Match `FUN_1006b140()` and related functions (#1623) * Match on BETA10 * Possible improvement on Matrix4::Swap * Document entropy build result * Comments at at Matrix4::Invert --------- Co-authored-by: jonschz --- LEGO1/lego/legoomni/include/legoanimpresenter.h | 4 ++++ LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp | 3 +++ LEGO1/realtime/matrix4d.inl.h | 12 ++++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoanimpresenter.h b/LEGO1/lego/legoomni/include/legoanimpresenter.h index a3d6cd60..802e8917 100644 --- a/LEGO1/lego/legoomni/include/legoanimpresenter.h +++ b/LEGO1/lego/legoomni/include/legoanimpresenter.h @@ -92,7 +92,11 @@ class LegoAnimPresenter : public MxVideoPresenter { const char* GetActionObjectName(); void SetCurrentWorld(LegoWorld* p_currentWorld) { m_currentWorld = p_currentWorld; } + + // FUNCTION: BETA10 0x1005aad0 void SetUnknown0x0cTo1() { m_unk0x9c = 1; } + + // FUNCTION: BETA10 0x1005ab00 void SetUnknown0xa0(Matrix4* p_unk0xa0) { m_unk0xa0 = p_unk0xa0; } LegoAnim* GetAnimation() { return m_anim; } diff --git a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp index 033525f4..f966cf38 100644 --- a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp @@ -703,6 +703,9 @@ MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi) if (p_roi == NULL) { return FAILURE; } +#ifdef BETA10 + MxMatrix unused_matrix; +#endif Matrix4* mn = new MxMatrix(); assert(mn); diff --git a/LEGO1/realtime/matrix4d.inl.h b/LEGO1/realtime/matrix4d.inl.h index b15e6135..c1643f76 100644 --- a/LEGO1/realtime/matrix4d.inl.h +++ b/LEGO1/realtime/matrix4d.inl.h @@ -290,6 +290,8 @@ void Matrix4::RotateZ(const float& p_angle) // FUNCTION: BETA10 0x1005a590 int Matrix4::Invert(Matrix4& p_mat) { + // Inlined at LEGO1 0x1006b2d3 + float copyData[4][4]; Matrix4 copy(copyData); copy = *this; @@ -312,6 +314,7 @@ int Matrix4::Invert(Matrix4& p_mat) } if (copy[i][i] < 0.001f && copy[i][i] > -0.001f) { + // FAILURE from mxtypes.h return -1; } @@ -349,14 +352,19 @@ int Matrix4::Invert(Matrix4& p_mat) } } + // SUCCESS from mxtypes.h return 0; } // FUNCTION: LEGO1 0x1006b500 +// FUNCTION: BETA10 0x1005aa20 void Matrix4::Swap(int p_d1, int p_d2) { - for (int i = 0; i < 4; i++) { - float e = m_data[p_d1][i]; + // This function is affected by entropy even in debug builds + int i; + float e; + for (i = 0; i < 4; i++) { + e = m_data[p_d1][i]; m_data[p_d1][i] = m_data[p_d2][i]; m_data[p_d2][i] = e; } From 356c64ce0ee510a1580049f83a64ac9e3c26146c Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Sun, 13 Jul 2025 21:01:06 +0200 Subject: [PATCH 09/25] Name state field, getter and setter in Act1State (#1621) --- LEGO1/lego/legoomni/include/isle.h | 21 ++- LEGO1/lego/legoomni/src/actors/ambulance.cpp | 4 +- LEGO1/lego/legoomni/src/actors/buildings.cpp | 18 +-- LEGO1/lego/legoomni/src/actors/bumpbouy.cpp | 2 +- LEGO1/lego/legoomni/src/actors/helicopter.cpp | 6 +- LEGO1/lego/legoomni/src/actors/jetski.cpp | 2 +- LEGO1/lego/legoomni/src/actors/pizza.cpp | 8 +- LEGO1/lego/legoomni/src/actors/skateboard.cpp | 6 +- LEGO1/lego/legoomni/src/actors/towtrack.cpp | 6 +- .../legoomni/src/common/legogamestate.cpp | 2 +- LEGO1/lego/legoomni/src/common/legoutils.cpp | 5 +- LEGO1/lego/legoomni/src/race/carrace.cpp | 8 +- LEGO1/lego/legoomni/src/race/jetskirace.cpp | 6 +- LEGO1/lego/legoomni/src/worlds/gasstation.cpp | 2 +- LEGO1/lego/legoomni/src/worlds/hospital.cpp | 4 +- LEGO1/lego/legoomni/src/worlds/isle.cpp | 126 +++++++++--------- LEGO1/lego/legoomni/src/worlds/jukebox.cpp | 2 +- 17 files changed, 122 insertions(+), 106 deletions(-) diff --git a/LEGO1/lego/legoomni/include/isle.h b/LEGO1/lego/legoomni/include/isle.h index 2c6c8091..53edd931 100644 --- a/LEGO1/lego/legoomni/include/isle.h +++ b/LEGO1/lego/legoomni/include/isle.h @@ -34,6 +34,21 @@ class Act1State : public LegoState { c_floor3 }; + enum { + e_none = 0, + e_initial = 1, + e_elevator = 2, + e_pizza = 3, + e_helicopter = 4, + e_transitionToJetski = 5, + e_transitionToRacecar = 6, + e_transitionToTowtrack = 7, + e_towtrack = 8, + e_transitionToAmbulance = 9, + e_ambulance = 10, + e_jukebox = 11, + }; + Act1State(); // FUNCTION: LEGO1 0x100338a0 @@ -58,11 +73,11 @@ class Act1State : public LegoState { void RemoveActors(); void PlaceActors(); - MxU32 GetUnknown18() { return m_unk0x018; } + MxU32 GetState() { return m_state; } ElevatorFloor GetElevatorFloor() { return (ElevatorFloor) m_elevFloor; } MxU8 GetUnknown21() { return m_unk0x021; } - void SetUnknown18(MxU32 p_unk0x18) { m_unk0x018 = p_unk0x18; } + void SetState(MxU32 p_state) { m_state = p_state; } void SetElevatorFloor(ElevatorFloor p_elevFloor) { m_elevFloor = p_elevFloor; } void SetUnknown21(MxU8 p_unk0x21) { m_unk0x021 = p_unk0x21; } @@ -73,7 +88,7 @@ class Act1State : public LegoState { Playlist m_cptClickDialogue; // 0x008 IsleScript::Script m_currentCptClickDialogue; // 0x014 - MxU32 m_unk0x018; // 0x018 + MxU32 m_state; // 0x018 MxS16 m_elevFloor; // 0x01c MxBool m_unk0x01e; // 0x01e MxBool m_unk0x01f; // 0x01f diff --git a/LEGO1/lego/legoomni/src/actors/ambulance.cpp b/LEGO1/lego/legoomni/src/actors/ambulance.cpp index b439db66..fa98fc65 100644 --- a/LEGO1/lego/legoomni/src/actors/ambulance.cpp +++ b/LEGO1/lego/legoomni/src/actors/ambulance.cpp @@ -364,7 +364,7 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param) // FUNCTION: BETA10 0x10023506 MxLong Ambulance::HandleClick() { - if (((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 != 10) { + if (((Act1State*) GameState()->GetState("Act1State"))->m_state != Act1State::e_ambulance) { return 1; } @@ -575,7 +575,7 @@ void Ambulance::Reset() { StopAction(m_lastAction); BackgroundAudioManager()->RaiseVolume(); - ((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 = 0; + ((Act1State*) GameState()->GetState("Act1State"))->m_state = Act1State::e_none; m_state->m_state = AmbulanceMissionState::e_ready; m_atBeachTask = 0; m_atPoliceTask = 0; diff --git a/LEGO1/lego/legoomni/src/actors/buildings.cpp b/LEGO1/lego/legoomni/src/actors/buildings.cpp index 833287bc..b9e736c4 100644 --- a/LEGO1/lego/legoomni/src/actors/buildings.cpp +++ b/LEGO1/lego/legoomni/src/actors/buildings.cpp @@ -53,7 +53,7 @@ MxLong InfoCenterEntity::HandleClick(LegoEventNotificationParam& p_param) isle->SetDestLocation(LegoGameState::Area::e_infomain); Act1State* act1state = (Act1State*) GameState()->GetState("Act1State"); - act1state->SetUnknown18(0); + act1state->SetState(Act1State::e_none); break; } case LegoGameState::Act::e_act2: { @@ -83,8 +83,8 @@ MxLong GasStationEntity::HandleClick(LegoEventNotificationParam& p_param) if (CanExit()) { Act1State* state = (Act1State*) GameState()->GetState("Act1State"); - if (state->GetUnknown18() != 8) { - state->SetUnknown18(0); + if (state->GetState() != Act1State::e_towtrack) { + state->SetState(Act1State::e_none); if (UserActor()->GetActorId() != GameState()->GetActorId()) { ((IslePathActor*) UserActor())->Exit(); @@ -107,8 +107,8 @@ MxLong HospitalEntity::HandleClick(LegoEventNotificationParam& p_param) if (CanExit()) { Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); - if (act1State->GetUnknown18() != 10) { - act1State->SetUnknown18(0); + if (act1State->GetState() != Act1State::e_ambulance) { + act1State->SetState(Act1State::e_none); if (UserActor()->GetActorId() != GameState()->GetActorId()) { ((IslePathActor*) UserActor())->Exit(); @@ -131,8 +131,8 @@ MxLong PoliceEntity::HandleClick(LegoEventNotificationParam& p_param) if (CanExit()) { Act1State* state = (Act1State*) GameState()->GetState("Act1State"); - if (state->GetUnknown18() != 10) { - state->SetUnknown18(0); + if (state->GetState() != Act1State::e_ambulance) { + state->SetState(Act1State::e_none); if (UserActor()->GetActorId() != GameState()->GetActorId()) { ((IslePathActor*) UserActor())->Exit(); @@ -154,7 +154,7 @@ MxLong BeachHouseEntity::HandleClick(LegoEventNotificationParam& p_param) { if (CanExit()) { Act1State* state = (Act1State*) GameState()->GetState("Act1State"); - state->SetUnknown18(0); + state->SetState(Act1State::e_none); if (UserActor()->GetActorId() != GameState()->GetActorId()) { ((IslePathActor*) UserActor())->Exit(); @@ -175,7 +175,7 @@ MxLong RaceStandsEntity::HandleClick(LegoEventNotificationParam& p_param) { if (CanExit()) { Act1State* state = (Act1State*) GameState()->GetState("Act1State"); - state->SetUnknown18(0); + state->SetState(Act1State::e_none); if (UserActor()->GetActorId() != GameState()->GetActorId()) { ((IslePathActor*) UserActor())->Exit(); diff --git a/LEGO1/lego/legoomni/src/actors/bumpbouy.cpp b/LEGO1/lego/legoomni/src/actors/bumpbouy.cpp index 371e4257..03c93f7b 100644 --- a/LEGO1/lego/legoomni/src/actors/bumpbouy.cpp +++ b/LEGO1/lego/legoomni/src/actors/bumpbouy.cpp @@ -45,7 +45,7 @@ MxLong BumpBouy::Notify(MxParam& p_param) Act1State* isleState = (Act1State*) GameState()->GetState("Act1State"); assert(isleState); - isleState->m_unk0x018 = 5; + isleState->m_state = Act1State::e_transitionToJetski; Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle); assert(isle); diff --git a/LEGO1/lego/legoomni/src/actors/helicopter.cpp b/LEGO1/lego/legoomni/src/actors/helicopter.cpp index 622fe71e..46353585 100644 --- a/LEGO1/lego/legoomni/src/actors/helicopter.cpp +++ b/LEGO1/lego/legoomni/src/actors/helicopter.cpp @@ -214,7 +214,7 @@ MxLong Helicopter::HandleControl(LegoControlManagerNotificationParam& p_param) Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); assert(act1State); if (m_state->m_unk0x08 == 0) { - act1State->m_unk0x018 = 4; + act1State->m_state = Act1State::e_helicopter; m_state->m_unk0x08 = 1; m_world->RemoveActor(this); InvokeAction(Extra::ActionType::e_start, script, IsleScript::c_HelicopterTakeOff_Anim, NULL); @@ -318,7 +318,7 @@ MxLong Helicopter::HandleEndAnim(LegoEndAnimNotificationParam& p_param) if (GameState()->GetCurrentAct() == LegoGameState::e_act1) { Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); assert(act1State); - act1State->m_unk0x018 = 4; + act1State->m_state = Act1State::e_helicopter; SpawnPlayer( LegoGameState::e_unk42, TRUE, @@ -359,7 +359,7 @@ MxLong Helicopter::HandleEndAnim(LegoEndAnimNotificationParam& p_param) if (GameState()->GetCurrentAct() == LegoGameState::e_act1) { Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); assert(act1State); - act1State->m_unk0x018 = 0; + act1State->m_state = Act1State::e_none; SpawnPlayer( LegoGameState::e_unk41, TRUE, diff --git a/LEGO1/lego/legoomni/src/actors/jetski.cpp b/LEGO1/lego/legoomni/src/actors/jetski.cpp index caf3d1f8..2abc3862 100644 --- a/LEGO1/lego/legoomni/src/actors/jetski.cpp +++ b/LEGO1/lego/legoomni/src/actors/jetski.cpp @@ -162,7 +162,7 @@ void Jetski::ActivateSceneActions() PlayMusic(JukeboxScript::c_JetskiRace_Music); Act1State* act1state = (Act1State*) GameState()->GetState("Act1State"); - if (!act1state->m_unk0x018) { + if (!act1state->m_state) { if (act1state->m_unk0x022) { PlayCamAnim(this, FALSE, 68, TRUE); } diff --git a/LEGO1/lego/legoomni/src/actors/pizza.cpp b/LEGO1/lego/legoomni/src/actors/pizza.cpp index 18da7fca..422cf87f 100644 --- a/LEGO1/lego/legoomni/src/actors/pizza.cpp +++ b/LEGO1/lego/legoomni/src/actors/pizza.cpp @@ -182,7 +182,7 @@ void Pizza::FUN_10038220(IsleScript::Script p_objectId) AnimationManager()->FUN_10064740(NULL); m_mission = m_state->GetMission(GameState()->GetActorId()); m_state->m_unk0x0c = 1; - m_act1state->m_unk0x018 = 3; + m_act1state->m_state = Act1State::e_pizza; m_mission->m_startTime = INT_MIN; g_isleFlags &= ~Isle::c_playMusic; AnimationManager()->EnableCamAnims(FALSE); @@ -200,7 +200,7 @@ void Pizza::FUN_100382b0() InvokeAction(Extra::e_stop, *g_isleScript, m_speechAction, NULL); } - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; m_state->m_unk0x0c = 0; UserActor()->SetActorState(LegoPathActor::c_initial); g_isleFlags |= Isle::c_playMusic; @@ -245,7 +245,7 @@ MxLong Pizza::HandleClick() } if (m_state->m_unk0x0c == 2) { - m_act1state->m_unk0x018 = 3; + m_act1state->m_state = Act1State::e_pizza; if (m_skateBoard == NULL) { m_skateBoard = (SkateBoard*) m_world->Find(m_atomId, IsleScript::c_SkateBoard_Actor); @@ -558,7 +558,7 @@ MxLong Pizza::HandleEndAction(MxEndActionNotificationParam& p_param) break; case 8: if (m_state->GetPlayedAction() == objectId) { - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; m_state->m_unk0x0c = 0; GameState()->m_currentArea = LegoGameState::e_isle; TickleManager()->UnregisterClient(this); diff --git a/LEGO1/lego/legoomni/src/actors/skateboard.cpp b/LEGO1/lego/legoomni/src/actors/skateboard.cpp index 12524111..d47b2178 100644 --- a/LEGO1/lego/legoomni/src/actors/skateboard.cpp +++ b/LEGO1/lego/legoomni/src/actors/skateboard.cpp @@ -56,7 +56,7 @@ MxResult SkateBoard::Create(MxDSAction& p_dsAction) // FUNCTION: LEGO1 0x10010050 void SkateBoard::Exit() { - if (m_act1state->m_unk0x018 == 3) { + if (m_act1state->m_state == Act1State::e_pizza) { Pizza* pizza = (Pizza*) CurrentWorld()->Find(*g_isleScript, IsleScript::c_Pizza_Actor); pizza->StopActions(); pizza->FUN_100382b0(); @@ -75,7 +75,7 @@ MxLong SkateBoard::HandleClick() { Act1State* state = (Act1State*) GameState()->GetState("Act1State"); - if (!CanExit() && state->m_unk0x018 != 3) { + if (!CanExit() && state->m_state != Act1State::e_pizza) { return 1; } @@ -148,7 +148,7 @@ MxLong SkateBoard::HandleNotification0() // FUNCTION: LEGO1 0x10010510 void SkateBoard::ActivateSceneActions() { - if (m_act1state->m_unk0x018 != 3) { + if (m_act1state->m_state != Act1State::e_pizza) { PlayMusic(JukeboxScript::c_BeachBlvd_Music); if (!m_act1state->m_unk0x022) { diff --git a/LEGO1/lego/legoomni/src/actors/towtrack.cpp b/LEGO1/lego/legoomni/src/actors/towtrack.cpp index bb117e5f..5d62fedc 100644 --- a/LEGO1/lego/legoomni/src/actors/towtrack.cpp +++ b/LEGO1/lego/legoomni/src/actors/towtrack.cpp @@ -272,7 +272,7 @@ MxLong TowTrack::HandleEndAction(MxEndActionNotificationParam& p_param) m_state->UpdateScore(LegoState::e_yellow, m_actorId); } else if (objectId == IsleScript::c_wgs098nu_RunAnim || objectId == IsleScript::c_wgs099nu_RunAnim || objectId == IsleScript::c_wgs100nu_RunAnim || objectId == IsleScript::c_wgs101nu_RunAnim || objectId == IsleScript::c_wgs102nu_RunAnim || objectId == IsleScript::c_wgs085nu_RunAnim || objectId == IsleScript::c_wgs086nu_RunAnim || objectId == IsleScript::c_wgs087nu_RunAnim || objectId == IsleScript::c_wgs088nu_RunAnim || objectId == IsleScript::c_wgs089nu_RunAnim || objectId == IsleScript::c_wgs091nu_RunAnim || objectId == IsleScript::c_wgs092nu_RunAnim || objectId == IsleScript::c_wgs093nu_RunAnim || objectId == IsleScript::c_wgs094nu_RunAnim || objectId == IsleScript::c_wgs095nu_RunAnim) { - ((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 = 0; + ((Act1State*) GameState()->GetState("Act1State"))->m_state = Act1State::e_none; AnimationManager()->FUN_1005f6d0(TRUE); g_isleFlags |= Isle::c_playMusic; AnimationManager()->EnableCamAnims(TRUE); @@ -403,7 +403,7 @@ MxLong TowTrack::HandlePathStruct(LegoPathStructNotificationParam& p_param) // FUNCTION: LEGO1 0x1004d690 MxLong TowTrack::HandleClick() { - if (((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 != 8) { + if (((Act1State*) GameState()->GetState("Act1State"))->m_state != Act1State::e_towtrack) { return 1; } @@ -549,7 +549,7 @@ void TowTrack::FUN_1004dbe0() InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL); } - ((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 = 0; + ((Act1State*) GameState()->GetState("Act1State"))->m_state = Act1State::e_none; m_state->m_unk0x08 = 0; g_isleFlags |= Isle::c_playMusic; AnimationManager()->EnableCamAnims(TRUE); diff --git a/LEGO1/lego/legoomni/src/common/legogamestate.cpp b/LEGO1/lego/legoomni/src/common/legogamestate.cpp index 3dbe88bc..eae457ed 100644 --- a/LEGO1/lego/legoomni/src/common/legogamestate.cpp +++ b/LEGO1/lego/legoomni/src/common/legogamestate.cpp @@ -952,7 +952,7 @@ void LegoGameState::SwitchArea(Area p_area) Act1State* state = (Act1State*) GameState()->GetState("Act1State"); LoadIsle(); - if (state->GetUnknown18() == 7) { + if (state->GetState() == Act1State::e_transitionToTowtrack) { VideoManager()->Get3DManager()->SetFrustrum(90, 0.1f, 250.0f); } else { diff --git a/LEGO1/lego/legoomni/src/common/legoutils.cpp b/LEGO1/lego/legoomni/src/common/legoutils.cpp index d5ecb1ad..2f9b1daf 100644 --- a/LEGO1/lego/legoomni/src/common/legoutils.cpp +++ b/LEGO1/lego/legoomni/src/common/legoutils.cpp @@ -583,9 +583,10 @@ MxBool CanExit() GameState()->m_currentArea != LegoGameState::e_polidoor) { if (UserActor() == NULL || !UserActor()->IsA("TowTrack")) { if (UserActor() == NULL || !UserActor()->IsA("Ambulance")) { - MxU32 unk0x18 = act1State->GetUnknown18(); + MxU32 mission = act1State->GetState(); - if (unk0x18 != 10 && unk0x18 != 8 && unk0x18 != 3) { + if (mission != Act1State::e_ambulance && mission != Act1State::e_towtrack && + mission != Act1State::e_pizza) { return TRUE; } } diff --git a/LEGO1/lego/legoomni/src/race/carrace.cpp b/LEGO1/lego/legoomni/src/race/carrace.cpp index fb4cc192..7a9cfef2 100644 --- a/LEGO1/lego/legoomni/src/race/carrace.cpp +++ b/LEGO1/lego/legoomni/src/race/carrace.cpp @@ -95,7 +95,7 @@ MxResult CarRace::Create(MxDSAction& p_dsAction) m_raceState = raceState; - m_act1State->m_unk0x018 = 6; + m_act1State->m_state = Act1State::e_transitionToRacecar; m_unk0x144 = -1; m_unk0x148 = -1; m_unk0x14c = -1; @@ -339,7 +339,7 @@ MxLong CarRace::HandleControl(LegoControlManagerNotificationParam& p_param) switch (p_param.m_clickedObjectId) { case 3: InvokeAction(Extra::e_stop, *g_carraceScript, CarraceScript::c_irtx08ra_PlayWav, NULL); - m_act1State->m_unk0x018 = 0; + m_act1State->m_state = Act1State::e_none; VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); NavController()->SetDeadZone(NavController()->GetDefaultDeadZone()); @@ -351,7 +351,7 @@ MxLong CarRace::HandleControl(LegoControlManagerNotificationParam& p_param) break; case 98: InvokeAction(Extra::e_stop, *g_carraceScript, CarraceScript::c_irtx08ra_PlayWav, NULL); - m_act1State->m_unk0x018 = 0; + m_act1State->m_state = Act1State::e_none; VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); NavController()->SetDeadZone(NavController()->GetDefaultDeadZone()); @@ -413,7 +413,7 @@ MxBool CarRace::Escape() AnimationManager()->FUN_10061010(FALSE); DeleteObjects(&m_atomId, 500, 999); - m_act1State->m_unk0x018 = 0; + m_act1State->m_state = Act1State::e_none; VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); VariableTable()->SetVariable(g_raceState, ""); diff --git a/LEGO1/lego/legoomni/src/race/jetskirace.cpp b/LEGO1/lego/legoomni/src/race/jetskirace.cpp index eddb7266..71746cd0 100644 --- a/LEGO1/lego/legoomni/src/race/jetskirace.cpp +++ b/LEGO1/lego/legoomni/src/race/jetskirace.cpp @@ -127,7 +127,7 @@ MxLong JetskiRace::HandleControl(LegoControlManagerNotificationParam& p_param) if (p_param.m_unk0x28 == 1) { switch (p_param.m_clickedObjectId) { case JetraceScript::c_JetskiArms_Ctl: - m_act1State->m_unk0x018 = 0; + m_act1State->m_state = Act1State::e_none; VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); LegoRaceCar::InitYouCantStopSound(); @@ -135,7 +135,7 @@ MxLong JetskiRace::HandleControl(LegoControlManagerNotificationParam& p_param) TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); break; case JetraceScript::c_JetskiInfo_Ctl: - m_act1State->m_unk0x018 = 0; + m_act1State->m_state = Act1State::e_none; VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); LegoRaceCar::InitYouCantStopSound(); @@ -288,7 +288,7 @@ MxBool JetskiRace::Escape() { AnimationManager()->FUN_10061010(FALSE); DeleteObjects(&m_atomId, 500, 999); - m_act1State->m_unk0x018 = 0; + m_act1State->m_state = Act1State::e_none; VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); m_destLocation = LegoGameState::e_infomain; diff --git a/LEGO1/lego/legoomni/src/worlds/gasstation.cpp b/LEGO1/lego/legoomni/src/worlds/gasstation.cpp index 40e757c7..4a449ba2 100644 --- a/LEGO1/lego/legoomni/src/worlds/gasstation.cpp +++ b/LEGO1/lego/legoomni/src/worlds/gasstation.cpp @@ -328,7 +328,7 @@ MxLong GasStation::HandleEndAction(MxEndActionNotificationParam& p_param) break; case GasStationState::e_afterAcceptingQuest: m_state->m_state = GasStationState::e_beforeExitingForQuest; - ((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 = 7; + ((Act1State*) GameState()->GetState("Act1State"))->m_state = Act1State::e_transitionToTowtrack; m_destLocation = LegoGameState::e_garageExited; m_radio.Stop(); BackgroundAudioManager()->Stop(); diff --git a/LEGO1/lego/legoomni/src/worlds/hospital.cpp b/LEGO1/lego/legoomni/src/worlds/hospital.cpp index 74d15678..6ab9c218 100644 --- a/LEGO1/lego/legoomni/src/worlds/hospital.cpp +++ b/LEGO1/lego/legoomni/src/worlds/hospital.cpp @@ -365,7 +365,7 @@ MxLong Hospital::HandleEndAction(MxEndActionNotificationParam& p_param) case HospitalState::e_afterAcceptingQuest: m_hospitalState->m_state = HospitalState::e_beforeEnteringAmbulance; act1State = (Act1State*) GameState()->GetState("Act1State"); - act1State->SetUnknown18(9); + act1State->SetState(Act1State::e_transitionToAmbulance); case HospitalState::e_exitToFront: if (m_exited == FALSE) { m_exited = TRUE; @@ -419,7 +419,7 @@ MxLong Hospital::HandleButtonDown(LegoControlManagerNotificationParam& p_param) Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); assert(act1State); - act1State->m_unk0x018 = 9; + act1State->m_state = Act1State::e_transitionToAmbulance; m_destLocation = LegoGameState::e_hospitalExited; DeleteObjects( diff --git a/LEGO1/lego/legoomni/src/worlds/isle.cpp b/LEGO1/lego/legoomni/src/worlds/isle.cpp index 2b630be4..aeedd601 100644 --- a/LEGO1/lego/legoomni/src/worlds/isle.cpp +++ b/LEGO1/lego/legoomni/src/worlds/isle.cpp @@ -142,11 +142,11 @@ MxLong Isle::Notify(MxParam& p_param) break; case c_notificationButtonUp: case c_notificationButtonDown: - switch (m_act1state->m_unk0x018) { - case 3: + switch (m_act1state->m_state) { + case Act1State::e_pizza: result = m_pizza->Notify(p_param); break; - case 10: + case Act1State::e_ambulance: result = m_ambulance->Notify(p_param); break; } @@ -155,14 +155,14 @@ MxLong Isle::Notify(MxParam& p_param) result = HandleControl((LegoControlManagerNotificationParam&) p_param); break; case c_notificationEndAnim: - switch (m_act1state->m_unk0x018) { - case 4: + switch (m_act1state->m_state) { + case Act1State::e_helicopter: result = UserActor()->Notify(p_param); break; - case 8: + case Act1State::e_towtrack: result = m_towtrack->Notify(p_param); break; - case 10: + case Act1State::e_ambulance: result = m_ambulance->Notify(p_param); break; } @@ -187,18 +187,18 @@ MxLong Isle::HandleEndAction(MxEndActionNotificationParam& p_param) { MxLong result; - switch (m_act1state->m_unk0x018) { - case 2: + switch (m_act1state->m_state) { + case Act1State::e_elevator: HandleElevatorEndAction(); result = 1; break; - case 3: + case Act1State::e_pizza: result = m_pizza->Notify(p_param); break; - case 8: + case Act1State::e_towtrack: result = m_towtrack->Notify(p_param); break; - case 10: + case Act1State::e_ambulance: result = m_ambulance->Notify(p_param); break; default: @@ -241,12 +241,12 @@ void Isle::HandleElevatorEndAction() case Act1State::c_floor1: m_destLocation = LegoGameState::e_infomain; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; break; case Act1State::c_floor2: if (m_act1state->m_unk0x01e) { m_act1state->m_unk0x01e = FALSE; - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; InputManager()->EnableInputProcessing(); } else { @@ -258,7 +258,7 @@ void Isle::HandleElevatorEndAction() case Act1State::c_floor3: m_destLocation = LegoGameState::e_elevopen; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; break; } } @@ -270,7 +270,7 @@ void Isle::ReadyWorld() if (m_act1state->GetUnknown21()) { GameState()->SwitchArea(LegoGameState::e_infomain); - m_act1state->SetUnknown18(0); + m_act1state->SetState(Act1State::e_none); m_act1state->SetUnknown21(0); } else if (GameState()->GetLoadedAct() != LegoGameState::e_act1) { @@ -289,7 +289,7 @@ MxLong Isle::HandleControl(LegoControlManagerNotificationParam& p_param) switch (p_param.m_clickedObjectId) { case IsleScript::c_ElevRide_Info_Ctl: - m_act1state->m_unk0x018 = 2; + m_act1state->m_state = Act1State::e_elevator; switch (m_act1state->m_elevFloor) { case Act1State::c_floor1: @@ -309,7 +309,7 @@ MxLong Isle::HandleControl(LegoControlManagerNotificationParam& p_param) m_act1state->m_elevFloor = Act1State::c_floor1; break; case IsleScript::c_ElevRide_Two_Ctl: - m_act1state->m_unk0x018 = 2; + m_act1state->m_state = Act1State::e_elevator; switch (m_act1state->m_elevFloor) { case Act1State::c_floor1: @@ -329,7 +329,7 @@ MxLong Isle::HandleControl(LegoControlManagerNotificationParam& p_param) m_act1state->m_elevFloor = Act1State::c_floor2; break; case IsleScript::c_ElevRide_Three_Ctl: - m_act1state->m_unk0x018 = 2; + m_act1state->m_state = Act1State::e_elevator; switch (m_act1state->m_elevFloor) { case Act1State::c_floor1: @@ -478,14 +478,14 @@ MxLong Isle::HandlePathStruct(LegoPathStructNotificationParam& p_param) } } - switch (m_act1state->m_unk0x018) { - case 3: + switch (m_act1state->m_state) { + case Act1State::e_pizza: result = m_pizza->Notify(p_param); break; - case 8: + case Act1State::e_towtrack: result = m_towtrack->Notify(p_param); break; - case 10: + case Act1State::e_ambulance: result = m_ambulance->Notify(p_param); break; } @@ -502,7 +502,7 @@ MxLong Isle::HandlePathStruct(LegoPathStructNotificationParam& p_param) result = 1; break; case 0x131: - if (m_act1state->m_unk0x018 != 10) { + if (m_act1state->m_state != Act1State::e_ambulance) { AnimationManager()->FUN_10064740(NULL); } result = 1; @@ -558,7 +558,7 @@ void Isle::Enable(MxBool p_enable) EnableAnimations(TRUE); - if (m_act1state->m_unk0x018 == 0) { + if (m_act1state->m_state == Act1State::e_none) { MxS32 locations[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for (MxU32 i = 0; i < 5; i++) { @@ -595,7 +595,7 @@ void Isle::Enable(MxBool p_enable) break; case LegoGameState::e_jetrace2: if (((JetskiRaceState*) GameState()->GetState("JetskiRaceState"))->m_unk0x28 == 2) { - m_act1state->m_unk0x018 = 5; + m_act1state->m_state = Act1State::e_transitionToJetski; } PlaceActor(UserActor()); @@ -704,10 +704,10 @@ void Isle::Enable(MxBool p_enable) break; } - switch (m_act1state->m_unk0x018) { - case 0: - case 1: - m_act1state->m_unk0x018 = 0; + switch (m_act1state->m_state) { + case Act1State::e_none: + case Act1State::e_initial: + m_act1state->m_state = Act1State::e_none; if (GameState()->m_currentArea == LegoGameState::e_pizzeriaExterior) { AnimationManager()->FUN_10064740(NULL); @@ -728,7 +728,7 @@ void Isle::Enable(MxBool p_enable) } } break; - case 5: { + case Act1State::e_transitionToJetski: { ((IslePathActor*) UserActor()) ->SpawnPlayer( LegoGameState::e_jetrace2, @@ -756,12 +756,12 @@ void Isle::Enable(MxBool p_enable) ->FUN_10060dc0(script, NULL, TRUE, LegoAnimationManager::e_unk1, NULL, FALSE, FALSE, TRUE, FALSE); } - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; EnableAnimations(FALSE); AnimationManager()->FUN_10064670(NULL); break; } - case 6: { + case Act1State::e_transitionToRacecar: { GameState()->m_currentArea = LegoGameState::e_carraceExterior; ((IslePathActor*) UserActor()) ->SpawnPlayer( @@ -790,12 +790,12 @@ void Isle::Enable(MxBool p_enable) ->FUN_10060dc0(script, NULL, TRUE, LegoAnimationManager::e_unk1, NULL, FALSE, FALSE, TRUE, FALSE); } - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; EnableAnimations(TRUE); break; } - case 7: - m_act1state->m_unk0x018 = 8; + case Act1State::e_transitionToTowtrack: + m_act1state->m_state = Act1State::e_towtrack; AnimationManager()->FUN_1005f6d0(FALSE); AnimationManager()->EnableCamAnims(FALSE); @@ -803,8 +803,8 @@ void Isle::Enable(MxBool p_enable) g_isleFlags &= ~c_playMusic; m_towtrack->FUN_1004dab0(); break; - case 9: - m_act1state->m_unk0x018 = 10; + case Act1State::e_transitionToAmbulance: + m_act1state->m_state = Act1State::e_ambulance; AnimationManager()->FUN_1005f6d0(FALSE); AnimationManager()->EnableCamAnims(FALSE); @@ -813,7 +813,7 @@ void Isle::Enable(MxBool p_enable) m_ambulance->Init(); break; case 11: - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; ((IslePathActor*) UserActor()) ->SpawnPlayer( LegoGameState::e_jukeboxExterior, @@ -828,17 +828,17 @@ void Isle::Enable(MxBool p_enable) SetAppCursor(e_cursorArrow); - if (m_act1state->m_unk0x018 != 8 && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_elevride) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_polidoor) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_garadoor) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_bike) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_dunecar) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_motocycle) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_copter) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_jetski) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_skateboard) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_jetrace2)) { + if (m_act1state->m_state != Act1State::e_towtrack && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_elevride) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_polidoor) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_garadoor) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_bike) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_dunecar) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_motocycle) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_copter) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_jetski) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_skateboard) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_jetrace2)) { Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } @@ -897,7 +897,7 @@ MxLong Isle::HandleTransitionEnd() DeleteObjects(&m_atomId, IsleScript::c_Avo900Ps_PlayWav, IsleScript::c_Avo907Ps_PlayWav); if (m_destLocation != LegoGameState::e_skateboard) { - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; } switch (m_destLocation) { @@ -1023,7 +1023,7 @@ MxLong Isle::HandleTransitionEnd() break; case LegoGameState::e_ambulance: m_act1state->m_unk0x01f = TRUE; - m_act1state->m_unk0x018 = 10; + m_act1state->m_state = Act1State::e_ambulance; FUN_10032d30(IsleScript::c_AmbulanceFuelMeter, JukeboxScript::c_MusicTheme1, NULL, TRUE); if (!m_act1state->m_unk0x01f) { @@ -1032,7 +1032,7 @@ MxLong Isle::HandleTransitionEnd() break; case LegoGameState::e_towtrack: m_act1state->m_unk0x01f = TRUE; - m_act1state->m_unk0x018 = 8; + m_act1state->m_state = Act1State::e_towtrack; FUN_10032d30(IsleScript::c_TowFuelMeter, JukeboxScript::c_MusicTheme1, NULL, TRUE); if (!m_act1state->m_unk0x01f) { @@ -1167,7 +1167,7 @@ void Isle::CreateState() m_act1state = (Act1State*) GameState()->GetState("Act1State"); if (!m_act1state) { m_act1state = (Act1State*) GameState()->CreateState("Act1State"); - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; } m_radio.CreateState(); @@ -1193,20 +1193,20 @@ MxBool Isle::Escape() m_radio.Stop(); BackgroundAudioManager()->Stop(); - switch (m_act1state->m_unk0x018) { - case 3: + switch (m_act1state->m_state) { + case Act1State::e_pizza: if (UserActor() != NULL) { m_pizza->StopActions(); m_pizza->FUN_100382b0(); } break; - case 8: + case Act1State::e_towtrack: if (UserActor() != NULL && !UserActor()->IsA("TowTrack")) { m_towtrack->StopActions(); m_towtrack->FUN_1004dbe0(); } break; - case 10: + case Act1State::e_ambulance: if (UserActor() != NULL && !UserActor()->IsA("Ambulance")) { m_ambulance->StopActions(); m_ambulance->Reset(); @@ -1239,7 +1239,7 @@ MxBool Isle::Escape() VariableTable()->SetVariable("VISIBILITY", "Show Gas"); } - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; m_destLocation = LegoGameState::e_infomain; return TRUE; } @@ -1247,21 +1247,21 @@ MxBool Isle::Escape() // FUNCTION: LEGO1 0x10033350 void Isle::FUN_10033350() { - if (m_act1state->m_unk0x018 == 10) { + if (m_act1state->m_state == Act1State::e_ambulance) { if (UserActor() != NULL && !UserActor()->IsA("Ambulance")) { m_ambulance->StopActions(); m_ambulance->Reset(); } } - if (m_act1state->m_unk0x018 == 8) { + if (m_act1state->m_state == Act1State::e_towtrack) { if (UserActor() != NULL && !UserActor()->IsA("TowTrack")) { m_towtrack->StopActions(); m_towtrack->FUN_1004dbe0(); } } - if (m_act1state->m_unk0x018 == 3) { + if (m_act1state->m_state == Act1State::e_pizza) { if (UserActor() != NULL) { m_pizza->StopActions(); m_pizza->FUN_100382b0(); @@ -1293,7 +1293,7 @@ void Isle::FUN_10033350() Act1State::Act1State() { m_elevFloor = Act1State::c_floor1; - m_unk0x018 = 1; + m_state = Act1State::e_initial; m_unk0x01e = FALSE; m_cptClickDialogue = Playlist((MxU32*) g_cptClickDialogue, sizeOfArray(g_cptClickDialogue), Playlist::e_loop); m_unk0x01f = FALSE; diff --git a/LEGO1/lego/legoomni/src/worlds/jukebox.cpp b/LEGO1/lego/legoomni/src/worlds/jukebox.cpp index d09b7e62..db244e00 100644 --- a/LEGO1/lego/legoomni/src/worlds/jukebox.cpp +++ b/LEGO1/lego/legoomni/src/worlds/jukebox.cpp @@ -211,7 +211,7 @@ MxBool JukeBox::HandleControl(LegoControlManagerNotificationParam& p_param) break; case JukeboxwScript::c_Note_Ctl: Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); - act1State->m_unk0x018 = 11; + act1State->m_state = Act1State::e_jukebox; m_destLocation = LegoGameState::Area::e_jukeboxExterior; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, 0, FALSE); break; From e155bea7fd76fa4ea1d339f7c1cd63863c2730c3 Mon Sep 17 00:00:00 2001 From: MS Date: Mon, 14 Jul 2025 11:44:14 -0400 Subject: [PATCH 10/25] Remove GetDriverList getter (#1624) --- CONFIG/MainDlg.cpp | 2 +- CONFIG/config.cpp | 2 +- LEGO1/mxdirectx/legodxinfo.cpp | 24 ++++++++++++------------ LEGO1/mxdirectx/mxdirect3d.cpp | 2 +- LEGO1/mxdirectx/mxdirectxinfo.cpp | 12 ++++++------ LEGO1/mxdirectx/mxdirectxinfo.h | 6 +++--- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/CONFIG/MainDlg.cpp b/CONFIG/MainDlg.cpp index c9fad610..cf88727a 100644 --- a/CONFIG/MainDlg.cpp +++ b/CONFIG/MainDlg.cpp @@ -65,7 +65,7 @@ BOOL CMainDialog::OnInitDialog() int device_i = 0; int selected = 0; char device_name[256]; - const list& driver_list = enumerator->GetDriverList(); + const list& driver_list = enumerator->m_ddInfo; for (list::const_iterator it_driver = driver_list.begin(); it_driver != driver_list.end(); it_driver++) { const MxDriver& driver = *it_driver; for (list::const_iterator it_device = driver.m_devices.begin(); diff --git a/CONFIG/config.cpp b/CONFIG/config.cpp index 54b16ee9..c42469ee 100644 --- a/CONFIG/config.cpp +++ b/CONFIG/config.cpp @@ -245,7 +245,7 @@ D3DCOLORMODEL CConfigApp::GetHardwareDeviceColorModel() const BOOL CConfigApp::IsPrimaryDriver() const { assert(m_driver && m_device_enumerator); - return m_driver == &m_device_enumerator->GetDriverList().front(); + return m_driver == &m_device_enumerator->m_ddInfo.front(); } // FUNCTION: CONFIG 0x00403430 diff --git a/LEGO1/mxdirectx/legodxinfo.cpp b/LEGO1/mxdirectx/legodxinfo.cpp index 35db14b7..35c98dec 100644 --- a/LEGO1/mxdirectx/legodxinfo.cpp +++ b/LEGO1/mxdirectx/legodxinfo.cpp @@ -55,7 +55,7 @@ int LegoDeviceEnumerate::ProcessDeviceBytes(int p_deviceNum, GUID& p_guid) GUID4 deviceGuid; memcpy(&deviceGuid, &p_guid, sizeof(GUID4)); - for (list::iterator it = m_list.begin(); it != m_list.end(); it++, i++) { + for (list::iterator it = m_ddInfo.begin(); it != m_ddInfo.end(); it++, i++) { if (p_deviceNum >= 0 && p_deviceNum < i) { return -1; } @@ -90,7 +90,7 @@ int LegoDeviceEnumerate::GetDevice(int p_deviceNum, MxDriver*& p_driver, Direct3 int i = 0; - for (list::iterator it = m_list.begin(); it != m_list.end(); it++) { + for (list::iterator it = m_ddInfo.begin(); it != m_ddInfo.end(); it++) { p_driver = &*it; for (list::iterator it2 = p_driver->m_devices.begin(); it2 != p_driver->m_devices.end(); @@ -114,7 +114,7 @@ int LegoDeviceEnumerate::FormatDeviceName(char* p_buffer, const MxDriver* p_ddIn int number = 0; assert(p_ddInfo && p_d3dInfo); - for (list::const_iterator it = m_list.begin(); it != m_list.end(); it++, number++) { + for (list::const_iterator it = m_ddInfo.begin(); it != m_ddInfo.end(); it++, number++) { if (&(*it) == p_ddInfo) { GUID4 guid; memcpy(&guid, p_d3dInfo->m_guid, sizeof(GUID4)); @@ -137,7 +137,7 @@ int LegoDeviceEnumerate::BETA_1011cc65(int p_idx, char* p_buffer) int i = 0; int j = 0; - for (list::iterator it = m_list.begin(); it != m_list.end(); it++, i++) { + for (list::iterator it = m_ddInfo.begin(); it != m_ddInfo.end(); it++, i++) { MxDriver& driver = *it; for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end(); it2++) { @@ -164,7 +164,7 @@ int LegoDeviceEnumerate::GetBestDevice() return -1; } - if (m_list.size() == 0) { + if (m_ddInfo.size() == 0) { return -1; } @@ -173,7 +173,7 @@ int LegoDeviceEnumerate::GetBestDevice() int k = -1; int cpu_mmx = SupportsMMX(); - for (list::iterator it = m_list.begin(); it != m_list.end(); it++, i++) { + for (list::iterator it = m_ddInfo.begin(); it != m_ddInfo.end(); it++, i++) { MxDriver& driver = *it; for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end(); it2++) { @@ -297,9 +297,9 @@ int LegoDeviceEnumerate::FUN_1009d210() return -1; } - for (list::iterator it = m_list.begin(); it != m_list.end();) { + for (list::iterator it = m_ddInfo.begin(); it != m_ddInfo.end();) { if (!DriverSupportsRequiredDisplayMode(*it)) { - m_list.erase(it++); + m_ddInfo.erase(it++); continue; } @@ -315,14 +315,14 @@ int LegoDeviceEnumerate::FUN_1009d210() } if (!driver.m_devices.size()) { - m_list.erase(it++); + m_ddInfo.erase(it++); } else { it++; } } - if (!m_list.size()) { + if (!m_ddInfo.size()) { return -1; } @@ -351,7 +351,7 @@ unsigned char LegoDeviceEnumerate::DriverSupportsRequiredDisplayMode(MxDriver& p // FUNCTION: BETA10 0x1011d235 unsigned char LegoDeviceEnumerate::FUN_1009d3d0(Direct3DDeviceInfo& p_device) { - if (m_list.size() <= 0) { + if (m_ddInfo.size() <= 0) { return FALSE; } @@ -365,7 +365,7 @@ unsigned char LegoDeviceEnumerate::FUN_1009d3d0(Direct3DDeviceInfo& p_device) } } - MxDriver& front = m_list.front(); + MxDriver& front = m_ddInfo.front(); for (list::iterator it = front.m_devices.begin(); it != front.m_devices.end(); it++) { if ((&*it) == &p_device) { return TRUE; diff --git a/LEGO1/mxdirectx/mxdirect3d.cpp b/LEGO1/mxdirectx/mxdirect3d.cpp index 028b7ced..5a3d9ff6 100644 --- a/LEGO1/mxdirectx/mxdirect3d.cpp +++ b/LEGO1/mxdirectx/mxdirect3d.cpp @@ -262,7 +262,7 @@ BOOL MxDirect3D::SetDevice(MxDeviceEnumerate& p_deviceEnumerate, MxDriver* p_dri assert(d); int i = 0; - for (list::iterator it = p_deviceEnumerate.m_list.begin(); it != p_deviceEnumerate.m_list.end(); + for (list::iterator it = p_deviceEnumerate.m_ddInfo.begin(); it != p_deviceEnumerate.m_ddInfo.end(); it++, i++) { MxDriver& driver = *it; diff --git a/LEGO1/mxdirectx/mxdirectxinfo.cpp b/LEGO1/mxdirectx/mxdirectxinfo.cpp index 11ca9da2..3070eb08 100644 --- a/LEGO1/mxdirectx/mxdirectxinfo.cpp +++ b/LEGO1/mxdirectx/mxdirectxinfo.cpp @@ -197,7 +197,7 @@ MxDeviceEnumerate::~MxDeviceEnumerate() BOOL MxDeviceEnumerate::EnumDirectDrawCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName) { MxDriver driver(p_guid, p_driverDesc, p_driverName); - m_list.push_back(driver); + m_ddInfo.push_back(driver); // Must be zeroed because held resources are copied by pointer only // and should not be freed at the end of this function @@ -208,7 +208,7 @@ BOOL MxDeviceEnumerate::EnumDirectDrawCallback(LPGUID p_guid, LPSTR p_driverDesc LPDIRECT3D2 lpDirect3d2 = NULL; LPDIRECTDRAW lpDD = NULL; - MxDriver& newDevice = m_list.back(); + MxDriver& newDevice = m_ddInfo.back(); HRESULT result = DirectDrawCreate(newDevice.m_guid, &lpDD, NULL); if (result != DD_OK) { @@ -236,7 +236,7 @@ BOOL MxDeviceEnumerate::EnumDirectDrawCallback(LPGUID p_guid, LPSTR p_driverDesc } else { if (!newDevice.m_devices.size()) { - m_list.pop_back(); + m_ddInfo.pop_back(); } } } @@ -306,12 +306,12 @@ HRESULT CALLBACK MxDeviceEnumerate::DevicesEnumerateCallback( // FUNCTION: BETA10 0x1011e27f HRESULT MxDeviceEnumerate::EnumDisplayModesCallback(LPDDSURFACEDESC p_ddsd) { - assert(m_list.size() > 0); + assert(m_ddInfo.size() > 0); assert(p_ddsd); // TODO: compat_mode? MxDisplayMode displayMode(p_ddsd->dwWidth, p_ddsd->dwHeight, p_ddsd->ddpfPixelFormat.dwRGBBitCount); - m_list.back().m_displayModes.push_back(displayMode); + m_ddInfo.back().m_displayModes.push_back(displayMode); return DDENUMRET_OK; } @@ -327,7 +327,7 @@ HRESULT MxDeviceEnumerate::EnumDevicesCallback( ) { Direct3DDeviceInfo device(p_guid, p_deviceDesc, p_deviceName, p_HWDesc, p_HELDesc); - m_list.back().m_devices.push_back(device); + m_ddInfo.back().m_devices.push_back(device); memset(&device, 0, sizeof(device)); return DDENUMRET_OK; } diff --git a/LEGO1/mxdirectx/mxdirectxinfo.h b/LEGO1/mxdirectx/mxdirectxinfo.h index 3fbecfc8..03370c1e 100644 --- a/LEGO1/mxdirectx/mxdirectxinfo.h +++ b/LEGO1/mxdirectx/mxdirectxinfo.h @@ -218,8 +218,8 @@ class MxDeviceEnumerate { ); friend class MxDirect3D; - - const list& GetDriverList() const { return m_list; } + friend class CConfigApp; + friend class CMainDialog; // SIZE 0x10 struct GUID4 { @@ -240,7 +240,7 @@ class MxDeviceEnumerate { unsigned char IsInitialized() const { return m_initialized; } protected: - list m_list; // 0x04 + list m_ddInfo; // 0x04 unsigned char m_initialized; // 0x10 }; From 3b79b4c83477ca6d133a945cbf33adb320329f30 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Mon, 14 Jul 2025 22:18:21 +0200 Subject: [PATCH 11/25] Use enum values for `LegoPathStructNotificationParam.GetTrigger()` (#1625) --- LEGO1/lego/legoomni/src/race/carrace.cpp | 2 +- LEGO1/lego/legoomni/src/race/jetskirace.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LEGO1/lego/legoomni/src/race/carrace.cpp b/LEGO1/lego/legoomni/src/race/carrace.cpp index 7a9cfef2..18ea1c89 100644 --- a/LEGO1/lego/legoomni/src/race/carrace.cpp +++ b/LEGO1/lego/legoomni/src/race/carrace.cpp @@ -179,7 +179,7 @@ MxLong CarRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) { MxLong result = 0; - if (p_param.GetTrigger() == 68) { + if (p_param.GetTrigger() == LegoPathStruct::c_d) { MxEntity* sender = (MxEntity*) p_param.GetSender(); MxS32 paramData = p_param.GetData(); diff --git a/LEGO1/lego/legoomni/src/race/jetskirace.cpp b/LEGO1/lego/legoomni/src/race/jetskirace.cpp index 71746cd0..2893868f 100644 --- a/LEGO1/lego/legoomni/src/race/jetskirace.cpp +++ b/LEGO1/lego/legoomni/src/race/jetskirace.cpp @@ -158,7 +158,7 @@ MxLong JetskiRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) MxLong result = 0; MxEntity* sender = (MxEntity*) p_param.GetSender(); - if (p_param.GetTrigger() == 68) { + if (p_param.GetTrigger() == LegoPathStruct::c_d) { MxS32 paramData = p_param.GetData(); switch (sender->GetEntityId()) { From 9c9baf3c3e81ef779cbb341809ff37053e0c6168 Mon Sep 17 00:00:00 2001 From: MS Date: Tue, 15 Jul 2025 10:43:40 -0400 Subject: [PATCH 12/25] Beta matching in `mxdirectxinfo.cpp` (#1626) * Use goto * Fix constructors * Reorder error strings * Compat mode todo * Rename p_context to p_d * Use count variable * Fix typo --- LEGO1/mxdirectx/mxdirectxinfo.cpp | 343 +++++++++++++++--------------- LEGO1/mxdirectx/mxdirectxinfo.h | 12 +- 2 files changed, 182 insertions(+), 173 deletions(-) diff --git a/LEGO1/mxdirectx/mxdirectxinfo.cpp b/LEGO1/mxdirectx/mxdirectxinfo.cpp index 3070eb08..ac3fce38 100644 --- a/LEGO1/mxdirectx/mxdirectxinfo.cpp +++ b/LEGO1/mxdirectx/mxdirectxinfo.cpp @@ -29,13 +29,12 @@ MxAssignedDevice::~MxAssignedDevice() } // FUNCTION: BETA10 0x1011d7f0 -MxDriver::MxDriver(LPGUID p_guid) +MxDriver::MxDriver() { m_guid = NULL; m_driverDesc = NULL; m_driverName = NULL; memset(&m_ddCaps, 0, sizeof(m_ddCaps)); - // TODO: ret vs ret 4 } // FUNCTION: CONFIG 0x00401180 @@ -98,6 +97,12 @@ void MxDriver::Init(LPGUID p_guid, LPCSTR p_driverDesc, LPCSTR p_driverName) } } +// FUNCTION: BETA10 0x1011dba4 +Direct3DDeviceInfo::Direct3DDeviceInfo() +{ + memset(this, 0, sizeof(*this)); +} + // FUNCTION: CONFIG 0x401420 // FUNCTION: LEGO1 0x1009bd20 // FUNCTION: BETA10 0x1011dbd0 @@ -213,36 +218,37 @@ BOOL MxDeviceEnumerate::EnumDirectDrawCallback(LPGUID p_guid, LPSTR p_driverDesc if (result != DD_OK) { BuildErrorString("DirectDraw Create failed: %s\n", EnumerateErrorToString(result)); - } - else { - lpDD->EnumDisplayModes(0, NULL, this, DisplayModesEnumerateCallback); - newDevice.m_ddCaps.dwSize = sizeof(newDevice.m_ddCaps); - result = lpDD->GetCaps(&newDevice.m_ddCaps, NULL); - - if (result != DD_OK) { - BuildErrorString("GetCaps failed: %s\n", EnumerateErrorToString(result)); - } - else { - result = lpDD->QueryInterface(IID_IDirect3D2, (LPVOID*) &lpDirect3d2); - - if (result != DD_OK) { - BuildErrorString("D3D creation failed: %s\n", EnumerateErrorToString(result)); - } - else { - result = lpDirect3d2->EnumDevices(DevicesEnumerateCallback, this); - - if (result != DD_OK) { - BuildErrorString("D3D enum devices failed: %s\n", EnumerateErrorToString(result)); - } - else { - if (!newDevice.m_devices.size()) { - m_ddInfo.pop_back(); - } - } - } - } + goto done; } + lpDD->EnumDisplayModes(0, NULL, this, DisplayModesEnumerateCallback); + newDevice.m_ddCaps.dwSize = sizeof(newDevice.m_ddCaps); + result = lpDD->GetCaps(&newDevice.m_ddCaps, NULL); + + if (result != DD_OK) { + BuildErrorString("GetCaps failed: %s\n", EnumerateErrorToString(result)); + goto done; + } + + result = lpDD->QueryInterface(IID_IDirect3D2, (LPVOID*) &lpDirect3d2); + + if (result != DD_OK) { + BuildErrorString("D3D creation failed: %s\n", EnumerateErrorToString(result)); + goto done; + } + + result = lpDirect3d2->EnumDevices(DevicesEnumerateCallback, this); + + if (result != DD_OK) { + BuildErrorString("D3D enum devices failed: %s\n", EnumerateErrorToString(result)); + goto done; + } + + if (!newDevice.m_devices.size()) { + m_ddInfo.pop_back(); + } + +done: if (lpDirect3d2) { lpDirect3d2->Release(); } @@ -263,7 +269,7 @@ void MxDeviceEnumerate::BuildErrorString(const char* p_format, ...) char buf[512]; va_start(args, p_format); - vsprintf(buf, p_format, args); + int count = vsprintf(buf, p_format, args); va_end(args); OutputDebugString(buf); @@ -272,13 +278,10 @@ void MxDeviceEnumerate::BuildErrorString(const char* p_format, ...) // FUNCTION: CONFIG 0x00401bf0 // FUNCTION: LEGO1 0x1009c4f0 // FUNCTION: BETA10 0x1011e1dd -HRESULT CALLBACK MxDeviceEnumerate::DisplayModesEnumerateCallback(LPDDSURFACEDESC p_ddsd, LPVOID p_context) +HRESULT CALLBACK MxDeviceEnumerate::DisplayModesEnumerateCallback(LPDDSURFACEDESC p_ddsd, LPVOID p_d) { - if (p_context == NULL) { - assert(0); - } - - return ((MxDeviceEnumerate*) p_context)->EnumDisplayModesCallback(p_ddsd); + assert(p_d); + return ((MxDeviceEnumerate*) p_d)->EnumDisplayModesCallback(p_ddsd); } // FUNCTION: CONFIG 0x00401c10 @@ -290,15 +293,14 @@ HRESULT CALLBACK MxDeviceEnumerate::DevicesEnumerateCallback( LPSTR p_deviceName, LPD3DDEVICEDESC p_HWDesc, LPD3DDEVICEDESC p_HELDesc, - LPVOID p_context + LPVOID p_d ) { - if (p_context == NULL) { + if (p_d == NULL) { assert(0); } - return ((MxDeviceEnumerate*) p_context) - ->EnumDevicesCallback(p_guid, p_deviceDesc, p_deviceName, p_HWDesc, p_HELDesc); + return ((MxDeviceEnumerate*) p_d)->EnumDevicesCallback(p_guid, p_deviceDesc, p_deviceName, p_HWDesc, p_HELDesc); } // FUNCTION: CONFIG 0x00401c40 @@ -309,9 +311,15 @@ HRESULT MxDeviceEnumerate::EnumDisplayModesCallback(LPDDSURFACEDESC p_ddsd) assert(m_ddInfo.size() > 0); assert(p_ddsd); - // TODO: compat_mode? +#ifdef COMPAT_MODE MxDisplayMode displayMode(p_ddsd->dwWidth, p_ddsd->dwHeight, p_ddsd->ddpfPixelFormat.dwRGBBitCount); m_ddInfo.back().m_displayModes.push_back(displayMode); +#else + m_ddInfo.back().m_displayModes.push_back( + MxDisplayMode(p_ddsd->dwWidth, p_ddsd->dwHeight, p_ddsd->ddpfPixelFormat.dwRGBBitCount) + ); +#endif + return DDENUMRET_OK; } @@ -355,13 +363,10 @@ int MxDeviceEnumerate::DoEnumerate() // FUNCTION: LEGO1 0x1009c710 // FUNCTION: BETA10 0x1011e476 BOOL CALLBACK -MxDeviceEnumerate::DirectDrawEnumerateCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName, LPVOID p_context) +MxDeviceEnumerate::DirectDrawEnumerateCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName, LPVOID p_d) { - if (p_context == NULL) { - assert(0); - } - - return ((MxDeviceEnumerate*) p_context)->EnumDirectDrawCallback(p_guid, p_driverDesc, p_driverName); + assert(p_d); + return ((MxDeviceEnumerate*) p_d)->EnumDirectDrawCallback(p_guid, p_driverDesc, p_driverName); } // FUNCTION: CONFIG 0x00401e30 @@ -372,79 +377,123 @@ const char* MxDeviceEnumerate::EnumerateErrorToString(HRESULT p_error) switch (p_error) { case DD_OK: return "No error."; - case DDERR_GENERIC: - return "Generic failure."; - case DDERR_UNSUPPORTED: - return "Action not supported."; - case DDERR_INVALIDPARAMS: - return "One or more of the parameters passed to the function are incorrect."; - case DDERR_OUTOFMEMORY: - return "DirectDraw does not have enough memory to perform the operation."; - case DDERR_CANNOTATTACHSURFACE: - return "This surface can not be attached to the requested surface."; case DDERR_ALREADYINITIALIZED: return "This object is already initialized."; - case DDERR_CURRENTLYNOTAVAIL: - return "Support is currently not available."; + case DDERR_BLTFASTCANTCLIP: + return "Return if a clipper object is attached to the source surface passed into a BltFast call."; + case DDERR_CANNOTATTACHSURFACE: + return "This surface can not be attached to the requested surface."; case DDERR_CANNOTDETACHSURFACE: return "This surface can not be detached from the requested surface."; - case DDERR_HEIGHTALIGN: - return "Height of rectangle provided is not a multiple of reqd alignment."; + case DDERR_CANTCREATEDC: + return "Windows can not create any more DCs."; + case DDERR_CANTDUPLICATE: + return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created."; + case DDERR_CLIPPERISUSINGHWND: + return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd."; + case DDERR_COLORKEYNOTSET: + return "No src color key specified for this operation."; + case DDERR_CURRENTLYNOTAVAIL: + return "Support is currently not available."; + case DDERR_DIRECTDRAWALREADYCREATED: + return "A DirectDraw object representing this driver has already been created for this process."; case DDERR_EXCEPTION: return "An exception was encountered while performing the requested operation."; - case DDERR_INVALIDCAPS: - return "One or more of the caps bits passed to the callback are incorrect."; + case DDERR_EXCLUSIVEMODEALREADYSET: + return "An attempt was made to set the cooperative level when it was already set to exclusive."; + case DDERR_GENERIC: + return "Generic failure."; + case DDERR_HEIGHTALIGN: + return "Height of rectangle provided is not a multiple of reqd alignment."; + case DDERR_HWNDALREADYSET: + return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or " + "palettes created."; + case DDERR_HWNDSUBCLASSED: + return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring " + "state."; + case DDERR_IMPLICITLYCREATED: + return "This surface can not be restored because it is an implicitly created surface."; case DDERR_INCOMPATIBLEPRIMARY: return "Unable to match primary surface creation request with existing primary surface."; - case DDERR_INVALIDMODE: - return "DirectDraw does not support the requested mode."; + case DDERR_INVALIDCAPS: + return "One or more of the caps bits passed to the callback are incorrect."; case DDERR_INVALIDCLIPLIST: return "DirectDraw does not support the provided cliplist."; - case DDERR_INVALIDPIXELFORMAT: - return "The pixel format was invalid as specified."; + case DDERR_INVALIDDIRECTDRAWGUID: + return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier."; + case DDERR_INVALIDMODE: + return "DirectDraw does not support the requested mode."; case DDERR_INVALIDOBJECT: return "DirectDraw received a pointer that was an invalid DIRECTDRAW object."; - case DDERR_LOCKEDSURFACES: - return "Operation could not be carried out because one or more surfaces are locked."; + case DDERR_INVALIDPARAMS: + return "One or more of the parameters passed to the function are incorrect."; + case DDERR_INVALIDPIXELFORMAT: + return "The pixel format was invalid as specified."; + case DDERR_INVALIDPOSITION: + return "Returned when the position of the overlay on the destination is no longer legal for that " + "destination."; case DDERR_INVALIDRECT: return "Rectangle provided was invalid."; + case DDERR_LOCKEDSURFACES: + return "Operation could not be carried out because one or more surfaces are locked."; + case DDERR_NO3D: + return "There is no 3D present."; case DDERR_NOALPHAHW: return "Operation could not be carried out because there is no alpha accleration hardware present or " "available."; - case DDERR_NO3D: - return "There is no 3D present."; - case DDERR_NOCOLORCONVHW: - return "Operation could not be carried out because there is no color conversion hardware present or available."; + case DDERR_NOBLTHW: + return "No blitter hardware present."; case DDERR_NOCLIPLIST: return "No cliplist available."; + case DDERR_NOCLIPPERATTACHED: + return "No clipper object attached to surface object."; + case DDERR_NOCOLORCONVHW: + return "Operation could not be carried out because there is no color conversion hardware present or " + "available."; case DDERR_NOCOLORKEY: return "Surface doesn't currently have a color key"; + case DDERR_NOCOLORKEYHW: + return "Operation could not be carried out because there is no hardware support of the destination color " + "key."; case DDERR_NOCOOPERATIVELEVELSET: return "Create function called without DirectDraw object method SetCooperativeLevel being called."; + case DDERR_NODC: + return "No DC was ever created for this surface."; + case DDERR_NODDROPSHW: + return "No DirectDraw ROP hardware."; + case DDERR_NODIRECTDRAWHW: + return "A hardware-only DirectDraw object creation was attempted but the driver did not support any " + "hardware."; + case DDERR_NOEMULATION: + return "Software emulation not available."; case DDERR_NOEXCLUSIVEMODE: return "Operation requires the application to have exclusive mode but the application does not have exclusive " "mode."; - case DDERR_NOCOLORKEYHW: - return "Operation could not be carried out because there is no hardware support of the destination color key."; - case DDERR_NOGDI: - return "There is no GDI present."; case DDERR_NOFLIPHW: return "Flipping visible surfaces is not supported."; - case DDERR_NOTFOUND: - return "Requested item was not found."; + case DDERR_NOGDI: + return "There is no GDI present."; + case DDERR_NOHWND: + return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel " + "HWND."; case DDERR_NOMIRRORHW: return "Operation could not be carried out because there is no hardware present or available."; + case DDERR_NOOVERLAYDEST: + return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on " + "to establish a destination."; + case DDERR_NOOVERLAYHW: + return "Operation could not be carried out because there is no overlay hardware present or available."; + case DDERR_NOPALETTEATTACHED: + return "No palette object attached to this surface."; + case DDERR_NOPALETTEHW: + return "No hardware support for 16 or 256 color palettes."; case DDERR_NORASTEROPHW: return "Operation could not be carried out because there is no appropriate raster op hardware present or " "available."; - case DDERR_NOOVERLAYHW: - return "Operation could not be carried out because there is no overlay hardware present or available."; - case DDERR_NOSTRETCHHW: - return "Operation could not be carried out because there is no hardware support for stretching."; case DDERR_NOROTATIONHW: return "Operation could not be carried out because there is no rotation hardware present or available."; - case DDERR_NOTEXTUREHW: - return "Operation could not be carried out because there is no texture mapping hardware present or available."; + case DDERR_NOSTRETCHHW: + return "Operation could not be carried out because there is no hardware support for stretching."; case DDERR_NOT4BITCOLOR: return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color " "palette."; @@ -453,118 +502,80 @@ const char* MxDeviceEnumerate::EnumerateErrorToString(HRESULT p_error) "index palette."; case DDERR_NOT8BITCOLOR: return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color."; - case DDERR_NOZBUFFERHW: - return "Operation could not be carried out because there is no hardware support for zbuffer blitting."; + case DDERR_NOTAOVERLAYSURFACE: + return "Returned when an overlay member is called for a non-overlay surface."; + case DDERR_NOTEXTUREHW: + return "Operation could not be carried out because there is no texture mapping hardware present or " + "available."; + case DDERR_NOTFLIPPABLE: + return "An attempt has been made to flip a surface that is not flippable."; + case DDERR_NOTFOUND: + return "Requested item was not found."; + case DDERR_NOTLOCKED: + return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this " + "process, has been attempted."; + case DDERR_NOTPALETTIZED: + return "The surface being used is not a palette-based surface."; case DDERR_NOVSYNCHW: return "Operation could not be carried out because there is no hardware support for vertical blank " "synchronized operations."; - case DDERR_OUTOFCAPS: - return "The hardware needed for the requested operation has already been allocated."; + case DDERR_NOZBUFFERHW: + return "Operation could not be carried out because there is no hardware support for zbuffer blitting."; case DDERR_NOZOVERLAYHW: return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support " "z layering of overlays."; - case DDERR_COLORKEYNOTSET: - return "No src color key specified for this operation."; + case DDERR_OUTOFCAPS: + return "The hardware needed for the requested operation has already been allocated."; + case DDERR_OUTOFMEMORY: + return "DirectDraw does not have enough memory to perform the operation."; case DDERR_OUTOFVIDEOMEMORY: return "DirectDraw does not have enough memory to perform the operation."; case DDERR_OVERLAYCANTCLIP: return "The hardware does not support clipped overlays."; case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: return "Can only have ony color key active at one time for overlays."; + case DDERR_OVERLAYNOTVISIBLE: + return "Returned when GetOverlayPosition is called on a hidden overlay."; case DDERR_PALETTEBUSY: return "Access to this palette is being refused because the palette is already locked by another thread."; - case DDERR_SURFACEALREADYDEPENDENT: - return "This surface is already a dependency of the surface it is being made a dependency of."; + case DDERR_PRIMARYSURFACEALREADYEXISTS: + return "This process already has created a primary surface."; + case DDERR_REGIONTOOSMALL: + return "Region passed to Clipper::GetClipList is too small."; case DDERR_SURFACEALREADYATTACHED: return "This surface is already attached to the surface it is being attached to."; - case DDERR_SURFACEISOBSCURED: - return "Access to surface refused because the surface is obscured."; + case DDERR_SURFACEALREADYDEPENDENT: + return "This surface is already a dependency of the surface it is being made a dependency of."; case DDERR_SURFACEBUSY: return "Access to this surface is being refused because the surface is already locked by another thread."; - case DDERR_SURFACENOTATTACHED: - return "The requested surface is not attached."; + case DDERR_SURFACEISOBSCURED: + return "Access to surface refused because the surface is obscured."; case DDERR_SURFACELOST: return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface " "object representing this surface should have Restore called on it."; - case DDERR_TOOBIGSIZE: - return "Size requested by DirectDraw is too large, but the individual height and width are OK."; + case DDERR_SURFACENOTATTACHED: + return "The requested surface is not attached."; case DDERR_TOOBIGHEIGHT: return "Height requested by DirectDraw is too large."; - case DDERR_UNSUPPORTEDFORMAT: - return "FOURCC format requested is unsupported by DirectDraw."; + case DDERR_TOOBIGSIZE: + return "Size requested by DirectDraw is too large, but the individual height and width are OK."; case DDERR_TOOBIGWIDTH: return "Width requested by DirectDraw is too large."; - case DDERR_VERTICALBLANKINPROGRESS: - return "Vertical blank is in progress."; + case DDERR_UNSUPPORTED: + return "Action not supported."; + case DDERR_UNSUPPORTEDFORMAT: + return "FOURCC format requested is unsupported by DirectDraw."; case DDERR_UNSUPPORTEDMASK: return "Bitmask in the pixel format requested is unsupported by DirectDraw."; - case DDERR_XALIGN: - return "Rectangle provided was not horizontally aligned on required boundary."; + case DDERR_VERTICALBLANKINPROGRESS: + return "Vertical blank is in progress."; case DDERR_WASSTILLDRAWING: return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is " "incomplete."; - case DDERR_INVALIDDIRECTDRAWGUID: - return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier."; - case DDERR_DIRECTDRAWALREADYCREATED: - return "A DirectDraw object representing this driver has already been created for this process."; - case DDERR_NODIRECTDRAWHW: - return "A hardware-only DirectDraw object creation was attempted but the driver did not support any hardware."; - case DDERR_PRIMARYSURFACEALREADYEXISTS: - return "This process already has created a primary surface."; - case DDERR_NOEMULATION: - return "Software emulation not available."; - case DDERR_REGIONTOOSMALL: - return "Region passed to Clipper::GetClipList is too small."; - case DDERR_CLIPPERISUSINGHWND: - return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd."; - case DDERR_NOCLIPPERATTACHED: - return "No clipper object attached to surface object."; - case DDERR_NOHWND: - return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel HWND."; - case DDERR_HWNDSUBCLASSED: - return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring " - "state."; - case DDERR_HWNDALREADYSET: - return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or " - "palettes created."; - case DDERR_NOPALETTEATTACHED: - return "No palette object attached to this surface."; - case DDERR_NOPALETTEHW: - return "No hardware support for 16 or 256 color palettes."; - case DDERR_BLTFASTCANTCLIP: - return "Return if a clipper object is attached to the source surface passed into a BltFast call."; - case DDERR_NOBLTHW: - return "No blitter hardware present."; - case DDERR_NODDROPSHW: - return "No DirectDraw ROP hardware."; - case DDERR_OVERLAYNOTVISIBLE: - return "Returned when GetOverlayPosition is called on a hidden overlay."; - case DDERR_NOOVERLAYDEST: - return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on " - "to establish a destination."; - case DDERR_INVALIDPOSITION: - return "Returned when the position of the overlay on the destination is no longer legal for that destination."; - case DDERR_NOTAOVERLAYSURFACE: - return "Returned when an overlay member is called for a non-overlay surface."; - case DDERR_EXCLUSIVEMODEALREADYSET: - return "An attempt was made to set the cooperative level when it was already set to exclusive."; - case DDERR_NOTFLIPPABLE: - return "An attempt has been made to flip a surface that is not flippable."; - case DDERR_CANTDUPLICATE: - return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created."; - case DDERR_NOTLOCKED: - return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this " - "process, has been attempted."; - case DDERR_CANTCREATEDC: - return "Windows can not create any more DCs."; - case DDERR_NODC: - return "No DC was ever created for this surface."; case DDERR_WRONGMODE: return "This surface can not be restored because it was created in a different mode."; - case DDERR_IMPLICITLYCREATED: - return "This surface can not be restored because it is an implicitly created surface."; - case DDERR_NOTPALETTIZED: - return "The surface being used is not a palette-based surface."; + case DDERR_XALIGN: + return "Rectangle provided was not horizontally aligned on required boundary."; default: return "Unrecognized error value."; } diff --git a/LEGO1/mxdirectx/mxdirectxinfo.h b/LEGO1/mxdirectx/mxdirectxinfo.h index 03370c1e..49fea43d 100644 --- a/LEGO1/mxdirectx/mxdirectxinfo.h +++ b/LEGO1/mxdirectx/mxdirectxinfo.h @@ -63,7 +63,7 @@ class MxAssignedDevice { // SIZE 0x1a4 struct Direct3DDeviceInfo { - Direct3DDeviceInfo() {} + Direct3DDeviceInfo(); ~Direct3DDeviceInfo(); Direct3DDeviceInfo( LPGUID p_guid, @@ -112,9 +112,8 @@ struct MxDisplayMode { // SIZE 0x190 struct MxDriver { - MxDriver() {} + MxDriver(); ~MxDriver(); - MxDriver(LPGUID p_guid); MxDriver(LPGUID p_guid, LPCSTR p_driverDesc, LPCSTR p_driverName); void Init(LPGUID p_guid, LPCSTR p_driverDesc, LPCSTR p_driverName); @@ -205,16 +204,15 @@ class MxDeviceEnumerate { ); const char* EnumerateErrorToString(HRESULT p_error); static void BuildErrorString(const char*, ...); - static BOOL CALLBACK - DirectDrawEnumerateCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName, LPVOID p_context); - static HRESULT CALLBACK DisplayModesEnumerateCallback(LPDDSURFACEDESC p_ddsd, LPVOID p_context); + static BOOL CALLBACK DirectDrawEnumerateCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName, LPVOID p_d); + static HRESULT CALLBACK DisplayModesEnumerateCallback(LPDDSURFACEDESC p_ddsd, LPVOID p_d); static HRESULT CALLBACK DevicesEnumerateCallback( LPGUID p_guid, LPSTR p_deviceDesc, LPSTR p_deviceName, LPD3DDEVICEDESC p_HWDesc, LPD3DDEVICEDESC p_HELDesc, - LPVOID p_context + LPVOID p_d ); friend class MxDirect3D; From bf98bfffdfa739d4d1e9a97d47a7cfb23b93fde4 Mon Sep 17 00:00:00 2001 From: MS Date: Tue, 15 Jul 2025 12:58:13 -0400 Subject: [PATCH 13/25] CONFIG (#1627) --- CMakeLists.txt | 1 + CONFIG/AboutDlg.cpp | 3 + CONFIG/AboutDlg.h | 10 ++ CONFIG/ConfigCommandLineInfo.cpp | 8 + CONFIG/ConfigCommandLineInfo.h | 3 + CONFIG/MainDlg.cpp | 205 ++++++++++++++------- CONFIG/MainDlg.h | 13 ++ CONFIG/config.cpp | 64 +++---- CONFIG/config.h | 36 ++-- CONFIG/detectdx5.cpp | 297 +++++++++++++++++++++---------- CONFIG/detectdx5.h | 2 +- CONFIG/res/resource.h | 2 + 12 files changed, 441 insertions(+), 203 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9fe6030..c8d030e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -593,6 +593,7 @@ if (MSVC_FOR_DECOMP) endif() if (ISLE_BUILD_CONFIG) + target_link_options(config PRIVATE "/OPT:REF") target_link_libraries(config PRIVATE mfc42) endif() diff --git a/CONFIG/AboutDlg.cpp b/CONFIG/AboutDlg.cpp index 9585d1c1..61d0d075 100644 --- a/CONFIG/AboutDlg.cpp +++ b/CONFIG/AboutDlg.cpp @@ -6,13 +6,16 @@ DECOMP_SIZE_ASSERT(CDialog, 0x60) DECOMP_SIZE_ASSERT(CAboutDialog, 0x60) // FUNCTION: CONFIG 0x00403c20 +// FUNCTION: CONFIGD 0x00408630 CAboutDialog::CAboutDialog() : CDialog(IDD) { } // FUNCTION: CONFIG 0x00403d20 +// FUNCTION: CONFIGD 0x004086a3 void CAboutDialog::DoDataExchange(CDataExchange* pDX) { + CWnd::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDialog, CDialog) diff --git a/CONFIG/AboutDlg.h b/CONFIG/AboutDlg.h index dc648d63..65db159f 100644 --- a/CONFIG/AboutDlg.h +++ b/CONFIG/AboutDlg.h @@ -6,6 +6,7 @@ #include "res/resource.h" // VTABLE: CONFIG 0x00406308 +// VTABLE: CONFIGD 0x0040c3f8 // SIZE 0x60 class CAboutDialog : public CDialog { public: @@ -22,18 +23,27 @@ class CAboutDialog : public CDialog { }; // SYNTHETIC: CONFIG 0x00403cb0 +// SYNTHETIC: CONFIGD 0x00409840 // CAboutDialog::`scalar deleting destructor' +// SYNTHETIC: CONFIG 0x00404100 +// SYNTHETIC: CONFIGD 0x00409890 +// CAboutDialog::~CAboutDialog + // FUNCTION: CONFIG 0x00403d30 +// FUNCTION: CONFIGD 0x004086c7 // CAboutDialog::_GetBaseMessageMap // FUNCTION: CONFIG 0x00403d40 +// FUNCTION: CONFIGD 0x004086dc // CAboutDialog::GetMessageMap // GLOBAL: CONFIG 0x00406100 +// GLOBAL: CONFIGD 0x0040c188 // CAboutDialog::messageMap // GLOBAL: CONFIG 0x00406108 +// GLOBAL: CONFIGD 0x0040c190 // CAboutDialog::_messageEntries #endif // !defined(AFX_ABOUTDLG_H) diff --git a/CONFIG/ConfigCommandLineInfo.cpp b/CONFIG/ConfigCommandLineInfo.cpp index cf3180c4..4542746f 100644 --- a/CONFIG/ConfigCommandLineInfo.cpp +++ b/CONFIG/ConfigCommandLineInfo.cpp @@ -6,12 +6,20 @@ DECOMP_SIZE_ASSERT(CCommandLineInfo, 0x24) DECOMP_SIZE_ASSERT(CConfigCommandLineInfo, 0x24) // FUNCTION: CONFIG 0x00403b10 +// FUNCTION: CONFIGD 0x00407caa CConfigCommandLineInfo::CConfigCommandLineInfo() { currentConfigApp->m_run_config_dialog = FALSE; } +// FUNCTION: CONFIG 0x00403ba0 +// FUNCTION: CONFIGD 0x00407d2e +CConfigCommandLineInfo::~CConfigCommandLineInfo() +{ +} + // FUNCTION: CONFIG 0x00403bf0 +// FUNCTION: CONFIGD 0x00407d96 void CConfigCommandLineInfo::ParseParam(LPCSTR pszParam, BOOL bFlag, BOOL bLast) { if (bFlag) { diff --git a/CONFIG/ConfigCommandLineInfo.h b/CONFIG/ConfigCommandLineInfo.h index 82510df1..762ecb16 100644 --- a/CONFIG/ConfigCommandLineInfo.h +++ b/CONFIG/ConfigCommandLineInfo.h @@ -7,15 +7,18 @@ #include "decomp.h" // VTABLE: CONFIG 0x004060e8 +// VTABLE: CONFIGD 0x0040c168 // SIZE 0x24 class CConfigCommandLineInfo : public CCommandLineInfo { public: CConfigCommandLineInfo(); + ~CConfigCommandLineInfo() override; void ParseParam(LPCSTR pszParam, BOOL bFlag, BOOL bLast) override; }; // SYNTHETIC: CONFIG 0x00403b80 +// SYNTHETIC: CONFIGD 0x004085e0 // CConfigCommandLineInfo::`scalar deleting destructor' #endif // !defined(AFX_CONFIGCOMMANDLINEINFO_H) diff --git a/CONFIG/MainDlg.cpp b/CONFIG/MainDlg.cpp index cf88727a..9a99f121 100644 --- a/CONFIG/MainDlg.cpp +++ b/CONFIG/MainDlg.cpp @@ -4,21 +4,24 @@ #include "config.h" #include "res/resource.h" +#include #include DECOMP_SIZE_ASSERT(CDialog, 0x60) DECOMP_SIZE_ASSERT(CMainDialog, 0x70) // FUNCTION: CONFIG 0x00403d50 +// FUNCTION: CONFIGD 0x004086f7 CMainDialog::CMainDialog(CWnd* pParent) : CDialog(IDD, pParent) { - afxCurrentWinApp; - m_icon = LoadIcon(AfxFindResourceHandle(MAKEINTRESOURCE(IDI_CONFIG), RT_GROUP_ICON), MAKEINTRESOURCE(IDI_CONFIG)); + m_icon = currentConfigApp->LoadIcon(IDI_CONFIG); } // FUNCTION: CONFIG 0x00403e50 +// FUNCTION: CONFIGD 0x00408785 void CMainDialog::DoDataExchange(CDataExchange* pDX) { + CWnd::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CMainDialog, CDialog) @@ -44,53 +47,64 @@ ON_COMMAND(IDC_CHK_MUSIC, OnCheckboxMusic) END_MESSAGE_MAP() // FUNCTION: CONFIG 0x00403e80 +// FUNCTION: CONFIGD 0x004087d9 BOOL CMainDialog::OnInitDialog() { CDialog::OnInitDialog(); SwitchToAdvanced(FALSE); - CMenu* system_menu = CMenu::FromHandle(::GetSystemMenu(m_hWnd, FALSE)); + CMenu* system_menu = CWnd::GetSystemMenu(FALSE); CString about_text; about_text.LoadString(IDS_ABOUT); - if (system_menu) { - AppendMenu(system_menu->m_hMenu, MF_SEPARATOR, 0, NULL); - AppendMenu(system_menu->m_hMenu, MF_STRING, 16, (LPCTSTR) about_text); + if (!about_text.IsEmpty()) { + system_menu->AppendMenu(MF_SEPARATOR, 0, (LPCTSTR) NULL); + system_menu->AppendMenu(MF_STRING, 16, (LPCTSTR) about_text); } - SendMessage(WM_SETICON, ICON_BIG, (LPARAM) m_icon); - SendMessage(WM_SETICON, ICON_SMALL, (LPARAM) m_icon); - LegoDeviceEnumerate* enumerator = currentConfigApp->m_device_enumerator; - enumerator->FUN_1009d210(); + + CWnd::SetIcon(m_icon, TRUE); + CWnd::SetIcon(m_icon, FALSE); + + LegoDeviceEnumerate* info = currentConfigApp->m_dxInfo; + assert(info); + + info->FUN_1009d210(); m_modified = currentConfigApp->ReadRegisterSettings(); - CWnd* list_3d_devices = GetDlgItem(IDC_LIST_3DDEVICES); + CListBox* list_3d_devices = (CListBox*) GetDlgItem(IDC_LIST_3DDEVICES); int driver_i = 0; int device_i = 0; int selected = 0; - char device_name[256]; - const list& driver_list = enumerator->m_ddInfo; - for (list::const_iterator it_driver = driver_list.begin(); it_driver != driver_list.end(); it_driver++) { + + for (list::iterator it_driver = info->m_ddInfo.begin(); it_driver != info->m_ddInfo.end(); + it_driver++, driver_i++) { const MxDriver& driver = *it_driver; + for (list::const_iterator it_device = driver.m_devices.begin(); it_device != driver.m_devices.end(); it_device++) { - const Direct3DDeviceInfo& device = *it_device; - if (&device == currentConfigApp->m_device) { + + if (&(*it_device) == currentConfigApp->m_d3dInfo) { selected = device_i; } + + char device_name[256]; + if (driver_i == 0) { + sprintf(device_name, "%s ( Primary Device )", (*it_device).m_deviceName); + } + else { + sprintf(device_name, "%s ( Secondary Device )", (*it_device).m_deviceName); + } + + list_3d_devices->AddString(device_name); device_i += 1; - sprintf( - device_name, - driver_i == 0 ? "%s ( Primary Device )" : "%s ( Secondary Device )", - device.m_deviceName - ); - ::SendMessage(list_3d_devices->m_hWnd, LB_ADDSTRING, 0, (LPARAM) device_name); } - driver_i += 1; } - ::SendMessage(list_3d_devices->m_hWnd, LB_SETCURSEL, selected, 0); + + list_3d_devices->SetCurSel(selected); UpdateInterface(); return TRUE; } // FUNCTION: CONFIG 0x00404080 +// FUNCTION: CONFIGD 0x00408ab7 void CMainDialog::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xfff0) == 0x10) { @@ -98,86 +112,109 @@ void CMainDialog::OnSysCommand(UINT nID, LPARAM lParam) about_dialog.DoModal(); } else { - Default(); + CWnd::OnSysCommand(nID, lParam); } } // FUNCTION: CONFIG 0x00404150 +// FUNCTION: CONFIGD 0x00408b49 void CMainDialog::OnPaint() { if (IsIconic()) { CPaintDC painter(this); - ::SendMessage(m_hWnd, WM_ICONERASEBKGND, (WPARAM) painter.m_hDC, 0); - RECT dim; + CWnd::SendMessage(WM_ICONERASEBKGND, (WPARAM) painter.GetSafeHdc(), 0); + + int iconWidth = GetSystemMetrics(SM_CXICON); + int iconHeight = GetSystemMetrics(SM_CYICON); + + CRect dim; GetClientRect(&dim); - DrawIcon( - painter.m_hDC, - (dim.right - dim.left - GetSystemMetrics(SM_CXICON) + 1) / 2, - (dim.bottom - dim.top - GetSystemMetrics(SM_CYICON) + 1) / 2, - m_icon - ); + + int x = (dim.Width() - iconWidth + 1) / 2; + int y = (dim.Height() - iconHeight + 1) / 2; + + painter.DrawIcon(x, y, m_icon); } else { - Default(); + CWnd::OnPaint(); } } // FUNCTION: CONFIG 0x00404230 +// FUNCTION: CONFIGD 0x00408c61 HCURSOR CMainDialog::OnQueryDragIcon() { return m_icon; } // FUNCTION: CONFIG 0x00404240 +// FUNCTION: CONFIGD 0x00408c7d void CMainDialog::OnList3DevicesSelectionChanged() { - LegoDeviceEnumerate* device_enumerator = currentConfigApp->m_device_enumerator; - int selected = ::SendMessage(GetDlgItem(IDC_LIST_3DDEVICES)->m_hWnd, LB_GETCURSEL, 0, 0); - device_enumerator->GetDevice(selected, currentConfigApp->m_driver, currentConfigApp->m_device); - if (currentConfigApp->GetHardwareDeviceColorModel()) { - GetDlgItem(IDC_CHK_DRAW_CURSOR)->EnableWindow(TRUE); - } - else { + CConfigApp* app = currentConfigApp; + assert(app); + + LegoDeviceEnumerate* device_enumerator = app->m_dxInfo; + assert(device_enumerator); + + CListBox* listbox = (CListBox*) GetDlgItem(IDC_LIST_3DDEVICES); + int selected = listbox->GetCurSel(); + int r = device_enumerator->GetDevice(selected, app->m_ddInfo, app->m_d3dInfo); + assert(r == 0); + + if (!currentConfigApp->GetHardwareDeviceColorModel()) { currentConfigApp->m_3d_video_ram = FALSE; currentConfigApp->m_flip_surfaces = FALSE; CheckDlgButton(IDC_CHK_3D_VIDEO_MEMORY, currentConfigApp->m_3d_video_ram); CheckDlgButton(IDC_CHK_FLIP_VIDEO_MEM_PAGES, currentConfigApp->m_flip_surfaces); } + else { + GetDlgItem(IDC_CHK_DRAW_CURSOR)->EnableWindow(TRUE); + } + m_modified = TRUE; UpdateInterface(); } // FUNCTION: CONFIG 0x00404320 +// FUNCTION: CONFIGD 0x00408d79 void CMainDialog::OnCancel() { CDialog::OnCancel(); } // FUNCTION: CONFIG 0x00404330 +// FUNCTION: CONFIGD 0x00408de5 void CMainDialog::OnDestroy() { - CDialog::Default(); + CWnd::OnDestroy(); } // FUNCTION: CONFIG 0x00404340 +// FUNCTION: CONFIGD 0x00408e03 void CMainDialog::OnButtonCancel() { if (m_modified) { currentConfigApp->WriteRegisterSettings(); } - OnCancel(); + CDialog::OnCancel(); } // FUNCTION: CONFIG 0x00404360 +// FUNCTION: CONFIGD 0x00408e2f void CMainDialog::UpdateInterface() { currentConfigApp->ValidateSettings(); - GetDlgItem(IDC_CHK_3D_VIDEO_MEMORY) - ->EnableWindow(!currentConfigApp->m_flip_surfaces && !currentConfigApp->GetHardwareDeviceColorModel()); - CheckDlgButton(IDC_CHK_FLIP_VIDEO_MEM_PAGES, currentConfigApp->m_flip_surfaces); + BOOL flip_surfaces = currentConfigApp->m_flip_surfaces; + + BOOL enable3d = !flip_surfaces && !currentConfigApp->GetHardwareDeviceColorModel(); + GetDlgItem(IDC_CHK_3D_VIDEO_MEMORY)->EnableWindow(enable3d); + + CheckDlgButton(IDC_CHK_FLIP_VIDEO_MEM_PAGES, flip_surfaces); CheckDlgButton(IDC_CHK_3D_VIDEO_MEMORY, currentConfigApp->m_3d_video_ram); BOOL full_screen = currentConfigApp->m_full_screen; currentConfigApp->AdjustDisplayBitDepthBasedOnRenderStatus(); + if (currentConfigApp->GetHardwareDeviceColorModel()) { CheckDlgButton(IDC_CHK_DRAW_CURSOR, TRUE); } @@ -186,24 +223,32 @@ void CMainDialog::UpdateInterface() currentConfigApp->m_draw_cursor = FALSE; GetDlgItem(IDC_CHK_DRAW_CURSOR)->EnableWindow(FALSE); } + if (full_screen) { - CheckRadioButton( - IDC_RAD_PALETTE_256, - IDC_RAD_PALETTE_16BIT, - currentConfigApp->m_display_bit_depth == 8 ? IDC_RAD_PALETTE_256 : IDC_RAD_PALETTE_16BIT - ); + if (currentConfigApp->m_display_bit_depth == 8) { + CheckRadioButton(IDC_RAD_PALETTE_256, IDC_RAD_PALETTE_16BIT, IDC_RAD_PALETTE_256); + } + else { + CheckRadioButton(IDC_RAD_PALETTE_256, IDC_RAD_PALETTE_16BIT, IDC_RAD_PALETTE_16BIT); + } } else { CheckDlgButton(IDC_RAD_PALETTE_256, 0); CheckDlgButton(IDC_RAD_PALETTE_16BIT, 0); currentConfigApp->m_display_bit_depth = 0; } - GetDlgItem(IDC_RAD_PALETTE_256) - ->EnableWindow(full_screen && currentConfigApp->GetConditionalDeviceRenderBitDepth()); - GetDlgItem(IDC_RAD_PALETTE_16BIT)->EnableWindow(full_screen && currentConfigApp->GetDeviceRenderBitStatus()); + + BOOL enable256 = full_screen && currentConfigApp->GetConditionalDeviceRenderBitDepth() != 0; + GetDlgItem(IDC_RAD_PALETTE_256)->EnableWindow(enable256); + + BOOL enable16 = full_screen && currentConfigApp->GetDeviceRenderBitStatus() != 0; + GetDlgItem(IDC_RAD_PALETTE_16BIT)->EnableWindow(enable16); + CheckDlgButton(IDC_CHK_3DSOUND, currentConfigApp->m_3d_sound); CheckDlgButton(IDC_CHK_DRAW_CURSOR, currentConfigApp->m_draw_cursor); + switch (currentConfigApp->m_model_quality) { + // DECOMP: case 0 removed for retail. case 1: CheckRadioButton(IDC_RAD_MODEL_QUALITY_LOW, IDC_RAD_MODEL_QUALITY_HIGH, IDC_RAD_MODEL_QUALITY_LOW); break; @@ -211,16 +256,29 @@ void CMainDialog::UpdateInterface() CheckRadioButton(IDC_RAD_MODEL_QUALITY_LOW, IDC_RAD_MODEL_QUALITY_HIGH, IDC_RAD_MODEL_QUALITY_HIGH); break; } - CheckRadioButton( - IDC_RAD_TEXTURE_QUALITY_LOW, - IDC_RAD_TEXTURE_QUALITY_HIGH, - currentConfigApp->m_texture_quality == 0 ? IDC_RAD_TEXTURE_QUALITY_LOW : IDC_RAD_TEXTURE_QUALITY_HIGH - ); + + if (currentConfigApp->m_texture_quality == 0) { + CheckRadioButton(IDC_RAD_TEXTURE_QUALITY_LOW, IDC_RAD_TEXTURE_QUALITY_HIGH, IDC_RAD_TEXTURE_QUALITY_LOW); + } + else { + CheckRadioButton(IDC_RAD_TEXTURE_QUALITY_LOW, IDC_RAD_TEXTURE_QUALITY_HIGH, IDC_RAD_TEXTURE_QUALITY_HIGH); + } + CheckDlgButton(IDC_CHK_JOYSTICK, currentConfigApp->m_use_joystick); CheckDlgButton(IDC_CHK_MUSIC, currentConfigApp->m_music); } +// STUB: CONFIGD 0x00409152 +void CMainDialog::OnCheckboxWideAngle() +{ + // DECOMP: m_wide_angle member removed for retail. + // currentConfigApp->m_wide_angle = IsDlgButtonChecked(IDC_CHK_WIDE_ANGLE); + // m_modified = TRUE; + // UpdateInterface(); +} + // FUNCTION: CONFIG 0x004045e0 +// FUNCTION: CONFIGD 0x00409198 void CMainDialog::OnCheckbox3DSound() { currentConfigApp->m_3d_sound = IsDlgButtonChecked(IDC_CHK_3DSOUND); @@ -229,6 +287,7 @@ void CMainDialog::OnCheckbox3DSound() } // FUNCTION: CONFIG 0x00404610 +// FUNCTION: CONFIGD 0x004091de void CMainDialog::OnCheckbox3DVideoMemory() { currentConfigApp->m_3d_video_ram = IsDlgButtonChecked(IDC_CHK_3D_VIDEO_MEMORY); @@ -237,6 +296,7 @@ void CMainDialog::OnCheckbox3DVideoMemory() } // FUNCTION: CONFIG 0x00404640 +// FUNCTION: CONFIGD 0x00409224 void CMainDialog::OnRadiobuttonPalette16bit() { currentConfigApp->m_display_bit_depth = 16; @@ -245,6 +305,7 @@ void CMainDialog::OnRadiobuttonPalette16bit() } // FUNCTION: CONFIG 0x00404670 +// FUNCTION: CONFIGD 0x00409261 void CMainDialog::OnRadiobuttonPalette256() { currentConfigApp->m_display_bit_depth = 8; @@ -253,6 +314,7 @@ void CMainDialog::OnRadiobuttonPalette256() } // FUNCTION: CONFIG 0x004046a0 +// FUNCTION: CONFIGD 0x0040929e void CMainDialog::OnCheckboxFlipVideoMemPages() { currentConfigApp->m_flip_surfaces = IsDlgButtonChecked(IDC_CHK_FLIP_VIDEO_MEM_PAGES); @@ -260,7 +322,24 @@ void CMainDialog::OnCheckboxFlipVideoMemPages() UpdateInterface(); } +// FUNCTION: CONFIGD 0x004092e4 +void CMainDialog::OnCheckboxFullScreen() +{ + currentConfigApp->m_full_screen = IsDlgButtonChecked(IDC_CHK_FULL_SCREEN); + m_modified = TRUE; + UpdateInterface(); +} + +// FUNCTION: CONFIGD 0x0040932a +void CMainDialog::OnRadiobuttonModelLowestQuality() +{ + currentConfigApp->m_model_quality = 0; + m_modified = TRUE; + UpdateInterface(); +} + // FUNCTION: CONFIG 0x004046d0 +// FUNCTION: CONFIGD 0x00409367 void CMainDialog::OnRadiobuttonModelLowQuality() { currentConfigApp->m_model_quality = 1; @@ -269,6 +348,7 @@ void CMainDialog::OnRadiobuttonModelLowQuality() } // FUNCTION: CONFIG 0x00404700 +// FUNCTION: CONFIGD 0x004093a4 void CMainDialog::OnRadiobuttonModelHighQuality() { currentConfigApp->m_model_quality = 2; @@ -277,6 +357,7 @@ void CMainDialog::OnRadiobuttonModelHighQuality() } // FUNCTION: CONFIG 0x00404730 +// FUNCTION: CONFIGD 0x004093e1 void CMainDialog::OnRadiobuttonTextureLowQuality() { currentConfigApp->m_texture_quality = 0; @@ -285,6 +366,7 @@ void CMainDialog::OnRadiobuttonTextureLowQuality() } // FUNCTION: CONFIG 0x00404760 +// FUNCTION: CONFIGD 0x0040941e void CMainDialog::OnRadiobuttonTextureHighQuality() { currentConfigApp->m_texture_quality = 1; @@ -293,6 +375,7 @@ void CMainDialog::OnRadiobuttonTextureHighQuality() } // FUNCTION: CONFIG 0x00404790 +// FUNCTION: CONFIGD 0x0040945b void CMainDialog::OnCheckboxJoystick() { currentConfigApp->m_use_joystick = IsDlgButtonChecked(IDC_CHK_JOYSTICK); @@ -311,8 +394,8 @@ void CMainDialog::SwitchToAdvanced(BOOL p_advanced) { RECT dialog_rect; RECT grp_advanced_rect; - ::GetWindowRect(m_hWnd, &dialog_rect); - ::GetWindowRect(GetDlgItem(IDC_GRP_ADVANCED)->m_hWnd, &grp_advanced_rect); + CWnd::GetWindowRect(&dialog_rect); + GetDlgItem(IDC_GRP_ADVANCED)->GetWindowRect(&grp_advanced_rect); CWnd* button_advanced = GetDlgItem(IDC_BTN_ADVANCED); m_advanced = p_advanced; int height; diff --git a/CONFIG/MainDlg.h b/CONFIG/MainDlg.h index eeebc868..b89299e3 100644 --- a/CONFIG/MainDlg.h +++ b/CONFIG/MainDlg.h @@ -7,6 +7,7 @@ #include "res/resource.h" // VTABLE: CONFIG 0x004063e0 +// VTABLE: CONFIGD 0x0040c500 // SIZE 0x70 class CMainDialog : public CDialog { public: @@ -35,11 +36,14 @@ class CMainDialog : public CDialog { void OnCancel(); void OnDestroy(); void OnButtonCancel(); + void OnCheckboxWideAngle(); void OnCheckbox3DSound(); void OnCheckbox3DVideoMemory(); void OnRadiobuttonPalette16bit(); void OnRadiobuttonPalette256(); void OnCheckboxFlipVideoMemPages(); + void OnCheckboxFullScreen(); + void OnRadiobuttonModelLowestQuality(); void OnRadiobuttonModelLowQuality(); void OnRadiobuttonModelHighQuality(); void OnRadiobuttonTextureLowQuality(); @@ -52,19 +56,28 @@ class CMainDialog : public CDialog { DECLARE_MESSAGE_MAP() }; +// SYNTHETIC: CONFIG 0x00403160 +// SYNTHETIC: CONFIGD 0x00408490 +// CMainDialog::~CMainDialog + // SYNTHETIC: CONFIG 0x00403de0 +// SYNTHETIC: CONFIGD 0x00409910 // CMainDialog::`scalar deleting destructor' // FUNCTION: CONFIG 0x00403e60 +// FUNCTION: CONFIGD 0x004087a9 // CMainDialog::_GetBaseMessageMap // FUNCTION: CONFIG 0x00403e70 +// FUNCTION: CONFIGD 0x004087be // CMainDialog::GetMessageMap // GLOBAL: CONFIG 0x00406120 +// GLOBAL: CONFIGD 0x0040c1a8 // CMainDialog::messageMap // GLOBAL: CONFIG 0x00406128 +// GLOBAL: CONFIGD 0x0040c1b0 // CMainDialog::_messageEntries #endif // !defined(AFX_MAINDLG_H) diff --git a/CONFIG/config.cpp b/CONFIG/config.cpp index c42469ee..9eac2dcb 100644 --- a/CONFIG/config.cpp +++ b/CONFIG/config.cpp @@ -55,14 +55,14 @@ BOOL CConfigApp::InitInstance() m_run_config_dialog = TRUE; } - m_device_enumerator = new LegoDeviceEnumerate; - if (m_device_enumerator->DoEnumerate()) { + m_dxInfo = new LegoDeviceEnumerate; + if (m_dxInfo->DoEnumerate()) { assert("Could not build device list." == NULL); return FALSE; } - m_driver = NULL; - m_device = NULL; + m_ddInfo = NULL; + m_d3dInfo = NULL; m_full_screen = TRUE; m_wide_view_angle = TRUE; m_use_joystick = FALSE; @@ -99,10 +99,10 @@ BOOL CConfigApp::InitInstance() ReadRegisterSettings(); ValidateSettings(); WriteRegisterSettings(); - delete m_device_enumerator; - m_device_enumerator = NULL; - m_driver = NULL; - m_device = NULL; + delete m_dxInfo; + m_dxInfo = NULL; + m_ddInfo = NULL; + m_d3dInfo = NULL; char password[256]; BOOL read = ReadReg("password", password, sizeof(password)); const char* exe = _stricmp("ogel", password) == 0 ? "isled.exe" : "isle.exe"; @@ -226,26 +226,26 @@ BOOL CConfigApp::IsDeviceInBasicRGBMode() const { /* * BUG: should be: - * return !GetHardwareDeviceColorModel() && (m_device->m_HELDesc.dcmColorModel & D3DCOLOR_RGB); + * return !GetHardwareDeviceColorModel() && (m_d3dInfo->m_HELDesc.dcmColorModel & D3DCOLOR_RGB); */ - assert(m_device); - return !GetHardwareDeviceColorModel() && m_device->m_HELDesc.dcmColorModel == D3DCOLOR_RGB; + assert(m_d3dInfo); + return !GetHardwareDeviceColorModel() && m_d3dInfo->m_HELDesc.dcmColorModel == D3DCOLOR_RGB; } // FUNCTION: CONFIG 0x00403400 // FUNCTION: CONFIGD 0x004070fa D3DCOLORMODEL CConfigApp::GetHardwareDeviceColorModel() const { - assert(m_device); - return m_device->m_HWDesc.dcmColorModel; + assert(m_d3dInfo); + return m_d3dInfo->m_HWDesc.dcmColorModel; } // FUNCTION: CONFIG 0x00403410 // FUNCTION: CONFIGD 0x0040714e BOOL CConfigApp::IsPrimaryDriver() const { - assert(m_driver && m_device_enumerator); - return m_driver == &m_device_enumerator->m_ddInfo.front(); + assert(m_ddInfo && m_dxInfo); + return m_ddInfo == &m_dxInfo->m_ddInfo.front(); } // FUNCTION: CONFIG 0x00403430 @@ -259,9 +259,9 @@ BOOL CConfigApp::ReadRegisterSettings() int r = -1; if (read) { - r = m_device_enumerator->ParseDeviceName(buffer); + r = m_dxInfo->ParseDeviceName(buffer); if (r >= 0) { - r = m_device_enumerator->GetDevice(r, m_driver, m_device); + r = m_dxInfo->GetDevice(r, m_ddInfo, m_d3dInfo); if (r) { r = -1; } @@ -269,14 +269,14 @@ BOOL CConfigApp::ReadRegisterSettings() } if (r < 0) { - m_device_enumerator->FUN_1009d210(); - r = m_device_enumerator->GetBestDevice(); + m_dxInfo->FUN_1009d210(); + r = m_dxInfo->GetBestDevice(); is_modified = TRUE; assert(r >= 0); - r = m_device_enumerator->GetDevice(r, m_driver, m_device); + r = m_dxInfo->GetDevice(r, m_ddInfo, m_d3dInfo); } - assert(r == 0 && m_driver && m_device); + assert(r == 0 && m_ddInfo && m_d3dInfo); if (!ReadRegInt("Display Bit Depth", &m_display_bit_depth)) { is_modified = TRUE; @@ -384,26 +384,26 @@ BOOL CConfigApp::ValidateSettings() // FUNCTION: CONFIGD 0x00407793 DWORD CConfigApp::GetConditionalDeviceRenderBitDepth() const { - assert(m_device); + assert(m_d3dInfo); if (IsDeviceInBasicRGBMode()) { return 0; } if (GetHardwareDeviceColorModel()) { return 0; } - return m_device->m_HELDesc.dwDeviceRenderBitDepth & DDBD_8; + return m_d3dInfo->m_HELDesc.dwDeviceRenderBitDepth & DDBD_8; } // FUNCTION: CONFIG 0x004037e0 // FUNCTION: CONFIGD 0x00407822 DWORD CConfigApp::GetDeviceRenderBitStatus() const { - assert(m_device); + assert(m_d3dInfo); if (GetHardwareDeviceColorModel()) { - return m_device->m_HWDesc.dwDeviceRenderBitDepth & DDBD_16; + return m_d3dInfo->m_HWDesc.dwDeviceRenderBitDepth & DDBD_16; } else { - return m_device->m_HELDesc.dwDeviceRenderBitDepth & DDBD_16; + return m_d3dInfo->m_HELDesc.dwDeviceRenderBitDepth & DDBD_16; } } @@ -447,10 +447,10 @@ void CConfigApp::WriteRegisterSettings() const WriteReg(NAME, buffer); \ } while (0) - assert(m_device_enumerator && m_driver && m_device); - m_device_enumerator->FormatDeviceName(buffer, m_driver, m_device); + assert(m_dxInfo && m_ddInfo && m_d3dInfo); + m_dxInfo->FormatDeviceName(buffer, m_ddInfo, m_d3dInfo); WriteReg("3D Device ID", buffer); - WriteReg("3D Device Name", m_device->m_deviceName); + WriteReg("3D Device Name", m_d3dInfo->m_deviceName); WriteRegInt("Display Bit Depth", m_display_bit_depth); WriteRegBool("Flip Surfaces", m_flip_surfaces); WriteRegBool("Full Screen", m_full_screen); @@ -472,9 +472,9 @@ void CConfigApp::WriteRegisterSettings() const // FUNCTION: CONFIGD 0x00407c44 int CConfigApp::ExitInstance() { - if (m_device_enumerator) { - delete m_device_enumerator; - m_device_enumerator = NULL; + if (m_dxInfo) { + delete m_dxInfo; + m_dxInfo = NULL; } return CWinApp::ExitInstance(); } diff --git a/CONFIG/config.h b/CONFIG/config.h index 02366100..1c8a94a4 100644 --- a/CONFIG/config.h +++ b/CONFIG/config.h @@ -11,7 +11,7 @@ class LegoDeviceEnumerate; struct Direct3DDeviceInfo; struct MxDriver; -#define currentConfigApp ((CConfigApp*) afxCurrentWinApp) +#define currentConfigApp ((CConfigApp*) AfxGetApp()) // VTABLE: CONFIG 0x00406040 // VTABLE: CONFIGD 0x0040c0a0 @@ -55,23 +55,23 @@ class CConfigApp : public CWinApp { BOOL IsLegoNotRunning(); public: - LegoDeviceEnumerate* m_device_enumerator; // 0x0c4 - MxDriver* m_driver; // 0x0c8 - Direct3DDeviceInfo* m_device; // 0x0cc - int m_display_bit_depth; // 0x0d0 - BOOL m_flip_surfaces; // 0x0d4 - BOOL m_full_screen; // 0x0d8 - BOOL m_3d_video_ram; // 0x0dc - BOOL m_wide_view_angle; // 0x0e0 - BOOL m_3d_sound; // 0x0e4 - BOOL m_draw_cursor; // 0x0e8 - BOOL m_use_joystick; // 0x0ec - int m_joystick_index; // 0x0f0 - BOOL m_run_config_dialog; // 0x0f4 - int m_model_quality; // 0x0f8 - int m_texture_quality; // 0x0fc - undefined m_unk0x100[4]; // 0x100 - BOOL m_music; // 0x104 + LegoDeviceEnumerate* m_dxInfo; // 0x0c4 + MxDriver* m_ddInfo; // 0x0c8 + Direct3DDeviceInfo* m_d3dInfo; // 0x0cc + int m_display_bit_depth; // 0x0d0 + BOOL m_flip_surfaces; // 0x0d4 + BOOL m_full_screen; // 0x0d8 + BOOL m_3d_video_ram; // 0x0dc + BOOL m_wide_view_angle; // 0x0e0 + BOOL m_3d_sound; // 0x0e4 + BOOL m_draw_cursor; // 0x0e8 + BOOL m_use_joystick; // 0x0ec + int m_joystick_index; // 0x0f0 + BOOL m_run_config_dialog; // 0x0f4 + int m_model_quality; // 0x0f8 + int m_texture_quality; // 0x0fc + undefined m_unk0x100[4]; // 0x100 + BOOL m_music; // 0x104 }; // SYNTHETIC: CONFIG 0x00402cd0 diff --git a/CONFIG/detectdx5.cpp b/CONFIG/detectdx5.cpp index 8a308a8d..4e27fbee 100644 --- a/CONFIG/detectdx5.cpp +++ b/CONFIG/detectdx5.cpp @@ -3,140 +3,255 @@ #include #include -typedef HRESULT WINAPI DirectDrawCreate_fn(GUID FAR* lpGUID, LPDIRECTDRAW FAR* lplpDD, IUnknown FAR* pUnkOuter); -typedef HRESULT WINAPI -DirectInputCreateA_fn(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA* ppDI, LPUNKNOWN punkOuter); +typedef HRESULT(WINAPI* DIRECTDRAWCREATE)(GUID*, LPDIRECTDRAW*, IUnknown*); +typedef HRESULT(WINAPI* DIRECTINPUTCREATE)(HINSTANCE, DWORD, LPDIRECTINPUT*, IUnknown*); // FUNCTION: CONFIG 0x004048f0 BOOL DetectDirectX5() { - unsigned int version; - BOOL found; - DetectDirectX(&version, &found); + DWORD version; + DWORD platform; + GetDXVersion(&version, &platform); return version >= 0x500; } // FUNCTION: CONFIG 0x00404920 -void DetectDirectX(unsigned int* p_version, BOOL* p_found) +void GetDXVersion(LPDWORD pdwDXVersion, LPDWORD pdwDXPlatform) { - OSVERSIONINFOA os_version; + // From GetDXVer.cpp + HRESULT hr; + HINSTANCE DDHinst = 0; + HINSTANCE DIHinst = 0; + LPDIRECTDRAW pDDraw = 0; + LPDIRECTDRAW2 pDDraw2 = 0; + DIRECTDRAWCREATE DirectDrawCreate = 0; + DIRECTINPUTCREATE DirectInputCreate = 0; + OSVERSIONINFO osVer; + LPDIRECTDRAWSURFACE pSurf = 0; + LPDIRECTDRAWSURFACE3 pSurf3 = 0; - os_version.dwOSVersionInfoSize = sizeof(os_version); - if (!GetVersionEx(&os_version)) { - *p_version = 0; - *p_found = 0; + /* + * First get the windows platform + */ + osVer.dwOSVersionInfoSize = sizeof(osVer); + if (!GetVersionEx(&osVer)) { + *pdwDXVersion = 0; + *pdwDXPlatform = 0; return; } - if (os_version.dwPlatformId == 2) { - *p_found = 2; - if (os_version.dwMajorVersion < 4) { - *p_found = 0; + + if (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT) { + *pdwDXPlatform = VER_PLATFORM_WIN32_NT; + /* + * NT is easy... NT 4.0 is DX2, 4.0 SP3 is DX3, 5.0 is DX5 + * and no DX on earlier versions. + */ + if (osVer.dwMajorVersion < 4) { + *pdwDXPlatform = 0; // No DX on NT3.51 or earlier return; } - if (os_version.dwMajorVersion != 4) { - *p_version = 0x501; + if (osVer.dwMajorVersion == 4) { + /* + * NT4 up to SP2 is DX2, and SP3 onwards is DX3, so we are at least DX2 + */ + *pdwDXVersion = 0x200; + + /* + * We're not supposed to be able to tell which SP we're on, so check for dinput + */ + DIHinst = LoadLibrary("DINPUT.DLL"); + if (DIHinst == 0) { + /* + * No DInput... must be DX2 on NT 4 pre-SP3 + */ + OutputDebugString("Couldn't LoadLibrary DInput\r\n"); + return; + } + + DirectInputCreate = (DIRECTINPUTCREATE) GetProcAddress(DIHinst, "DirectInputCreateA"); + FreeLibrary(DIHinst); + + if (DirectInputCreate == 0) { + /* + * No DInput... must be pre-SP3 DX2 + */ + OutputDebugString("Couldn't GetProcAddress DInputCreate\r\n"); + return; + } + + /* + * It must be NT4, DX2 + */ + *pdwDXVersion = 0x300; // DX3 on NT4 SP3 or higher return; } - *p_version = 0x200; - HMODULE dinput_module = LoadLibrary("DINPUT.DLL"); - if (!dinput_module) { - OutputDebugString("Couldn't LoadLibrary DInput\r\n"); - return; - } - DirectInputCreateA_fn* func_DirectInputCreateA = - (DirectInputCreateA_fn*) GetProcAddress(dinput_module, "DirectInputCreateA"); - FreeLibrary(dinput_module); - if (!func_DirectInputCreateA) { - OutputDebugString("Couldn't GetProcAddress DInputCreate\r\n"); - return; - } - *p_version = 0x300; + /* + * Else it's NT5 or higher, and it's DX5a or higher: + */ + *pdwDXVersion = 0x501; // DX5a on NT5 return; } - *p_found = 1; - if (LOWORD(os_version.dwBuildNumber) >= 0x550) { - *p_version = 0x501; + + /* + * Not NT... must be Win9x + */ + *pdwDXPlatform = VER_PLATFORM_WIN32_WINDOWS; + + /* + * If we are on Memphis or higher, then we are at least DX5a + */ + if ((osVer.dwBuildNumber & 0xffff) > 1353) // Check for higher than developer release + { + *pdwDXVersion = 0x501; // DX5a on Memphis or higher return; } - HMODULE ddraw_module = LoadLibrary("DDRAW.DLL"); - if (!ddraw_module) { - *p_version = 0; - *p_found = 0; - FreeLibrary(ddraw_module); + + /* + * Now we know we are in Windows 9x (or maybe 3.1), so anything's possible. + * First see if DDRAW.DLL even exists. + */ + DDHinst = LoadLibrary("DDRAW.DLL"); + if (DDHinst == 0) { + *pdwDXVersion = 0; + *pdwDXPlatform = 0; + FreeLibrary(DDHinst); return; } - DirectDrawCreate_fn* func_DirectDrawCreate = - (DirectDrawCreate_fn*) GetProcAddress(ddraw_module, "DirectDrawCreate"); - if (!func_DirectDrawCreate) { - *p_version = 0; - *p_found = 0; - FreeLibrary(ddraw_module); + + /* + * See if we can create the DirectDraw object. + */ + DirectDrawCreate = (DIRECTDRAWCREATE) GetProcAddress(DDHinst, "DirectDrawCreate"); + if (DirectDrawCreate == 0) { + *pdwDXVersion = 0; + *pdwDXPlatform = 0; + FreeLibrary(DDHinst); OutputDebugString("Couldn't LoadLibrary DDraw\r\n"); return; } - LPDIRECTDRAW ddraw; - if (FAILED(func_DirectDrawCreate(NULL, &ddraw, NULL))) { - *p_version = 0; - *p_found = 0; - FreeLibrary(ddraw_module); + + hr = DirectDrawCreate(NULL, &pDDraw, NULL); + if (FAILED(hr)) { + *pdwDXVersion = 0; + *pdwDXPlatform = 0; + FreeLibrary(DDHinst); OutputDebugString("Couldn't create DDraw\r\n"); return; } - *p_version = 0x100; - LPDIRECTDRAW2 ddraw2; - if (FAILED(ddraw->QueryInterface(IID_IDirectDraw2, (LPVOID*) &ddraw2))) { - ddraw->Release(); - FreeLibrary(ddraw_module); + + /* + * So DirectDraw exists. We are at least DX1. + */ + *pdwDXVersion = 0x100; + + /* + * Let's see if IID_IDirectDraw2 exists. + */ + hr = pDDraw->QueryInterface(IID_IDirectDraw2, (LPVOID*) &pDDraw2); + if (FAILED(hr)) { + /* + * No IDirectDraw2 exists... must be DX1 + */ + pDDraw->Release(); + FreeLibrary(DDHinst); OutputDebugString("Couldn't QI DDraw2\r\n"); return; } - ddraw->Release(); - *p_version = 0x200; - HMODULE dinput_module = LoadLibrary("DINPUT.DLL"); - if (!dinput_module) { + /* + * IDirectDraw2 exists. We must be at least DX2 + */ + pDDraw2->Release(); + *pdwDXVersion = 0x200; + + /* + * See if we can create the DirectInput object. + */ + DIHinst = LoadLibrary("DINPUT.DLL"); + if (DIHinst == 0) { + /* + * No DInput... must be DX2 + */ OutputDebugString("Couldn't LoadLibrary DInput\r\n"); - ddraw2->Release(); - FreeLibrary(ddraw_module); + pDDraw->Release(); + FreeLibrary(DDHinst); return; } - DirectInputCreateA_fn* func_DirectInputCreateA = - (DirectInputCreateA_fn*) GetProcAddress(dinput_module, "DirectInputCreateA"); - FreeLibrary(dinput_module); - if (!func_DirectInputCreateA) { - FreeLibrary(ddraw_module); - ddraw2->Release(); + + DirectInputCreate = (DIRECTINPUTCREATE) GetProcAddress(DIHinst, "DirectInputCreateA"); + FreeLibrary(DIHinst); + + if (DirectInputCreate == 0) { + /* + * No DInput... must be DX2 + */ + FreeLibrary(DDHinst); + pDDraw->Release(); OutputDebugString("Couldn't GetProcAddress DInputCreate\r\n"); return; } - *p_version = 0x300; - DDSURFACEDESC surface_desc; - memset(&surface_desc, 0, sizeof(surface_desc)); - surface_desc.dwSize = sizeof(surface_desc); - surface_desc.dwFlags = DDSD_CAPS; - surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - if (FAILED(ddraw2->SetCooperativeLevel(NULL, DDSCL_NORMAL))) { - ddraw2->Release(); - FreeLibrary(ddraw_module); - *p_version = 0; + + /* + * DirectInputCreate exists. That's enough to tell us that we are at least DX3 + */ + *pdwDXVersion = 0x300; + + /* + * Checks for 3a vs 3b? + */ + + /* + * We can tell if DX5 is present by checking for the existence of IDirectDrawSurface3. + * First we need a surface to QI off of. + */ + DDSURFACEDESC desc; + + ZeroMemory(&desc, sizeof(desc)); + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_CAPS; + desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + hr = pDDraw->SetCooperativeLevel(NULL, DDSCL_NORMAL); + if (FAILED(hr)) { + /* + * Failure. This means DDraw isn't properly installed. + */ + pDDraw->Release(); + FreeLibrary(DDHinst); + *pdwDXVersion = 0; OutputDebugString("Couldn't Set coop level\r\n"); return; } - LPDIRECTDRAWSURFACE surface; - if (FAILED(ddraw2->CreateSurface(&surface_desc, &surface, NULL))) { - ddraw2->Release(); - FreeLibrary(ddraw_module); - *p_version = 0; + + hr = pDDraw->CreateSurface(&desc, &pSurf, NULL); + if (FAILED(hr)) { + /* + * Failure. This means DDraw isn't properly installed. + */ + pDDraw->Release(); + FreeLibrary(DDHinst); + *pdwDXVersion = 0; OutputDebugString("Couldn't CreateSurface\r\n"); return; } - LPDIRECTDRAWSURFACE3 surface3; - if (FAILED(surface->QueryInterface(IID_IDirectDrawSurface3, (LPVOID*) &surface3))) { - ddraw2->Release(); - FreeLibrary(ddraw_module); + + /* + * Try for the IDirectDrawSurface3 interface. If it works, we're on DX5 at least + */ + if (FAILED(pSurf->QueryInterface(IID_IDirectDrawSurface3, (LPVOID*) &pSurf3))) { + pDDraw->Release(); + FreeLibrary(DDHinst); + return; } - *p_version = 0x500; - surface3->Release(); - ddraw2->Release(); - FreeLibrary(ddraw_module); + + /* + * QI for IDirectDrawSurface3 succeeded. We must be at least DX5 + */ + *pdwDXVersion = 0x500; + + pSurf->Release(); + pDDraw->Release(); + FreeLibrary(DDHinst); + + return; } diff --git a/CONFIG/detectdx5.h b/CONFIG/detectdx5.h index 6f45837c..ddb56f60 100644 --- a/CONFIG/detectdx5.h +++ b/CONFIG/detectdx5.h @@ -5,6 +5,6 @@ extern BOOL DetectDirectX5(); -extern void DetectDirectX(unsigned int* p_version, BOOL* p_found); +extern void GetDXVersion(LPDWORD pdwDXVersion, LPDWORD pdwDXPlatform); #endif // !defined(AFX_DETECTDX5_H) diff --git a/CONFIG/res/resource.h b/CONFIG/res/resource.h index 4c72eaa1..bf3dfe74 100644 --- a/CONFIG/res/resource.h +++ b/CONFIG/res/resource.h @@ -7,10 +7,12 @@ #define IDC_LIST_3DDEVICES 1000 #define IDC_CHK_FLIP_VIDEO_MEM_PAGES 1001 +#define IDC_CHK_FULL_SCREEN 1002 // beta only #define IDC_CHK_3D_VIDEO_MEMORY 1003 #define IDC_RAD_PALETTE_256 1004 #define IDC_RAD_PALETTE_16BIT 1005 #define IDC_CHK_3DSOUND 1006 +#define IDC_CHK_WIDE_ANGLE 1007 // beta only #define IDC_CHK_DRAW_CURSOR 1008 #define IDC_RAD_MODEL_QUALITY_LOW 1010 #define IDC_RAD_MODEL_QUALITY_HIGH 1011 From 8a82ebeb7e1642bfcfb0d05bba0d266d0508453b Mon Sep 17 00:00:00 2001 From: Joshua Peisach Date: Tue, 15 Jul 2025 13:16:25 -0400 Subject: [PATCH 14/25] Fix typo in SetSkyColor (#1628) --- LEGO1/lego/legoomni/src/video/legovideomanager.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp index 2039d381..c9c79097 100644 --- a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp +++ b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp @@ -634,13 +634,13 @@ void LegoVideoManager::EnableFullScreenMovie(MxBool p_enable, MxBool p_scale) // FUNCTION: LEGO1 0x1007c440 void LegoVideoManager::SetSkyColor(float p_red, float p_green, float p_blue) { - PALETTEENTRY colorStrucure; + PALETTEENTRY colorStructure; - colorStrucure.peRed = (p_red * 255.0f); - colorStrucure.peGreen = (p_green * 255.0f); - colorStrucure.peBlue = (p_blue * 255.0f); - colorStrucure.peFlags = D3DPAL_RESERVED | PC_NOCOLLAPSE; - m_videoParam.GetPalette()->SetSkyColor(&colorStrucure); + colorStructure.peRed = (p_red * 255.0f); + colorStructure.peGreen = (p_green * 255.0f); + colorStructure.peBlue = (p_blue * 255.0f); + colorStructure.peFlags = D3DPAL_RESERVED | PC_NOCOLLAPSE; + m_videoParam.GetPalette()->SetSkyColor(&colorStructure); m_videoParam.GetPalette()->SetOverrideSkyColor(TRUE); m_3dManager->GetLego3DView()->GetView()->SetBackgroundColor(p_red, p_green, p_blue); } From 05360b4468c1d840a83dae198544842c25f59b75 Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Tue, 15 Jul 2025 20:39:22 +0200 Subject: [PATCH 15/25] Clear unknowns in `TowTrack` and `TowTrackMissionState` (#1629) --- LEGO1/lego/legoomni/include/towtrack.h | 41 +++++++------ LEGO1/lego/legoomni/src/actors/towtrack.cpp | 65 +++++++++++---------- LEGO1/lego/legoomni/src/worlds/isle.cpp | 6 +- 3 files changed, 60 insertions(+), 52 deletions(-) diff --git a/LEGO1/lego/legoomni/include/towtrack.h b/LEGO1/lego/legoomni/include/towtrack.h index 812751bf..e9e41418 100644 --- a/LEGO1/lego/legoomni/include/towtrack.h +++ b/LEGO1/lego/legoomni/include/towtrack.h @@ -12,6 +12,13 @@ class MxEndActionNotificationParam; // SIZE 0x28 class TowTrackMissionState : public LegoState { public: + enum { + e_none = 0, + e_started = 1, + e_hookedUp = 2, + e_hookingUp = 3, + }; + TowTrackMissionState(); // FUNCTION: LEGO1 0x1004dde0 @@ -126,19 +133,19 @@ class TowTrackMissionState : public LegoState { // SYNTHETIC: LEGO1 0x1004e060 // TowTrackMissionState::`scalar deleting destructor' - undefined4 m_unk0x08; // 0x08 - MxLong m_startTime; // 0x0c - MxBool m_unk0x10; // 0x10 - MxS16 m_peScore; // 0x12 - MxS16 m_maScore; // 0x14 - MxS16 m_paScore; // 0x16 - MxS16 m_niScore; // 0x18 - MxS16 m_laScore; // 0x1a - MxS16 m_peHighScore; // 0x1c - MxS16 m_maHighScore; // 0x1e - MxS16 m_paHighScore; // 0x20 - MxS16 m_niHighScore; // 0x22 - MxS16 m_laHighScore; // 0x24 + MxU32 m_state; // 0x08 + MxLong m_startTime; // 0x0c + MxBool m_takingTooLong; // 0x10 + MxS16 m_peScore; // 0x12 + MxS16 m_maScore; // 0x14 + MxS16 m_paScore; // 0x16 + MxS16 m_niScore; // 0x18 + MxS16 m_laScore; // 0x1a + MxS16 m_peHighScore; // 0x1c + MxS16 m_maHighScore; // 0x1e + MxS16 m_paHighScore; // 0x20 + MxS16 m_niHighScore; // 0x22 + MxS16 m_laHighScore; // 0x24 }; // VTABLE: LEGO1 0x100d7ee0 @@ -174,10 +181,10 @@ class TowTrack : public IslePathActor { virtual MxLong HandleEndAction(MxEndActionNotificationParam& p_param); // vtable+0xf0 void CreateState(); - void FUN_1004dab0(); + void Init(); void ActivateSceneActions(); void StopActions(); - void FUN_1004dbe0(); + void Reset(); // SYNTHETIC: LEGO1 0x1004c950 // TowTrack::`scalar deleting destructor' @@ -192,8 +199,8 @@ class TowTrack : public IslePathActor { TowTrackMissionState* m_state; // 0x164 MxS16 m_unk0x168; // 0x168 MxS16 m_actorId; // 0x16a - MxS16 m_unk0x16c; // 0x16c - MxS16 m_unk0x16e; // 0x16e + MxS16 m_treeBlockageTriggered; // 0x16c + MxS16 m_speedComplaintTriggered; // 0x16e IsleScript::Script m_lastAction; // 0x170 IsleScript::Script m_lastAnimation; // 0x174 MxFloat m_fuel; // 0x178 diff --git a/LEGO1/lego/legoomni/src/actors/towtrack.cpp b/LEGO1/lego/legoomni/src/actors/towtrack.cpp index 5d62fedc..6c3f5785 100644 --- a/LEGO1/lego/legoomni/src/actors/towtrack.cpp +++ b/LEGO1/lego/legoomni/src/actors/towtrack.cpp @@ -32,9 +32,9 @@ TowTrack::TowTrack() m_unk0x168 = 0; m_actorId = -1; m_state = NULL; - m_unk0x16c = 0; + m_treeBlockageTriggered = 0; m_lastAction = IsleScript::c_noneIsle; - m_unk0x16e = 0; + m_speedComplaintTriggered = 0; m_lastAnimation = IsleScript::c_noneIsle; m_maxLinearVel = 40.0; m_fuel = 1.0; @@ -62,7 +62,7 @@ MxResult TowTrack::Create(MxDSAction& p_dsAction) m_state = (TowTrackMissionState*) GameState()->GetState("TowTrackMissionState"); if (!m_state) { m_state = new TowTrackMissionState(); - m_state->m_unk0x08 = 0; + m_state->m_state = TowTrackMissionState::e_none; GameState()->RegisterState(m_state); } } @@ -96,9 +96,10 @@ void TowTrack::Animate(float p_time) sprintf(buf, "%g", m_fuel); VariableTable()->SetVariable(g_varTOWFUEL, buf); - if (p_time - m_state->m_startTime > 100000.0f && m_state->m_unk0x08 == 1 && !m_state->m_unk0x10) { + if (p_time - m_state->m_startTime > 100000.0f && m_state->m_state == TowTrackMissionState::e_started && + !m_state->m_takingTooLong) { PlayAction(IsleScript::c_Avo909In_PlayWav); - m_state->m_unk0x10 = TRUE; + m_state->m_takingTooLong = TRUE; } } } @@ -188,7 +189,7 @@ MxLong TowTrack::HandleEndAction(MxEndActionNotificationParam& p_param) } } else if (objectId == IsleScript::c_wrt074sl_RunAnim || objectId == IsleScript::c_wrt075rh_RunAnim || objectId == IsleScript::c_wrt076df_RunAnim || objectId == IsleScript::c_wrt078ni_RunAnim) { - m_state->m_unk0x08 = 2; + m_state->m_state = TowTrackMissionState::e_hookedUp; CurrentWorld()->PlaceActor(UserActor()); HandleClick(); } @@ -297,10 +298,10 @@ MxLong TowTrack::HandlePathStruct(LegoPathStructNotificationParam& p_param) return 0; } - if (m_state->m_unk0x08 == 2 && + if (m_state->m_state == TowTrackMissionState::e_hookedUp && ((p_param.GetTrigger() == LegoPathStruct::c_camAnim && (p_param.GetData() == 9 || p_param.GetData() == 8)) || (p_param.GetTrigger() == LegoPathStruct::c_w && p_param.GetData() == 0x169))) { - m_state->m_unk0x08 = 0; + m_state->m_state = TowTrackMissionState::e_none; MxLong time = Timer()->GetTime() - m_state->m_startTime; Leave(); @@ -315,8 +316,8 @@ MxLong TowTrack::HandlePathStruct(LegoPathStructNotificationParam& p_param) PlayFinalAnimation(IsleScript::c_wgs097nu_RunAnim); } } - else if (m_state->m_unk0x08 == 1 && p_param.GetTrigger() == LegoPathStruct::c_camAnim && p_param.GetData() == 0x37) { - m_state->m_unk0x08 = 3; + else if (m_state->m_state == TowTrackMissionState::e_started && p_param.GetTrigger() == LegoPathStruct::c_camAnim && p_param.GetData() == 0x37) { + m_state->m_state = TowTrackMissionState::e_hookingUp; StopActions(); if (m_lastAction != IsleScript::c_noneIsle) { @@ -326,20 +327,20 @@ MxLong TowTrack::HandlePathStruct(LegoPathStructNotificationParam& p_param) Leave(); PlayFinalAnimation(IsleScript::c_wrt060bm_RunAnim); } - else if (p_param.GetTrigger() == LegoPathStruct::c_w && m_state->m_unk0x08 == 1) { + else if (p_param.GetTrigger() == LegoPathStruct::c_w && m_state->m_state == TowTrackMissionState::e_started) { if (p_param.GetData() == 0x15f) { - if (m_unk0x16c == 0) { - m_unk0x16c = 1; + if (m_treeBlockageTriggered == 0) { + m_treeBlockageTriggered = 1; InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_wns050p1_RunAnim, NULL); } } else if (p_param.GetData() == 0x160) { - if (m_unk0x16e == 0) { - m_unk0x16e = 1; + if (m_speedComplaintTriggered == 0) { + m_speedComplaintTriggered = 1; InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_wns046mg_RunAnim, NULL); } - if (!m_state->m_unk0x10 && m_lastAction == IsleScript::c_noneIsle) { + if (!m_state->m_takingTooLong && m_lastAction == IsleScript::c_noneIsle) { if (m_actorId < LegoActor::c_pepper || m_actorId > LegoActor::c_laura) { m_actorId = LegoActor::c_laura; } @@ -407,7 +408,7 @@ MxLong TowTrack::HandleClick() return 1; } - if (m_state->m_unk0x08 == 3) { + if (m_state->m_state == TowTrackMissionState::e_hookingUp) { return 1; } @@ -426,11 +427,11 @@ MxLong TowTrack::HandleClick() InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_TowTrackDashboard, NULL); ControlManager()->Register(this); - if (m_state->m_unk0x08 == 0) { + if (m_state->m_state == TowTrackMissionState::e_none) { return 1; } - if (m_state->m_unk0x08 == 2) { + if (m_state->m_state == TowTrackMissionState::e_hookedUp) { SpawnPlayer(LegoGameState::e_unk52, TRUE, 0); FindROI("rcred")->SetVisibility(FALSE); } @@ -439,7 +440,7 @@ MxLong TowTrack::HandleClick() m_lastAction = IsleScript::c_noneIsle; m_lastAnimation = IsleScript::c_noneIsle; m_state->m_startTime = Timer()->GetTime(); - m_state->m_unk0x10 = FALSE; + m_state->m_takingTooLong = FALSE; InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_wns057rd_RunAnim, NULL); InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_wns048p1_RunAnim, NULL); InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_wns049p1_RunAnim, NULL); @@ -457,7 +458,7 @@ void TowTrack::Exit() { GameState()->m_currentArea = LegoGameState::e_garageExterior; StopActions(); - FUN_1004dbe0(); + Reset(); Leave(); } @@ -507,9 +508,9 @@ MxLong TowTrack::HandleControl(LegoControlManagerNotificationParam& p_param) } // FUNCTION: LEGO1 0x1004dab0 -void TowTrack::FUN_1004dab0() +void TowTrack::Init() { - m_state->m_unk0x08 = 1; + m_state->m_state = TowTrackMissionState::e_started; HandleClick(); } @@ -518,8 +519,8 @@ void TowTrack::ActivateSceneActions() { PlayMusic(JukeboxScript::c_JBMusic2); - if (m_state->m_unk0x08 != 0) { - if (m_state->m_unk0x08 == 2) { + if (m_state->m_state != TowTrackMissionState::e_none) { + if (m_state->m_state == TowTrackMissionState::e_hookedUp) { PlayAction(IsleScript::c_wrt082na_PlayWav); } else { @@ -543,22 +544,22 @@ void TowTrack::StopActions() } // FUNCTION: LEGO1 0x1004dbe0 -void TowTrack::FUN_1004dbe0() +void TowTrack::Reset() { if (m_lastAction != -1) { InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL); } ((Act1State*) GameState()->GetState("Act1State"))->m_state = Act1State::e_none; - m_state->m_unk0x08 = 0; + m_state->m_state = TowTrackMissionState::e_none; g_isleFlags |= Isle::c_playMusic; AnimationManager()->EnableCamAnims(TRUE); AnimationManager()->FUN_1005f6d0(TRUE); m_state->m_startTime = INT_MIN; - m_state->m_unk0x10 = FALSE; + m_state->m_takingTooLong = FALSE; m_state = NULL; - m_unk0x16c = 0; - m_unk0x16e = 0; + m_treeBlockageTriggered = 0; + m_speedComplaintTriggered = 0; } // FUNCTION: LEGO1 0x1004dc80 @@ -593,9 +594,9 @@ void TowTrack::PlayAction(IsleScript::Script p_objectId) // FUNCTION: LEGO1 0x1004dd30 TowTrackMissionState::TowTrackMissionState() { - m_unk0x08 = 0; + m_state = TowTrackMissionState::e_none; m_startTime = 0; - m_unk0x10 = FALSE; + m_takingTooLong = FALSE; m_peScore = 0; m_maScore = 0; m_paScore = 0; diff --git a/LEGO1/lego/legoomni/src/worlds/isle.cpp b/LEGO1/lego/legoomni/src/worlds/isle.cpp index aeedd601..3ec9af8c 100644 --- a/LEGO1/lego/legoomni/src/worlds/isle.cpp +++ b/LEGO1/lego/legoomni/src/worlds/isle.cpp @@ -801,7 +801,7 @@ void Isle::Enable(MxBool p_enable) AnimationManager()->EnableCamAnims(FALSE); g_isleFlags &= ~c_playMusic; - m_towtrack->FUN_1004dab0(); + m_towtrack->Init(); break; case Act1State::e_transitionToAmbulance: m_act1state->m_state = Act1State::e_ambulance; @@ -1203,7 +1203,7 @@ MxBool Isle::Escape() case Act1State::e_towtrack: if (UserActor() != NULL && !UserActor()->IsA("TowTrack")) { m_towtrack->StopActions(); - m_towtrack->FUN_1004dbe0(); + m_towtrack->Reset(); } break; case Act1State::e_ambulance: @@ -1257,7 +1257,7 @@ void Isle::FUN_10033350() if (m_act1state->m_state == Act1State::e_towtrack) { if (UserActor() != NULL && !UserActor()->IsA("TowTrack")) { m_towtrack->StopActions(); - m_towtrack->FUN_1004dbe0(); + m_towtrack->Reset(); } } From 3543f5f4944eabb654b75560c96a6fb67928a5ad Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Tue, 15 Jul 2025 12:16:38 -0700 Subject: [PATCH 16/25] Fix CONFIG app after isle/master merge --- CONFIG/MainDlg.cpp | 2 +- CONFIG/config.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONFIG/MainDlg.cpp b/CONFIG/MainDlg.cpp index dfba47ea..1b93f8d9 100644 --- a/CONFIG/MainDlg.cpp +++ b/CONFIG/MainDlg.cpp @@ -98,7 +98,7 @@ bool CMainDialog::OnInitDialog() int device_i = 0; int selected = 0; char device_name[256]; - const list& driver_list = enumerator->GetDriverList(); + const list& driver_list = enumerator->m_ddInfo; for (list::const_iterator it_driver = driver_list.begin(); it_driver != driver_list.end(); it_driver++) { const MxDriver& driver = *it_driver; for (list::const_iterator it_device = driver.m_devices.begin(); diff --git a/CONFIG/config.cpp b/CONFIG/config.cpp index c88f779b..aaca44e7 100644 --- a/CONFIG/config.cpp +++ b/CONFIG/config.cpp @@ -126,7 +126,7 @@ D3DCOLORMODEL CConfigApp::GetHardwareDeviceColorModel() const // FUNCTION: CONFIG 0x00403410 bool CConfigApp::IsPrimaryDriver() const { - return m_driver == &m_device_enumerator->GetDriverList().front(); + return m_driver == &m_device_enumerator->m_ddInfo.front(); } // FUNCTION: CONFIG 0x00403430 From 87c89885baf9de0d1cdc7e60b42e4b6fde55de98 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Tue, 15 Jul 2025 13:21:41 -0700 Subject: [PATCH 17/25] For MaxLOD values > 5, disable LOD threshold and view limits (#609) --- CONFIG/res/maindialog.ui | 2 +- LEGO1/viewmanager/viewmanager.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CONFIG/res/maindialog.ui b/CONFIG/res/maindialog.ui index 526c31d8..f51f70a5 100644 --- a/CONFIG/res/maindialog.ui +++ b/CONFIG/res/maindialog.ui @@ -291,7 +291,7 @@ A higher setting will cause higher quality textures to be drawn regardless of di - 50 + 60 5 diff --git a/LEGO1/viewmanager/viewmanager.cpp b/LEGO1/viewmanager/viewmanager.cpp index fd0d4a84..a6f4aaba 100644 --- a/LEGO1/viewmanager/viewmanager.cpp +++ b/LEGO1/viewmanager/viewmanager.cpp @@ -235,7 +235,7 @@ inline void ViewManager::ManageVisibilityAndDetailRecursively(ViewROI* p_from, i if (p_from->GetWorldBoundingSphere().Radius() > 0.001F) { float projectedSize = ProjectedSize(p_from->GetWorldBoundingSphere()); - if (projectedSize < seconds_allowed * g_viewDistance) { + if (RealtimeView::GetUserMaxLOD() <= 5.0f && projectedSize < seconds_allowed * g_viewDistance) { if (p_from->GetLodLevel() != ViewROI::c_lodLevelInvisible) { ManageVisibilityAndDetailRecursively(p_from, ViewROI::c_lodLevelInvisible); } @@ -361,7 +361,7 @@ inline int ViewManager::CalculateLODLevel(float p_maximumScale, float p_initialS assert(from); if (GetFirstLODIndex(from) != 0) { - if (p_maximumScale < g_minLODThreshold) { + if (RealtimeView::GetUserMaxLOD() <= 5.0f && p_maximumScale < g_minLODThreshold) { return 0; } else { From f20fc475c7abf80dcfcf15ddaff2b3de4859a034 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Tue, 15 Jul 2025 14:47:37 -0700 Subject: [PATCH 18/25] Integrate SDL Haptic API (#607) * Integrate SDL Haptic API * Close other devices * Fixes --- ISLE/isleapp.cpp | 54 +++- ISLE/isleapp.h | 2 - .../lego/legoomni/include/legoinputmanager.h | 29 +- .../legoomni/src/input/legoinputmanager.cpp | 284 +++++++++++++----- LEGO1/lego/sources/misc/legoutil.h | 8 + tools/ncc/skip.yml | 3 + 6 files changed, 284 insertions(+), 96 deletions(-) diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index 867f1744..5a071664 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -137,8 +137,6 @@ IsleApp::IsleApp() m_drawCursor = FALSE; m_use3dSound = TRUE; m_useMusic = TRUE; - m_useJoystick = TRUE; - m_joystickIndex = 0; m_wideViewAngle = TRUE; m_islandQuality = 2; m_islandTexture = 1; @@ -297,7 +295,7 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0"); SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); - if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD)) { + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD | SDL_INIT_HAPTIC)) { char buffer[256]; SDL_snprintf( buffer, @@ -340,6 +338,23 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) // Get reference to window *appstate = g_isle->GetWindowHandle(); + // Currently, SDL doesn't send SDL_EVENT_MOUSE_ADDED at startup (unlike for gamepads) + // This will probably be fixed in the future: https://github.com/libsdl-org/SDL/issues/12815 + { + int count; + SDL_MouseID* mice = SDL_GetMice(&count); + + if (mice) { + for (int i = 0; i < count; i++) { + if (InputManager()) { + InputManager()->AddMouse(mice[i]); + } + } + + SDL_free(mice); + } + } + #ifdef __EMSCRIPTEN__ SDL_AddEventWatch( [](void* userdata, SDL_Event* event) -> bool { @@ -423,6 +438,10 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) return SDL_APP_CONTINUE; } + if (InputManager()) { + InputManager()->UpdateLastInputMethod(event); + } + switch (event->type) { case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: case SDL_EVENT_MOUSE_MOTION: @@ -482,13 +501,26 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) } break; } - case SDL_EVENT_GAMEPAD_ADDED: - case SDL_EVENT_GAMEPAD_REMOVED: { + case SDL_EVENT_MOUSE_ADDED: if (InputManager()) { - InputManager()->GetJoystick(); + InputManager()->AddMouse(event->mdevice.which); + } + break; + case SDL_EVENT_MOUSE_REMOVED: + if (InputManager()) { + InputManager()->RemoveMouse(event->mdevice.which); + } + break; + case SDL_EVENT_GAMEPAD_ADDED: + if (InputManager()) { + InputManager()->AddJoystick(event->jdevice.which); + } + break; + case SDL_EVENT_GAMEPAD_REMOVED: + if (InputManager()) { + InputManager()->RemoveJoystick(event->jdevice.which); } break; - } case SDL_EVENT_GAMEPAD_BUTTON_DOWN: { switch (event->gbutton.button) { case SDL_GAMEPAD_BUTTON_DPAD_UP: @@ -903,10 +935,6 @@ MxResult IsleApp::SetupWindow() MxTransitionManager::configureMxTransitionManager(m_transitionType); RealtimeView::SetUserMaxLOD(m_maxLod); if (LegoOmni::GetInstance()) { - if (LegoOmni::GetInstance()->GetInputManager()) { - LegoOmni::GetInstance()->GetInputManager()->SetUseJoystick(m_useJoystick); - LegoOmni::GetInstance()->GetInputManager()->SetJoystickIndex(m_joystickIndex); - } if (LegoOmni::GetInstance()->GetVideoManager()) { LegoOmni::GetInstance()->GetVideoManager()->SetCursorBitmap(m_cursorCurrentBitmap); } @@ -998,8 +1026,6 @@ bool IsleApp::LoadConfig() iniparser_set(dict, "isle:3DSound", m_use3dSound ? "true" : "false"); iniparser_set(dict, "isle:Music", m_useMusic ? "true" : "false"); - iniparser_set(dict, "isle:UseJoystick", m_useJoystick ? "true" : "false"); - iniparser_set(dict, "isle:JoystickIndex", SDL_itoa(m_joystickIndex, buf, 10)); SDL_snprintf(buf, sizeof(buf), "%f", m_cursorSensitivity); iniparser_set(dict, "isle:Cursor Sensitivity", buf); @@ -1058,8 +1084,6 @@ bool IsleApp::LoadConfig() m_wideViewAngle = iniparser_getboolean(dict, "isle:Wide View Angle", m_wideViewAngle); m_use3dSound = iniparser_getboolean(dict, "isle:3DSound", m_use3dSound); m_useMusic = iniparser_getboolean(dict, "isle:Music", m_useMusic); - m_useJoystick = iniparser_getboolean(dict, "isle:UseJoystick", m_useJoystick); - m_joystickIndex = iniparser_getint(dict, "isle:JoystickIndex", m_joystickIndex); m_cursorSensitivity = iniparser_getdouble(dict, "isle:Cursor Sensitivity", m_cursorSensitivity); MxS32 backBuffersInVRAM = iniparser_getboolean(dict, "isle:Back Buffers in Video RAM", -1); diff --git a/ISLE/isleapp.h b/ISLE/isleapp.h index 4bec7dd6..cfe11bf0 100644 --- a/ISLE/isleapp.h +++ b/ISLE/isleapp.h @@ -80,8 +80,6 @@ class IsleApp { MxS32 m_hasLightSupport; // 0x24 MxS32 m_use3dSound; // 0x28 MxS32 m_useMusic; // 0x2c - MxS32 m_useJoystick; // 0x30 - MxS32 m_joystickIndex; // 0x34 MxS32 m_wideViewAngle; // 0x38 MxS32 m_islandQuality; // 0x3c MxS32 m_islandTexture; // 0x40 diff --git a/LEGO1/lego/legoomni/include/legoinputmanager.h b/LEGO1/lego/legoomni/include/legoinputmanager.h index ebb3b352..b86cd137 100644 --- a/LEGO1/lego/legoomni/include/legoinputmanager.h +++ b/LEGO1/lego/legoomni/include/legoinputmanager.h @@ -8,6 +8,7 @@ #include "mxpresenter.h" #include "mxqueue.h" +#include #include #include #include @@ -19,6 +20,7 @@ #endif #include +#include class LegoCameraController; class LegoControlManager; @@ -129,8 +131,6 @@ class LegoInputManager : public MxPresenter { void SetUnknown88(MxBool p_unk0x88) { m_unk0x88 = p_unk0x88; } void SetUnknown335(MxBool p_unk0x335) { m_unk0x335 = p_unk0x335; } void SetUnknown336(MxBool p_unk0x336) { m_unk0x336 = p_unk0x336; } - void SetUseJoystick(MxBool p_useJoystick) { m_useJoystick = p_useJoystick; } - void SetJoystickIndex(MxS32 p_joystickIndex) { m_joystickIndex = p_joystickIndex; } // FUNCTION: BETA10 0x1002e290 void DisableInputProcessing() @@ -153,13 +153,26 @@ class LegoInputManager : public MxPresenter { void GetKeyboardState(); MxResult GetNavigationKeyStates(MxU32& p_keyFlags); MxResult GetNavigationTouchStates(MxU32& p_keyFlags); + LEGO1_EXPORT void AddMouse(SDL_MouseID p_mouseID); + LEGO1_EXPORT void RemoveMouse(SDL_MouseID p_mouseID); + LEGO1_EXPORT void AddJoystick(SDL_JoystickID p_joystickID); + LEGO1_EXPORT void RemoveJoystick(SDL_JoystickID p_joystickID); LEGO1_EXPORT MxBool HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touchScheme); LEGO1_EXPORT MxBool HandleRumbleEvent(); + LEGO1_EXPORT void UpdateLastInputMethod(SDL_Event* p_event); // SYNTHETIC: LEGO1 0x1005b8d0 // LegoInputManager::`scalar deleting destructor' private: + // clang-format off + enum class SDL_MouseID_v : SDL_MouseID {}; + enum class SDL_JoystickID_v : SDL_JoystickID {}; + enum class SDL_TouchID_v : SDL_TouchID {}; + // clang-format on + + void InitializeHaptics(); + MxCriticalSection m_criticalSection; // 0x58 LegoNotifyList* m_keyboardNotifyList; // 0x5c LegoCameraController* m_camera; // 0x60 @@ -176,16 +189,16 @@ class LegoInputManager : public MxPresenter { MxBool m_unk0x88; // 0x88 const bool* m_keyboardState; MxBool m_unk0x195; // 0x195 - SDL_JoystickID* m_joyids; - SDL_Gamepad* m_joystick; - MxS32 m_joystickIndex; // 0x19c - MxBool m_useJoystick; // 0x334 - MxBool m_unk0x335; // 0x335 - MxBool m_unk0x336; // 0x336 + MxBool m_unk0x335; // 0x335 + MxBool m_unk0x336; // 0x336 std::map m_touchOrigins; std::map m_touchFlags; std::map> m_touchLastMotion; + std::map> m_mice; + std::map> m_joysticks; + std::map m_otherHaptics; + std::variant m_lastInputMethod; }; // TEMPLATE: LEGO1 0x10028850 diff --git a/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp b/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp index 7c80e78e..432b4fe7 100644 --- a/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp +++ b/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp @@ -11,6 +11,8 @@ #include "mxdebug.h" #include "roi/legoroi.h" +#include + DECOMP_SIZE_ASSERT(LegoInputManager, 0x338) DECOMP_SIZE_ASSERT(LegoNotifyList, 0x18) DECOMP_SIZE_ASSERT(LegoNotifyListCursor, 0x10) @@ -40,10 +42,6 @@ LegoInputManager::LegoInputManager() m_unk0x81 = FALSE; m_unk0x88 = FALSE; m_unk0x195 = 0; - m_joyids = NULL; - m_joystickIndex = -1; - m_joystick = NULL; - m_useJoystick = FALSE; m_unk0x335 = FALSE; m_unk0x336 = FALSE; m_unk0x74 = 0x19; @@ -71,8 +69,6 @@ MxResult LegoInputManager::Create(HWND p_hwnd) m_eventQueue = new LegoEventQueue; } - GetJoystick(); - if (!m_keyboardNotifyList || !m_eventQueue) { Destroy(); result = FAILURE; @@ -98,7 +94,23 @@ void LegoInputManager::Destroy() delete m_controlManager; } - SDL_free(m_joyids); + for (const auto& [id, joystick] : m_joysticks) { + if (joystick.second) { + SDL_CloseHaptic(joystick.second); + } + + SDL_CloseGamepad(joystick.first); + } + + for (const auto& [id, mouse] : m_mice) { + if (mouse.second) { + SDL_CloseHaptic(mouse.second); + } + } + + for (const auto& [id, haptic] : m_otherHaptics) { + SDL_CloseHaptic(haptic); + } } // FUNCTION: LEGO1 0x1005c0f0 @@ -145,74 +157,33 @@ MxResult LegoInputManager::GetNavigationKeyStates(MxU32& p_keyFlags) return SUCCESS; } -// FUNCTION: LEGO1 0x1005c240 -MxResult LegoInputManager::GetJoystick() -{ - if (m_joystick != NULL && SDL_GamepadConnected(m_joystick) == TRUE) { - return SUCCESS; - } - - MxS32 numJoysticks = 0; - if (m_joyids != NULL) { - SDL_free(m_joyids); - m_joyids = NULL; - } - m_joyids = SDL_GetGamepads(&numJoysticks); - - if (m_useJoystick != FALSE && numJoysticks != 0) { - MxS32 joyid = m_joystickIndex; - if (joyid >= 0) { - m_joystick = SDL_OpenGamepad(m_joyids[joyid]); - if (m_joystick != NULL) { - return SUCCESS; - } - } - - for (joyid = 0; joyid < numJoysticks; joyid++) { - m_joystick = SDL_OpenGamepad(m_joyids[joyid]); - if (m_joystick != NULL) { - return SUCCESS; - } - } - } - - return FAILURE; -} - // FUNCTION: LEGO1 0x1005c320 MxResult LegoInputManager::GetJoystickState(MxU32* p_joystickX, MxU32* p_joystickY, MxU32* p_povPosition) { - if (m_useJoystick != FALSE) { - if (GetJoystick() == -1) { - if (m_joystick != NULL) { - // GetJoystick() failed but handle to joystick is still open, close it - SDL_CloseGamepad(m_joystick); - m_joystick = NULL; - } + if (m_joysticks.empty()) { + return FAILURE; + } - return FAILURE; - } - - MxS16 xPos = SDL_GetGamepadAxis(m_joystick, SDL_GAMEPAD_AXIS_LEFTX); - MxS16 yPos = SDL_GetGamepadAxis(m_joystick, SDL_GAMEPAD_AXIS_LEFTY); + MxS16 xPos, yPos = 0; + for (const auto& [id, joystick] : m_joysticks) { + xPos = SDL_GetGamepadAxis(joystick.first, SDL_GAMEPAD_AXIS_LEFTX); + yPos = SDL_GetGamepadAxis(joystick.first, SDL_GAMEPAD_AXIS_LEFTY); if (xPos > -8000 && xPos < 8000) { - // Ignore small axis values xPos = 0; } if (yPos > -8000 && yPos < 8000) { - // Ignore small axis values yPos = 0; } - // normalize values acquired from joystick axes - *p_joystickX = ((xPos + 32768) * 100) / 65535; - *p_joystickY = ((yPos + 32768) * 100) / 65535; - *p_povPosition = -1; - - return SUCCESS; + if (xPos || yPos) { + break; + } } - return FAILURE; + *p_joystickX = ((xPos + 32768) * 100) / 65535; + *p_joystickY = ((yPos + 32768) * 100) / 65535; + *p_povPosition = -1; + return SUCCESS; } // FUNCTION: LEGO1 0x1005c470 @@ -546,6 +517,74 @@ MxResult LegoInputManager::GetNavigationTouchStates(MxU32& p_keyStates) return SUCCESS; } +void LegoInputManager::AddMouse(SDL_MouseID p_mouseID) +{ + if (m_mice.count(p_mouseID)) { + return; + } + + // Currently no way to get an individual haptic device for a mouse. + SDL_Haptic* haptic = SDL_OpenHapticFromMouse(); + if (haptic) { + if (!SDL_InitHapticRumble(haptic)) { + SDL_CloseHaptic(haptic); + haptic = nullptr; + } + } + + m_mice[p_mouseID] = {nullptr, haptic}; +} + +void LegoInputManager::RemoveMouse(SDL_MouseID p_mouseID) +{ + if (!m_mice.count(p_mouseID)) { + return; + } + + if (m_mice[p_mouseID].second) { + SDL_CloseHaptic(m_mice[p_mouseID].second); + } + + m_mice.erase(p_mouseID); +} + +void LegoInputManager::AddJoystick(SDL_JoystickID p_joystickID) +{ + if (m_joysticks.count(p_joystickID)) { + return; + } + + SDL_Gamepad* joystick = SDL_OpenGamepad(p_joystickID); + if (joystick) { + SDL_Haptic* haptic = SDL_OpenHapticFromJoystick(SDL_GetGamepadJoystick(joystick)); + if (haptic) { + if (!SDL_InitHapticRumble(haptic)) { + SDL_CloseHaptic(haptic); + haptic = nullptr; + } + } + + m_joysticks[p_joystickID] = {joystick, haptic}; + } + else { + SDL_Log("Failed to open gamepad: %s", SDL_GetError()); + } +} + +void LegoInputManager::RemoveJoystick(SDL_JoystickID p_joystickID) +{ + if (!m_joysticks.count(p_joystickID)) { + return; + } + + if (m_joysticks[p_joystickID].second) { + SDL_CloseHaptic(m_joysticks[p_joystickID].second); + } + + SDL_CloseGamepad(m_joysticks[p_joystickID].first); + m_joysticks.erase(p_joystickID); +} + MxBool LegoInputManager::HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touchScheme) { const SDL_TouchFingerEvent& event = p_event->tfinger; @@ -629,15 +668,118 @@ MxBool LegoInputManager::HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touc MxBool LegoInputManager::HandleRumbleEvent() { - if (m_joystick != NULL && SDL_GamepadConnected(m_joystick) == TRUE) { - const Uint16 frequency = 65535 / 2; - const Uint32 durationMs = 700; - SDL_RumbleGamepad(m_joystick, frequency, frequency, durationMs); - } - else { - return FALSE; + static bool g_hapticsInitialized = false; + + if (!g_hapticsInitialized) { + InitializeHaptics(); + g_hapticsInitialized = true; } - // Add support for SDL Haptic API - return TRUE; + SDL_Haptic* haptic = nullptr; + std::visit( + overloaded{ + [&haptic, this](SDL_MouseID_v p_id) { + if (m_mice.count((SDL_MouseID) p_id)) { + haptic = m_mice[(SDL_MouseID) p_id].second; + } + }, + [&haptic, this](SDL_JoystickID_v p_id) { + if (m_joysticks.count((SDL_JoystickID) p_id)) { + haptic = m_joysticks[(SDL_JoystickID) p_id].second; + } + }, + [&haptic, this](SDL_TouchID_v p_id) { + // We can't currently correlate Touch devices with Haptic devices + if (!m_otherHaptics.empty()) { + haptic = m_otherHaptics.begin()->second; + } + } + }, + m_lastInputMethod + ); + + const float strength = 0.5f; + const Uint32 durationMs = 700; + + if (haptic) { + return SDL_PlayHapticRumble(haptic, strength, durationMs); + } + + // A joystick isn't necessarily a haptic device; try basic rumble instead + if (const SDL_JoystickID_v* joystick = std::get_if(&m_lastInputMethod)) { + if (m_joysticks.count((SDL_JoystickID) *joystick)) { + return SDL_RumbleGamepad( + m_joysticks[(SDL_JoystickID) *joystick].first, + strength * 65535, + strength * 65535, + durationMs + ); + } + } + + return FALSE; +} + +void LegoInputManager::InitializeHaptics() +{ + // We don't get added/removed events for haptic devices that are not joysticks or mice, + // so we initialize "otherHaptics" once at this point. + std::vector existingHaptics; + + for (const auto& [id, mouse] : m_mice) { + if (mouse.second) { + existingHaptics.push_back(SDL_GetHapticID(mouse.second)); + } + } + + for (const auto& [id, joystick] : m_joysticks) { + if (joystick.second) { + existingHaptics.push_back(SDL_GetHapticID(joystick.second)); + } + } + + int count; + SDL_HapticID* haptics = SDL_GetHaptics(&count); + if (haptics) { + for (int i = 0; i < count; i++) { + if (std::find(existingHaptics.begin(), existingHaptics.end(), haptics[i]) == existingHaptics.end()) { + SDL_Haptic* haptic = SDL_OpenHaptic(haptics[i]); + if (haptic) { + if (SDL_InitHapticRumble(haptic)) { + m_otherHaptics[haptics[i]] = haptic; + } + else { + SDL_CloseHaptic(haptic); + } + } + } + } + + SDL_free(haptics); + } +} + +void LegoInputManager::UpdateLastInputMethod(SDL_Event* p_event) +{ + switch (p_event->type) { + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: + m_lastInputMethod = SDL_MouseID_v{p_event->button.which}; + break; + case SDL_EVENT_MOUSE_MOTION: + m_lastInputMethod = SDL_MouseID_v{p_event->motion.which}; + break; + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: + m_lastInputMethod = SDL_JoystickID_v{p_event->gbutton.which}; + break; + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + m_lastInputMethod = SDL_JoystickID_v{p_event->gaxis.which}; + break; + case SDL_EVENT_FINGER_MOTION: + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_UP: + m_lastInputMethod = SDL_TouchID_v{p_event->tfinger.touchID}; + break; + } } diff --git a/LEGO1/lego/sources/misc/legoutil.h b/LEGO1/lego/sources/misc/legoutil.h index 871a9b72..78f52d0f 100644 --- a/LEGO1/lego/sources/misc/legoutil.h +++ b/LEGO1/lego/sources/misc/legoutil.h @@ -59,4 +59,12 @@ inline T RToD(T p_r) return p_r * 180.0F / 3.1416F; } +template +struct overloaded : Ts... { + using Ts::operator()...; +}; + +template +overloaded(Ts...) -> overloaded; + #endif // __LEGOUTIL_H diff --git a/tools/ncc/skip.yml b/tools/ncc/skip.yml index c5ceef72..2bae0ab4 100644 --- a/tools/ncc/skip.yml +++ b/tools/ncc/skip.yml @@ -74,3 +74,6 @@ cksize: "Re-defined Windows name" fccType: "Re-defined Windows name" dwDataOffset: "Re-defined Windows name" fccType: "Re-defined Windows name" +SDL_MouseID_v: "SDL-based name" +SDL_JoystickID_v: "SDL-based name" +SDL_TouchID_v: "SDL-based name" \ No newline at end of file From d0dc595fc52cbc954cf96a3fb8a73a6120e059a1 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Tue, 15 Jul 2025 15:18:55 -0700 Subject: [PATCH 19/25] (Touch controls) Use full virtual joystick instead of hybrid (#612) * Test touch joystick * Change radius --- .../lego/legoomni/include/legoinputmanager.h | 6 +- .../legoomni/src/input/legoinputmanager.cpp | 78 ++++++++----------- 2 files changed, 38 insertions(+), 46 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoinputmanager.h b/LEGO1/lego/legoomni/include/legoinputmanager.h index b86cd137..bbe0a2b5 100644 --- a/LEGO1/lego/legoomni/include/legoinputmanager.h +++ b/LEGO1/lego/legoomni/include/legoinputmanager.h @@ -94,6 +94,7 @@ class LegoInputManager : public MxPresenter { }; enum TouchScheme { + e_none = -1, e_mouse = 0, e_arrowKeys, e_gamepad, @@ -192,9 +193,10 @@ class LegoInputManager : public MxPresenter { MxBool m_unk0x335; // 0x335 MxBool m_unk0x336; // 0x336 - std::map m_touchOrigins; + TouchScheme m_touchScheme = e_none; + SDL_Point m_touchVirtualThumb = {0, 0}; + SDL_FPoint m_touchVirtualThumbOrigin; std::map m_touchFlags; - std::map> m_touchLastMotion; std::map> m_mice; std::map> m_joysticks; std::map m_otherHaptics; diff --git a/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp b/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp index 432b4fe7..1bb0295d 100644 --- a/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp +++ b/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp @@ -160,7 +160,7 @@ MxResult LegoInputManager::GetNavigationKeyStates(MxU32& p_keyFlags) // FUNCTION: LEGO1 0x1005c320 MxResult LegoInputManager::GetJoystickState(MxU32* p_joystickX, MxU32* p_joystickY, MxU32* p_povPosition) { - if (m_joysticks.empty()) { + if (m_joysticks.empty() && m_touchScheme != e_gamepad) { return FAILURE; } @@ -180,6 +180,11 @@ MxResult LegoInputManager::GetJoystickState(MxU32* p_joystickX, MxU32* p_joystic } } + if (!xPos && !yPos) { + xPos = m_touchVirtualThumb.x; + yPos = m_touchVirtualThumb.y; + } + *p_joystickX = ((xPos + 32768) * 100) / 65535; *p_joystickY = ((yPos + 32768) * 100) / 65535; *p_povPosition = -1; @@ -499,18 +504,9 @@ void LegoInputManager::EnableInputProcessing() MxResult LegoInputManager::GetNavigationTouchStates(MxU32& p_keyStates) { - for (auto& [fingerID, touchFlags] : m_touchFlags) { - p_keyStates |= touchFlags; - - // We need to clear these as they are not meant to be persistent in e_gamepad mode. - if (m_touchOrigins.count(fingerID) && m_touchLastMotion.count(fingerID)) { - const MxU32 inactivityThreshold = 3; - - if (m_touchLastMotion[fingerID].first++ > inactivityThreshold) { - touchFlags &= ~c_left; - touchFlags &= ~c_right; - m_touchOrigins[fingerID].x = m_touchLastMotion[fingerID].second.x; - } + if (m_touchScheme == e_arrowKeys) { + for (auto& [fingerID, touchFlags] : m_touchFlags) { + p_keyStates |= touchFlags; } } @@ -588,6 +584,7 @@ void LegoInputManager::RemoveJoystick(SDL_JoystickID p_joystickID) MxBool LegoInputManager::HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touchScheme) { const SDL_TouchFingerEvent& event = p_event->tfinger; + m_touchScheme = p_touchScheme; switch (p_touchScheme) { case e_mouse: @@ -619,49 +616,42 @@ MxBool LegoInputManager::HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touc break; } break; - case e_gamepad: + case e_gamepad: { + static SDL_FingerID g_finger = (SDL_FingerID) 0; + switch (p_event->type) { case SDL_EVENT_FINGER_DOWN: - m_touchOrigins[event.fingerID] = {event.x, event.y}; + if (!g_finger) { + g_finger = event.fingerID; + m_touchVirtualThumb = {0, 0}; + m_touchVirtualThumbOrigin = {event.x, event.y}; + } break; case SDL_EVENT_FINGER_UP: - m_touchOrigins.erase(event.fingerID); - m_touchFlags.erase(event.fingerID); + if (event.fingerID == g_finger) { + g_finger = 0; + m_touchVirtualThumb = {0, 0}; + m_touchVirtualThumbOrigin = {0, 0}; + } break; case SDL_EVENT_FINGER_MOTION: - if (m_touchOrigins.count(event.fingerID)) { - const float activationThreshold = 0.03f; - m_touchFlags[event.fingerID] &= ~c_down; - m_touchFlags[event.fingerID] &= ~c_up; + if (event.fingerID == g_finger) { + const float thumbstickRadius = 0.25f; + const float deltaX = + SDL_clamp(event.x - m_touchVirtualThumbOrigin.x, -thumbstickRadius, thumbstickRadius); + const float deltaY = + SDL_clamp(event.y - m_touchVirtualThumbOrigin.y, -thumbstickRadius, thumbstickRadius); - const float deltaY = event.y - m_touchOrigins[event.fingerID].y; - if (SDL_fabsf(deltaY) > activationThreshold) { - if (deltaY > 0) { - m_touchFlags[event.fingerID] |= c_down; - } - else if (deltaY < 0) { - m_touchFlags[event.fingerID] |= c_up; - } - } - - const float deltaX = event.x - m_touchOrigins[event.fingerID].x; - if (SDL_fabsf(deltaX) > activationThreshold && event.dx) { - if (event.dx > 0) { - m_touchFlags[event.fingerID] |= c_right; - m_touchFlags[event.fingerID] &= ~c_left; - } - else if (event.dx < 0) { - m_touchFlags[event.fingerID] |= c_left; - m_touchFlags[event.fingerID] &= ~c_right; - } - - m_touchLastMotion[event.fingerID] = {0, {event.x, event.y}}; - } + m_touchVirtualThumb = { + (int) (deltaX / thumbstickRadius * 32767.0f), + (int) (deltaY / thumbstickRadius * 32767.0f), + }; } break; } break; } + } return TRUE; } From deca5e5a2efc302b571a54acfd2276edef11d149 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Tue, 15 Jul 2025 16:50:14 -0700 Subject: [PATCH 20/25] Add device and gamepad haptics to web port (#613) * Add device and gamepad haptics to web port * Update skip.yml --- CMakeLists.txt | 1 + ISLE/emscripten/haptic.cpp | 52 +++++++++++++++++++ ISLE/emscripten/haptic.h | 8 +++ ISLE/isleapp.cpp | 18 ++++++- .../lego/legoomni/include/legoinputmanager.h | 18 ++++--- .../legoomni/src/input/legoinputmanager.cpp | 44 ++++++++++++---- tools/ncc/skip.yml | 1 + 7 files changed, 125 insertions(+), 17 deletions(-) create mode 100644 ISLE/emscripten/haptic.cpp create mode 100644 ISLE/emscripten/haptic.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a457968..a3bdb8e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -555,6 +555,7 @@ if (ISLE_BUILD_APP) ISLE/emscripten/config.cpp ISLE/emscripten/events.cpp ISLE/emscripten/filesystem.cpp + ISLE/emscripten/haptic.cpp ISLE/emscripten/messagebox.cpp ISLE/emscripten/window.cpp ) diff --git a/ISLE/emscripten/haptic.cpp b/ISLE/emscripten/haptic.cpp new file mode 100644 index 00000000..364701d2 --- /dev/null +++ b/ISLE/emscripten/haptic.cpp @@ -0,0 +1,52 @@ +#include "haptic.h" + +#include "compat.h" +#include "lego/sources/misc/legoutil.h" +#include "legoinputmanager.h" +#include "misc.h" + +#include + +void Emscripten_HandleRumbleEvent(float p_lowFrequencyRumble, float p_highFrequencyRumble, MxU32 p_milliseconds) +{ + std::visit( + overloaded{ + [](LegoInputManager::SDL_KeyboardID_v p_id) {}, + [](LegoInputManager::SDL_MouseID_v p_id) {}, + [p_lowFrequencyRumble, p_highFrequencyRumble, p_milliseconds](LegoInputManager::SDL_JoystickID_v p_id) { + const char* name = SDL_GetJoystickNameForID((SDL_JoystickID) p_id); + if (name) { + MAIN_THREAD_EM_ASM( + { + const name = UTF8ToString($0); + const gamepads = navigator.getGamepads(); + for (const gamepad of gamepads) { + if (gamepad && gamepad.connected && gamepad.id == name && gamepad.vibrationActuator) { + gamepad.vibrationActuator.playEffect("dual-rumble", { + startDelay : 0, + weakMagnitude : $1, + strongMagnitude : $2, + duration : $3, + }); + break; + } + } + }, + name, + SDL_clamp(p_lowFrequencyRumble, 0, 1), + SDL_clamp(p_highFrequencyRumble, 0, 1), + p_milliseconds + ); + } + }, + [](LegoInputManager::SDL_TouchID_v p_id) { + MAIN_THREAD_EM_ASM({ + if (navigator.vibrate) { + navigator.vibrate(700); + } + }); + } + }, + InputManager()->GetLastInputMethod() + ); +} diff --git a/ISLE/emscripten/haptic.h b/ISLE/emscripten/haptic.h new file mode 100644 index 00000000..51605128 --- /dev/null +++ b/ISLE/emscripten/haptic.h @@ -0,0 +1,8 @@ +#ifndef EMSCRIPTEN_HAPTIC_H +#define EMSCRIPTEN_HAPTIC_H + +#include "mxtypes.h" + +void Emscripten_HandleRumbleEvent(float p_lowFrequencyRumble, float p_highFrequencyRumble, MxU32 p_milliseconds); + +#endif // EMSCRIPTEN_HAPTIC_H diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index 5a071664..a3ddb0d2 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -54,6 +54,7 @@ #include "emscripten/config.h" #include "emscripten/events.h" #include "emscripten/filesystem.h" +#include "emscripten/haptic.h" #include "emscripten/messagebox.h" #include "emscripten/window.h" #endif @@ -501,6 +502,16 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) } break; } + case SDL_EVENT_KEYBOARD_ADDED: + if (InputManager()) { + InputManager()->AddKeyboard(event->kdevice.which); + } + break; + case SDL_EVENT_KEYBOARD_REMOVED: + if (InputManager()) { + InputManager()->RemoveKeyboard(event->kdevice.which); + } + break; case SDL_EVENT_MOUSE_ADDED: if (InputManager()) { InputManager()->AddMouse(event->mdevice.which); @@ -789,8 +800,11 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) } } else if (event->user.type == g_legoSdlEvents.m_hitActor && g_isle->GetHaptic()) { - if (InputManager()) { - InputManager()->HandleRumbleEvent(); + if (!InputManager()->HandleRumbleEvent(0.5f, 0.5f, 0.5f, 700)) { +// Platform-specific handling +#ifdef __EMSCRIPTEN__ + Emscripten_HandleRumbleEvent(0.5f, 0.5f, 700); +#endif } } diff --git a/LEGO1/lego/legoomni/include/legoinputmanager.h b/LEGO1/lego/legoomni/include/legoinputmanager.h index bbe0a2b5..04ac7294 100644 --- a/LEGO1/lego/legoomni/include/legoinputmanager.h +++ b/LEGO1/lego/legoomni/include/legoinputmanager.h @@ -154,24 +154,29 @@ class LegoInputManager : public MxPresenter { void GetKeyboardState(); MxResult GetNavigationKeyStates(MxU32& p_keyFlags); MxResult GetNavigationTouchStates(MxU32& p_keyFlags); + LEGO1_EXPORT void AddKeyboard(SDL_KeyboardID p_keyboardID); + LEGO1_EXPORT void RemoveKeyboard(SDL_KeyboardID p_keyboardID); LEGO1_EXPORT void AddMouse(SDL_MouseID p_mouseID); LEGO1_EXPORT void RemoveMouse(SDL_MouseID p_mouseID); LEGO1_EXPORT void AddJoystick(SDL_JoystickID p_joystickID); LEGO1_EXPORT void RemoveJoystick(SDL_JoystickID p_joystickID); LEGO1_EXPORT MxBool HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touchScheme); - LEGO1_EXPORT MxBool HandleRumbleEvent(); + LEGO1_EXPORT MxBool + HandleRumbleEvent(float p_strength, float p_lowFrequencyRumble, float p_highFrequencyRumble, MxU32 p_milliseconds); LEGO1_EXPORT void UpdateLastInputMethod(SDL_Event* p_event); + const auto& GetLastInputMethod() { return m_lastInputMethod; } - // SYNTHETIC: LEGO1 0x1005b8d0 - // LegoInputManager::`scalar deleting destructor' - -private: // clang-format off + enum class SDL_KeyboardID_v : SDL_KeyboardID {}; enum class SDL_MouseID_v : SDL_MouseID {}; enum class SDL_JoystickID_v : SDL_JoystickID {}; enum class SDL_TouchID_v : SDL_TouchID {}; // clang-format on + // SYNTHETIC: LEGO1 0x1005b8d0 + // LegoInputManager::`scalar deleting destructor' + +private: void InitializeHaptics(); MxCriticalSection m_criticalSection; // 0x58 @@ -197,10 +202,11 @@ class LegoInputManager : public MxPresenter { SDL_Point m_touchVirtualThumb = {0, 0}; SDL_FPoint m_touchVirtualThumbOrigin; std::map m_touchFlags; + std::map> m_keyboards; std::map> m_mice; std::map> m_joysticks; std::map m_otherHaptics; - std::variant m_lastInputMethod; + std::variant m_lastInputMethod; }; // TEMPLATE: LEGO1 0x10028850 diff --git a/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp b/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp index 1bb0295d..f7fef27e 100644 --- a/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp +++ b/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp @@ -160,7 +160,8 @@ MxResult LegoInputManager::GetNavigationKeyStates(MxU32& p_keyFlags) // FUNCTION: LEGO1 0x1005c320 MxResult LegoInputManager::GetJoystickState(MxU32* p_joystickX, MxU32* p_joystickY, MxU32* p_povPosition) { - if (m_joysticks.empty() && m_touchScheme != e_gamepad) { + if (!std::holds_alternative(m_lastInputMethod) && + !(std::holds_alternative(m_lastInputMethod) && m_touchScheme == e_gamepad)) { return FAILURE; } @@ -513,6 +514,24 @@ MxResult LegoInputManager::GetNavigationTouchStates(MxU32& p_keyStates) return SUCCESS; } +void LegoInputManager::AddKeyboard(SDL_KeyboardID p_keyboardID) +{ + if (m_keyboards.count(p_keyboardID)) { + return; + } + + m_keyboards[p_keyboardID] = {nullptr, nullptr}; +} + +void LegoInputManager::RemoveKeyboard(SDL_KeyboardID p_keyboardID) +{ + if (!m_keyboards.count(p_keyboardID)) { + return; + } + + m_keyboards.erase(p_keyboardID); +} + void LegoInputManager::AddMouse(SDL_MouseID p_mouseID) { if (m_mice.count(p_mouseID)) { @@ -656,7 +675,12 @@ MxBool LegoInputManager::HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touc return TRUE; } -MxBool LegoInputManager::HandleRumbleEvent() +MxBool LegoInputManager::HandleRumbleEvent( + float p_strength, + float p_lowFrequencyRumble, + float p_highFrequencyRumble, + MxU32 p_milliseconds +) { static bool g_hapticsInitialized = false; @@ -668,6 +692,7 @@ MxBool LegoInputManager::HandleRumbleEvent() SDL_Haptic* haptic = nullptr; std::visit( overloaded{ + [](SDL_KeyboardID_v p_id) {}, [&haptic, this](SDL_MouseID_v p_id) { if (m_mice.count((SDL_MouseID) p_id)) { haptic = m_mice[(SDL_MouseID) p_id].second; @@ -688,11 +713,8 @@ MxBool LegoInputManager::HandleRumbleEvent() m_lastInputMethod ); - const float strength = 0.5f; - const Uint32 durationMs = 700; - if (haptic) { - return SDL_PlayHapticRumble(haptic, strength, durationMs); + return SDL_PlayHapticRumble(haptic, p_strength, p_milliseconds); } // A joystick isn't necessarily a haptic device; try basic rumble instead @@ -700,9 +722,9 @@ MxBool LegoInputManager::HandleRumbleEvent() if (m_joysticks.count((SDL_JoystickID) *joystick)) { return SDL_RumbleGamepad( m_joysticks[(SDL_JoystickID) *joystick].first, - strength * 65535, - strength * 65535, - durationMs + SDL_clamp(p_lowFrequencyRumble, 0, 1) * USHRT_MAX, + SDL_clamp(p_highFrequencyRumble, 0, 1) * USHRT_MAX, + p_milliseconds ); } } @@ -752,6 +774,10 @@ void LegoInputManager::InitializeHaptics() void LegoInputManager::UpdateLastInputMethod(SDL_Event* p_event) { switch (p_event->type) { + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: + m_lastInputMethod = SDL_KeyboardID_v{p_event->key.which}; + break; case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: m_lastInputMethod = SDL_MouseID_v{p_event->button.which}; diff --git a/tools/ncc/skip.yml b/tools/ncc/skip.yml index 2bae0ab4..322cded0 100644 --- a/tools/ncc/skip.yml +++ b/tools/ncc/skip.yml @@ -74,6 +74,7 @@ cksize: "Re-defined Windows name" fccType: "Re-defined Windows name" dwDataOffset: "Re-defined Windows name" fccType: "Re-defined Windows name" +SDL_KeyboardID_v: "SDL-based name" SDL_MouseID_v: "SDL-based name" SDL_JoystickID_v: "SDL-based name" SDL_TouchID_v: "SDL-based name" \ No newline at end of file From ad2832b096dd9111aaec6d3055270ac51b187259 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Tue, 15 Jul 2025 17:18:54 -0700 Subject: [PATCH 21/25] (Web port) Pass vibration milliseconds into device haptics --- ISLE/emscripten/haptic.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ISLE/emscripten/haptic.cpp b/ISLE/emscripten/haptic.cpp index 364701d2..4a7244e5 100644 --- a/ISLE/emscripten/haptic.cpp +++ b/ISLE/emscripten/haptic.cpp @@ -39,12 +39,15 @@ void Emscripten_HandleRumbleEvent(float p_lowFrequencyRumble, float p_highFreque ); } }, - [](LegoInputManager::SDL_TouchID_v p_id) { - MAIN_THREAD_EM_ASM({ - if (navigator.vibrate) { - navigator.vibrate(700); - } - }); + [p_milliseconds](LegoInputManager::SDL_TouchID_v p_id) { + MAIN_THREAD_EM_ASM( + { + if (navigator.vibrate) { + navigator.vibrate($0); + } + }, + p_milliseconds + ); } }, InputManager()->GetLastInputMethod() From b6a4f65db432145c83a92869b8baccdec8f131fa Mon Sep 17 00:00:00 2001 From: VoxelTek <53562267+VoxelTek@users.noreply.github.com> Date: Wed, 16 Jul 2025 10:29:42 +1000 Subject: [PATCH 22/25] Add CLI help message, accessible with --help (#614) * Add CLI --help argument * Make clang-format happy * Move to switch instead of creating temp var * Remove unnecesary break Co-authored-by: Christian Semmler * Remove unnecesary break 2 Co-authored-by: Christian Semmler * Make clang-format happy again --------- Co-authored-by: Christian Semmler --- ISLE/isleapp.cpp | 29 +++++++++++++++++++++++++---- ISLE/isleapp.h | 3 ++- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index a3ddb0d2..46e1c2e2 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -315,7 +315,8 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) // Create global app instance g_isle = new IsleApp(); - if (g_isle->ParseArguments(argc, argv) != SUCCESS) { + switch (g_isle->ParseArguments(argc, argv)) { + case SDL_APP_FAILURE: Any_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, "LEGO® Island Error", @@ -323,6 +324,10 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) window ); return SDL_APP_FAILURE; + case SDL_APP_SUCCESS: + return SDL_APP_SUCCESS; + case SDL_APP_CONTINUE: + break; } // Create window @@ -1301,7 +1306,7 @@ void IsleApp::SetupCursor(Cursor p_cursor) } } -MxResult IsleApp::ParseArguments(int argc, char** argv) +SDL_AppResult IsleApp::ParseArguments(int argc, char** argv) { for (int i = 1, consumed; i < argc; i += consumed) { consumed = -1; @@ -1318,13 +1323,29 @@ MxResult IsleApp::ParseArguments(int argc, char** argv) #endif consumed = 1; } + else if (strcmp(argv[i], "--help") == 0) { + DisplayArgumentHelp(); + return SDL_APP_SUCCESS; + } if (consumed <= 0) { SDL_Log("Invalid argument(s): %s", argv[i]); - return FAILURE; + DisplayArgumentHelp(); + return SDL_APP_FAILURE; } } - return SUCCESS; + return SDL_APP_CONTINUE; +} + +void IsleApp::DisplayArgumentHelp() +{ + SDL_Log("Usage: isle [options]"); + SDL_Log("Options:"); + SDL_Log(" --ini Set custom path to .ini config"); +#ifdef ISLE_DEBUG + SDL_Log(" --debug Launch in debug mode"); +#endif + SDL_Log(" --help Show this help message"); } MxResult IsleApp::VerifyFilesystem() diff --git a/ISLE/isleapp.h b/ISLE/isleapp.h index cfe11bf0..f175cecf 100644 --- a/ISLE/isleapp.h +++ b/ISLE/isleapp.h @@ -61,7 +61,7 @@ class IsleApp { void SetGameStarted(MxS32 p_gameStarted) { m_gameStarted = p_gameStarted; } void SetDrawCursor(MxS32 p_drawCursor) { m_drawCursor = p_drawCursor; } - MxResult ParseArguments(int argc, char** argv); + SDL_AppResult ParseArguments(int argc, char** argv); MxResult VerifyFilesystem(); void DetectGameVersion(); void MoveVirtualMouseViaJoystick(); @@ -99,6 +99,7 @@ class IsleApp { const CursorBitmap* m_cursorCurrentBitmap; char* m_mediaPath; MxFloat m_cursorSensitivity; + void DisplayArgumentHelp(); char* m_iniPath; MxFloat m_maxLod; From 84bd0a1a8731d6ff8db534b48e21be5e46a0f075 Mon Sep 17 00:00:00 2001 From: VoxelTek <53562267+VoxelTek@users.noreply.github.com> Date: Wed, 16 Jul 2025 12:29:45 +1000 Subject: [PATCH 23/25] Rework of isle-config, add resolution adjustment and max framerate settings (#608) * Add resolution adjustment, framerate limit, etc - isle-config has been reworked to be a smaller, more organised window - resolution adjustment has now been added to isle-config, so that the resolution on windowed game start can be set - max framerate setting added to isle-config - higher-quality options disabled in isle-config if computer has too little RAM (unlikely) * Make clang-format happy * Switch to MxS32, move variable declaration to end * Adjust sizing of resolution spinboxes * Add full screen video mode When full screen is enabled, the game goes full-screen, and the screen resolution changes. * Rework to add Exclusive Fullscreen option. * Remove comment * Raise max LoD value to 60 * Fix tab order * Simplify code --- CONFIG/MainDlg.cpp | 110 +++ CONFIG/MainDlg.h | 6 + CONFIG/config.cpp | 21 +- CONFIG/config.h | 6 + CONFIG/res/maindialog.ui | 1470 ++++++++++++++++++++++---------------- ISLE/isleapp.cpp | 25 + ISLE/isleapp.h | 6 +- 7 files changed, 1017 insertions(+), 627 deletions(-) diff --git a/CONFIG/MainDlg.cpp b/CONFIG/MainDlg.cpp index 1b93f8d9..3f69d096 100644 --- a/CONFIG/MainDlg.cpp +++ b/CONFIG/MainDlg.cpp @@ -58,6 +58,7 @@ CMainDialog::CMainDialog(QWidget* pParent) : QDialog(pParent) connect(m_ui->musicCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxMusic); connect(m_ui->sound3DCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckbox3DSound); connect(m_ui->fullscreenCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxFullscreen); + connect(m_ui->exclusiveFullscreenCheckbox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxExclusiveFullscreen); connect(m_ui->rumbleCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxRumble); connect(m_ui->textureCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxTexture); connect(m_ui->touchComboBox, &QComboBox::currentIndexChanged, this, &CMainDialog::TouchControlsChanged); @@ -80,7 +81,44 @@ CMainDialog::CMainDialog(QWidget* pParent) : QDialog(pParent) connect(m_ui->maxActorsSlider, &QSlider::valueChanged, this, &CMainDialog::MaxActorsChanged); connect(m_ui->maxActorsSlider, &QSlider::sliderMoved, this, &CMainDialog::MaxActorsChanged); + connect(m_ui->aspectRatioComboBox, &QComboBox::currentIndexChanged, this, &CMainDialog::AspectRatioChanged); + connect(m_ui->xResSpinBox, &QSpinBox::valueChanged, this, &CMainDialog::XResChanged); + connect(m_ui->yResSpinBox, &QSpinBox::valueChanged, this, &CMainDialog::YResChanged); + connect(m_ui->framerateSpinBox, &QSpinBox::valueChanged, this, &CMainDialog::FramerateChanged); + layout()->setSizeConstraint(QLayout::SetFixedSize); + + if (currentConfigApp->m_ram_quality_limit != 0) { + m_modified = true; + const QString ramError = QString("Insufficient RAM!"); + m_ui->sound3DCheckBox->setChecked(false); + m_ui->sound3DCheckBox->setEnabled(false); + m_ui->sound3DCheckBox->setToolTip(ramError); + m_ui->modelQualityHighRadioButton->setEnabled(false); + m_ui->modelQualityHighRadioButton->setToolTip(ramError); + m_ui->modelQualityLowRadioButton->setEnabled(true); + if (currentConfigApp->m_ram_quality_limit == 2) { + m_ui->modelQualityLowRadioButton->setChecked(true); + m_ui->modelQualityMediumRadioButton->setEnabled(false); + m_ui->modelQualityMediumRadioButton->setToolTip(ramError); + m_ui->maxLoDSlider->setMaximum(30); + m_ui->maxActorsSlider->setMaximum(15); + } + else { + m_ui->modelQualityMediumRadioButton->setChecked(true); + m_ui->modelQualityMediumRadioButton->setEnabled(true); + m_ui->maxLoDSlider->setMaximum(40); + m_ui->maxActorsSlider->setMaximum(30); + } + } + else { + m_ui->sound3DCheckBox->setEnabled(true); + m_ui->modelQualityLowRadioButton->setEnabled(true); + m_ui->modelQualityMediumRadioButton->setEnabled(true); + m_ui->modelQualityHighRadioButton->setEnabled(true); + m_ui->maxLoDSlider->setMaximum(60); + m_ui->maxActorsSlider->setMaximum(40); + } } CMainDialog::~CMainDialog() @@ -125,6 +163,7 @@ bool CMainDialog::OnInitDialog() m_ui->LoDNum->setNum((int) currentConfigApp->m_max_lod * 10); m_ui->maxActorsSlider->setValue(currentConfigApp->m_max_actors); m_ui->maxActorsNum->setNum(currentConfigApp->m_max_actors); + UpdateInterface(); return true; } @@ -221,6 +260,8 @@ void CMainDialog::UpdateInterface() } m_ui->musicCheckBox->setChecked(currentConfigApp->m_music); m_ui->fullscreenCheckBox->setChecked(currentConfigApp->m_full_screen); + m_ui->exclusiveFullscreenCheckbox->setEnabled(currentConfigApp->m_full_screen); + m_ui->exclusiveFullscreenCheckbox->setChecked(currentConfigApp->m_exclusive_full_screen); m_ui->rumbleCheckBox->setChecked(currentConfigApp->m_haptic); m_ui->touchComboBox->setCurrentIndex(currentConfigApp->m_touch_scheme); m_ui->transitionTypeComboBox->setCurrentIndex(currentConfigApp->m_transition_type); @@ -231,6 +272,11 @@ void CMainDialog::UpdateInterface() m_ui->texturePath->setEnabled(currentConfigApp->m_texture_load); m_ui->texturePathOpen->setEnabled(currentConfigApp->m_texture_load); + + m_ui->aspectRatioComboBox->setCurrentIndex(currentConfigApp->m_aspect_ratio); + m_ui->xResSpinBox->setValue(currentConfigApp->m_x_res); + m_ui->yResSpinBox->setValue(currentConfigApp->m_y_res); + m_ui->framerateSpinBox->setValue(static_cast(std::round(1000.0f / currentConfigApp->m_frame_delta))); } // FUNCTION: CONFIG 0x004045e0 @@ -301,6 +347,14 @@ void CMainDialog::OnCheckboxMusic(bool checked) void CMainDialog::OnCheckboxFullscreen(bool checked) { currentConfigApp->m_full_screen = checked; + m_ui->exclusiveFullscreenCheckbox->setEnabled(checked); + m_modified = true; + UpdateInterface(); +} + +void CMainDialog::OnCheckboxExclusiveFullscreen(bool checked) +{ + currentConfigApp->m_exclusive_full_screen = checked; m_modified = true; UpdateInterface(); } @@ -444,3 +498,59 @@ void CMainDialog::TexturePathEdited() } UpdateInterface(); } + +void CMainDialog::AspectRatioChanged(int index) +{ + currentConfigApp->m_aspect_ratio = index; + EnsureAspectRatio(); + m_modified = true; + UpdateInterface(); +} + +void CMainDialog::XResChanged(int i) +{ + currentConfigApp->m_x_res = i; + m_modified = true; + UpdateInterface(); +} + +void CMainDialog::YResChanged(int i) +{ + currentConfigApp->m_y_res = i; + EnsureAspectRatio(); + m_modified = true; + UpdateInterface(); +} + +void CMainDialog::EnsureAspectRatio() +{ + if (currentConfigApp->m_aspect_ratio != 3) { + m_ui->xResSpinBox->setReadOnly(true); + switch (currentConfigApp->m_aspect_ratio) { + case 0: { + float standardAspect = 4.0f / 3.0f; + currentConfigApp->m_x_res = static_cast(std::round((currentConfigApp->m_y_res) * standardAspect)); + break; + } + case 1: { + float wideAspect = 16.0f / 9.0f; + currentConfigApp->m_x_res = static_cast(std::round((currentConfigApp->m_y_res) * wideAspect)); + break; + } + case 2: { + currentConfigApp->m_x_res = currentConfigApp->m_y_res; + break; + } + } + } + else { + m_ui->xResSpinBox->setReadOnly(false); + } +} + +void CMainDialog::FramerateChanged(int i) +{ + currentConfigApp->m_frame_delta = (1000.0f / static_cast(i)); + m_modified = true; + UpdateInterface(); +} diff --git a/CONFIG/MainDlg.h b/CONFIG/MainDlg.h index 40156790..ece4dbfd 100644 --- a/CONFIG/MainDlg.h +++ b/CONFIG/MainDlg.h @@ -42,6 +42,7 @@ private slots: void OnRadiobuttonTextureHighQuality(bool checked); void OnCheckboxMusic(bool checked); void OnCheckboxFullscreen(bool checked); + void OnCheckboxExclusiveFullscreen(bool checked); void OnCheckboxRumble(bool checked); void OnCheckboxTexture(bool checked); void TouchControlsChanged(int index); @@ -57,6 +58,11 @@ private slots: void MaxActorsChanged(int value); void SelectTexturePathDialog(); void TexturePathEdited(); + void XResChanged(int i); + void YResChanged(int i); + void AspectRatioChanged(int index); + void EnsureAspectRatio(); + void FramerateChanged(int i); }; // SYNTHETIC: CONFIG 0x00403de0 diff --git a/CONFIG/config.cpp b/CONFIG/config.cpp index aaca44e7..d0f1dda6 100644 --- a/CONFIG/config.cpp +++ b/CONFIG/config.cpp @@ -67,9 +67,14 @@ bool CConfigApp::InitInstance() return FALSE; } SDL_DestroyWindow(window); + m_aspect_ratio = 0; + m_x_res = 640; + m_y_res = 480; + m_frame_delta = 10.0f; m_driver = NULL; m_device = NULL; m_full_screen = TRUE; + m_exclusive_full_screen = FALSE; m_transition_type = 3; // 3: Mosaic m_wide_view_angle = TRUE; m_use_joystick = TRUE; @@ -84,6 +89,7 @@ bool CConfigApp::InitInstance() m_texture_path = "/textures/"; int totalRamMiB = SDL_GetSystemRAM(); if (totalRamMiB < 12) { + m_ram_quality_limit = 2; m_3d_sound = FALSE; m_model_quality = 0; m_texture_quality = 1; @@ -91,6 +97,7 @@ bool CConfigApp::InitInstance() m_max_actors = 5; } else if (totalRamMiB < 20) { + m_ram_quality_limit = 1; m_3d_sound = FALSE; m_model_quality = 1; m_texture_quality = 1; @@ -98,6 +105,7 @@ bool CConfigApp::InitInstance() m_max_actors = 10; } else { + m_ram_quality_limit = 0; m_model_quality = 2; m_3d_sound = TRUE; m_texture_quality = 1; @@ -158,6 +166,7 @@ bool CConfigApp::ReadRegisterSettings() m_display_bit_depth = iniparser_getint(dict, "isle:Display Bit Depth", -1); m_flip_surfaces = iniparser_getboolean(dict, "isle:Flip Surfaces", m_flip_surfaces); m_full_screen = iniparser_getboolean(dict, "isle:Full Screen", m_full_screen); + m_exclusive_full_screen = iniparser_getboolean(dict, "isle:Exclusive Full Screen", m_exclusive_full_screen); m_transition_type = iniparser_getint(dict, "isle:Transition Type", m_transition_type); m_touch_scheme = iniparser_getint(dict, "isle:Touch Scheme", m_touch_scheme); m_3d_video_ram = iniparser_getboolean(dict, "isle:Back Buffers in Video RAM", m_3d_video_ram); @@ -174,6 +183,10 @@ bool CConfigApp::ReadRegisterSettings() m_max_actors = iniparser_getint(dict, "isle:Max Allowed Extras", m_max_actors); m_texture_load = iniparser_getboolean(dict, "extensions:texture loader", m_texture_load); m_texture_path = iniparser_getstring(dict, "texture loader:texture path", m_texture_path.c_str()); + m_aspect_ratio = iniparser_getint(dict, "isle:Aspect Ratio", m_aspect_ratio); + m_x_res = iniparser_getint(dict, "isle:Horizontal Resolution", m_x_res); + m_y_res = iniparser_getint(dict, "isle:Vertical Resolution", m_y_res); + m_frame_delta = iniparser_getdouble(dict, "isle:Frame Delta", m_frame_delta); iniparser_freedict(dict); return true; } @@ -230,7 +243,7 @@ bool CConfigApp::ValidateSettings() is_modified = TRUE; } - if (m_max_lod < 0.0f || m_max_lod > 5.0f) { + if (m_max_lod < 0.0f || m_max_lod > 6.0f) { m_max_lod = 3.5f; is_modified = TRUE; } @@ -326,6 +339,7 @@ void CConfigApp::WriteRegisterSettings() const SetIniInt(dict, "isle:Display Bit Depth", m_display_bit_depth); SetIniBool(dict, "isle:Flip Surfaces", m_flip_surfaces); SetIniBool(dict, "isle:Full Screen", m_full_screen); + SetIniBool(dict, "isle:Exclusive Full Screen", m_exclusive_full_screen); SetIniBool(dict, "isle:Wide View Angle", m_wide_view_angle); SetIniInt(dict, "isle:Transition Type", m_transition_type); @@ -350,6 +364,11 @@ void CConfigApp::WriteRegisterSettings() const iniparser_set(dict, "isle:Max LOD", std::to_string(m_max_lod).c_str()); SetIniInt(dict, "isle:Max Allowed Extras", m_max_actors); + SetIniInt(dict, "isle:Aspect Ratio", m_aspect_ratio); + SetIniInt(dict, "isle:Horizontal Resolution", m_x_res); + SetIniInt(dict, "isle:Vertical Resolution", m_y_res); + iniparser_set(dict, "isle:Frame Delta", std::to_string(m_frame_delta).c_str()); + #undef SetIniBool #undef SetIniInt diff --git a/CONFIG/config.h b/CONFIG/config.h index 796a5659..ad3321ac 100644 --- a/CONFIG/config.h +++ b/CONFIG/config.h @@ -59,12 +59,17 @@ class CConfigApp { // DECLARE_MESSAGE_MAP() public: + int m_aspect_ratio; + int m_x_res; + int m_y_res; + float m_frame_delta; LegoDeviceEnumerate* m_device_enumerator; MxDriver* m_driver; Direct3DDeviceInfo* m_device; int m_display_bit_depth; bool m_flip_surfaces; bool m_full_screen; + bool m_exclusive_full_screen; int m_transition_type; bool m_3d_video_ram; bool m_wide_view_angle; @@ -85,6 +90,7 @@ class CConfigApp { float m_max_lod; int m_max_actors; int m_touch_scheme; + int m_ram_quality_limit; }; extern CConfigApp g_theApp; diff --git a/CONFIG/res/maindialog.ui b/CONFIG/res/maindialog.ui index f51f70a5..5a0d3b31 100644 --- a/CONFIG/res/maindialog.ui +++ b/CONFIG/res/maindialog.ui @@ -6,8 +6,8 @@ 0 0 - 550 - 700 + 600 + 480 @@ -68,654 +68,861 @@ - - - - 0 - 0 - + + + 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 50 - 16777215 - - - - Open - - - - - - - - 0 - 0 - - - - - 50 - 16777215 - - - - Open - - - - - - - - 0 - 0 - - - - Save Path: - - - Qt::PlainText - - - - - - - Path to the game data files. -Set this to the CD image root. - - - - - - - Folder where save files are kept. - - - - - - - - 0 - 0 - - - - Data Path: - - - Qt::PlainText - - - - - - - - - - - 0 - 80 - - - - - 0 - - - 0 - - - - - - 0 - 0 - - - - Maximum number of LEGO actors to exist in the world at a time. -The game will gradually increase the number of actors until this maximum is reached and while performance is acceptable. - - - Maximum Actors (5..40) - - + + + Game + + + + - - - - 0 - 0 - - - - 5 - - - 40 - - - 5 - - - 20 - - - 20 - - - false - - - Qt::Horizontal - - - QSlider::NoTicks - - - 5 - - - - - - - - 0 - 0 - - - - - 15 - 0 - - - - 20 - - - - - - - - - - - 0 - 0 - - - - - 0 - 70 - - - - Maximum Level of Detail (LOD). -A higher setting will cause higher quality textures to be drawn regardless of distance. - - - Maximum LOD - - - - - - - 0 - 0 - - - - 60 - - - 5 - - - 10 - - - 35 - - - false - - - Qt::Horizontal - - - QSlider::NoTicks - - - 10 - - - - - - - - 0 - 0 - - - - - 15 - 0 - - - - 35 - - - - - - - - - - - 0 - 0 - - - - Set 3D model detail level. - - - Island Model Quality - - - - + - Broken, not recommended. - - - color: rgb(255, 0, 0); + Enable 3D positional audio effects. - Low - BROKEN! + 3D Sound - - - Medium + + + Enable in-game background music. - - - - - High + Music - - - - - - true - - - - 0 - 0 - - - - Set texture detail level. - - - Island Texture Quality - - - false - - - - 0 + + + + + Qt::Orientation::Vertical - - 0 + + + 20 + 40 + - - - - Fast - - - - - - - High - - - - - - - - - - - - - - 0 - 0 - - - - - 0 - - - 0 - - - - - Enable 3D positional audio effects. - - - 3D Sound - - - - - - - Enable in-game background music. - - - Music - - - - - - - Toggle fullscreen display mode. - - - Fullscreen - - - - - - - true - - - Enable controller rumble. - - - Rumble - - - true - - - - - - - - - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - Sets the transition effect to be used in game. - - - Transition Type - - - - - - Mosaic - - - 3 - - - - Idle - Broken - - - - - No Animation - - - - - Dissolve - - - - + + + + + + + 0 + 0 + + + + Sets the transition effect to be used in game. + + + Transition Type + + + + + Mosaic - - - - Wipe Down + + 3 - - - - Windows + + + Idle - Broken + + + + + No Animation + + + + + Dissolve + + + + + Mosaic + + + + + Wipe Down + + + + + Windows + + + + + Unknown - Broken + + + + + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + + + Folder where save files are kept. - - - - Unknown - Broken + + + + + + Path to the game data files. +Set this to the CD image root. - - - - - - - - - - <html><head/><body><p><span style=" font-weight:600;">Virtual Gamepad (Recommended):</span> Slide your finger to move and turn.</p><p><span style=" font-weight:600;">Virtual Arrow Keys:</span> Tap screen areas to move. The top moves forward, the bottom turns or moves back.</p><p><span style=" font-weight:600;">Virtual Mouse:</span> Emulates classic mouse controls with touch.</p></body></html> - - - Touch Control Scheme - - - - - - 2 - - - - Virtual Mouse + + + + + + + 0 + 0 + - - - Virtual Arrow Keys + Data Path: + + + Qt::TextFormat::PlainText + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + - - - Virtual Gamepad + Open - - - - - - - - - - - - - Texture Loader Extension - - - - - - false - - - Path to texture replacements. - - - textures/ - - - - - - - false - - - - 0 - 0 - - - - - 50 - 16777215 - - - - Open - - - - - - - Enabled - - - - - - - - - - - 0 - 0 - - - - 3D graphics device used to render the game. - - - Graphics Devices - - - false - - - - 6 - - - 6 - - - 6 - - - 6 - - - - - true - - - - 0 - 0 - - - - - 16777215 - 100 - - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::SelectItems - - - - + + + + + + + 0 + 0 + + + + Save Path: + + + Qt::TextFormat::PlainText + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + Open + + + + + + + + + + + Graphics + + + + + + + 0 + 0 + + + + + 0 + 70 + + + + Maximum Level of Detail (LOD). +A higher setting will cause higher quality textures to be drawn regardless of distance. + + + Maximum LOD + + + + + + + 0 + 0 + + + + 60 + + + 5 + + + 10 + + + 35 + + + false + + + Qt::Orientation::Horizontal + + + QSlider::TickPosition::NoTicks + + + 10 + + + + + + + + 0 + 0 + + + + + 15 + 0 + + + + 35 + + + + + + + + + + + 0 + 0 + + + + 3D graphics device used to render the game. + + + Graphics Devices + + + false + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + true + + + + 0 + 0 + + + + + 16777215 + 100 + + + + QAbstractItemView::EditTrigger::NoEditTriggers + + + true + + + QAbstractItemView::SelectionBehavior::SelectItems + + + + + + + + + + true + + + + 0 + 0 + + + + Set texture detail level. + + + Island Texture Quality + + + false + + + + 0 + + + 0 + + + + + Fast + + + + + + + High + + + + + + + + + + + 0 + 0 + + + + Maximum number of LEGO actors to exist in the world at a time. +The game will gradually increase the number of actors until this maximum is reached and while performance is acceptable. + + + Maximum Actors + + + + + + + 0 + 0 + + + + 5 + + + 40 + + + 5 + + + 20 + + + 20 + + + false + + + Qt::Orientation::Horizontal + + + QSlider::TickPosition::NoTicks + + + 5 + + + + + + + + 0 + 0 + + + + + 15 + 0 + + + + 20 + + + + + + + + + + + 0 + 0 + + + + Set 3D model detail level. + + + Island Model Quality + + + + + + Broken, not recommended. + + + color: rgb(255, 0, 0); + + + Low - BROKEN! + + + + + + + Medium + + + + + + + High + + + + + + + + + + + Display + + + + + + General + + + + + + <html><head/><body><p>Maximum framerate. Values above 100fps are untested.</p></body></html> + + + fps + + + Max Framerate: + + + 200 + + + 100 + + + + + + + + + Toggle fullscreen display mode. + + + Fullscreen + + + + + + + false + + + Grants the app full control of the display for better performance and lower input lag. May cause slower alt-tabbing. + + + Exclusive Fullscreen + + + + + + + + + + + + Windowed Resolution + + + + + + <html><head/><body><p>The aspect ratio you intend to use.<br/>Select <span style=" font-weight:700;">Custom</span> to define your own width and height.<br/>Has no effect on the game itself.</p></body></html> + + + 0 + + + + Standard (4:3) + + + + + Widescreen (16:9) + + + + + Square (1:1) + + + + + Custom + + + + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Horizontal resolution. </p><p>Locked to aspect ratio, unless <span style=" font-weight:700;">Custom</span> is select as the aspect ratio.</p></body></html> + + + Qt::AlignmentFlag::AlignCenter + + + true + + + 10000 + + + 640 + + + 10 + + + + + + + + 0 + 0 + + + + x + + + Qt::AlignmentFlag::AlignCenter + + + + + + + true + + + + 0 + 0 + + + + <html><head/><body><p>Vertical resolution. </p><p>If an aspect ratio other than <span style=" font-weight:700;">Custom</span> is selected, this directly affects the horizontal resolution.</p></body></html> + + + Qt::AlignmentFlag::AlignCenter + + + 10000 + + + 480 + + + + + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + Controls + + + + + + <html><head/><body><p><span style=" font-weight:600;">Virtual Gamepad (Recommended):</span> Slide your finger to move and turn.</p><p><span style=" font-weight:600;">Virtual Arrow Keys:</span> Tap screen areas to move. The top moves forward, the bottom turns or moves back.</p><p><span style=" font-weight:600;">Virtual Mouse:</span> Emulates classic mouse controls with touch.</p></body></html> + + + Touch Control Scheme + + + + + + 2 + + + + Virtual Mouse + + + + + Virtual Arrow Keys + + + + + Virtual Gamepad + + + + + + + + + + + true + + + Enable controller rumble. + + + Rumble + + + true + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + Extensions + + + + + + Settings for Texture Loader extension. + + + Texture Loader Extension + + + + + + Enabled + + + + + + + false + + + Path to texture replacements. + + + textures/ + + + + + + + false + + + + 0 + 0 + + + + + 50 + 16777215 + + + + Open + + + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + @@ -784,10 +991,14 @@ A higher setting will cause higher quality textures to be drawn regardless of di + tabWidget dataPath dataPathOpen savePath savePathOpen + transitionTypeComboBox + sound3DCheckBox + musicCheckBox textureQualityFastRadioButton textureQualityHighRadioButton modelQualityLowRadioButton @@ -795,9 +1006,18 @@ A higher setting will cause higher quality textures to be drawn regardless of di modelQualityHighRadioButton maxLoDSlider maxActorsSlider - sound3DCheckBox - musicCheckBox devicesList + fullscreenCheckBox + exclusiveFullscreenCheckbox + framerateSpinBox + aspectRatioComboBox + xResSpinBox + yResSpinBox + touchComboBox + rumbleCheckBox + textureCheckBox + texturePath + texturePathOpen okButton launchButton cancelButton diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index 46e1c2e2..10894633 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -175,6 +175,10 @@ IsleApp::IsleApp() m_cursorSensitivity = 4; m_touchScheme = LegoInputManager::e_gamepad; m_haptic = TRUE; + m_xRes = 640; + m_yRes = 480; + m_frameRate = 100.0f; + m_exclusiveFullScreen = FALSE; } // FUNCTION: ISLE 0x4011a0 @@ -888,6 +892,15 @@ MxResult IsleApp::SetupWindow() #endif window = SDL_CreateWindowWithProperties(props); + + if (m_exclusiveFullScreen && m_fullScreen) { + SDL_DisplayMode closestMode; + SDL_DisplayID displayID = SDL_GetDisplayForWindow(window); + if (SDL_GetClosestFullscreenDisplayMode(displayID, m_xRes, m_yRes, m_frameRate, true, &closestMode)) { + SDL_SetWindowFullscreenMode(window, &closestMode); + } + } + #ifdef MINIWIN m_windowHandle = reinterpret_cast(window); #else @@ -1040,6 +1053,7 @@ bool IsleApp::LoadConfig() iniparser_set(dict, "isle:Flip Surfaces", m_flipSurfaces ? "true" : "false"); iniparser_set(dict, "isle:Full Screen", m_fullScreen ? "true" : "false"); + iniparser_set(dict, "isle:Exclusive Full Screen", m_exclusiveFullScreen ? "true" : "false"); iniparser_set(dict, "isle:Wide View Angle", m_wideViewAngle ? "true" : "false"); iniparser_set(dict, "isle:3DSound", m_use3dSound ? "true" : "false"); @@ -1058,6 +1072,9 @@ bool IsleApp::LoadConfig() iniparser_set(dict, "isle:Transition Type", SDL_itoa(m_transitionType, buf, 10)); iniparser_set(dict, "isle:Touch Scheme", SDL_itoa(m_touchScheme, buf, 10)); iniparser_set(dict, "isle:Haptic", m_haptic ? "true" : "false"); + iniparser_set(dict, "isle:Horizontal Resolution", SDL_itoa(m_xRes, buf, 10)); + iniparser_set(dict, "isle:Vertical Resolution", SDL_itoa(m_yRes, buf, 10)); + iniparser_set(dict, "isle:Frame Delta", SDL_itoa(m_frameDelta, buf, 10)); #ifdef EXTENSIONS iniparser_set(dict, "extensions", NULL); @@ -1100,6 +1117,7 @@ bool IsleApp::LoadConfig() m_flipSurfaces = iniparser_getboolean(dict, "isle:Flip Surfaces", m_flipSurfaces); m_fullScreen = iniparser_getboolean(dict, "isle:Full Screen", m_fullScreen); + m_exclusiveFullScreen = iniparser_getboolean(dict, "isle:Exclusive Full Screen", m_exclusiveFullScreen); m_wideViewAngle = iniparser_getboolean(dict, "isle:Wide View Angle", m_wideViewAngle); m_use3dSound = iniparser_getboolean(dict, "isle:3DSound", m_use3dSound); m_useMusic = iniparser_getboolean(dict, "isle:Music", m_useMusic); @@ -1128,6 +1146,13 @@ bool IsleApp::LoadConfig() (MxTransitionManager::TransitionType) iniparser_getint(dict, "isle:Transition Type", m_transitionType); m_touchScheme = (LegoInputManager::TouchScheme) iniparser_getint(dict, "isle:Touch Scheme", m_touchScheme); m_haptic = iniparser_getboolean(dict, "isle:Haptic", m_haptic); + m_xRes = iniparser_getint(dict, "isle:Horizontal Resolution", m_xRes); + m_yRes = iniparser_getint(dict, "isle:Vertical Resolution", m_yRes); + if (!m_fullScreen) { + m_videoParam.GetRect() = MxRect32(0, 0, (m_xRes - 1), (m_yRes - 1)); + } + m_frameRate = (1000.0f / iniparser_getdouble(dict, "isle:Frame Delta", m_frameDelta)); + m_frameDelta = static_cast(std::round(iniparser_getdouble(dict, "isle:Frame Delta", m_frameDelta))); const char* deviceId = iniparser_getstring(dict, "isle:3D Device ID", NULL); if (deviceId != NULL) { diff --git a/ISLE/isleapp.h b/ISLE/isleapp.h index f175cecf..4a23ea23 100644 --- a/ISLE/isleapp.h +++ b/ISLE/isleapp.h @@ -72,7 +72,7 @@ class IsleApp { char* m_cdPath; // 0x04 char* m_deviceId; // 0x08 char* m_savePath; // 0x0c - MxS32 m_fullScreen; // 0x10 + MxBool m_fullScreen; // 0x10 MxS32 m_flipSurfaces; // 0x14 MxS32 m_backBuffersInVram; // 0x18 MxS32 m_using8bit; // 0x1c @@ -107,6 +107,10 @@ class IsleApp { MxTransitionManager::TransitionType m_transitionType; LegoInputManager::TouchScheme m_touchScheme; MxBool m_haptic; + MxS32 m_xRes; + MxS32 m_yRes; + MxFloat m_frameRate; + MxBool m_exclusiveFullScreen; }; extern IsleApp* g_isle; From bf3820c054fb1a069941af379506746360694991 Mon Sep 17 00:00:00 2001 From: VoxelTek <53562267+VoxelTek@users.noreply.github.com> Date: Wed, 16 Jul 2025 18:22:36 +1000 Subject: [PATCH 24/25] Fix debug mode when OpenGL is set as graphics device (#615) --- miniwin/src/d3drm/backends/opengl1/renderer.cpp | 6 ++++++ miniwin/src/d3drm/backends/opengles2/renderer.cpp | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/miniwin/src/d3drm/backends/opengl1/renderer.cpp b/miniwin/src/d3drm/backends/opengl1/renderer.cpp index e537a396..88b3b81b 100644 --- a/miniwin/src/d3drm/backends/opengl1/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengl1/renderer.cpp @@ -175,6 +175,7 @@ static Uint32 UploadTextureData(SDL_Surface* src, bool useNPOT, bool isUI, float Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) { + SDL_GL_MakeCurrent(DDWindow, m_context); auto texture = static_cast(iTexture); auto surface = static_cast(texture->m_surface); @@ -314,6 +315,7 @@ Uint32 OpenGL1Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGr HRESULT OpenGL1Renderer::BeginFrame() { + SDL_GL_MakeCurrent(DDWindow, m_context); GL11_BeginFrame((Matrix4x4*) &m_projection[0][0]); int lightIdx = 0; @@ -361,6 +363,7 @@ HRESULT OpenGL1Renderer::FinalizeFrame() void OpenGL1Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform) { + SDL_GL_MakeCurrent(DDWindow, m_context); m_width = width; m_height = height; m_viewportTransform = viewportTransform; @@ -371,12 +374,14 @@ void OpenGL1Renderer::Resize(int width, int height, const ViewportTransform& vie void OpenGL1Renderer::Clear(float r, float g, float b) { + SDL_GL_MakeCurrent(DDWindow, m_context); m_dirty = true; GL11_Clear(r, g, b); } void OpenGL1Renderer::Flip() { + SDL_GL_MakeCurrent(DDWindow, m_context); if (m_dirty) { SDL_GL_SwapWindow(DDWindow); m_dirty = false; @@ -385,6 +390,7 @@ void OpenGL1Renderer::Flip() void OpenGL1Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) { + SDL_GL_MakeCurrent(DDWindow, m_context); m_dirty = true; float left = -m_viewportTransform.offsetX / m_viewportTransform.scale; diff --git a/miniwin/src/d3drm/backends/opengles2/renderer.cpp b/miniwin/src/d3drm/backends/opengles2/renderer.cpp index 50e43d02..e1c86a62 100644 --- a/miniwin/src/d3drm/backends/opengles2/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengles2/renderer.cpp @@ -390,6 +390,7 @@ void OpenGLES2Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) { + SDL_GL_MakeCurrent(DDWindow, m_context); auto texture = static_cast(iTexture); auto surface = static_cast(texture->m_surface); @@ -484,6 +485,7 @@ Uint32 OpenGLES2Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* mesh HRESULT OpenGLES2Renderer::BeginFrame() { + SDL_GL_MakeCurrent(DDWindow, m_context); m_dirty = true; glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); @@ -599,6 +601,7 @@ HRESULT OpenGLES2Renderer::FinalizeFrame() void OpenGLES2Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform) { + SDL_GL_MakeCurrent(DDWindow, m_context); m_width = width; m_height = height; m_viewportTransform = viewportTransform; @@ -639,6 +642,7 @@ void OpenGLES2Renderer::Resize(int width, int height, const ViewportTransform& v void OpenGLES2Renderer::Clear(float r, float g, float b) { + SDL_GL_MakeCurrent(DDWindow, m_context); m_dirty = true; glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); @@ -651,6 +655,7 @@ void OpenGLES2Renderer::Clear(float r, float g, float b) void OpenGLES2Renderer::Flip() { + SDL_GL_MakeCurrent(DDWindow, m_context); if (!m_dirty) { return; } @@ -714,6 +719,7 @@ void OpenGLES2Renderer::Flip() void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) { + SDL_GL_MakeCurrent(DDWindow, m_context); m_dirty = true; glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); From df84f4d7a597e2dca935b7e50d7f53b98636d65e Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Thu, 17 Jul 2025 00:32:37 +0900 Subject: [PATCH 25/25] =?UTF-8?q?=F0=9F=A9=B9=20fix:=20use=20actual=20tran?= =?UTF-8?q?sparent=20pixel=20if=20surface=20supports=20alpha=20channel=20(?= =?UTF-8?q?#616)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LEGO1/omni/src/video/mxdisplaysurface.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index a6c2d086..2248a0ad 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -1198,6 +1198,8 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::CreateCursorSurface(const CursorBitmap* p_ } MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + MxBool isAlphaAvailable = ((ddsd.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == DDPF_ALPHAPIXELS) && + (ddsd.ddpfPixelFormat.dwRGBAlphaBitMask != 0); ddsd.dwWidth = p_cursorBitmap->width; ddsd.dwHeight = p_cursorBitmap->height; @@ -1260,7 +1262,12 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::CreateCursorSurface(const CursorBitmap* p_ MxS32 pixel; if (!isOpaque) { - pixel = RGB8888_CREATE(0xff, 0, 0xff, 0); // Transparent pixel + if (isAlphaAvailable) { + pixel = RGB8888_CREATE(0, 0, 0, 0); + } + else { + pixel = RGB8888_CREATE(0xff, 0, 0xff, 0); + } // Transparent pixel } else { pixel = isBlack ? RGB8888_CREATE(0, 0, 0, 0xff) : RGB8888_CREATE(0xff, 0xff, 0xff, 0xff); @@ -1290,10 +1297,12 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::CreateCursorSurface(const CursorBitmap* p_ break; } default: { - DDCOLORKEY colorkey; - colorkey.dwColorSpaceHighValue = RGB8888_CREATE(0xff, 0, 0xff, 0); - colorkey.dwColorSpaceLowValue = RGB8888_CREATE(0xff, 0, 0xff, 0); - newSurface->SetColorKey(DDCKEY_SRCBLT, &colorkey); + if (!isAlphaAvailable) { + DDCOLORKEY colorkey; + colorkey.dwColorSpaceHighValue = RGB8888_CREATE(0xff, 0, 0xff, 0); + colorkey.dwColorSpaceLowValue = RGB8888_CREATE(0xff, 0, 0xff, 0); + newSurface->SetColorKey(DDCKEY_SRCBLT, &colorkey); + } break; } }