Advertisement
Guest User

Untitled

a guest
May 29th, 2017
557
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 103.30 KB | None | 0 0
  1. /*****************************************************************************
  2. *
  3. * PROJECT: Multi Theft Auto v1.0
  4. * (Shared logic for modifications)
  5. * LICENSE: See LICENSE in the top level directory
  6. * FILE: mods/shared_logic/CClientVehicle.cpp
  7. * PURPOSE: Vehicle entity class
  8. * DEVELOPERS: Christian Myhre Lundheim <>
  9. * Ed Lyons <eai@opencoding.net>
  10. * Oliver Brown <>
  11. * Kent Simon <>
  12. * Jax <>
  13. * Cecill Etheredge <ijsf@gmx.net>
  14. * Kevin Whiteside <kevuwk@gmail.com>
  15. * Chris McArthur <>
  16. * Derek Abdine <>
  17. * Stanislav Bobrov <lil_toady@hotmail.com>
  18. * Alberto Alonso <rydencillo@gmail.com>
  19. *
  20. *****************************************************************************/
  21.  
  22. #include "StdInc.h"
  23.  
  24. using std::list;
  25.  
  26. extern CClientGame* g_pClientGame;
  27.  
  28.  
  29. // To hide the ugly "pointer truncation from DWORD* to unsigned long warning
  30. #pragma warning(disable:4311)
  31.  
  32. // Maximum distance between current position and target position (for interpolation)
  33. // before we disable interpolation and warp to the position instead
  34. #define VEHICLE_INTERPOLATION_WARP_THRESHOLD 20
  35.  
  36. CClientVehicle::CClientVehicle ( CClientManager* pManager, ElementID ID, unsigned short usModel ) : CClientStreamElement ( pManager->GetVehicleStreamer (), ID )
  37. {
  38. // Initialize members
  39. m_pManager = pManager;
  40. m_pObjectManager = m_pManager->GetObjectManager ();
  41. m_pVehicleManager = pManager->GetVehicleManager ();
  42. m_pModelRequester = pManager->GetModelRequestManager ();
  43. m_usModel = usModel;
  44. m_eVehicleType = CClientVehicleManager::GetVehicleType ( usModel );
  45. m_bHasDamageModel = CClientVehicleManager::HasDamageModel ( m_eVehicleType );
  46. m_pVehicle = NULL;
  47. m_pUpgrades = new CVehicleUpgrades ( this );
  48. m_pClump = NULL;
  49. #if WITH_VEHICLE_HANDLING
  50. m_pOriginalHandlingEntry = g_pGame->GetHandlingManager ()->GetOriginalHandlingData ( static_cast < eVehicleTypes > ( usModel ) );
  51. m_pHandlingEntry = g_pGame->GetHandlingManager ()->CreateHandlingData ();
  52. m_pHandlingEntry->ApplyHandlingData ( (CHandlingEntry*)m_pOriginalHandlingEntry );
  53. #endif
  54.  
  55. SetTypeName ( "vehicle" );
  56.  
  57. // Grab the model info and the bounding box
  58. m_pModelInfo = g_pGame->GetModelInfo ( usModel );
  59. m_ucMaxPassengers = CClientVehicleManager::GetMaxPassengerCount ( usModel );
  60.  
  61. // Set our default properties
  62. m_pDriver = NULL;
  63. m_pOccupyingDriver = NULL;
  64. memset ( m_pPassengers, 0, sizeof ( m_pPassengers ) );
  65. memset ( m_pOccupyingPassengers, 0, sizeof ( m_pOccupyingPassengers ) );
  66. m_pPreviousLink = NULL;
  67. m_pNextLink = NULL;
  68. m_Matrix.vFront.fY = 1.0f;
  69. m_Matrix.vUp.fZ = 1.0f;
  70. m_Matrix.vRight.fX = 1.0f;
  71. m_MatrixLast = m_Matrix;
  72. m_dLastRotationTime = 0;
  73. m_fHealth = DEFAULT_VEHICLE_HEALTH;
  74. m_fTurretHorizontal = 0.0f;
  75. m_fTurretVertical = 0.0f;
  76. m_fGasPedal = 0.0f;
  77. m_bVisible = true;
  78. m_bIsCollisionEnabled = true;
  79. m_bEngineOn = false;
  80. m_bEngineBroken = false;
  81. m_bSireneOrAlarmActive = false;
  82. m_bLandingGearDown = true;
  83. m_usAdjustablePropertyValue = 0;
  84. m_bDoorsLocked = false;
  85. m_bDoorsUndamageable = false;
  86. m_bCanShootPetrolTank = true;
  87. m_bCanBeTargettedByHeatSeekingMissiles = true;
  88. m_bColorSaved = false;
  89. m_bIsFrozen = false;
  90. m_bScriptFrozen = false;
  91. m_bFrozenWaitingForGroundToLoad = false;
  92. m_fGroundCheckTolerance = 0.f;
  93. m_fObjectsAroundTolerance = 0.f;
  94. GetInitialDoorStates ( m_ucDoorStates );
  95. memset ( m_ucWheelStates, 0, sizeof ( m_ucWheelStates ) );
  96. memset ( m_ucPanelStates, 0, sizeof ( m_ucPanelStates ) );
  97. memset ( m_ucLightStates, 0, sizeof ( m_ucLightStates ) );
  98. m_bCanBeDamaged = true;
  99. m_bSyncUnoccupiedDamage = false;
  100. m_bScriptCanBeDamaged = true;
  101. m_bTyresCanBurst = true;
  102. m_ucOverrideLights = 0;
  103. m_pTowedVehicle = NULL;
  104. m_pTowedByVehicle = NULL;
  105. m_eWinchType = WINCH_NONE;
  106. m_pPickedUpWinchEntity = NULL;
  107. m_ucPaintjob = 3;
  108. m_fDirtLevel = 0.0f;
  109. m_bSmokeTrail = false;
  110. m_bJustBlewUp = false;
  111. m_ucAlpha = 255;
  112. m_bAlphaChanged = false;
  113. m_bBlowNextFrame = false;
  114. m_bIsOnGround = false;
  115. m_ulIllegalTowBreakTime = 0;
  116. m_bBlown = false;
  117. m_LastSyncedData = new SLastSyncedVehData;
  118. m_bIsDerailed = false;
  119. m_bIsDerailable = true;
  120. m_bTrainDirection = false;
  121. m_fTrainSpeed = 0.0f;
  122. m_bTaxiLightOn = false;
  123. m_vecGravity = CVector ( 0.0f, 0.0f, -1.0f );
  124. m_HeadLightColor = SColorRGBA ( 255, 255, 255, 255 );
  125. m_bHeliSearchLightVisible = false;
  126. m_fHeliRotorSpeed = 0.0f;
  127.  
  128. #ifdef MTA_DEBUG
  129. m_pLastSyncer = NULL;
  130. m_ulLastSyncTime = 0;
  131. m_szLastSyncType = "none";
  132. #endif
  133.  
  134. m_interp.rot.ulFinishTime = 0;
  135. m_interp.pos.ulFinishTime = 0;
  136. ResetInterpolation ();
  137.  
  138. // Check if we have landing gears
  139. m_bHasLandingGear = DoCheckHasLandingGear ();
  140. m_bHasAdjustableProperty = CClientVehicleManager::HasAdjustableProperty ( m_usModel );
  141.  
  142. // Add this vehicle to the vehicle list
  143. m_pVehicleManager->AddToList ( this );
  144. }
  145.  
  146.  
  147. CClientVehicle::~CClientVehicle ( void )
  148. {
  149. // Unreference us
  150. m_pManager->UnreferenceEntity ( this );
  151.  
  152. // Unlink any towing attachments
  153. if ( m_pTowedVehicle )
  154. m_pTowedVehicle->m_pTowedByVehicle = NULL;
  155. if ( m_pTowedByVehicle )
  156. m_pTowedByVehicle->m_pTowedVehicle = NULL;
  157.  
  158. AttachTo ( NULL );
  159.  
  160. // Remove all our projectiles
  161. RemoveAllProjectiles ();
  162.  
  163. // Destroy the vehicle
  164. Destroy ();
  165.  
  166. // Make sure we haven't requested any model that will make us crash
  167. // when it's done loading.
  168. m_pModelRequester->Cancel ( this, false );
  169.  
  170. // Unreference us from the driving player model (if any)
  171. if ( m_pDriver )
  172. {
  173. m_pDriver->SetVehicleInOutState ( VEHICLE_INOUT_NONE );
  174. UnpairPedAndVehicle( m_pDriver, this );
  175. }
  176.  
  177. // And the occupying ones eventually
  178. if ( m_pOccupyingDriver )
  179. {
  180. m_pOccupyingDriver->SetVehicleInOutState ( VEHICLE_INOUT_NONE );
  181. UnpairPedAndVehicle( m_pOccupyingDriver, this );
  182. }
  183.  
  184. // And the passenger models
  185. int i;
  186. for ( i = 0; i < (sizeof(m_pPassengers)/sizeof(CClientPed*)); i++ )
  187. {
  188. if ( m_pPassengers [i] )
  189. {
  190. m_pPassengers [i]->m_uiOccupiedVehicleSeat = 0;
  191. m_pPassengers [i]->SetVehicleInOutState ( VEHICLE_INOUT_NONE );
  192. UnpairPedAndVehicle( m_pPassengers [i], this );
  193. }
  194. }
  195.  
  196. // Occupying passenger models
  197. for ( i = 0; i < (sizeof(m_pOccupyingPassengers)/sizeof(CClientPed*)); i++ )
  198. {
  199. if ( m_pOccupyingPassengers [i] )
  200. {
  201. m_pOccupyingPassengers [i]->m_uiOccupiedVehicleSeat = 0;
  202. m_pOccupyingPassengers [i]->SetVehicleInOutState ( VEHICLE_INOUT_NONE );
  203. UnpairPedAndVehicle( m_pOccupyingPassengers [i], this );
  204. }
  205. }
  206.  
  207. // Remove us from the vehicle list
  208. Unlink ();
  209.  
  210. delete m_pUpgrades;
  211. #if WITH_VEHICLE_HANDLING
  212. delete m_pHandlingEntry;
  213. #endif
  214. }
  215.  
  216.  
  217. void CClientVehicle::Unlink ( void )
  218. {
  219. m_pVehicleManager->RemoveFromList ( this );
  220. m_pVehicleManager->m_Attached.remove ( this );
  221. ListRemove( m_pVehicleManager->m_StreamedIn, this );
  222. }
  223.  
  224.  
  225. void CClientVehicle::GetName ( char* szBuf )
  226. {
  227. // Get the name
  228. const char* szName = m_pModelInfo->GetNameIfVehicle ();
  229. if ( szName )
  230. {
  231. strcpy ( szBuf, szName );
  232. }
  233. else
  234. {
  235. // Shouldn't happen, copy over an empty string
  236. szBuf[0] = '\0';
  237. }
  238. }
  239.  
  240.  
  241. void CClientVehicle::GetPosition ( CVector& vecPosition ) const
  242. {
  243. if ( m_bIsFrozen )
  244. {
  245. vecPosition = m_matFrozen.vPos;
  246. }
  247. // Is this a trailer being towed?
  248. else if ( m_pTowedByVehicle )
  249. {
  250. // Is it streamed out or not attached properly?
  251. if ( !m_pVehicle || !m_pVehicle->GetTowedByVehicle () )
  252. {
  253. // Grab the position behind the vehicle (should take X/Y rotation into acount)
  254. m_pTowedByVehicle->GetPosition ( vecPosition );
  255.  
  256. CVector vecRotation;
  257. m_pTowedByVehicle->GetRotationRadians ( vecRotation );
  258. vecPosition.fX -= ( 5.0f * sin ( vecRotation.fZ ) );
  259. vecPosition.fY -= ( 5.0f * cos ( vecRotation.fZ ) );
  260. }
  261. else
  262. {
  263. vecPosition = *m_pVehicle->GetPosition ( );
  264. }
  265. }
  266. // Streamed in?
  267. else if ( m_pVehicle )
  268. {
  269. vecPosition = *m_pVehicle->GetPosition ();
  270. }
  271. // Attached to something?
  272. else if ( m_pAttachedToEntity )
  273. {
  274. m_pAttachedToEntity->GetPosition ( vecPosition );
  275. vecPosition += m_vecAttachedPosition;
  276. }
  277. else
  278. {
  279. vecPosition = m_Matrix.vPos;
  280. }
  281. }
  282.  
  283.  
  284. void CClientVehicle::SetRoll ( const CVector &vecRoll )
  285. {
  286. if ( m_pVehicle )
  287. {
  288. m_pVehicle->SetRoll ( const_cast < CVector* > ( &vecRoll ) );
  289. }
  290. m_Matrix.vRight = vecRoll;
  291. m_matFrozen.vRight = vecRoll;
  292. }
  293.  
  294.  
  295. void CClientVehicle::SetDirection ( const CVector &vecDir )
  296. {
  297. if ( m_pVehicle )
  298. {
  299. m_pVehicle->SetDirection ( const_cast < CVector* > ( &vecDir ) );
  300. }
  301. m_Matrix.vFront = vecDir;
  302. m_matFrozen.vFront = vecDir;
  303. }
  304.  
  305. void CClientVehicle::SetWas ( const CVector &vecWas )
  306. {
  307. if ( m_pVehicle )
  308. {
  309. m_pVehicle->SetWas ( const_cast < CVector* > ( &vecWas ) );
  310. }
  311. m_Matrix.vUp = vecWas;
  312. m_matFrozen.vUp = vecWas;
  313. }
  314.  
  315.  
  316. void CClientVehicle::SetPosition ( const CVector& vecPosition, bool bResetInterpolation )
  317. {
  318. // Is the local player in the vehicle
  319. if ( g_pClientGame->GetLocalPlayer ()->GetOccupiedVehicle () == this )
  320. {
  321. // If move is big enough, do ground checks
  322. float DistanceMoved = ( m_Matrix.vPos - vecPosition ).Length ();
  323. if ( DistanceMoved > 50 && !IsFrozen () )
  324. SetFrozenWaitingForGroundToLoad ( true );
  325. }
  326.  
  327. if ( m_pVehicle )
  328. {
  329. m_pVehicle->SetPosition ( const_cast < CVector* > ( &vecPosition ) );
  330.  
  331. // Jax: can someone find a cleaner alternative for this, it fixes vehicles not being affected by gravity (supposed to be a flag used only on creation, but isnt)
  332. if ( !m_pDriver )
  333. {
  334. CVector vecMoveSpeed;
  335. m_pVehicle->GetMoveSpeed ( &vecMoveSpeed );
  336. if ( vecMoveSpeed.fX == 0.0f && vecMoveSpeed.fY == 0.0f && vecMoveSpeed.fZ == 0.0f )
  337. {
  338. vecMoveSpeed.fZ -= 0.01f;
  339. m_pVehicle->SetMoveSpeed ( &vecMoveSpeed );
  340. }
  341. }
  342. }
  343. // Have we moved to a different position?
  344. if ( m_Matrix.vPos != vecPosition )
  345. {
  346. // Store our new position
  347. m_Matrix.vPos = vecPosition;
  348. m_matFrozen.vPos = vecPosition;
  349.  
  350. // Update our streaming position
  351. UpdateStreamPosition ( vecPosition );
  352. }
  353.  
  354. // If we have any occupants, update their positions
  355. for ( int i = 0; i <= NUMELMS ( m_pPassengers ) ; i++ )
  356. if ( CClientPed* pOccupant = GetOccupant ( i ) )
  357. pOccupant->SetPosition ( vecPosition );
  358.  
  359. // Reset interpolation
  360. if ( bResetInterpolation )
  361. RemoveTargetPosition ();
  362. }
  363.  
  364.  
  365. void CClientVehicle::GetRotationDegrees ( CVector& vecRotation ) const
  366. {
  367. // Grab our rotations in radians
  368. GetRotationRadians ( vecRotation );
  369. ConvertRadiansToDegrees ( vecRotation );
  370. }
  371.  
  372.  
  373. void CClientVehicle::GetRotationRadians ( CVector& vecRotation ) const
  374. {
  375. // Grab the rotation in radians from the matrix
  376. CMatrix matTemp;
  377. GetMatrix ( matTemp );
  378. g_pMultiplayer->ConvertMatrixToEulerAngles ( matTemp, vecRotation.fX, vecRotation.fY, vecRotation.fZ );
  379.  
  380. // ChrML: We flip the actual rotation direction so that the rotation is consistent with
  381. // objects and players.
  382. vecRotation.fX = ( 2 * PI ) - vecRotation.fX;
  383. vecRotation.fY = ( 2 * PI ) - vecRotation.fY;
  384. vecRotation.fZ = ( 2 * PI ) - vecRotation.fZ;
  385. }
  386.  
  387.  
  388. void CClientVehicle::SetRotationDegrees ( const CVector& vecRotation, bool bResetInterpolation )
  389. {
  390. // Convert from degrees to radians
  391. CVector vecTemp;
  392. vecTemp.fX = vecRotation.fX * 3.1415926535897932384626433832795f / 180.0f;
  393. vecTemp.fY = vecRotation.fY * 3.1415926535897932384626433832795f / 180.0f;
  394. vecTemp.fZ = vecRotation.fZ * 3.1415926535897932384626433832795f / 180.0f;
  395.  
  396. // Set the rotation as radians
  397. SetRotationRadians ( vecTemp, bResetInterpolation );
  398. }
  399.  
  400.  
  401. void CClientVehicle::SetRotationRadians ( const CVector& vecRotation, bool bResetInterpolation )
  402. {
  403. // Grab the matrix, apply the rotation to it and set it again
  404. // ChrML: We flip the actual rotation direction so that the rotation is consistent with
  405. // objects and players.
  406. CMatrix matTemp;
  407. GetMatrix ( matTemp );
  408. g_pMultiplayer->ConvertEulerAnglesToMatrix ( matTemp, ( 2 * PI ) - vecRotation.fX, ( 2 * PI ) - vecRotation.fY, ( 2 * PI ) - vecRotation.fZ );
  409. SetMatrix ( matTemp );
  410.  
  411. // Reset target rotatin
  412. if ( bResetInterpolation )
  413. RemoveTargetRotation ();
  414. }
  415.  
  416.  
  417. void CClientVehicle::ReportMissionAudioEvent ( unsigned short usSound )
  418. {
  419. if ( m_pVehicle )
  420. {
  421. // g_pGame->GetAudio ()->ReportMissionAudioEvent ( m_pVehicle, usSound );
  422. }
  423. }
  424.  
  425. bool CClientVehicle::SetTaxiLightOn ( bool bLightOn )
  426. {
  427. m_bTaxiLightOn = bLightOn;
  428. if ( m_pVehicle )
  429. {
  430. m_pVehicle->SetTaxiLightOn ( bLightOn );
  431. return true;
  432. }
  433. return false;
  434. }
  435.  
  436. float CClientVehicle::GetDistanceFromCentreOfMassToBaseOfModel ( void )
  437. {
  438. if ( m_pVehicle )
  439. {
  440. return m_pVehicle->GetDistanceFromCentreOfMassToBaseOfModel ();
  441. }
  442. return 0.0f;
  443. }
  444.  
  445. bool CClientVehicle::GetMatrix ( CMatrix& Matrix ) const
  446. {
  447. if ( m_bIsFrozen )
  448. {
  449. Matrix = m_matFrozen;
  450. }
  451. else
  452. {
  453. if ( m_pVehicle )
  454. {
  455. m_pVehicle->GetMatrix ( &Matrix );
  456. }
  457. else
  458. {
  459. Matrix = m_Matrix;
  460. }
  461. }
  462.  
  463. return true;
  464. }
  465.  
  466.  
  467. bool CClientVehicle::SetMatrix ( const CMatrix& Matrix )
  468. {
  469. if ( m_pVehicle )
  470. {
  471. m_pVehicle->SetMatrix ( const_cast < CMatrix* > ( &Matrix ) );
  472.  
  473. // If it is a boat, we need to call FixBoatOrientation or it won't move/rotate properly
  474. if ( m_eVehicleType == CLIENTVEHICLE_BOAT )
  475. {
  476. m_pVehicle->FixBoatOrientation ();
  477. }
  478. }
  479.  
  480. // Have we moved to a different position?
  481. if ( m_Matrix.vPos != Matrix.vPos )
  482. {
  483. // Update our streaming position
  484. UpdateStreamPosition ( Matrix.vPos );
  485. }
  486.  
  487. m_Matrix = Matrix;
  488. m_matFrozen = Matrix;
  489. m_MatrixPure = Matrix;
  490.  
  491. // If we have any occupants, update their positions
  492. if ( m_pDriver ) m_pDriver->SetPosition ( m_Matrix.vPos );
  493. for ( int i = 0; i < ( sizeof ( m_pPassengers ) / sizeof ( CClientPed * ) ) ; i++ )
  494. {
  495. if ( m_pPassengers [ i ] )
  496. {
  497. m_pPassengers [ i ]->SetPosition ( m_Matrix.vPos );
  498. }
  499. }
  500.  
  501. return true;
  502. }
  503.  
  504.  
  505. void CClientVehicle::GetMoveSpeed ( CVector& vecMoveSpeed ) const
  506. {
  507. if ( m_bIsFrozen )
  508. {
  509. vecMoveSpeed = CVector ( 0, 0, 0 );
  510. }
  511. else
  512. {
  513. if ( m_pVehicle )
  514. {
  515. m_pVehicle->GetMoveSpeed ( &vecMoveSpeed );
  516. }
  517. else
  518. {
  519. vecMoveSpeed = m_vecMoveSpeed;
  520. }
  521. }
  522. }
  523.  
  524.  
  525. void CClientVehicle::GetMoveSpeedMeters ( CVector& vecMoveSpeed ) const
  526. {
  527. if ( m_bIsFrozen )
  528. {
  529. vecMoveSpeed = CVector ( 0, 0, 0 );
  530. }
  531. else
  532. {
  533. vecMoveSpeed = m_vecMoveSpeedMeters;
  534. }
  535. }
  536.  
  537.  
  538. void CClientVehicle::SetMoveSpeed ( const CVector& vecMoveSpeed )
  539. {
  540. if ( !m_bIsFrozen )
  541. {
  542. if ( m_pVehicle )
  543. {
  544. m_pVehicle->SetMoveSpeed ( const_cast < CVector* > ( &vecMoveSpeed ) );
  545. }
  546. m_vecMoveSpeed = vecMoveSpeed;
  547. }
  548. }
  549.  
  550.  
  551. void CClientVehicle::GetTurnSpeed ( CVector& vecTurnSpeed ) const
  552. {
  553. if ( m_bIsFrozen )
  554. {
  555. vecTurnSpeed = CVector ( 0, 0, 0 );
  556. }
  557. if ( m_pVehicle )
  558. {
  559. m_pVehicle->GetTurnSpeed ( &vecTurnSpeed );
  560. }
  561. else
  562. {
  563. vecTurnSpeed = m_vecTurnSpeed;
  564. }
  565. }
  566.  
  567.  
  568. void CClientVehicle::SetTurnSpeed ( const CVector& vecTurnSpeed )
  569. {
  570. if ( !m_bIsFrozen )
  571. {
  572. if ( m_pVehicle )
  573. {
  574. m_pVehicle->SetTurnSpeed ( const_cast < CVector* > ( &vecTurnSpeed ) );
  575. }
  576. m_vecTurnSpeed = vecTurnSpeed;
  577. }
  578. }
  579.  
  580.  
  581. bool CClientVehicle::IsVisible ( void )
  582. {
  583. if ( m_pVehicle )
  584. {
  585. return m_pVehicle->IsVisible ();
  586. }
  587.  
  588. return m_bVisible;
  589. }
  590.  
  591.  
  592. void CClientVehicle::SetVisible ( bool bVisible )
  593. {
  594. if ( m_pVehicle )
  595. {
  596. m_pVehicle->SetVisible ( bVisible );
  597. }
  598. m_bVisible = bVisible;
  599. }
  600.  
  601.  
  602. bool CClientVehicle::AreDoorsLocked ( void )
  603. {
  604. if ( m_pVehicle )
  605. {
  606. return m_pVehicle->AreDoorsLocked ();
  607. }
  608. return m_bDoorsLocked;
  609. }
  610.  
  611.  
  612. void CClientVehicle::SetDoorsLocked ( bool bLocked )
  613. {
  614. if ( m_pVehicle )
  615. {
  616. m_pVehicle->LockDoors ( bLocked );
  617. }
  618. m_bDoorsLocked = bLocked;
  619. }
  620.  
  621.  
  622. bool CClientVehicle::AreDoorsUndamageable ( void )
  623. {
  624. if ( m_pVehicle )
  625. {
  626. return m_pVehicle->AreDoorsUndamageable ();
  627. }
  628. return m_bDoorsUndamageable;
  629. }
  630.  
  631.  
  632. void CClientVehicle::SetDoorsUndamageable ( bool bUndamageable )
  633. {
  634. if ( m_pVehicle )
  635. {
  636. m_pVehicle->SetDoorsUndamageable ( bUndamageable );
  637. }
  638. m_bDoorsUndamageable = bUndamageable;
  639. }
  640.  
  641.  
  642. float CClientVehicle::GetHealth ( void ) const
  643. {
  644. // If we're blown, return 0
  645. if ( m_bBlown ) return 0.0f;
  646.  
  647. if ( m_pVehicle )
  648. {
  649. return m_pVehicle->GetHealth ();
  650. }
  651.  
  652. return m_fHealth;
  653. }
  654.  
  655.  
  656. void CClientVehicle::SetHealth ( float fHealth )
  657. {
  658. if ( m_pVehicle )
  659. {
  660. // Is the car is dead and we want to un-die it?
  661. if ( fHealth > 0.0f && GetHealth () <= 0.0f )
  662. {
  663. Destroy ();
  664. m_fHealth = fHealth; // NEEDS to be here!
  665. Create ();
  666. }
  667. else
  668. {
  669. m_pVehicle->SetHealth ( fHealth );
  670. }
  671. }
  672. m_fHealth = fHealth;
  673. }
  674.  
  675. void CClientVehicle::Fix ( void )
  676. {
  677. m_bBlown = false;
  678. m_bBlowNextFrame = false;
  679. if ( m_pVehicle )
  680. {
  681. m_pVehicle->Fix ();
  682. // Make sure its visible, if its supposed to be
  683. m_pVehicle->SetVisible ( m_bVisible );
  684. }
  685.  
  686. SetHealth ( DEFAULT_VEHICLE_HEALTH );
  687.  
  688. unsigned char ucDoorStates [ MAX_DOORS ];
  689. GetInitialDoorStates ( ucDoorStates );
  690. for ( int i = 0 ; i < MAX_DOORS ; i++ ) SetDoorStatus ( i, ucDoorStates [ i ] );
  691. for ( int i = 0 ; i < MAX_PANELS ; i++ ) SetPanelStatus ( i, 0 );
  692. for ( int i = 0 ; i < MAX_LIGHTS ; i++ ) SetLightStatus ( i, 0 );
  693. for ( int i = 0 ; i < MAX_WHEELS ; i++ ) SetWheelStatus ( i, 0 );
  694. }
  695.  
  696.  
  697. void CClientVehicle::Blow ( bool bAllowMovement )
  698. {
  699. if ( m_pVehicle )
  700. {
  701. // Make sure it can be damaged
  702. m_pVehicle->SetCanBeDamaged ( true );
  703.  
  704. // Grab our current speeds
  705. CVector vecMoveSpeed, vecTurnSpeed;
  706. GetMoveSpeed ( vecMoveSpeed );
  707. GetTurnSpeed ( vecTurnSpeed );
  708.  
  709. // Set the health to 0
  710. m_pVehicle->SetHealth ( 0.0f );
  711.  
  712. // "Fuck" the car completely, so we don't have weird client-side jumpyness because of differently synced wheel states on clients
  713. FuckCarCompletely ( true );
  714.  
  715. m_pVehicle->BlowUp ( NULL, 0 );
  716.  
  717. // And force the wheel states to "burst"
  718. SetWheelStatus ( FRONT_LEFT_WHEEL, DT_WHEEL_BURST );
  719. SetWheelStatus ( FRONT_RIGHT_WHEEL, DT_WHEEL_BURST );
  720. SetWheelStatus ( REAR_LEFT_WHEEL, DT_WHEEL_BURST );
  721. SetWheelStatus ( REAR_RIGHT_WHEEL, DT_WHEEL_BURST );
  722.  
  723. if ( !bAllowMovement )
  724. {
  725. // Make sure it doesn't change speeds (slightly cleaner for syncing)
  726. SetMoveSpeed ( vecMoveSpeed );
  727. SetTurnSpeed ( vecTurnSpeed );
  728. }
  729.  
  730. // Restore the old can be damaged state
  731. CalcAndUpdateCanBeDamagedFlag ();
  732. }
  733. m_fHealth = 0.0f;
  734. m_bBlown = true;
  735. }
  736.  
  737.  
  738. void CClientVehicle::GetColor ( unsigned char& ucColor1, unsigned char& ucColor2, unsigned char& ucColor3, unsigned char& ucColor4 )
  739. {
  740. if ( m_pVehicle )
  741. {
  742. m_pVehicle->GetColor ( &ucColor1, &ucColor2, &ucColor3, &ucColor4 );
  743. }
  744. else
  745. {
  746. ucColor1 = m_ucColor1;
  747. ucColor2 = m_ucColor2;
  748. ucColor3 = m_ucColor3;
  749. ucColor4 = m_ucColor4;
  750. }
  751. }
  752.  
  753.  
  754. void CClientVehicle::SetColor ( unsigned char ucColor1, unsigned char ucColor2, unsigned char ucColor3, unsigned char ucColor4 )
  755. {
  756. if ( m_pVehicle )
  757. {
  758. m_pVehicle->SetColor ( ucColor1, ucColor2, ucColor3, ucColor4 );
  759. }
  760. m_ucColor1 = ucColor1;
  761. m_ucColor2 = ucColor2;
  762. m_ucColor3 = ucColor3;
  763. m_ucColor4 = ucColor4;
  764. m_bColorSaved = true;
  765. }
  766.  
  767.  
  768. void CClientVehicle::GetTurretRotation ( float& fHorizontal, float& fVertical )
  769. {
  770. if ( m_pVehicle )
  771. {
  772. // Car, plane or quad?
  773. if ( m_eVehicleType == CLIENTVEHICLE_CAR ||
  774. m_eVehicleType == CLIENTVEHICLE_PLANE ||
  775. m_eVehicleType == CLIENTVEHICLE_QUADBIKE )
  776. {
  777. m_pVehicle->GetTurretRotation ( &fHorizontal, &fVertical );
  778. }
  779. else
  780. {
  781. fHorizontal = 0;
  782. fVertical = 0;
  783. }
  784. }
  785. else
  786. {
  787. fHorizontal = m_fTurretHorizontal;
  788. fVertical = m_fTurretVertical;
  789. }
  790. }
  791.  
  792.  
  793. void CClientVehicle::SetTurretRotation ( float fHorizontal, float fVertical )
  794. {
  795. if ( m_pVehicle )
  796. {
  797. // Car, plane or quad?
  798. if ( m_eVehicleType == CLIENTVEHICLE_CAR ||
  799. m_eVehicleType == CLIENTVEHICLE_PLANE ||
  800. m_eVehicleType == CLIENTVEHICLE_QUADBIKE )
  801. {
  802. m_pVehicle->SetTurretRotation ( fHorizontal, fVertical );
  803. }
  804. }
  805. m_fTurretHorizontal = fHorizontal;
  806. m_fTurretVertical = fVertical;
  807. }
  808.  
  809.  
  810. void CClientVehicle::SetModelBlocking ( unsigned short usModel, bool bLoadImmediately )
  811. {
  812. // Different vehicle ID than we have now?
  813. if ( m_usModel != usModel )
  814. {
  815. // Destroy the old vehicle if we have one
  816. if ( m_pVehicle )
  817. {
  818. Destroy ();
  819. }
  820.  
  821. // Get rid of our upgrades, they might be incompatible
  822. if ( m_pUpgrades )
  823. m_pUpgrades->RemoveAll ( false );
  824.  
  825. // Are we swapping from a vortex or skimmer?
  826. bool bResetWheelAndDoorStates = ( m_usModel == VT_VORTEX || m_usModel == VT_SKIMMER );
  827.  
  828. // Set the new vehicle id and type
  829. m_usModel = usModel;
  830. m_eVehicleType = CClientVehicleManager::GetVehicleType ( usModel );
  831. m_bHasDamageModel = CClientVehicleManager::HasDamageModel ( m_eVehicleType );
  832.  
  833. if ( bResetWheelAndDoorStates )
  834. {
  835. GetInitialDoorStates ( m_ucDoorStates );
  836. memset ( m_ucWheelStates, 0, sizeof ( m_ucWheelStates ) );
  837. }
  838.  
  839. // Check if we have landing gears and adjustable properties
  840. m_bHasLandingGear = DoCheckHasLandingGear ();
  841. m_bHasAdjustableProperty = CClientVehicleManager::HasAdjustableProperty ( m_usModel );
  842. m_usAdjustablePropertyValue = 0;
  843.  
  844. // Grab the model info and the bounding box
  845. m_pModelInfo = g_pGame->GetModelInfo ( usModel );
  846. m_ucMaxPassengers = CClientVehicleManager::GetMaxPassengerCount ( usModel );
  847.  
  848. #if WITH_VEHICLE_HANDLING
  849. // Reset handling to fit the vehicle
  850. m_pOriginalHandlingEntry = g_pGame->GetHandlingManager()->GetOriginalHandlingData ( (eVehicleTypes)usModel );
  851. m_pHandlingEntry->ApplyHandlingData ( (CHandlingEntry*)m_pOriginalHandlingEntry );
  852. m_pHandlingEntry->Recalculate ();
  853. #endif
  854.  
  855. // Create the vehicle if we're streamed in
  856. if ( IsStreamedIn () )
  857. {
  858. // Preload the model
  859. if( !m_pModelInfo->IsLoaded () )
  860. {
  861. m_pModelInfo->Request ( true, true );
  862. m_pModelInfo->MakeCustomModel ();
  863. }
  864.  
  865. // Create the vehicle now. Don't prerequest the model ID for this func.
  866. Create ();
  867. }
  868. }
  869. }
  870.  
  871.  
  872. bool CClientVehicle::IsEngineBroken ( void )
  873. {
  874. if ( m_pVehicle )
  875. {
  876. return m_pVehicle->IsEngineBroken ();
  877. }
  878.  
  879. return m_bEngineBroken;
  880. }
  881.  
  882.  
  883. void CClientVehicle::SetEngineBroken ( bool bEngineBroken )
  884. {
  885. if ( m_pVehicle )
  886. {
  887. m_pVehicle->SetEngineBroken ( bEngineBroken );
  888. m_pVehicle->SetEngineOn ( !bEngineBroken );
  889.  
  890. // We need to recreate the vehicle if we're going from broken to unbroken
  891. if ( !bEngineBroken && m_pVehicle->IsEngineBroken () )
  892. {
  893. ReCreate ();
  894. }
  895. }
  896. m_bEngineBroken = bEngineBroken;
  897. }
  898.  
  899.  
  900. bool CClientVehicle::IsEngineOn ( void )
  901. {
  902. if ( m_pVehicle )
  903. {
  904. return m_pVehicle->IsEngineOn ();
  905. }
  906.  
  907. return m_bEngineOn;
  908. }
  909.  
  910.  
  911. void CClientVehicle::SetEngineOn ( bool bEngineOn )
  912. {
  913. if ( m_pVehicle )
  914. {
  915. m_pVehicle->SetEngineOn ( bEngineOn );
  916. }
  917.  
  918. m_bEngineOn = bEngineOn;
  919. }
  920.  
  921.  
  922. bool CClientVehicle::CanBeDamaged ( void )
  923. {
  924. if ( m_pVehicle )
  925. {
  926. return m_pVehicle->GetCanBeDamaged ();
  927. }
  928.  
  929. return m_bCanBeDamaged;
  930. }
  931.  
  932.  
  933. // This can be called frequently to ensure the correct setting gets to the SA vehicle
  934. void CClientVehicle::CalcAndUpdateCanBeDamagedFlag ( void )
  935. {
  936. bool bCanBeDamaged = false;
  937.  
  938. // CanBeDamaged if local driver or syncing unoccupiedVehicle
  939. if ( m_pDriver && m_pDriver->IsLocalPlayer () )
  940. bCanBeDamaged = true;
  941.  
  942. if ( m_bSyncUnoccupiedDamage )
  943. bCanBeDamaged = true;
  944.  
  945. // Script override
  946. if ( !m_bScriptCanBeDamaged )
  947. bCanBeDamaged = false;
  948.  
  949. if ( m_pVehicle )
  950. {
  951. m_pVehicle->SetCanBeDamaged ( bCanBeDamaged );
  952. }
  953.  
  954. m_bCanBeDamaged = bCanBeDamaged;
  955. }
  956.  
  957.  
  958. void CClientVehicle::SetScriptCanBeDamaged ( bool bCanBeDamaged )
  959. {
  960. // Needed so script doesn't interfere with syncing unoccupied vehicles
  961. m_bScriptCanBeDamaged = bCanBeDamaged;
  962. CalcAndUpdateCanBeDamagedFlag ();
  963. CalcAndUpdateTyresCanBurstFlag ();
  964. }
  965.  
  966.  
  967. void CClientVehicle::SetSyncUnoccupiedDamage ( bool bCanBeDamaged )
  968. {
  969. m_bSyncUnoccupiedDamage = bCanBeDamaged;
  970. CalcAndUpdateCanBeDamagedFlag ();
  971. CalcAndUpdateTyresCanBurstFlag ();
  972. }
  973.  
  974.  
  975. bool CClientVehicle::GetTyresCanBurst ( void )
  976. {
  977. if ( m_pVehicle )
  978. {
  979. return !m_pVehicle->GetTyresDontBurst ();
  980. }
  981.  
  982. return m_bTyresCanBurst;
  983. }
  984.  
  985.  
  986. // This can be called frequently to ensure the correct setting gets to the SA vehicle
  987. void CClientVehicle::CalcAndUpdateTyresCanBurstFlag ( void )
  988. {
  989. bool bTyresCanBurst = false;
  990.  
  991. // TyresCanBurst if local driver or syncing unoccupiedVehicle
  992. if ( m_pDriver && m_pDriver->IsLocalPlayer () )
  993. bTyresCanBurst = true;
  994.  
  995. if ( m_bSyncUnoccupiedDamage )
  996. bTyresCanBurst = true;
  997.  
  998. // Script override
  999. // if ( !m_bScriptCanBeDamaged )
  1000. // bTyresCanBurst = false;
  1001.  
  1002. if ( m_pVehicle )
  1003. {
  1004. m_pVehicle->SetTyresDontBurst ( !bTyresCanBurst );
  1005. }
  1006.  
  1007. m_bTyresCanBurst = bTyresCanBurst;
  1008. }
  1009.  
  1010.  
  1011. float CClientVehicle::GetGasPedal ( void )
  1012. {
  1013. if ( m_pVehicle )
  1014. {
  1015. return m_pVehicle->GetGasPedal ();
  1016. }
  1017.  
  1018. return m_fGasPedal;
  1019. }
  1020.  
  1021.  
  1022. bool CClientVehicle::IsBelowWater ( void ) const
  1023. {
  1024. CVector vecPosition;
  1025. GetPosition ( vecPosition );
  1026. float fWaterLevel = 0.0f;
  1027.  
  1028. if ( g_pGame->GetWaterManager ()->GetWaterLevel ( vecPosition, &fWaterLevel, true, NULL ) )
  1029. {
  1030. if ( vecPosition.fZ < fWaterLevel - 0.7 )
  1031. {
  1032. return true;
  1033. }
  1034. }
  1035.  
  1036. return false;
  1037. }
  1038.  
  1039.  
  1040. bool CClientVehicle::IsDrowning ( void ) const
  1041. {
  1042. if ( m_pVehicle )
  1043. {
  1044. return m_pVehicle->IsDrowning ();
  1045. }
  1046.  
  1047. return false;
  1048. }
  1049.  
  1050.  
  1051. bool CClientVehicle::IsDriven ( void ) const
  1052. {
  1053. if ( m_pVehicle )
  1054. {
  1055. return m_pVehicle->IsBeingDriven () ? true:false;
  1056. }
  1057. else
  1058. {
  1059. return GetOccupant ( 0 ) != NULL;
  1060. }
  1061. }
  1062.  
  1063.  
  1064. bool CClientVehicle::IsUpsideDown ( void ) const
  1065. {
  1066. if ( m_pVehicle )
  1067. {
  1068. return m_pVehicle->IsUpsideDown ();
  1069. }
  1070.  
  1071. // TODO: Figure out this using matrix?
  1072. return false;
  1073. }
  1074.  
  1075.  
  1076. bool CClientVehicle::IsBlown ( void ) const
  1077. {
  1078. // Game layer functions aren't reliable
  1079. return m_bBlown;
  1080. }
  1081.  
  1082.  
  1083. bool CClientVehicle::IsSirenOrAlarmActive ( void )
  1084. {
  1085. if ( m_pVehicle )
  1086. {
  1087. return m_pVehicle->IsSirenOrAlarmActive () ? true:false;
  1088. }
  1089.  
  1090. return m_bSireneOrAlarmActive;
  1091. }
  1092.  
  1093.  
  1094. void CClientVehicle::SetSirenOrAlarmActive ( bool bActive )
  1095. {
  1096. if ( m_pVehicle )
  1097. {
  1098. m_pVehicle->SetSirenOrAlarmActive ( bActive );
  1099. }
  1100. m_bSireneOrAlarmActive = bActive;
  1101. }
  1102.  
  1103.  
  1104. float CClientVehicle::GetLandingGearPosition ( void )
  1105. {
  1106. if ( m_bHasLandingGear )
  1107. {
  1108. if ( m_pVehicle )
  1109. {
  1110. return m_pVehicle->GetLandingGearPosition ();
  1111. }
  1112. }
  1113.  
  1114. return 0.0f;
  1115. }
  1116.  
  1117.  
  1118. void CClientVehicle::SetLandingGearPosition ( float fPosition )
  1119. {
  1120. if ( m_bHasLandingGear )
  1121. {
  1122. if ( m_pVehicle )
  1123. {
  1124. m_pVehicle->SetLandingGearPosition ( fPosition );
  1125. }
  1126. }
  1127. }
  1128.  
  1129.  
  1130. bool CClientVehicle::IsLandingGearDown ( void )
  1131. {
  1132. if ( m_bHasLandingGear )
  1133. {
  1134. if ( m_pVehicle )
  1135. {
  1136. return m_pVehicle->IsLandingGearDown ();
  1137. }
  1138.  
  1139. return m_bLandingGearDown;
  1140. }
  1141.  
  1142. return true;
  1143. }
  1144.  
  1145.  
  1146. void CClientVehicle::SetLandingGearDown ( bool bLandingGearDown )
  1147. {
  1148. if ( m_bHasLandingGear )
  1149. {
  1150. if ( m_pVehicle )
  1151. {
  1152. m_pVehicle->SetLandingGearDown ( bLandingGearDown );
  1153. }
  1154. m_bLandingGearDown = bLandingGearDown;
  1155. }
  1156. }
  1157.  
  1158.  
  1159. unsigned short CClientVehicle::GetAdjustablePropertyValue ( void )
  1160. {
  1161. unsigned short usPropertyValue;
  1162. if ( m_pVehicle )
  1163. {
  1164. usPropertyValue = m_pVehicle->GetAdjustablePropertyValue ();
  1165. // If it's a Hydra invert it with 5000 (as 0 is "forward"), so we can maintain a standard of 0 being "normal"
  1166. if ( m_usModel == VT_HYDRA ) usPropertyValue = 5000 - usPropertyValue;
  1167. }
  1168. else
  1169. {
  1170. usPropertyValue = m_usAdjustablePropertyValue;
  1171. }
  1172.  
  1173. // Return it
  1174. return usPropertyValue;
  1175. }
  1176.  
  1177.  
  1178. void CClientVehicle::SetAdjustablePropertyValue ( unsigned short usValue )
  1179. {
  1180. if ( m_usModel == VT_HYDRA ) usValue = 5000 - usValue;
  1181.  
  1182. _SetAdjustablePropertyValue ( usValue );
  1183. }
  1184.  
  1185.  
  1186. void CClientVehicle::_SetAdjustablePropertyValue ( unsigned short usValue )
  1187. {
  1188. // Set it
  1189. if ( m_pVehicle )
  1190. {
  1191. if ( m_bHasAdjustableProperty )
  1192. {
  1193. m_pVehicle->SetAdjustablePropertyValue ( usValue );
  1194.  
  1195. // Update our collision for this adjustable?
  1196. if ( HasMovingCollision () )
  1197. {
  1198. float fAngle = ( float ) usValue / 2499.0f;
  1199. m_pVehicle->UpdateMovingCollision ( fAngle );
  1200. }
  1201. }
  1202. }
  1203. m_usAdjustablePropertyValue = usValue;
  1204. }
  1205.  
  1206.  
  1207. bool CClientVehicle::HasMovingCollision ( void )
  1208. {
  1209. return ( m_usModel == VT_FORKLIFT || m_usModel == VT_FIRELA || m_usModel == VT_ANDROM ||
  1210. m_usModel == VT_DUMPER || m_usModel == VT_DOZER || m_usModel == VT_PACKER );
  1211. }
  1212.  
  1213.  
  1214. unsigned char CClientVehicle::GetDoorStatus ( unsigned char ucDoor )
  1215. {
  1216. if ( ucDoor < MAX_DOORS )
  1217. {
  1218. if ( m_pVehicle && HasDamageModel () )
  1219. {
  1220. return m_pVehicle->GetDamageManager ()->GetDoorStatus ( static_cast < eDoors > ( ucDoor ) );
  1221. }
  1222.  
  1223. return m_ucDoorStates [ucDoor];
  1224. }
  1225.  
  1226. return 0;
  1227. }
  1228.  
  1229.  
  1230. unsigned char CClientVehicle::GetWheelStatus ( unsigned char ucWheel )
  1231. {
  1232. if ( ucWheel < MAX_WHEELS )
  1233. {
  1234. // Return our custom state?
  1235. if ( m_ucWheelStates [ucWheel] == DT_WHEEL_INTACT_COLLISIONLESS ) return DT_WHEEL_INTACT_COLLISIONLESS;
  1236.  
  1237. if ( m_pVehicle )
  1238. {
  1239. if ( HasDamageModel () )
  1240. return m_pVehicle->GetDamageManager ()->GetWheelStatus ( static_cast < eWheels > ( ucWheel ) );
  1241. if ( m_eVehicleType == CLIENTVEHICLE_BIKE && ucWheel < 2 )
  1242. return m_pVehicle->GetBikeWheelStatus ( ucWheel );
  1243. }
  1244.  
  1245. return m_ucWheelStates [ucWheel];
  1246. }
  1247.  
  1248. return 0;
  1249. }
  1250.  
  1251.  
  1252. unsigned char CClientVehicle::GetPanelStatus ( unsigned char ucPanel )
  1253. {
  1254. if ( ucPanel < MAX_PANELS )
  1255. {
  1256. if ( m_pVehicle && HasDamageModel () )
  1257. {
  1258. return m_pVehicle->GetDamageManager ()->GetPanelStatus ( ucPanel );
  1259. }
  1260.  
  1261. return m_ucPanelStates [ ucPanel ];
  1262. }
  1263.  
  1264. return 0;
  1265. }
  1266.  
  1267.  
  1268. unsigned char CClientVehicle::GetLightStatus ( unsigned char ucLight )
  1269. {
  1270. if ( ucLight < MAX_LIGHTS )
  1271. {
  1272. if ( m_pVehicle && HasDamageModel () )
  1273. {
  1274. return m_pVehicle->GetDamageManager ()->GetLightStatus ( ucLight );
  1275. }
  1276. return m_ucLightStates [ ucLight ];
  1277. }
  1278.  
  1279. return 0;
  1280. }
  1281.  
  1282.  
  1283. void CClientVehicle::SetDoorStatus ( unsigned char ucDoor, unsigned char ucStatus )
  1284. {
  1285. if ( ucDoor < MAX_DOORS )
  1286. {
  1287. if ( m_pVehicle && HasDamageModel () )
  1288. {
  1289. m_pVehicle->GetDamageManager ()->SetDoorStatus ( static_cast < eDoors > ( ucDoor ), ucStatus );
  1290. }
  1291. m_ucDoorStates [ucDoor] = ucStatus;
  1292. }
  1293. }
  1294.  
  1295.  
  1296. void CClientVehicle::SetWheelStatus ( unsigned char ucWheel, unsigned char ucStatus, bool bSilent )
  1297. {
  1298. if ( ucWheel < MAX_WHEELS )
  1299. {
  1300. if ( m_pVehicle )
  1301. {
  1302. // Is our new status a burst tyre? and do we need to call BurstTyre?
  1303. if ( ucStatus == DT_WHEEL_BURST && !bSilent ) m_pVehicle->BurstTyre ( ucWheel );
  1304.  
  1305. // Are we using our custom state?
  1306. unsigned char ucGTAStatus = ucStatus;
  1307. if ( ucStatus == DT_WHEEL_INTACT_COLLISIONLESS ) ucGTAStatus = DT_WHEEL_MISSING;
  1308.  
  1309. // Do we have a damage model?
  1310. if ( HasDamageModel () )
  1311. {
  1312. m_pVehicle->GetDamageManager ()->SetWheelStatus ( ( eWheels ) ( ucWheel ), ucGTAStatus );
  1313.  
  1314. // Update the wheel's visibility
  1315. m_pVehicle->SetWheelVisibility ( ( eWheels ) ucWheel, ( ucStatus != DT_WHEEL_MISSING ) );
  1316. }
  1317. else if ( m_eVehicleType == CLIENTVEHICLE_BIKE && ucWheel < 2 )
  1318. m_pVehicle->SetBikeWheelStatus ( ucWheel, ucGTAStatus );
  1319. }
  1320. m_ucWheelStates [ucWheel] = ucStatus;
  1321. }
  1322. }
  1323.  
  1324.  
  1325. void CClientVehicle::SetPanelStatus ( unsigned char ucPanel, unsigned char ucStatus )
  1326. {
  1327. if ( ucPanel < MAX_PANELS )
  1328. {
  1329. if ( m_pVehicle && HasDamageModel () )
  1330. {
  1331. m_pVehicle->GetDamageManager ()->SetPanelStatus ( static_cast < ePanels > ( ucPanel ), ucStatus );
  1332. }
  1333. m_ucPanelStates [ ucPanel ] = ucStatus;
  1334. }
  1335. }
  1336.  
  1337.  
  1338. void CClientVehicle::SetLightStatus ( unsigned char ucLight, unsigned char ucStatus )
  1339. {
  1340. if ( ucLight < MAX_LIGHTS )
  1341. {
  1342. if ( m_pVehicle && HasDamageModel () )
  1343. {
  1344. m_pVehicle->GetDamageManager ()->SetLightStatus ( static_cast < eLights > ( ucLight ), ucStatus );
  1345. }
  1346. m_ucLightStates [ ucLight ] = ucStatus;
  1347. }
  1348. }
  1349.  
  1350.  
  1351. float CClientVehicle::GetHeliRotorSpeed ( void )
  1352. {
  1353. if ( m_pVehicle && m_eVehicleType == CLIENTVEHICLE_HELI )
  1354. {
  1355. return m_pVehicle->GetHeliRotorSpeed ();
  1356. }
  1357.  
  1358. return m_fHeliRotorSpeed;
  1359. }
  1360.  
  1361.  
  1362. void CClientVehicle::SetHeliRotorSpeed ( float fSpeed )
  1363. {
  1364. if ( m_pVehicle && m_eVehicleType == CLIENTVEHICLE_HELI )
  1365. {
  1366. m_pVehicle->SetHeliRotorSpeed ( fSpeed );
  1367. }
  1368. m_fHeliRotorSpeed = fSpeed;
  1369. }
  1370.  
  1371.  
  1372. bool CClientVehicle::IsHeliSearchLightVisible ( void )
  1373. {
  1374. if ( m_pVehicle && m_eVehicleType == CLIENTVEHICLE_HELI )
  1375. {
  1376. return m_pVehicle->IsHeliSearchLightVisible ();
  1377. }
  1378. return m_bHeliSearchLightVisible;
  1379. }
  1380.  
  1381.  
  1382. void CClientVehicle::SetHeliSearchLightVisible ( bool bVisible )
  1383. {
  1384. if ( m_pVehicle && m_eVehicleType == CLIENTVEHICLE_HELI )
  1385. {
  1386. m_pVehicle->SetHeliSearchLightVisible ( bVisible );
  1387. }
  1388. m_bHeliSearchLightVisible = bVisible;
  1389. }
  1390.  
  1391.  
  1392. void CClientVehicle::SetCollisionEnabled ( bool bCollisionEnabled )
  1393. {
  1394. if ( m_pVehicle )
  1395. {
  1396. if ( m_bHasAdjustableProperty )
  1397. {
  1398. m_pVehicle->SetUsesCollision ( bCollisionEnabled );
  1399. }
  1400. }
  1401.  
  1402. m_bIsCollisionEnabled = bCollisionEnabled;
  1403. }
  1404.  
  1405.  
  1406. bool CClientVehicle::GetCanShootPetrolTank ( void )
  1407. {
  1408. if ( m_pVehicle )
  1409. {
  1410. return m_pVehicle->GetCanShootPetrolTank ();
  1411. }
  1412.  
  1413. return m_bCanShootPetrolTank;
  1414. }
  1415.  
  1416.  
  1417. void CClientVehicle::SetCanShootPetrolTank ( bool bCanShoot )
  1418. {
  1419. if ( m_pVehicle )
  1420. {
  1421. m_pVehicle->SetCanShootPetrolTank ( bCanShoot );
  1422. }
  1423. m_bCanShootPetrolTank = bCanShoot;
  1424. }
  1425.  
  1426.  
  1427. bool CClientVehicle::GetCanBeTargettedByHeatSeekingMissiles ( void )
  1428. {
  1429. if ( m_pVehicle )
  1430. {
  1431. return m_pVehicle->GetCanBeTargettedByHeatSeekingMissiles ();
  1432. }
  1433.  
  1434. return m_bCanBeTargettedByHeatSeekingMissiles;
  1435. }
  1436.  
  1437.  
  1438. void CClientVehicle::SetCanBeTargettedByHeatSeekingMissiles ( bool bEnabled )
  1439. {
  1440. if ( m_pVehicle )
  1441. {
  1442. m_pVehicle->SetCanBeTargettedByHeatSeekingMissiles ( bEnabled );
  1443. }
  1444. m_bCanBeTargettedByHeatSeekingMissiles = bEnabled;
  1445. }
  1446.  
  1447.  
  1448. void CClientVehicle::SetAlpha ( unsigned char ucAlpha )
  1449. {
  1450. if ( ucAlpha != m_ucAlpha )
  1451. {
  1452. if ( m_pVehicle )
  1453. {
  1454. m_pVehicle->SetAlpha ( ucAlpha );
  1455. }
  1456. m_ucAlpha = ucAlpha;
  1457. m_bAlphaChanged = true;
  1458. }
  1459. }
  1460.  
  1461.  
  1462. CClientPed* CClientVehicle::GetOccupant ( int iSeat ) const
  1463. {
  1464. // Return the driver if the seat is 0
  1465. if ( iSeat == 0 )
  1466. {
  1467. return m_pDriver;
  1468. }
  1469. else if ( iSeat <= (sizeof(m_pPassengers)/sizeof(CClientPed*)) )
  1470. {
  1471. return m_pPassengers [iSeat - 1];
  1472. }
  1473.  
  1474. return NULL;
  1475. }
  1476.  
  1477.  
  1478. CClientPed* CClientVehicle::GetControllingPlayer ( void )
  1479. {
  1480. CClientPed* pControllingPlayer = m_pDriver;
  1481.  
  1482. if ( pControllingPlayer == NULL )
  1483. {
  1484. CClientVehicle* pCurrentVehicle = this;
  1485. CClientVehicle* pTowedByVehicle = m_pTowedByVehicle;
  1486. pControllingPlayer = pCurrentVehicle->GetOccupant ( 0 );
  1487. while ( pTowedByVehicle )
  1488. {
  1489. pCurrentVehicle = pTowedByVehicle;
  1490. pTowedByVehicle = pCurrentVehicle->GetTowedByVehicle ();
  1491. CClientPed* pCurrentDriver = pCurrentVehicle->GetOccupant ( 0 );
  1492. if ( pCurrentDriver )
  1493. pControllingPlayer = pCurrentDriver;
  1494. }
  1495. }
  1496.  
  1497. return pControllingPlayer;
  1498. }
  1499.  
  1500.  
  1501. void CClientVehicle::ClearForOccupants ( void )
  1502. {
  1503. // TODO: Also check passenger seats for players
  1504. // If there are people in the vehicle, remove them from the vehicle
  1505. CClientPed* pPed = GetOccupant ( 0 );
  1506. if ( pPed )
  1507. {
  1508. pPed->RemoveFromVehicle ();
  1509. }
  1510. }
  1511.  
  1512.  
  1513. void CClientVehicle::PlaceProperlyOnGround ( void )
  1514. {
  1515. if ( m_pVehicle )
  1516. {
  1517. // Place it properly at the ground depending on what kind of vehicle it is
  1518. if ( m_eVehicleType == CLIENTVEHICLE_BMX || m_eVehicleType == CLIENTVEHICLE_BIKE )
  1519. {
  1520. m_pVehicle->PlaceBikeOnRoadProperly ();
  1521. }
  1522. else if ( m_eVehicleType != CLIENTVEHICLE_BOAT )
  1523. {
  1524. m_pVehicle->PlaceAutomobileOnRoadProperly ();
  1525. }
  1526. }
  1527. }
  1528.  
  1529.  
  1530. void CClientVehicle::FuckCarCompletely ( bool bKeepWheels )
  1531. {
  1532. if ( m_pVehicle )
  1533. {
  1534. if ( HasDamageModel () )
  1535. {
  1536. m_pVehicle->GetDamageManager()->FuckCarCompletely ( bKeepWheels );
  1537. }
  1538. }
  1539. }
  1540.  
  1541.  
  1542. unsigned long CClientVehicle::GetMemoryValue ( unsigned long ulOffset )
  1543. {
  1544. if ( m_pVehicle )
  1545. {
  1546. return *m_pVehicle->GetMemoryValue ( ulOffset );
  1547. }
  1548.  
  1549. return 0;
  1550. }
  1551.  
  1552.  
  1553. unsigned long CClientVehicle::GetGameBaseAddress ( void )
  1554. {
  1555. if ( m_pVehicle )
  1556. {
  1557. return reinterpret_cast < unsigned long > ( m_pVehicle->GetMemoryValue ( 0 ) );
  1558. }
  1559.  
  1560. return 0;
  1561. }
  1562.  
  1563.  
  1564. void CClientVehicle::WorldIgnore ( bool bWorldIgnore )
  1565. {
  1566. if ( bWorldIgnore )
  1567. {
  1568. if ( m_pVehicle )
  1569. {
  1570. g_pGame->GetWorld ()->IgnoreEntity ( m_pVehicle );
  1571. }
  1572. }
  1573. else
  1574. {
  1575. g_pGame->GetWorld ()->IgnoreEntity ( NULL );
  1576. }
  1577. }
  1578.  
  1579.  
  1580. void CClientVehicle::FadeOut ( bool bFadeOut )
  1581. {
  1582. if ( m_pVehicle )
  1583. {
  1584. m_pVehicle->FadeOut ( bFadeOut );
  1585. }
  1586. }
  1587.  
  1588.  
  1589. bool CClientVehicle::IsFadingOut ( void )
  1590. {
  1591. if ( m_pVehicle )
  1592. {
  1593. return m_pVehicle->IsFadingOut ();
  1594. }
  1595.  
  1596. return false;
  1597. }
  1598.  
  1599.  
  1600. void CClientVehicle::SetFrozen ( bool bFrozen )
  1601. {
  1602. if ( m_bScriptFrozen && bFrozen )
  1603. {
  1604. m_bIsFrozen = bFrozen;
  1605. CVector vecTemp;
  1606. if ( m_pVehicle )
  1607. {
  1608. m_pVehicle->GetMatrix ( &m_matFrozen );
  1609. m_pVehicle->SetMoveSpeed ( &vecTemp );
  1610. m_pVehicle->SetTurnSpeed ( &vecTemp );
  1611. }
  1612. else
  1613. {
  1614. m_matFrozen = m_Matrix;
  1615. m_vecMoveSpeed = vecTemp;
  1616. m_vecTurnSpeed = vecTemp;
  1617. }
  1618. }
  1619. else if ( !m_bScriptFrozen )
  1620. {
  1621. m_bIsFrozen = bFrozen;
  1622.  
  1623. if ( bFrozen )
  1624. {
  1625. CVector vecTemp;
  1626. if ( m_pVehicle )
  1627. {
  1628. m_pVehicle->GetMatrix ( &m_matFrozen );
  1629. m_pVehicle->SetMoveSpeed ( &vecTemp );
  1630. m_pVehicle->SetTurnSpeed ( &vecTemp );
  1631. }
  1632. else
  1633. {
  1634. m_matFrozen = m_Matrix;
  1635. m_vecMoveSpeed = vecTemp;
  1636. m_vecTurnSpeed = vecTemp;
  1637. }
  1638. }
  1639. }
  1640. }
  1641.  
  1642.  
  1643. bool CClientVehicle::IsFrozenWaitingForGroundToLoad ( void ) const
  1644. {
  1645. return m_bFrozenWaitingForGroundToLoad;
  1646. }
  1647.  
  1648.  
  1649. void CClientVehicle::SetFrozenWaitingForGroundToLoad ( bool bFrozen )
  1650. {
  1651. if ( !g_pGame->IsASyncLoadingEnabled ( true ) )
  1652. return;
  1653.  
  1654. if ( m_bFrozenWaitingForGroundToLoad != bFrozen )
  1655. {
  1656. m_bFrozenWaitingForGroundToLoad = bFrozen;
  1657.  
  1658. if ( bFrozen )
  1659. {
  1660. g_pGame->SuspendASyncLoading ( true );
  1661. m_fGroundCheckTolerance = 0.f;
  1662. m_fObjectsAroundTolerance = -1.f;
  1663.  
  1664. CVector vecTemp;
  1665. if ( m_pVehicle )
  1666. {
  1667. m_pVehicle->GetMatrix ( &m_matFrozen );
  1668. m_pVehicle->SetMoveSpeed ( &vecTemp );
  1669. m_pVehicle->SetTurnSpeed ( &vecTemp );
  1670. }
  1671. else
  1672. {
  1673. m_matFrozen = m_Matrix;
  1674. m_vecMoveSpeed = vecTemp;
  1675. m_vecTurnSpeed = vecTemp;
  1676. }
  1677. }
  1678. else
  1679. {
  1680. g_pGame->SuspendASyncLoading ( false );
  1681. }
  1682. }
  1683. }
  1684.  
  1685.  
  1686. CClientVehicle* CClientVehicle::GetPreviousTrainCarriage ( void )
  1687. {
  1688. return NULL;
  1689. }
  1690.  
  1691.  
  1692. CClientVehicle* CClientVehicle::GetNextTrainCarriage ( void )
  1693. {
  1694. return NULL;
  1695. }
  1696.  
  1697.  
  1698. void CClientVehicle::SetPreviousTrainCarriage ( CClientVehicle* pPrevious )
  1699. {
  1700. // Tell the given vehicle we're the previous link and save the given vehicle as the next link
  1701. m_pPreviousLink = pPrevious;
  1702. if ( pPrevious )
  1703. {
  1704. pPrevious->m_pNextLink = this;
  1705. }
  1706.  
  1707. // If both vehicles are streamed in, do the link
  1708. if ( m_pVehicle && pPrevious->m_pVehicle )
  1709. {
  1710. m_pVehicle->SetPreviousTrainCarriage ( pPrevious->m_pVehicle );
  1711. }
  1712. }
  1713.  
  1714.  
  1715. void CClientVehicle::SetNextTrainCarriage ( CClientVehicle* pNext )
  1716. {
  1717. // Tell the given vehicle we're the previous link and save the given vehicle as the next link
  1718. m_pNextLink = pNext;
  1719. if ( pNext )
  1720. {
  1721. pNext->m_pPreviousLink = this;
  1722. }
  1723.  
  1724. // If both vehicles are streamed in, do the link
  1725. if ( m_pVehicle && pNext->m_pVehicle )
  1726. {
  1727. m_pVehicle->SetNextTrainCarriage ( pNext->m_pVehicle );
  1728. }
  1729. }
  1730.  
  1731.  
  1732. bool CClientVehicle::IsDerailed ( void )
  1733. {
  1734. if ( GetVehicleType() == CLIENTVEHICLE_TRAIN )
  1735. {
  1736. if ( m_pVehicle )
  1737. {
  1738. return m_pVehicle->IsDerailed ();
  1739. }
  1740. return m_bIsDerailed;
  1741. }
  1742. else
  1743. return false;
  1744. }
  1745.  
  1746.  
  1747. void CClientVehicle::SetDerailed ( bool bDerailed )
  1748. {
  1749. if ( GetVehicleType() == CLIENTVEHICLE_TRAIN )
  1750. {
  1751. if ( m_pVehicle && bDerailed != IsDerailed () )
  1752. {
  1753. m_pVehicle->SetDerailed ( bDerailed );
  1754. }
  1755. m_bIsDerailed = bDerailed;
  1756. }
  1757. }
  1758.  
  1759. bool CClientVehicle::IsDerailable ( void )
  1760. {
  1761. if ( m_pVehicle )
  1762. {
  1763. return m_pVehicle->IsDerailable ();
  1764. }
  1765. return m_bIsDerailable;
  1766. }
  1767.  
  1768. void CClientVehicle::SetDerailable ( bool bDerailable )
  1769. {
  1770. if ( m_pVehicle )
  1771. {
  1772. m_pVehicle->SetDerailable ( bDerailable );
  1773. }
  1774. m_bIsDerailable = bDerailable;
  1775. }
  1776.  
  1777.  
  1778. bool CClientVehicle::GetTrainDirection ( void )
  1779. {
  1780. if ( m_pVehicle )
  1781. {
  1782. return m_pVehicle->GetTrainDirection ();
  1783. }
  1784. return m_bTrainDirection;
  1785. }
  1786.  
  1787.  
  1788. void CClientVehicle::SetTrainDirection ( bool bDirection )
  1789. {
  1790. if ( m_pVehicle && GetVehicleType() == CLIENTVEHICLE_TRAIN )
  1791. {
  1792. m_pVehicle->SetTrainDirection ( bDirection );
  1793. }
  1794. m_bTrainDirection = bDirection;
  1795. }
  1796.  
  1797.  
  1798. float CClientVehicle::GetTrainSpeed ( void )
  1799. {
  1800. if ( m_pVehicle )
  1801. {
  1802. return m_pVehicle->GetTrainSpeed ();
  1803. }
  1804. return m_fTrainSpeed;
  1805. }
  1806.  
  1807.  
  1808. void CClientVehicle::SetTrainSpeed ( float fSpeed )
  1809. {
  1810. if ( m_pVehicle && GetVehicleType() == CLIENTVEHICLE_TRAIN )
  1811. {
  1812. m_pVehicle->SetTrainSpeed ( fSpeed );
  1813. }
  1814. m_fTrainSpeed = fSpeed;
  1815. }
  1816.  
  1817.  
  1818. void CClientVehicle::SetOverrideLights ( unsigned char ucOverrideLights )
  1819. {
  1820. if ( m_pVehicle )
  1821. {
  1822. m_pVehicle->SetOverrideLights ( static_cast < unsigned int > ( ucOverrideLights ) );
  1823. }
  1824. m_ucOverrideLights = ucOverrideLights;
  1825. }
  1826.  
  1827.  
  1828. void CClientVehicle::StreamedInPulse ( void )
  1829. {
  1830. // Make sure the vehicle doesn't go too far down
  1831. if ( m_pVehicle )
  1832. {
  1833. if ( m_bBlowNextFrame )
  1834. {
  1835. Blow ( false );
  1836. m_bBlowNextFrame = false;
  1837. }
  1838.  
  1839. // Are we an unmanned, invisible, blown-up plane?
  1840. if ( !GetOccupant () && m_eVehicleType == CLIENTVEHICLE_PLANE && m_bBlown && !m_pVehicle->IsVisible () )
  1841. {
  1842. // Disable our collisions
  1843. m_pVehicle->SetUsesCollision ( false );
  1844. }
  1845. else
  1846. {
  1847. // Vehicles have a way of getting their cols back, so we have to force this each frame (not much overhead anyway)
  1848. m_pVehicle->SetUsesCollision ( m_bIsCollisionEnabled );
  1849. }
  1850.  
  1851. // Handle waiting for the ground to load
  1852. if ( IsFrozenWaitingForGroundToLoad () )
  1853. HandleWaitingForGroundToLoad ();
  1854.  
  1855. // If we are frozen, make sure we freeze our matrix and keep move/turn speed at 0,0,0
  1856. if ( m_bIsFrozen )
  1857. {
  1858. CVector vecTemp;
  1859. m_pVehicle->SetMatrix ( &m_matFrozen );
  1860. m_pVehicle->SetMoveSpeed ( &vecTemp );
  1861. m_pVehicle->SetTurnSpeed ( &vecTemp );
  1862. }
  1863. else
  1864. {
  1865. // Cols been loaded for where the vehicle is? Only check this if it has no drivers.
  1866. if ( m_pDriver ||
  1867. ( g_pGame->GetWorld ()->HasCollisionBeenLoaded ( &m_matFrozen.vPos ) /*&&
  1868. m_pObjectManager->ObjectsAroundPointLoaded ( m_matFrozen.vPos, 200.0f, m_usDimension )*/ ) )
  1869. {
  1870. // Remember the matrix
  1871. m_pVehicle->GetMatrix ( &m_matFrozen );
  1872. }
  1873. else
  1874. {
  1875. // Force the position to the last remembered matrix (..and make sure gravity doesn't pull it down)
  1876. m_pVehicle->SetMatrix ( &m_matFrozen );
  1877. m_pVehicle->SetMoveSpeed ( &CVector ( 0.0f, 0.0f, 0.0f ) );
  1878.  
  1879. // Added by ChrML 27. Nov: Shouldn't cause any problems
  1880. m_pVehicle->SetUsesCollision ( false );
  1881. }
  1882. }
  1883.  
  1884. // Calculate the velocity
  1885. CMatrix MatrixCurrent;
  1886. m_pVehicle->GetMatrix ( &MatrixCurrent );
  1887. m_vecMoveSpeedMeters = ( MatrixCurrent.vPos - m_MatrixLast.vPos ) * g_pGame->GetFPS ();
  1888. // Store the current matrix
  1889. m_MatrixLast = MatrixCurrent;
  1890.  
  1891. // We dont interpolate attached trailers
  1892. if ( m_pTowedByVehicle )
  1893. {
  1894. RemoveTargetPosition ();
  1895. RemoveTargetRotation ();
  1896. }
  1897.  
  1898. /*
  1899. // Are we blown?
  1900. if ( m_bBlown )
  1901. {
  1902. // Has our engine status been reset to on_fire somewhere?
  1903. CDamageManager* pDamageManager = m_pVehicle->GetDamageManager ();
  1904. if ( pDamageManager->GetEngineStatus () == DT_ENGINE_ON_FIRE )
  1905. {
  1906. // Change it back to fucked
  1907. pDamageManager->SetEngineStatus ( DT_ENGINE_ENGINE_PIPES_BURST );
  1908. }
  1909. }
  1910. */
  1911.  
  1912. Interpolate ();
  1913.  
  1914. // Grab our current position
  1915. CVector vecPosition = *m_pVehicle->GetPosition ();
  1916.  
  1917. if ( m_pAttachedToEntity )
  1918. {
  1919. m_pAttachedToEntity->GetPosition ( vecPosition );
  1920. vecPosition += m_vecAttachedPosition;
  1921. }
  1922.  
  1923. // Have we moved?
  1924. if ( vecPosition != m_Matrix.vPos )
  1925. {
  1926. // If we're setting the position, check whether we're under-water.
  1927. // If so, we need to set the Underwater flag so the render draw order is changed.
  1928. m_pVehicle->SetUnderwater ( IsBelowWater () );
  1929.  
  1930. // Store our new position
  1931. m_Matrix.vPos = vecPosition;
  1932. m_matFrozen.vPos = vecPosition;
  1933.  
  1934. // Update our streaming position
  1935. UpdateStreamPosition ( vecPosition );
  1936. }
  1937. }
  1938. }
  1939.  
  1940.  
  1941. void CClientVehicle::StreamIn ( bool bInstantly )
  1942. {
  1943. // We need to create now?
  1944. if ( bInstantly )
  1945. {
  1946. // Request its model blocking
  1947. if ( m_pModelRequester->RequestBlocking ( m_usModel ) )
  1948. {
  1949. // Create us
  1950. Create ();
  1951. }
  1952. else NotifyUnableToCreate ();
  1953. }
  1954. else
  1955. {
  1956. // Request its model.
  1957. if ( m_pModelRequester->Request ( m_usModel, this ) )
  1958. {
  1959. // If it got loaded immediately, create the vehicle now.
  1960. // Otherwise we create it when the model loaded callback calls us
  1961. Create ();
  1962. }
  1963. else NotifyUnableToCreate ();
  1964. }
  1965. }
  1966.  
  1967.  
  1968. void CClientVehicle::StreamOut ( void )
  1969. {
  1970. // Destroy the vehicle.
  1971. Destroy ();
  1972.  
  1973. // Make sure we don't have any model requests
  1974. // pending in the model request manager. If we
  1975. // had and don't do this it could create us when
  1976. // we're not streamed in.
  1977. m_pModelRequester->Cancel ( this, true );
  1978. }
  1979.  
  1980.  
  1981. void CClientVehicle::AttachTo ( CClientEntity* pEntity )
  1982. {
  1983. // Add/remove us to/from our managers attached list
  1984. if ( m_pAttachedToEntity && !pEntity ) m_pVehicleManager->m_Attached.remove ( this );
  1985. else if ( !m_pAttachedToEntity && pEntity ) m_pVehicleManager->m_Attached.push_back ( this );
  1986.  
  1987. CClientEntity::AttachTo ( pEntity );
  1988. }
  1989.  
  1990.  
  1991. bool CClientVehicle::DoCheckHasLandingGear ( void )
  1992. {
  1993. return ( m_usModel == VT_ANDROM ||
  1994. m_usModel == VT_AT400 ||
  1995. m_usModel == VT_NEVADA ||
  1996. m_usModel == VT_RUSTLER ||
  1997. m_usModel == VT_SHAMAL ||
  1998. m_usModel == VT_HYDRA ||
  1999. m_usModel == VT_STUNT );
  2000. }
  2001.  
  2002.  
  2003. void CClientVehicle::Create ( void )
  2004. {
  2005. // If the vehicle doesn't exist
  2006. if ( !m_pVehicle )
  2007. {
  2008. #ifdef MTA_DEBUG
  2009. g_pCore->GetConsole ()->Printf ( "CClientVehicle::Create %d", GetModel() );
  2010. #endif
  2011.  
  2012. // Check again that the limit isn't reached. We are required to do so because
  2013. // we load async. The streamer isn't always aware of our limits.
  2014. if ( CClientVehicleManager::IsVehicleLimitReached () )
  2015. {
  2016. // Tell the streamer we could not create it
  2017. NotifyUnableToCreate ();
  2018. return;
  2019. }
  2020.  
  2021. // Add a reference to the vehicle model we're creating.
  2022. m_pModelInfo->AddRef ( true );
  2023.  
  2024. // Might want to make this settable by users? Could just leave it like this, don't mind.
  2025. // Doesn't appear to work with trucks - only cars - stored string is up to 8 chars, will be reset after
  2026. // each vehicle spawned of this model type (i.e. after AddVehicle below)
  2027. if ( !m_strRegPlate.empty () )
  2028. m_pModelInfo->SetCustomCarPlateText ( m_strRegPlate.c_str () );
  2029.  
  2030. // Create the vehicle
  2031. if ( CClientVehicleManager::IsTrainModel ( m_usModel ) )
  2032. {
  2033. DWORD dwModels [1];
  2034. dwModels [0] = m_usModel;
  2035. m_pVehicle = g_pGame->GetPools ()->AddTrain ( &m_Matrix.vPos, dwModels, 1, m_bTrainDirection );
  2036. }
  2037. else
  2038. {
  2039. m_pVehicle = g_pGame->GetPools ()->AddVehicle ( static_cast < eVehicleTypes > ( m_usModel ) );
  2040. }
  2041.  
  2042. // Failed. Remove our reference to the vehicle model and return
  2043. if ( !m_pVehicle )
  2044. {
  2045. // Tell the streamer we could not create it
  2046. NotifyUnableToCreate ();
  2047.  
  2048. m_pModelInfo->RemoveRef ();
  2049. return;
  2050. }
  2051.  
  2052. // Put our pointer in its custom data
  2053. m_pVehicle->SetStoredPointer ( this );
  2054.  
  2055. // Jump straight to the target position if we have one
  2056. if ( HasTargetPosition () )
  2057. {
  2058. GetTargetPosition ( m_Matrix.vPos );
  2059. }
  2060.  
  2061. // Jump straight to the target rotation if we have one
  2062. if ( HasTargetRotation () )
  2063. {
  2064. CVector vecTemp = m_interp.rot.vecTarget;
  2065. ConvertDegreesToRadians ( vecTemp );
  2066. g_pMultiplayer->ConvertEulerAnglesToMatrix ( m_Matrix, ( 2 * PI ) - vecTemp.fX, ( 2 * PI ) - vecTemp.fY, ( 2 * PI ) - vecTemp.fZ );
  2067. }
  2068.  
  2069. // Got any settings to restore?
  2070. m_pVehicle->SetMatrix ( &m_Matrix );
  2071. m_matFrozen = m_Matrix;
  2072. m_pVehicle->SetMoveSpeed ( &m_vecMoveSpeed );
  2073. m_pVehicle->SetTurnSpeed ( &m_vecTurnSpeed );
  2074. m_pVehicle->SetVisible ( m_bVisible );
  2075. m_pVehicle->SetUsesCollision ( m_bIsCollisionEnabled );
  2076. m_pVehicle->SetEngineBroken ( m_bEngineBroken );
  2077. m_pVehicle->SetSirenOrAlarmActive ( m_bSireneOrAlarmActive );
  2078. SetLandingGearDown ( m_bLandingGearDown );
  2079. _SetAdjustablePropertyValue ( m_usAdjustablePropertyValue );
  2080. m_pVehicle->LockDoors ( m_bDoorsLocked );
  2081. m_pVehicle->SetDoorsUndamageable ( m_bDoorsUndamageable );
  2082. m_pVehicle->SetCanShootPetrolTank ( m_bCanShootPetrolTank );
  2083. m_pVehicle->SetTaxiLightOn ( m_bTaxiLightOn );
  2084. m_pVehicle->SetCanBeTargettedByHeatSeekingMissiles ( m_bCanBeTargettedByHeatSeekingMissiles );
  2085. CalcAndUpdateTyresCanBurstFlag ();
  2086. if ( GetVehicleType () == CLIENTVEHICLE_TRAIN )
  2087. {
  2088. m_pVehicle->SetDerailed ( m_bIsDerailed );
  2089. m_pVehicle->SetDerailable ( m_bIsDerailable );
  2090. m_pVehicle->SetTrainDirection ( m_bTrainDirection );
  2091. m_pVehicle->SetTrainSpeed ( m_fTrainSpeed );
  2092. }
  2093.  
  2094. // Re-add all the upgrades
  2095. if ( m_pUpgrades )
  2096. m_pUpgrades->ReAddAll ();
  2097.  
  2098. m_pVehicle->SetOverrideLights ( m_ucOverrideLights );
  2099. m_pVehicle->SetRemap ( static_cast < unsigned int > ( m_ucPaintjob ) );
  2100. m_pVehicle->SetBodyDirtLevel ( m_fDirtLevel );
  2101. m_pVehicle->SetEngineOn ( m_bEngineOn );
  2102. m_pVehicle->SetAreaCode ( m_ucInterior );
  2103. m_pVehicle->SetSmokeTrailEnabled ( m_bSmokeTrail );
  2104. m_pVehicle->SetGravity ( &m_vecGravity );
  2105. m_pVehicle->SetHeadLightColor ( m_HeadLightColor );
  2106.  
  2107. if ( m_eVehicleType == CLIENTVEHICLE_HELI )
  2108. {
  2109. m_pVehicle->SetHeliRotorSpeed ( m_fHeliRotorSpeed );
  2110. m_pVehicle->SetHeliSearchLightVisible ( m_bHeliSearchLightVisible );
  2111. }
  2112.  
  2113. m_pVehicle->SetUnderwater ( IsBelowWater () );
  2114.  
  2115. // HACK: temp fix until windows are fixed using setAlpha
  2116. if ( m_bAlphaChanged )
  2117. m_pVehicle->SetAlpha ( m_ucAlpha );
  2118.  
  2119. m_pVehicle->SetHealth ( m_fHealth );
  2120.  
  2121. if ( m_bBlown || m_fHealth == 0.0f ) m_bBlowNextFrame = true;
  2122.  
  2123. CalcAndUpdateCanBeDamagedFlag ();
  2124.  
  2125. // Restore the color
  2126. if ( m_bColorSaved )
  2127. {
  2128. m_pVehicle->SetColor ( m_ucColor1, m_ucColor2, m_ucColor3, m_ucColor4 );
  2129. }
  2130.  
  2131. // Link us with stored next and previous vehicles
  2132. if ( m_pPreviousLink && m_pPreviousLink->m_pVehicle )
  2133. {
  2134. m_pVehicle->SetPreviousTrainCarriage ( m_pPreviousLink->m_pVehicle );
  2135. }
  2136.  
  2137. if ( m_pNextLink && m_pNextLink->m_pVehicle )
  2138. {
  2139. m_pVehicle->SetNextTrainCarriage ( m_pNextLink->m_pVehicle );
  2140. }
  2141.  
  2142. // Restore turret rotation
  2143. if ( m_eVehicleType == CLIENTVEHICLE_CAR ||
  2144. m_eVehicleType == CLIENTVEHICLE_PLANE ||
  2145. m_eVehicleType == CLIENTVEHICLE_QUADBIKE )
  2146. {
  2147. m_pVehicle->SetTurretRotation ( m_fTurretHorizontal, m_fTurretVertical );
  2148. }
  2149.  
  2150. // Does this car have a damage model?
  2151. if ( HasDamageModel () )
  2152. {
  2153. // Set the damage model doors
  2154. CDamageManager* pDamageManager = m_pVehicle->GetDamageManager ();
  2155.  
  2156. for ( int i = 0; i < MAX_DOORS; i++ )
  2157. pDamageManager->SetDoorStatus ( static_cast < eDoors > ( i ), m_ucDoorStates [i] );
  2158. for ( int i = 0; i < MAX_PANELS; i++ )
  2159. pDamageManager->SetPanelStatus ( static_cast < ePanels > ( i ), m_ucPanelStates [i] );
  2160. for ( int i = 0; i < MAX_LIGHTS; i++ )
  2161. pDamageManager->SetLightStatus ( static_cast < eLights > ( i ), m_ucLightStates [i] );
  2162. }
  2163. for ( int i = 0; i < MAX_WHEELS; i++ )
  2164. SetWheelStatus ( i, m_ucWheelStates [i], true );
  2165.  
  2166. // Eventually warp driver back in
  2167. if ( m_pDriver ) m_pDriver->WarpIntoVehicle ( this, 0 );
  2168.  
  2169. // Warp the passengers back in
  2170. for ( unsigned int i = 0; i < 8; i++ )
  2171. {
  2172. if ( m_pPassengers [i] )
  2173. {
  2174. m_pPassengers [i]->WarpIntoVehicle ( this, i + 1 );
  2175. if ( m_pPassengers [i] )
  2176. m_pPassengers [i]->StreamIn ( true );
  2177. }
  2178. }
  2179.  
  2180. // Reattach a towed vehicle?
  2181. if ( m_pTowedVehicle )
  2182. {
  2183. CVehicle* pGameVehicle = m_pTowedVehicle->GetGameVehicle ();
  2184. if ( pGameVehicle )
  2185. pGameVehicle->SetTowLink ( m_pVehicle );
  2186. }
  2187.  
  2188. // Reattach if we're being towed
  2189. if ( m_pTowedByVehicle )
  2190. {
  2191. CVector vecTowedByPos;
  2192. m_pTowedByVehicle->GetPosition ( vecTowedByPos );
  2193. SetPosition ( vecTowedByPos );
  2194.  
  2195. CVehicle* pGameVehicle = m_pTowedByVehicle->GetGameVehicle ();
  2196. if ( pGameVehicle )
  2197. {
  2198. m_pVehicle->SetTowLink ( pGameVehicle );
  2199. }
  2200. }
  2201.  
  2202. // Reattach to an entity + any entities attached to this
  2203. ReattachEntities ();
  2204.  
  2205. // Give it a tap so it doesn't stick in the air if movespeed is standing still
  2206. if ( m_vecMoveSpeed.fX < 0.01f && m_vecMoveSpeed.fX > -0.01f &&
  2207. m_vecMoveSpeed.fY < 0.01f && m_vecMoveSpeed.fY > -0.01f &&
  2208. m_vecMoveSpeed.fZ < 0.01f && m_vecMoveSpeed.fZ > -0.01f )
  2209. {
  2210. m_vecMoveSpeed = CVector ( 0.0f, 0.0f, 0.01f );
  2211. m_pVehicle->SetMoveSpeed ( &m_vecMoveSpeed );
  2212. }
  2213.  
  2214. // Validate
  2215. m_pManager->RestoreEntity ( this );
  2216.  
  2217. // Set the frozen matrix to our position
  2218. m_matFrozen = m_Matrix;
  2219.  
  2220. // Reset the interpolation
  2221. ResetInterpolation ();
  2222.  
  2223. #if WITH_VEHICLE_HANDLING
  2224. // Re-apply handling entry
  2225. if ( m_pHandlingEntry )
  2226. {
  2227. m_pVehicle->SetHandlingData ( m_pHandlingEntry );
  2228. }
  2229. #endif
  2230. // Tell the streamer we've created this object
  2231. NotifyCreate ();
  2232. }
  2233. }
  2234.  
  2235.  
  2236. void CClientVehicle::Destroy ( void )
  2237. {
  2238. // If the vehicle exists
  2239. if ( m_pVehicle )
  2240. {
  2241. #ifdef MTA_DEBUG
  2242. g_pCore->GetConsole ()->Printf ( "CClientVehicle::Destroy %d", GetModel() );
  2243. #endif
  2244.  
  2245. // Invalidate
  2246. m_pManager->InvalidateEntity ( this );
  2247.  
  2248. // Store anything we allow GTA to change
  2249. m_pVehicle->GetMatrix ( &m_Matrix );
  2250. m_pVehicle->GetMoveSpeed ( &m_vecMoveSpeed );
  2251. m_pVehicle->GetTurnSpeed ( &m_vecTurnSpeed );
  2252. m_fHealth = GetHealth ();
  2253. m_bSireneOrAlarmActive = m_pVehicle->IsSirenOrAlarmActive () ? true:false;
  2254. m_bLandingGearDown = IsLandingGearDown ();
  2255. m_usAdjustablePropertyValue = m_pVehicle->GetAdjustablePropertyValue ();
  2256. m_bEngineOn = m_pVehicle->IsEngineOn ();
  2257. m_bIsOnGround = IsOnGround ();
  2258. m_bIsDerailed = IsDerailed ();
  2259. m_fHeliRotorSpeed = GetHeliRotorSpeed ();
  2260. m_bHeliSearchLightVisible = IsHeliSearchLightVisible ();
  2261. #if WITH_VEHICLE_HANDLING
  2262. m_pHandlingEntry = m_pVehicle->GetHandlingData();
  2263. #endif
  2264. if ( m_eVehicleType == CLIENTVEHICLE_CAR ||
  2265. m_eVehicleType == CLIENTVEHICLE_PLANE ||
  2266. m_eVehicleType == CLIENTVEHICLE_QUADBIKE )
  2267. {
  2268. m_pVehicle->GetTurretRotation ( &m_fTurretHorizontal, &m_fTurretVertical );
  2269. }
  2270.  
  2271. // This vehicle has a damage model?
  2272. if ( HasDamageModel () )
  2273. {
  2274. // Grab the damage model
  2275. CDamageManager* pDamageManager = m_pVehicle->GetDamageManager ();
  2276.  
  2277. for ( int i = 0; i < MAX_DOORS; i++ )
  2278. m_ucDoorStates [i] = pDamageManager->GetDoorStatus ( static_cast < eDoors > ( i ) );
  2279. for ( int i = 0; i < MAX_PANELS; i++ )
  2280. m_ucPanelStates [i] = pDamageManager->GetPanelStatus ( static_cast < ePanels > ( i ) );
  2281. for ( int i = 0; i < MAX_LIGHTS; i++ )
  2282. m_ucLightStates [i] = pDamageManager->GetLightStatus ( static_cast < eLights > ( i ) );
  2283. }
  2284. for ( int i = 0; i < MAX_WHEELS; i++ )
  2285. m_ucWheelStates [i] = GetWheelStatus ( i );
  2286.  
  2287. // Remove the driver from the vehicle
  2288. CClientPed* pPed = GetOccupant ( 0 );
  2289. if ( pPed )
  2290. {
  2291. // Only remove him physically. Don't let the ped update us
  2292. pPed->InternalRemoveFromVehicle ( m_pVehicle );
  2293. }
  2294.  
  2295. // Remove all the passengers physically
  2296. for ( unsigned int i = 0; i < 8; i++ )
  2297. {
  2298. if ( m_pPassengers [i] )
  2299. {
  2300. m_pPassengers [i]->InternalRemoveFromVehicle ( m_pVehicle );
  2301. }
  2302. }
  2303.  
  2304. // Do we have any occupying players? (that could be working on entering this vehicle)
  2305. if ( m_pOccupyingDriver && m_pOccupyingDriver->m_pOccupyingVehicle == this )
  2306. {
  2307. if ( m_pOccupyingDriver->IsGettingIntoVehicle () || m_pOccupyingDriver->IsGettingOutOfVehicle () )
  2308. {
  2309. m_pOccupyingDriver->RemoveFromVehicle ();
  2310. }
  2311. }
  2312. for ( unsigned int i = 0; i < 8; i++ )
  2313. {
  2314. if ( m_pOccupyingPassengers [i] && m_pOccupyingPassengers [i]->m_pOccupyingVehicle == this )
  2315. {
  2316. if ( m_pOccupyingPassengers [i]->IsGettingIntoVehicle () || m_pOccupyingPassengers [i]->IsGettingOutOfVehicle () )
  2317. {
  2318. m_pOccupyingPassengers [i]->RemoveFromVehicle ();
  2319. }
  2320. }
  2321. }
  2322.  
  2323. // Destroy the vehicle
  2324. g_pGame->GetPools ()->RemoveVehicle ( m_pVehicle );
  2325. m_pVehicle = NULL;
  2326.  
  2327. // Remove reference to its model
  2328. m_pModelInfo->RemoveRef ();
  2329.  
  2330. NotifyDestroy ();
  2331. }
  2332. }
  2333.  
  2334.  
  2335. void CClientVehicle::ReCreate ( void )
  2336. {
  2337. // Recreate the vehicle if it exists
  2338. if ( m_pVehicle )
  2339. {
  2340. Destroy ();
  2341. Create ();
  2342. }
  2343. }
  2344.  
  2345.  
  2346. void CClientVehicle::ModelRequestCallback ( CModelInfo* pModelInfo )
  2347. {
  2348. // Create the vehicle. The model is now loaded.
  2349. Create ();
  2350. }
  2351.  
  2352.  
  2353. void CClientVehicle::NotifyCreate ( void )
  2354. {
  2355. m_pVehicleManager->OnCreation ( this );
  2356. CClientStreamElement::NotifyCreate ();
  2357. }
  2358.  
  2359.  
  2360. void CClientVehicle::NotifyDestroy ( void )
  2361. {
  2362. m_pVehicleManager->OnDestruction ( this );
  2363. }
  2364.  
  2365.  
  2366. CClientVehicle* CClientVehicle::GetTowedVehicle ( void )
  2367. {
  2368. if ( m_pVehicle )
  2369. {
  2370. CVehicle* pGameVehicle = m_pVehicle->GetTowedVehicle ();
  2371. if ( pGameVehicle ) return m_pVehicleManager->Get ( pGameVehicle, false );
  2372. }
  2373.  
  2374. return m_pTowedVehicle;
  2375. }
  2376.  
  2377.  
  2378. CClientVehicle* CClientVehicle::GetRealTowedVehicle ( void )
  2379. {
  2380. if ( m_pVehicle )
  2381. {
  2382. CVehicle* pGameVehicle = m_pVehicle->GetTowedVehicle ();
  2383. if ( pGameVehicle ) return m_pVehicleManager->Get ( pGameVehicle, false );
  2384.  
  2385. // This is the only difference from ::GetTowedVehicle
  2386. return NULL;
  2387. }
  2388.  
  2389. return m_pTowedVehicle;
  2390. }
  2391.  
  2392.  
  2393. bool CClientVehicle::SetTowedVehicle ( CClientVehicle* pVehicle )
  2394. {
  2395. if ( pVehicle == m_pTowedVehicle )
  2396. return true;
  2397.  
  2398. // Do we already have a towed vehicle?
  2399. if ( m_pTowedVehicle && pVehicle != m_pTowedVehicle )
  2400. {
  2401. // Remove it
  2402. CVehicle * pGameVehicle = m_pTowedVehicle->GetGameVehicle ();
  2403. if ( pGameVehicle && m_pVehicle )
  2404. pGameVehicle->BreakTowLink ();
  2405. m_pTowedVehicle->m_pTowedByVehicle = NULL;
  2406. m_pTowedVehicle = NULL;
  2407. }
  2408.  
  2409. // Do we have a new one to set?
  2410. if ( pVehicle )
  2411. {
  2412. // Are we trying to establish a circular loop? (this would freeze everything up)
  2413. CClientVehicle* pCircTestVehicle = pVehicle;
  2414. while ( pCircTestVehicle )
  2415. {
  2416. if ( pCircTestVehicle == this )
  2417. return false;
  2418. pCircTestVehicle = pCircTestVehicle->m_pTowedVehicle;
  2419. }
  2420.  
  2421. pVehicle->m_pTowedByVehicle = this;
  2422.  
  2423. // Add it
  2424. if ( m_pVehicle )
  2425. {
  2426. CVehicle * pGameVehicle = pVehicle->GetGameVehicle ();
  2427.  
  2428. if ( pGameVehicle )
  2429. {
  2430. // Both vehicles are streamed in
  2431. if ( m_pVehicle->GetTowedVehicle () != pGameVehicle )
  2432. pGameVehicle->SetTowLink ( m_pVehicle );
  2433. }
  2434. else
  2435. {
  2436. // If only the towing vehicle is streamed in, force the towed vehicle to stream in
  2437. pVehicle->StreamIn ( true );
  2438. }
  2439. }
  2440. else
  2441. {
  2442. // If the towing vehicle is not streamed in, the towed vehicle can't be streamed in,
  2443. // so we move it to the towed position.
  2444. CVector vecPosition;
  2445. pVehicle->GetPosition ( vecPosition );
  2446. pVehicle->UpdateStreamPosition ( vecPosition );
  2447. }
  2448. }
  2449. else
  2450. m_ulIllegalTowBreakTime = 0;
  2451.  
  2452. m_pTowedVehicle = pVehicle;
  2453. return true;
  2454. }
  2455.  
  2456.  
  2457. bool CClientVehicle::SetWinchType ( eWinchType winchType )
  2458. {
  2459. if ( GetModel () == 417 ) // Leviathan
  2460. {
  2461. if ( m_pVehicle )
  2462. {
  2463. if ( m_eWinchType == WINCH_NONE )
  2464. {
  2465. m_pVehicle->SetWinchType ( winchType );
  2466. m_eWinchType = winchType;
  2467. }
  2468. return true;
  2469. }
  2470. else
  2471. {
  2472. m_eWinchType = winchType;
  2473. return true;
  2474. }
  2475. }
  2476.  
  2477. return false;
  2478. }
  2479.  
  2480.  
  2481. bool CClientVehicle::PickupEntityWithWinch ( CClientEntity* pEntity )
  2482. {
  2483. if ( m_pVehicle )
  2484. {
  2485. if ( m_eWinchType != WINCH_NONE )
  2486. {
  2487. CEntity* pGameEntity = NULL;
  2488. eClientEntityType entityType = pEntity->GetType ();
  2489. switch ( entityType )
  2490. {
  2491. case CCLIENTOBJECT:
  2492. {
  2493. CClientObject* pObject = static_cast < CClientObject* > ( pEntity );
  2494. pGameEntity = pObject->GetGameObject ();
  2495. break;
  2496. }
  2497. case CCLIENTPED:
  2498. case CCLIENTPLAYER:
  2499. {
  2500. CClientPed* pModel = static_cast < CClientPed* > ( pEntity );
  2501. pGameEntity = pModel->GetGameEntity ();
  2502. break;
  2503. }
  2504. case CCLIENTVEHICLE:
  2505. {
  2506. CClientVehicle* pVehicle = static_cast < CClientVehicle* > ( pEntity );
  2507. pGameEntity = pVehicle->GetGameVehicle ();
  2508. break;
  2509. }
  2510. }
  2511.  
  2512. if ( pGameEntity )
  2513. {
  2514. m_pVehicle->PickupEntityWithWinch ( pGameEntity );
  2515. m_pPickedUpWinchEntity = pEntity;
  2516.  
  2517. return true;
  2518. }
  2519. }
  2520. }
  2521.  
  2522. return false;
  2523. }
  2524.  
  2525.  
  2526. bool CClientVehicle::ReleasePickedUpEntityWithWinch ( void )
  2527. {
  2528. if ( m_pVehicle )
  2529. {
  2530. if ( m_pPickedUpWinchEntity )
  2531. {
  2532. m_pVehicle->ReleasePickedUpEntityWithWinch ();
  2533. m_pPickedUpWinchEntity = NULL;
  2534.  
  2535. return true;
  2536. }
  2537. }
  2538.  
  2539. return false;
  2540. }
  2541.  
  2542.  
  2543. void CClientVehicle::SetRopeHeightForHeli ( float fRopeHeight )
  2544. {
  2545. if ( m_pVehicle )
  2546. {
  2547. m_pVehicle->SetRopeHeightForHeli ( fRopeHeight );
  2548. }
  2549. }
  2550.  
  2551.  
  2552. CClientEntity* CClientVehicle::GetPickedUpEntityWithWinch ( void )
  2553. {
  2554. CClientEntity* pEntity = m_pPickedUpWinchEntity;
  2555. if ( m_pVehicle )
  2556. {
  2557. CPhysical* pPhysical = m_pVehicle->QueryPickedUpEntityWithWinch ();
  2558. if ( pPhysical )
  2559. {
  2560. eEntityType entityType = pPhysical->GetEntityType ();
  2561. switch ( entityType )
  2562. {
  2563. case ENTITY_TYPE_VEHICLE:
  2564. {
  2565. CVehicle* pGameVehicle = dynamic_cast < CVehicle* > ( pPhysical );
  2566. CClientVehicle* pVehicle = m_pVehicleManager->Get ( pGameVehicle, false );
  2567. if ( pVehicle )
  2568. pEntity = static_cast < CClientEntity* > ( pVehicle );
  2569. break;
  2570. }
  2571. case ENTITY_TYPE_PED:
  2572. {
  2573. CPlayerPed* pPlayerPed = dynamic_cast < CPlayerPed* > ( pPhysical );
  2574. CClientPed* pModel = m_pManager->GetPedManager ()->Get ( pPlayerPed, false, false );
  2575. if ( pModel )
  2576. pEntity = static_cast < CClientEntity* > ( pModel );
  2577. break;
  2578. }
  2579. case ENTITY_TYPE_OBJECT:
  2580. {
  2581. CObject* pGameObject = dynamic_cast < CObject* > ( pPhysical );
  2582. CClientObject* pObject = m_pManager->GetObjectManager ()->Get ( pGameObject, false );
  2583. if ( pObject )
  2584. pEntity = static_cast < CClientEntity* > ( pObject );
  2585. break;
  2586. }
  2587. }
  2588. }
  2589. }
  2590.  
  2591. return pEntity;
  2592. }
  2593.  
  2594.  
  2595. void CClientVehicle::SetRegPlate ( const char* szPlate )
  2596. {
  2597. if ( szPlate )
  2598. {
  2599. m_strRegPlate = szPlate;
  2600. }
  2601. }
  2602.  
  2603.  
  2604. unsigned char CClientVehicle::GetPaintjob ( void )
  2605. {
  2606. if ( m_pVehicle )
  2607. {
  2608. int iRemap = m_pVehicle->GetRemapIndex ();
  2609. return (iRemap == -1) ? 3 : iRemap;
  2610. }
  2611.  
  2612. return m_ucPaintjob;
  2613. }
  2614.  
  2615.  
  2616. void CClientVehicle::SetPaintjob ( unsigned char ucPaintjob )
  2617. {
  2618. if ( ucPaintjob != m_ucPaintjob && ucPaintjob <= 4 )
  2619. {
  2620. if ( m_pVehicle )
  2621. {
  2622. m_pVehicle->SetRemap ( static_cast < unsigned int > ( ucPaintjob ) );
  2623. }
  2624. m_ucPaintjob = ucPaintjob;
  2625. m_bColorSaved = false;
  2626. }
  2627. }
  2628.  
  2629.  
  2630. float CClientVehicle::GetDirtLevel ( void )
  2631. {
  2632. if ( m_pVehicle )
  2633. {
  2634. return m_pVehicle->GetBodyDirtLevel ();
  2635. }
  2636.  
  2637. return m_fDirtLevel;
  2638. }
  2639.  
  2640.  
  2641. void CClientVehicle::SetDirtLevel ( float fDirtLevel )
  2642. {
  2643. if ( m_pVehicle )
  2644. {
  2645. m_pVehicle->SetBodyDirtLevel ( fDirtLevel );
  2646. }
  2647. m_fDirtLevel = fDirtLevel;
  2648. }
  2649. bool CClientVehicle::IsOnWater ( void )
  2650. {
  2651. if ( m_pVehicle )
  2652. {
  2653. float fWaterLevel;
  2654. CVector vecPosition, vecTemp;
  2655. GetPosition ( vecPosition );
  2656. float fDistToBaseOfModel = vecPosition.fZ - m_pVehicle->GetDistanceFromCentreOfMassToBaseOfModel();
  2657. if ( g_pGame->GetWaterManager ()->GetWaterLevel ( vecPosition, &fWaterLevel, true, &vecTemp ) )
  2658. {
  2659. if (fDistToBaseOfModel <= fWaterLevel) {
  2660. return true;
  2661. }
  2662. }
  2663. }
  2664. return false;
  2665. }
  2666.  
  2667. bool CClientVehicle::IsInWater ( void )
  2668. {
  2669. if ( m_pModelInfo )
  2670. {
  2671. CBoundingBox* pBoundingBox = m_pModelInfo->GetBoundingBox ();
  2672. if ( pBoundingBox )
  2673. {
  2674. CVector vecMin = pBoundingBox->vecBoundMin;
  2675. CVector vecPosition, vecTemp;
  2676. GetPosition ( vecPosition );
  2677. vecMin += vecPosition;
  2678. float fWaterLevel;
  2679. if ( g_pGame->GetWaterManager ()->GetWaterLevel ( vecPosition, &fWaterLevel, true, &vecTemp ) )
  2680. {
  2681. if ( vecPosition.fZ <= fWaterLevel )
  2682. {
  2683. return true;
  2684. }
  2685. }
  2686. }
  2687. }
  2688. return false;
  2689. }
  2690.  
  2691.  
  2692. float CClientVehicle::GetDistanceFromGround ( void )
  2693. {
  2694. CVector vecPosition;
  2695. GetPosition ( vecPosition );
  2696. float fGroundLevel = static_cast < float > ( g_pGame->GetWorld ()->FindGroundZFor3DPosition ( &vecPosition ) );
  2697.  
  2698. CBoundingBox* pBoundingBox = m_pModelInfo->GetBoundingBox ();
  2699. if ( pBoundingBox )
  2700. fGroundLevel -= pBoundingBox->vecBoundMin.fZ + pBoundingBox->vecBoundOffset.fZ;
  2701.  
  2702. return ( vecPosition.fZ - fGroundLevel );
  2703. }
  2704.  
  2705.  
  2706. bool CClientVehicle::IsOnGround ( void )
  2707. {
  2708. if ( m_pModelInfo )
  2709. {
  2710. CBoundingBox* pBoundingBox = m_pModelInfo->GetBoundingBox ();
  2711. if ( pBoundingBox )
  2712. {
  2713. CVector vecMin = pBoundingBox->vecBoundMin;
  2714. CVector vecPosition;
  2715. GetPosition ( vecPosition );
  2716. vecMin += vecPosition;
  2717. float fGroundLevel = static_cast < float > (
  2718. g_pGame->GetWorld ()->FindGroundZFor3DPosition ( &vecPosition ) );
  2719.  
  2720. /* Is the lowest point of the bounding box lower than 0.5 above the floor,
  2721. or is the lowest point of the bounding box higher than 0.3 below the floor */
  2722. return ( ( fGroundLevel > vecMin.fZ && ( fGroundLevel - vecMin.fZ ) < 0.5f ) ||
  2723. ( vecMin.fZ > fGroundLevel && ( vecMin.fZ - fGroundLevel ) < 0.3f ) );
  2724. }
  2725. }
  2726. return m_bIsOnGround;
  2727. }
  2728.  
  2729.  
  2730. void CClientVehicle::LockSteering ( bool bLock )
  2731. {
  2732. // STATUS_TRAIN_MOVING or STATUS_PLAYER_DISABLED will do. STATUS_TRAIN_NOT_MOVING is neater but will screw up planes (turns off the engine).
  2733.  
  2734. eEntityStatus Status = m_pVehicle->GetEntityStatus ();
  2735.  
  2736. if ( bLock && Status != STATUS_TRAIN_MOVING ) {
  2737. m_NormalStatus = Status;
  2738. m_pVehicle->SetEntityStatus ( STATUS_TRAIN_MOVING );
  2739. } else if ( !bLock && Status == STATUS_TRAIN_MOVING ) {
  2740. m_pVehicle->SetEntityStatus ( m_NormalStatus );
  2741. }
  2742.  
  2743. return;
  2744. }
  2745.  
  2746.  
  2747. bool CClientVehicle::IsSmokeTrailEnabled ( void )
  2748. {
  2749. if ( m_pVehicle )
  2750. {
  2751. return m_pVehicle->IsSmokeTrailEnabled ();
  2752. }
  2753. return m_bSmokeTrail;
  2754. }
  2755.  
  2756.  
  2757. void CClientVehicle::SetSmokeTrailEnabled ( bool bEnabled )
  2758. {
  2759. if ( m_pVehicle )
  2760. {
  2761. m_pVehicle->SetSmokeTrailEnabled ( bEnabled );
  2762. }
  2763. m_bSmokeTrail = bEnabled;
  2764. }
  2765.  
  2766.  
  2767. void CClientVehicle::ResetInterpolation ( void )
  2768. {
  2769. if ( HasTargetPosition () )
  2770. SetPosition ( m_interp.pos.vecTarget );
  2771. if ( HasTargetRotation () )
  2772. SetRotationDegrees ( m_interp.rot.vecTarget );
  2773. m_interp.pos.ulFinishTime = 0;
  2774. m_interp.rot.ulFinishTime = 0;
  2775. }
  2776.  
  2777.  
  2778. void CClientVehicle::AddMatrix ( CMatrix& Matrix, double dTime, unsigned short usTickRate )
  2779. {
  2780. /*
  2781. // See if we need an update yet (since the rotation could have a lower tick rate)
  2782. if ( ( ( dTime - m_dLastRotationTime ) * 1000 ) >= usTickRate ) {
  2783. m_fLERP = LERP_FACTOR;
  2784.  
  2785. // Set the source quaternion to whatever we have right now
  2786. m_QuatA = m_QuatLERP;
  2787.  
  2788. // Set the destination quaternion to whatever we just received
  2789. m_QuatB = CQuat ( &Matrix );
  2790.  
  2791. // Store the matrix into the pure matrix
  2792. m_MatrixPure = Matrix;
  2793.  
  2794. // Debug stuff
  2795. #ifdef MTA_DEBUG_INTERPOLATION
  2796. g_pCore->GetGraphics()->DrawTextTTF(232,200,300,216,0xDDDDDDDD, "RENEW", 1.0f, 0);
  2797. #endif
  2798.  
  2799. // Store the time for this rotation
  2800. m_dLastRotationTime = dTime;
  2801. }
  2802. */
  2803. }
  2804.  
  2805.  
  2806. void CClientVehicle::AddVelocity ( CVector& vecVelocity )
  2807. {
  2808. m_vecMoveSpeedInterpolate = vecVelocity;
  2809. }
  2810.  
  2811.  
  2812. void CClientVehicle::Interpolate ( void )
  2813. {
  2814. // Interpolate it if: It has a driver and it's not local and we're not syncing it or
  2815. // It has no driver and we're not syncing it.
  2816. if ( ( m_pDriver && !m_pDriver->IsLocalPlayer () && !static_cast < CDeathmatchVehicle* > ( this ) ->IsSyncing () ) ||
  2817. ( !m_pDriver && !static_cast < CDeathmatchVehicle* > ( this ) ->IsSyncing () ) )
  2818. {
  2819. UpdateTargetPosition ();
  2820. UpdateTargetRotation ();
  2821. }
  2822. else
  2823. {
  2824. // Otherwize make sure we have no interpolation stuff stored
  2825. RemoveTargetPosition ();
  2826. RemoveTargetRotation ();
  2827. }
  2828. }
  2829.  
  2830.  
  2831. void CClientVehicle::GetInitialDoorStates ( unsigned char * pucDoorStates )
  2832. {
  2833. switch ( m_usModel )
  2834. {
  2835. case VT_BAGGAGE:
  2836. case VT_BANDITO:
  2837. case VT_BFINJECT:
  2838. case VT_CADDY:
  2839. case VT_DOZER:
  2840. case VT_FORKLIFT:
  2841. case VT_KART:
  2842. case VT_MOWER:
  2843. case VT_QUAD:
  2844. case VT_RCBANDIT:
  2845. case VT_RCCAM:
  2846. case VT_RCGOBLIN:
  2847. case VT_RCRAIDER:
  2848. case VT_RCTIGER:
  2849. case VT_TRACTOR:
  2850. case VT_VORTEX:
  2851. memset ( pucDoorStates, DT_DOOR_MISSING, 6 );
  2852.  
  2853. // Keep the bonet and boot intact
  2854. pucDoorStates [ 0 ] = pucDoorStates [ 1 ] = DT_DOOR_INTACT;
  2855. break;
  2856. default:
  2857. memset ( pucDoorStates, DT_DOOR_INTACT, 6 );
  2858. }
  2859. }
  2860.  
  2861.  
  2862. void CClientVehicle::SetTargetPosition ( CVector& vecPosition, unsigned long ulDelay )
  2863. {
  2864. // Are we streamed in?
  2865. if ( m_pVehicle )
  2866. {
  2867. UpdateTargetPosition ();
  2868.  
  2869. unsigned long ulTime = CClientTime::GetTime ();
  2870. CVector vecLocalPosition;
  2871. GetPosition ( vecLocalPosition );
  2872.  
  2873. #ifdef MTA_DEBUG
  2874. m_interp.pos.vecStart = vecLocalPosition;
  2875. #endif
  2876. m_interp.pos.vecTarget = vecPosition;
  2877. // Calculate the relative error
  2878. m_interp.pos.vecError = vecPosition - vecLocalPosition;
  2879.  
  2880. // Apply the error over 400ms (i.e. 1/4 per 100ms )
  2881. m_interp.pos.vecError *= Lerp < const float > ( 0.25f, UnlerpClamped( 100, ulDelay, 400 ), 1.0f );
  2882.  
  2883. // Get the interpolation interval
  2884. m_interp.pos.ulStartTime = ulTime;
  2885. m_interp.pos.ulFinishTime = ulTime + ulDelay;
  2886.  
  2887. // Initialize the interpolation
  2888. m_interp.pos.fLastAlpha = 0.0f;
  2889. }
  2890. else
  2891. {
  2892. // Update our position now
  2893. SetPosition ( vecPosition );
  2894. }
  2895. }
  2896.  
  2897.  
  2898. void CClientVehicle::RemoveTargetPosition ( void )
  2899. {
  2900. m_interp.pos.ulFinishTime = 0;
  2901. }
  2902.  
  2903.  
  2904. void CClientVehicle::SetTargetRotation ( CVector& vecRotation, unsigned long ulDelay )
  2905. {
  2906. // Are we streamed in?
  2907. if ( m_pVehicle )
  2908. {
  2909. UpdateTargetRotation ();
  2910.  
  2911. unsigned long ulTime = CClientTime::GetTime ();
  2912. CVector vecLocalRotation;
  2913. GetRotationDegrees ( vecLocalRotation );
  2914.  
  2915. #ifdef MTA_DEBUG
  2916. m_interp.rot.vecStart = vecLocalRotation;
  2917. #endif
  2918. m_interp.rot.vecTarget = vecRotation;
  2919. // Get the error
  2920. m_interp.rot.vecError.fX = GetOffsetDegrees ( vecLocalRotation.fX, vecRotation.fX );
  2921. m_interp.rot.vecError.fY = GetOffsetDegrees ( vecLocalRotation.fY, vecRotation.fY );
  2922. m_interp.rot.vecError.fZ = GetOffsetDegrees ( vecLocalRotation.fZ, vecRotation.fZ );
  2923.  
  2924. // Get the interpolation interval
  2925. m_interp.rot.ulStartTime = ulTime;
  2926. m_interp.rot.ulFinishTime = ulTime + ulDelay;
  2927.  
  2928. // Initialize the interpolation
  2929. m_interp.rot.fLastAlpha = 0.0f;
  2930. }
  2931. else
  2932. {
  2933. // Update our rotation now
  2934. SetRotationDegrees ( vecRotation );
  2935. }
  2936. }
  2937.  
  2938.  
  2939. void CClientVehicle::RemoveTargetRotation ( void )
  2940. {
  2941. m_interp.rot.ulFinishTime = 0;
  2942. }
  2943.  
  2944. void CClientVehicle::UpdateTargetPosition ( void )
  2945. {
  2946. if ( HasTargetPosition () )
  2947. {
  2948. // Grab the current game position
  2949. CVector vecCurrentPosition;
  2950. GetPosition ( vecCurrentPosition );
  2951.  
  2952. // Get the factor of time spent from the interpolation start
  2953. // to the current time.
  2954. unsigned long ulCurrentTime = CClientTime::GetTime ();
  2955. float fAlpha = SharedUtil::Unlerp ( m_interp.pos.ulStartTime,
  2956. ulCurrentTime,
  2957. m_interp.pos.ulFinishTime );
  2958.  
  2959. // Don't let it overcompensate the error too much
  2960. fAlpha = SharedUtil::Clamp ( 0.0f, fAlpha, 1.5f );
  2961.  
  2962. // Get the current error portion to compensate
  2963. float fCurrentAlpha = fAlpha - m_interp.pos.fLastAlpha;
  2964. m_interp.pos.fLastAlpha = fAlpha;
  2965.  
  2966. // Apply the error compensation
  2967. CVector vecCompensation = SharedUtil::Lerp ( CVector (), fCurrentAlpha, m_interp.pos.vecError );
  2968.  
  2969. // If we finished compensating the error, finish it for the next pulse
  2970. if ( fAlpha == 1.5f )
  2971. {
  2972. m_interp.pos.ulFinishTime = 0;
  2973. }
  2974.  
  2975. CVector vecNewPosition = vecCurrentPosition + vecCompensation;
  2976.  
  2977. // Check if the distance to interpolate is too far.
  2978. if ( ( vecCurrentPosition - m_interp.pos.vecTarget ).Length () > VEHICLE_INTERPOLATION_WARP_THRESHOLD )
  2979. {
  2980. // Abort all interpolation
  2981. m_interp.pos.ulFinishTime = 0;
  2982. vecNewPosition = m_interp.pos.vecTarget;
  2983.  
  2984. if ( HasTargetRotation () )
  2985. SetRotationDegrees ( m_interp.rot.vecTarget );
  2986. m_interp.rot.ulFinishTime = 0;
  2987. }
  2988.  
  2989. SetPosition ( vecNewPosition, false );
  2990.  
  2991. if ( !m_bIsCollisionEnabled )
  2992. {
  2993. if ( m_eVehicleType != CLIENTVEHICLE_HELI && m_eVehicleType != CLIENTVEHICLE_BOAT )
  2994. {
  2995. // Ghostmode upwards movement compensation
  2996. CVector MoveSpeed;
  2997. m_pVehicle->GetMoveSpeed ( &MoveSpeed );
  2998. float SpeedXY = CVector( MoveSpeed.fX, MoveSpeed.fY, 0 ).Length ();
  2999. if ( MoveSpeed.fZ > 0.00 && MoveSpeed.fZ < 0.02 && MoveSpeed.fZ > SpeedXY )
  3000. MoveSpeed.fZ = SpeedXY;
  3001. m_pVehicle->SetMoveSpeed ( &MoveSpeed );
  3002. }
  3003. }
  3004.  
  3005. #ifdef MTA_DEBUG
  3006. if ( g_pClientGame->IsShowingInterpolation () &&
  3007. g_pClientGame->GetLocalPlayer ()->GetOccupiedVehicle () == this )
  3008. {
  3009. // DEBUG
  3010. SString strBuffer ( "-== Vehicle interpolation ==-\n"
  3011. "vecStart: %f %f %f\n"
  3012. "vecTarget: %f %f %f\n"
  3013. "Position: %f %f %f\n"
  3014. "Error: %f %f %f\n"
  3015. "Alpha: %f\n"
  3016. "Interpolating: %s\n",
  3017. m_interp.pos.vecStart.fX, m_interp.pos.vecStart.fY, m_interp.pos.vecStart.fZ,
  3018. m_interp.pos.vecTarget.fX, m_interp.pos.vecTarget.fY, m_interp.pos.vecTarget.fZ,
  3019. vecNewPosition.fX, vecNewPosition.fY, vecNewPosition.fZ,
  3020. m_interp.pos.vecError.fX, m_interp.pos.vecError.fY, m_interp.pos.vecError.fZ,
  3021. fAlpha, ( m_interp.pos.ulFinishTime == 0 ? "no" : "yes" ) );
  3022. g_pClientGame->GetManager ()->GetDisplayManager ()->DrawText2D ( strBuffer, CVector ( 0.45f, 0.05f, 0 ), 1.0f, 0xFFFFFFFF );
  3023. }
  3024. #endif
  3025.  
  3026. // Update our contact players
  3027. CVector vecPlayerPosition;
  3028. CVector vecOffset;
  3029. list < CClientPed * > ::iterator iter = m_Contacts.begin ();
  3030. for ( ; iter != m_Contacts.end () ; iter++ )
  3031. {
  3032. CClientPed * pModel = *iter;
  3033. pModel->GetPosition ( vecPlayerPosition );
  3034. vecOffset = vecPlayerPosition - vecCurrentPosition;
  3035. vecPlayerPosition = vecNewPosition + vecOffset;
  3036. pModel->SetPosition ( vecPlayerPosition );
  3037. }
  3038. }
  3039. }
  3040.  
  3041.  
  3042. void CClientVehicle::UpdateTargetRotation ( void )
  3043. {
  3044. // Do we have a rotation to move towards? and are we streamed in?
  3045. if ( HasTargetRotation () )
  3046. {
  3047. // Grab the current game rotation
  3048. CVector vecCurrentRotation;
  3049. GetRotationDegrees ( vecCurrentRotation );
  3050.  
  3051. // Get the factor of time spent from the interpolation start
  3052. // to the current time.
  3053. unsigned long ulCurrentTime = CClientTime::GetTime ();
  3054. float fAlpha = SharedUtil::Unlerp ( m_interp.rot.ulStartTime,
  3055. ulCurrentTime,
  3056. m_interp.rot.ulFinishTime );
  3057.  
  3058. // Don't let it to overcompensate the error
  3059. fAlpha = SharedUtil::Clamp ( 0.0f, fAlpha, 1.0f );
  3060.  
  3061. // Get the current error portion to compensate
  3062. float fCurrentAlpha = fAlpha - m_interp.rot.fLastAlpha;
  3063. m_interp.rot.fLastAlpha = fAlpha;
  3064.  
  3065. CVector vecCompensation = SharedUtil::Lerp ( CVector (), fCurrentAlpha, m_interp.rot.vecError );
  3066.  
  3067. // If we finished compensating the error, finish it for the next pulse
  3068. if ( fAlpha == 1.0f )
  3069. {
  3070. m_interp.rot.ulFinishTime = 0;
  3071. }
  3072.  
  3073. SetRotationDegrees ( vecCurrentRotation + vecCompensation, false );
  3074. }
  3075. }
  3076.  
  3077.  
  3078. bool CClientVehicle::IsEnterable ( void )
  3079. {
  3080. if ( m_pVehicle )
  3081. {
  3082. // Server vehicle?
  3083. if ( !IsLocalEntity () )
  3084. {
  3085. if ( GetHealth () > 0.0f )
  3086. {
  3087. if ( !IsInWater() || (GetVehicleType() == CLIENTVEHICLE_BOAT ||
  3088. m_usModel == 447 /* sea sparrow */
  3089. || m_usModel == 417 /* levithan */
  3090. || m_usModel == 460 /* skimmer */ ) )
  3091. {
  3092. return true;
  3093. }
  3094. }
  3095. }
  3096. }
  3097. return false;
  3098. }
  3099.  
  3100. bool CClientVehicle::HasRadio ( void )
  3101. {
  3102. if ( m_eVehicleType != CLIENTVEHICLE_BMX ) return true;
  3103. return false;
  3104. }
  3105.  
  3106.  
  3107. bool CClientVehicle::HasPoliceRadio ( void )
  3108. {
  3109. switch ( m_usModel )
  3110. {
  3111. case VT_COPCARLA:
  3112. case VT_COPCARSF:
  3113. case VT_COPCARVG:
  3114. case VT_COPCARRU:
  3115. case VT_POLMAV:
  3116. case VT_COPBIKE:
  3117. case VT_SWATVAN:
  3118. return true;
  3119. break;
  3120. default:
  3121. break;
  3122. }
  3123. return false;
  3124. }
  3125.  
  3126. void CClientVehicle::RemoveAllProjectiles ( void )
  3127. {
  3128. CClientProjectile * pProjectile = NULL;
  3129. list < CClientProjectile* > ::iterator iter = m_Projectiles.begin ();
  3130. for ( ; iter != m_Projectiles.end () ; iter++ )
  3131. {
  3132. pProjectile = *iter;
  3133. pProjectile->m_pCreator = NULL;
  3134. g_pClientGame->GetElementDeleter ()->Delete ( pProjectile );
  3135. }
  3136. m_Projectiles.clear ();
  3137. }
  3138.  
  3139. void CClientVehicle::SetGravity ( const CVector& vecGravity )
  3140. {
  3141. if ( m_pVehicle )
  3142. m_pVehicle->SetGravity ( &vecGravity );
  3143.  
  3144. m_vecGravity = vecGravity;
  3145. }
  3146.  
  3147.  
  3148. SColor CClientVehicle::GetHeadLightColor ( void )
  3149. {
  3150. if ( m_pVehicle )
  3151. {
  3152. return m_pVehicle->GetHeadLightColor ();
  3153. }
  3154. return m_HeadLightColor;
  3155. }
  3156.  
  3157.  
  3158. int CClientVehicle::GetCurrentGear ( void )
  3159. {
  3160. if ( m_pVehicle )
  3161. {
  3162. return m_pVehicle->GetCurrentGear ();
  3163. }
  3164. return 0;
  3165. }
  3166.  
  3167.  
  3168. void CClientVehicle::SetHeadLightColor ( const SColor color )
  3169. {
  3170. if ( m_pVehicle )
  3171. {
  3172. m_pVehicle->SetHeadLightColor ( color );
  3173. }
  3174. m_HeadLightColor = color;
  3175. }
  3176.  
  3177.  
  3178. //
  3179. // Below here is basically awful.
  3180. // But there you go.
  3181. //
  3182.  
  3183. #if OCCUPY_DEBUG_INFO
  3184. #define INFO(x) g_pCore->GetConsole ()->Printf x
  3185. #define WARN(x) g_pCore->GetConsole ()->Printf x
  3186. #else
  3187. #define INFO(x) {}
  3188. #define WARN(x) {}
  3189. #endif
  3190.  
  3191. std::string GetPlayerName ( CClientPed* pClientPed )
  3192. {
  3193. if ( !pClientPed )
  3194. return "null";
  3195. if ( IS_PLAYER ( pClientPed ) )
  3196. {
  3197. CClientPlayer* pPlayer = static_cast < CClientPlayer * > ( pClientPed );
  3198. return pPlayer->GetNick ();
  3199. }
  3200. return "ped";
  3201. }
  3202.  
  3203. //
  3204. // Make a ped become an occupied driver/passenger
  3205. // Static function
  3206. //
  3207. void CClientVehicle::SetPedOccupiedVehicle ( CClientPed* pClientPed, CClientVehicle* pVehicle, unsigned int uiSeat )
  3208. {
  3209. INFO (( "SetPedOccupiedVehicle:%s in vehicle:0x%08x seat:%d", GetPlayerName( pClientPed ).c_str (), pVehicle, uiSeat ));
  3210.  
  3211. if ( !pClientPed || !pVehicle )
  3212. return;
  3213.  
  3214. // Clear ped from any current occupied seat in this vehicle
  3215. if ( pClientPed->m_pOccupiedVehicle == pVehicle )
  3216. {
  3217. if ( pVehicle->m_pDriver == pClientPed )
  3218. pVehicle->m_pDriver = NULL;
  3219.  
  3220. for ( int i = 0 ; i < NUMELMS ( pVehicle->m_pPassengers ) ; i++ )
  3221. if ( pVehicle->m_pPassengers[i] == pClientPed )
  3222. pVehicle->m_pPassengers[i] = NULL;
  3223. }
  3224.  
  3225. // Vehicle vars
  3226. if ( uiSeat == 0 )
  3227. {
  3228. if ( pVehicle->m_pDriver && pVehicle->m_pDriver != pClientPed )
  3229. {
  3230. WARN (( "Emergency occupied driver eject by %s on %s\n", GetPlayerName( pClientPed ).c_str (), GetPlayerName( pVehicle->m_pDriver ).c_str () ));
  3231. UnpairPedAndVehicle ( pVehicle->m_pDriver, pVehicle );
  3232. }
  3233. pVehicle->m_pDriver = pClientPed;
  3234. }
  3235. else
  3236. {
  3237. assert ( uiSeat <= NUMELMS(pVehicle->m_pPassengers) );
  3238. if ( pVehicle->m_pPassengers [uiSeat-1] && pVehicle->m_pPassengers [uiSeat-1] != pClientPed )
  3239. {
  3240. WARN (( "Emergency occupied passenger eject by %s on %s\n", GetPlayerName( pClientPed ).c_str (), GetPlayerName( pVehicle->m_pPassengers [uiSeat-1] ).c_str () ));
  3241. UnpairPedAndVehicle ( pVehicle->m_pPassengers [uiSeat-1], pVehicle );
  3242. }
  3243. pVehicle->m_pPassengers [uiSeat-1] = pClientPed;
  3244. }
  3245.  
  3246. // Ped vars
  3247. pClientPed->m_pOccupiedVehicle = pVehicle;
  3248. pClientPed->m_uiOccupiedVehicleSeat = uiSeat;
  3249.  
  3250. // Checks
  3251. ValidatePedAndVehiclePair ( pClientPed, pVehicle );
  3252. }
  3253.  
  3254.  
  3255. //
  3256. // Make a ped become an occupying driver/passenger
  3257. // Static function
  3258. //
  3259. void CClientVehicle::SetPedOccupyingVehicle ( CClientPed* pClientPed, CClientVehicle* pVehicle, unsigned int uiSeat )
  3260. {
  3261. INFO (( "SetPedOccupyingVehicle:%s in vehicle:0x%08x seat:%d", GetPlayerName( pClientPed ).c_str (), pVehicle, uiSeat ));
  3262.  
  3263. if ( !pClientPed || !pVehicle )
  3264. return;
  3265.  
  3266. // Clear ped from any current occupying seat in this vehicle
  3267. if ( pClientPed->m_pOccupyingVehicle == pVehicle )
  3268. {
  3269. if ( pVehicle->m_pOccupyingDriver == pClientPed )
  3270. pVehicle->m_pOccupyingDriver = NULL;
  3271.  
  3272. for ( int i = 0 ; i < NUMELMS ( pVehicle->m_pOccupyingPassengers ) ; i++ )
  3273. if ( pVehicle->m_pOccupyingPassengers[i] == pClientPed )
  3274. pVehicle->m_pOccupyingPassengers[i] = NULL;
  3275. }
  3276.  
  3277. // Vehicle vars
  3278. if ( uiSeat == 0 )
  3279. {
  3280. if ( pVehicle->m_pOccupyingDriver && pVehicle->m_pOccupyingDriver != pClientPed )
  3281. {
  3282. WARN (( "Emergency occupying driver eject by %s on %s\n", GetPlayerName( pClientPed ).c_str (), GetPlayerName( pVehicle->m_pOccupyingDriver ).c_str () ));
  3283. UnpairPedAndVehicle ( pVehicle->m_pOccupyingDriver, pVehicle );
  3284. }
  3285. pVehicle->m_pOccupyingDriver = pClientPed;
  3286. }
  3287. else
  3288. {
  3289. assert ( uiSeat <= NUMELMS(pVehicle->m_pOccupyingPassengers) );
  3290. if ( pVehicle->m_pOccupyingPassengers [uiSeat-1] && pVehicle->m_pOccupyingPassengers [uiSeat-1] != pClientPed )
  3291. {
  3292. WARN (( "Emergency occupying passenger eject by %s on %s\n", GetPlayerName( pClientPed ).c_str (), GetPlayerName( pVehicle->m_pOccupyingPassengers [uiSeat-1] ).c_str () ));
  3293. UnpairPedAndVehicle ( pVehicle->m_pOccupyingPassengers [uiSeat-1], pVehicle );
  3294. }
  3295. pVehicle->m_pOccupyingPassengers [uiSeat-1] = pClientPed;
  3296. }
  3297.  
  3298. // Ped vars
  3299. pClientPed->m_pOccupyingVehicle = pVehicle;
  3300. // if ( uiSeat >= 0 && uiSeat < 8 )
  3301. // pClientPed->m_uiOccupyingSeat = uiSeat;
  3302.  
  3303. // Checks
  3304. ValidatePedAndVehiclePair ( pClientPed, pVehicle );
  3305. }
  3306.  
  3307.  
  3308. //
  3309. // Check ped <> vehicle pointers
  3310. // Static function
  3311. //
  3312. void CClientVehicle::ValidatePedAndVehiclePair( CClientPed* pClientPed, CClientVehicle* pVehicle )
  3313. {
  3314. #if MTA_DEBUG
  3315. // Occupied
  3316. // Vehicle vars
  3317. if ( pVehicle->m_pDriver )
  3318. assert ( pVehicle->m_pDriver->m_pOccupiedVehicle == pVehicle );
  3319.  
  3320. for ( int i = 0 ; i < NUMELMS ( pVehicle->m_pPassengers ) ; i++ )
  3321. if ( pVehicle->m_pPassengers[i] )
  3322. assert ( pVehicle->m_pPassengers[i]->m_pOccupiedVehicle == pVehicle );
  3323.  
  3324. // Ped vars
  3325. if ( pClientPed->m_pOccupiedVehicle )
  3326. {
  3327. // Make sure refed once by vehicle
  3328. int iCount = 0;
  3329. if ( pClientPed->m_pOccupiedVehicle->m_pDriver == pClientPed )
  3330. iCount++;
  3331.  
  3332. for ( int i = 0 ; i < NUMELMS ( pClientPed->m_pOccupiedVehicle->m_pPassengers ) ; i++ )
  3333. if ( pClientPed->m_pOccupiedVehicle->m_pPassengers[i] == pClientPed )
  3334. iCount++;
  3335.  
  3336. assert ( iCount == 1 );
  3337. }
  3338.  
  3339. // Occupying
  3340. // Vehicle vars
  3341. if ( pVehicle->m_pOccupyingDriver )
  3342. assert ( pVehicle->m_pOccupyingDriver->m_pOccupyingVehicle == pVehicle );
  3343.  
  3344. for ( int i = 0 ; i < NUMELMS ( pVehicle->m_pOccupyingPassengers ) ; i++ )
  3345. if ( pVehicle->m_pOccupyingPassengers[i] )
  3346. assert ( pVehicle->m_pOccupyingPassengers[i]->m_pOccupyingVehicle == pVehicle );
  3347.  
  3348. // Ped vars
  3349. if ( pClientPed->m_pOccupyingVehicle )
  3350. {
  3351. // Make sure refed once by vehicle
  3352. int iCount = 0;
  3353. if ( pClientPed->m_pOccupyingVehicle->m_pOccupyingDriver == pClientPed )
  3354. iCount++;
  3355.  
  3356. for ( int i = 0 ; i < NUMELMS ( pClientPed->m_pOccupyingVehicle->m_pOccupyingPassengers ) ; i++ )
  3357. if ( pClientPed->m_pOccupyingVehicle->m_pOccupyingPassengers[i] == pClientPed )
  3358. iCount++;
  3359.  
  3360. assert ( iCount == 1 );
  3361. }
  3362. #endif
  3363. }
  3364.  
  3365.  
  3366. //
  3367. // Make sure there is no association between a ped and a vehicle
  3368. // Static function
  3369. //
  3370. void CClientVehicle::UnpairPedAndVehicle( CClientPed* pClientPed, CClientVehicle* pVehicle )
  3371. {
  3372. if ( !pClientPed || !pVehicle )
  3373. return;
  3374.  
  3375. // Checks
  3376. ValidatePedAndVehiclePair ( pClientPed, pVehicle );
  3377.  
  3378. // Occupied
  3379. // Vehicle vars
  3380. if ( pVehicle->m_pDriver == pClientPed )
  3381. {
  3382. INFO (( "UnpairPedAndVehicle: m_pDriver:%s from vehicle:0x%08x", GetPlayerName( pClientPed ).c_str (), pVehicle ));
  3383. pVehicle->m_pDriver = NULL;
  3384. }
  3385.  
  3386.  
  3387. for ( int i = 0 ; i < NUMELMS ( pVehicle->m_pPassengers ) ; i++ )
  3388. if ( pVehicle->m_pPassengers[i] == pClientPed )
  3389. {
  3390. INFO (( "UnpairPedAndVehicle: m_pPassenger:%s seat:%d from vehicle:0x%08x", GetPlayerName( pClientPed ).c_str (), i + 1, pVehicle ));
  3391. pVehicle->m_pPassengers[i] = NULL;
  3392. }
  3393.  
  3394. // Ped vars
  3395. if ( pClientPed->m_pOccupiedVehicle == pVehicle )
  3396. {
  3397. INFO (( "UnpairPedAndVehicle: pClientPed:%s from m_pOccupiedVehicle:0x%08x", GetPlayerName( pClientPed ).c_str (), pVehicle ));
  3398. pClientPed->m_pOccupiedVehicle = NULL;
  3399. pClientPed->m_uiOccupiedVehicleSeat = 0xFF;
  3400. }
  3401.  
  3402. // Occupying
  3403. // Vehicle vars
  3404. if ( pVehicle->m_pOccupyingDriver == pClientPed )
  3405. {
  3406. INFO (( "UnpairPedAndVehicle: m_pOccupyingDriver:%s from vehicle:0x%08x", GetPlayerName( pClientPed ).c_str (), pVehicle ));
  3407. pVehicle->m_pOccupyingDriver = NULL;
  3408. }
  3409.  
  3410. for ( int i = 0 ; i < NUMELMS ( pVehicle->m_pOccupyingPassengers ) ; i++ )
  3411. if ( pVehicle->m_pOccupyingPassengers[i] == pClientPed )
  3412. {
  3413. INFO (( "UnpairPedAndVehicle: m_pOccupyingPassenger:%s seat:%d from vehicle:0x%08x", GetPlayerName( pClientPed ).c_str (), i + 1, pVehicle ));
  3414. pVehicle->m_pOccupyingPassengers[i] = NULL;
  3415. }
  3416.  
  3417. // Ped vars
  3418. if ( pClientPed->m_pOccupyingVehicle == pVehicle )
  3419. {
  3420. INFO (( "UnpairPedAndVehicle: pClientPed:%s from m_pOccupyingVehicle:0x%08x", GetPlayerName( pClientPed ).c_str (), pVehicle ));
  3421. pClientPed->m_pOccupyingVehicle = NULL;
  3422. //pClientPed->m_uiOccupyingSeat = 0xFF;
  3423. }
  3424. }
  3425.  
  3426.  
  3427. //
  3428. // Make sure there is no association between a ped and its vehicle
  3429. // Static function
  3430. //
  3431. void CClientVehicle::UnpairPedAndVehicle( CClientPed* pClientPed )
  3432. {
  3433. UnpairPedAndVehicle ( pClientPed, pClientPed->GetOccupiedVehicle () );
  3434. UnpairPedAndVehicle ( pClientPed, pClientPed->m_pOccupyingVehicle );
  3435. UnpairPedAndVehicle ( pClientPed, pClientPed->GetRealOccupiedVehicle () );
  3436.  
  3437. if ( pClientPed->m_pOccupiedVehicle )
  3438. {
  3439. WARN (( "*** Unexpected m_pOccupiedVehicle:0x%08x for %s\n", pClientPed->m_pOccupiedVehicle, GetPlayerName( pClientPed ).c_str () ));
  3440. pClientPed->m_pOccupiedVehicle = NULL;
  3441. }
  3442.  
  3443. if ( pClientPed->m_pOccupyingVehicle )
  3444. {
  3445. WARN (( "*** Unexpected m_pOccupyingVehicle:0x%08x for %s\n", pClientPed->m_pOccupyingVehicle, GetPlayerName( pClientPed ).c_str () ));
  3446. pClientPed->m_pOccupyingVehicle = NULL;
  3447. }
  3448. }
  3449.  
  3450. #if WITH_VEHICLE_HANDLING
  3451. void CClientVehicle::ApplyHandling( void )
  3452. {
  3453. if ( m_pVehicle )
  3454. {
  3455. m_pVehicle->GetHandlingData()->Recalculate();
  3456. // Update vehicle settings
  3457. m_pVehicle->UpdateHandlingStatus ();
  3458. }
  3459. }
  3460.  
  3461.  
  3462. CHandlingEntry* CClientVehicle::GetHandlingData( void )
  3463. {
  3464. if ( m_pVehicle )
  3465. {
  3466. return m_pVehicle->GetHandlingData();
  3467. }
  3468. else if ( m_pHandlingEntry )
  3469. {
  3470. return m_pHandlingEntry;
  3471. }
  3472. return NULL;
  3473. }
  3474. #endif
  3475.  
  3476.  
  3477. CSphere CClientVehicle::GetWorldBoundingSphere ( void )
  3478. {
  3479. CSphere sphere;
  3480. CModelInfo* pModelInfo = g_pGame->GetModelInfo ( GetModel () );
  3481. if ( pModelInfo )
  3482. {
  3483. CBoundingBox* pBoundingBox = pModelInfo->GetBoundingBox ();
  3484. if ( pBoundingBox )
  3485. {
  3486. sphere.vecPosition = pBoundingBox->vecBoundOffset;
  3487. sphere.fRadius = pBoundingBox->fRadius;
  3488. }
  3489. }
  3490. sphere.vecPosition += GetStreamPosition ();
  3491. return sphere;
  3492. }
  3493.  
  3494.  
  3495. // Currently, this should only be called if the local player is, or was just in the vehicle
  3496. void CClientVehicle::HandleWaitingForGroundToLoad ( void )
  3497. {
  3498. // Check if near any MTA objects
  3499. bool bNearObject = false;
  3500. CVector vecPosition;
  3501. GetPosition ( vecPosition );
  3502. CClientEntityResult result;
  3503. GetClientSpatialDatabase ()->SphereQuery ( result, CSphere ( vecPosition + CVector ( 0, 0, -3 ), 5 ) );
  3504. for ( CClientEntityResult::const_iterator it = result.begin () ; it != result.end (); ++it )
  3505. {
  3506. if ( (*it)->GetType () == CCLIENTOBJECT )
  3507. {
  3508. bNearObject = true;
  3509. break;
  3510. }
  3511. }
  3512.  
  3513. if ( !bNearObject )
  3514. {
  3515. // If not near any MTA objects, then don't bother waiting
  3516. SetFrozenWaitingForGroundToLoad ( false );
  3517. #ifdef ASYNC_LOADING_DEBUG_OUTPUTA
  3518. OutputDebugLine ( " FreezeUntilCollisionLoaded - Early stop" );
  3519. #endif
  3520. return;
  3521. }
  3522.  
  3523. // Reset position
  3524. CVector vecTemp;
  3525. m_pVehicle->SetMatrix ( &m_matFrozen );
  3526. m_pVehicle->SetMoveSpeed ( &vecTemp );
  3527. m_pVehicle->SetTurnSpeed ( &vecTemp );
  3528. m_vecMoveSpeedMeters = vecTemp;
  3529. m_vecMoveSpeed = vecTemp;
  3530. m_vecTurnSpeed = vecTemp;
  3531.  
  3532. // Load load load
  3533. if ( GetModelInfo () )
  3534. g_pGame->GetStreaming()->LoadAllRequestedModels ();
  3535.  
  3536. // Start out with a fairly big radius to check, and shrink it down over time
  3537. float fUseRadius = 50.0f * ( 1.f - Max ( 0.f, m_fObjectsAroundTolerance ) );
  3538.  
  3539. // Gather up some flags
  3540. CClientObjectManager* pObjectManager = g_pClientGame->GetObjectManager ();
  3541. bool bASync = g_pGame->IsASyncLoadingEnabled ();
  3542. bool bMTAObjLimit = pObjectManager->IsObjectLimitReached ();
  3543. bool bHasModel = GetModelInfo () != NULL;
  3544. #ifndef ASYNC_LOADING_DEBUG_OUTPUTA
  3545. bool bMTALoaded = pObjectManager->ObjectsAroundPointLoaded ( vecPosition, fUseRadius, m_usDimension );
  3546. #else
  3547. SString strAround;
  3548. bool bMTALoaded = pObjectManager->ObjectsAroundPointLoaded ( vecPosition, fUseRadius, m_usDimension, &strAround );
  3549. #endif
  3550.  
  3551. #ifdef ASYNC_LOADING_DEBUG_OUTPUTA
  3552. SString status = SString ( "%2.2f,%2.2f,%2.2f bASync:%d bHasModel:%d bMTALoaded:%d bMTAObjLimit:%d m_fGroundCheckTolerance:%2.2f m_fObjectsAroundTolerance:%2.2f fUseRadius:%2.1f"
  3553. ,vecPosition.fX, vecPosition.fY, vecPosition.fZ
  3554. ,bASync, bHasModel, bMTALoaded, bMTAObjLimit, m_fGroundCheckTolerance, m_fObjectsAroundTolerance, fUseRadius );
  3555. #endif
  3556.  
  3557. // See if ground is ready
  3558. if ( ( !bHasModel || !bMTALoaded ) && m_fObjectsAroundTolerance < 1.f )
  3559. {
  3560. m_fGroundCheckTolerance = 0.f;
  3561. m_fObjectsAroundTolerance = Min ( 1.f, m_fObjectsAroundTolerance + 0.01f );
  3562. #ifdef ASYNC_LOADING_DEBUG_OUTPUTA
  3563. status += ( " FreezeUntilCollisionLoaded - wait" );
  3564. #endif
  3565. }
  3566. else
  3567. {
  3568. // Models should be loaded, but sometimes the collision is still not ready
  3569. // Do a ground distance check to make sure.
  3570. // Make the check tolerance larger with each passing frame
  3571. m_fGroundCheckTolerance = Min ( 1.f, m_fGroundCheckTolerance + 0.01f );
  3572. float fDist = GetDistanceFromGround ();
  3573. float fUseDist = fDist * ( 1.f - m_fGroundCheckTolerance );
  3574. if ( fUseDist > -0.2f && fUseDist < 1.5f )
  3575. SetFrozenWaitingForGroundToLoad ( false );
  3576.  
  3577. #ifdef ASYNC_LOADING_DEBUG_OUTPUTA
  3578. status += ( SString ( " GetDistanceFromGround: fDist:%2.2f fUseDist:%2.2f", fDist, fUseDist ) );
  3579. #endif
  3580.  
  3581. // Stop waiting after 3 frames, if the object limit has not been reached. (bASync should always be false here)
  3582. if ( m_fGroundCheckTolerance > 0.03f && !bMTAObjLimit && !bASync )
  3583. SetFrozenWaitingForGroundToLoad ( false );
  3584. }
  3585.  
  3586. #ifdef ASYNC_LOADING_DEBUG_OUTPUTA
  3587. OutputDebugLine ( status );
  3588. g_pCore->GetGraphics ()->DrawText ( 10, 220, -1, 1, status );
  3589.  
  3590. std::vector < SString > lineList;
  3591. strAround.Split ( "\n", lineList );
  3592. for ( unsigned int i = 0 ; i < lineList.size () ; i++ )
  3593. g_pCore->GetGraphics ()->DrawText ( 10, 230 + i * 10, -1, 1, lineList[i] );
  3594. #endif
  3595. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement