@@ -1563,6 +1563,74 @@ void _declspec(naked) HOOK_CStreaming_AreAnimsUsedByRequestedModels()
15631563 }
15641564}
15651565
1566+ // ////////////////////////////////////////////////////////////////////////////////////////
1567+ //
1568+ // CTrain::ProcessControl
1569+ //
1570+ // This hook overwrites the logic to wrap the train's rail distance, because in the
1571+ // original game code this could cause an infinite loop
1572+ //
1573+ // ////////////////////////////////////////////////////////////////////////////////////////
1574+ // 0x6F8F83 | 88 9E CA 05 00 00 | mov [esi + 5CAh], bl
1575+ // >>> 0x6F8F89 | D9 86 A8 05 00 00 | fld dword ptr [esi + 5A8h]
1576+ // 0x6F8F8F | D8 1D 50 8B 85 00 | fcomp ds: __real @00000000
1577+ #define HOOKPOS_CTrain__ProcessControl 0x6F8F89
1578+ #define HOOKSIZE_CTrain__ProcessControl 6
1579+ static DWORD CONTINUE_CTrain__ProcessControl = 0x6F8FE5 ;
1580+
1581+ // 0xC37FEC; float RailTrackLength[NUM_TRACKS]
1582+ static float * RailTrackLength = reinterpret_cast <float *>(0xC37FEC );
1583+
1584+ static void _cdecl WrapTrainRailDistance (CVehicleSAInterface* train)
1585+ {
1586+ // Check if the train is driving on a valid rail track (id < NUM_TRACKS)
1587+ if (train->m_ucRailTrackID >= 4 )
1588+ {
1589+ train->m_fTrainRailDistance = 0 .0f ;
1590+ return ;
1591+ }
1592+
1593+ // Check if the current rail track has a valid length (>= 1.0f)
1594+ const float railTrackLength = RailTrackLength[train->m_ucRailTrackID ];
1595+
1596+ if (railTrackLength < 1 .0f )
1597+ {
1598+ train->m_fTrainRailDistance = 0 .0f ;
1599+ return ;
1600+ }
1601+
1602+ // Check if the current rail distance is in the interval [0, railTrackLength)
1603+ float railDistance = train->m_fTrainRailDistance ;
1604+
1605+ if (railDistance >= 0 .0f && railDistance < railTrackLength)
1606+ return ;
1607+
1608+ // Wrap the current rail distance
1609+ if (railDistance > 0 .0f )
1610+ {
1611+ railDistance = std::fmodf (railDistance, railTrackLength);
1612+ }
1613+ else
1614+ {
1615+ railDistance = railTrackLength - std::fmodf (std::fabsf (railDistance), railTrackLength);
1616+ }
1617+
1618+ train->m_fTrainRailDistance = railDistance;
1619+ }
1620+
1621+ static void _declspec (naked) HOOK_CTrain__ProcessControl()
1622+ {
1623+ _asm
1624+ {
1625+ pushad
1626+ push esi // CVehicleSAInterface*
1627+ call WrapTrainRailDistance
1628+ add esp, 4
1629+ popad
1630+ jmp CONTINUE_CTrain__ProcessControl
1631+ }
1632+ }
1633+
15661634// ////////////////////////////////////////////////////////////////////////////////////////
15671635//
15681636// Setup hooks for CrashFixHacks
@@ -1612,6 +1680,7 @@ void CMultiplayerSA::InitHooks_CrashFixHacks()
16121680 EZHookInstall (CTaskComplexCarSlowBeDraggedOut_CreateFirstSubTask);
16131681 EZHookInstallChecked (printf);
16141682 EZHookInstallChecked (RwMatrixMultiply);
1683+ EZHookInstall (CTrain__ProcessControl);
16151684
16161685 // Install train crossing crashfix (the temporary variable is required for the template logic)
16171686 void (*temp)() = HOOK_TrainCrossingBarrierCrashFix<RETURN_CObject_Destructor_TrainCrossing_Check, RETURN_CObject_Destructor_TrainCrossing_Invalid>;
0 commit comments