Advertisement
Guest User

Untitled

a guest
Jul 19th, 2019
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 120.74 KB | None | 0 0
  1. /****************************************************************************
  2. * VEHICLE HANDLER ENTITY DEFINITION
  3. *
  4. * Description: Vehicle handler entity. Stores information about
  5. * the vehicle's parts and so on. It is the main body of the vehicle.
  6. ***************************************************************************/
  7.  
  8. class Vehicle_Controller;
  9.  
  10. Vehicle_Handler CurrentGameVehicle; // Pointer to the current game vehicle
  11.  
  12. // Radial Menu Action definitions
  13. #include "scripts/Entities/RadialActionDefs.h"
  14.  
  15. vector VSunPos; // Sunlight position and distance vector (for use in power generation) [0] = Azimuth, [1] = Zenith, [2] = Distance in AU
  16. vector VWeather; // Weather vector (for use in power generation etc) [0] = Weather value, [1] = Wind direction, [2] = Wind speed
  17. string VSkyPreset; // The currently set sky preset (for switching between NV and normal)
  18.  
  19. Controller CallCtrlerOnCancel; // Linked to in the cancel function in CCGame.c
  20.  
  21. class Controller
  22. {
  23. /* Vehicle_Controller owner;
  24.  
  25. void SetOwner(Vehicle_Controller own)
  26. {
  27. owner = own;
  28. }
  29. */
  30. void ~Controller()
  31. {
  32. if (CallCtrlerOnCancel == this)
  33. CallCtrlerOnCancel = NULL;
  34. }
  35.  
  36. bool Controller_OnCancel()
  37. {
  38. return true;
  39. }
  40.  
  41. void Controller_OnSelect(Vehicle_Controller controller)
  42. {
  43. }
  44.  
  45. void Controller_OnUnselect(Vehicle_Controller controller)
  46. {
  47. }
  48.  
  49. void Controller_Init(Vehicle_Controller controller)
  50. {
  51. }
  52.  
  53. void Controller_PostInit(Vehicle_Controller controller)
  54. {
  55. }
  56.  
  57. void Controller_Exit(Vehicle_Controller controller)
  58. {
  59. }
  60.  
  61. void Controller_OnFrm(Vehicle_Controller controller)
  62. {
  63. }
  64.  
  65. void Controller_OnPFrm(Vehicle_Controller controller)
  66. {
  67. }
  68.  
  69. void Controller_OnDeleteWidgets(Vehicle_Controller controller)
  70. {
  71. }
  72.  
  73. void Controller_OnPreSim(Vehicle_Controller controller)
  74. {
  75. }
  76.  
  77. void Controller_OnSim(Vehicle_Controller controller)
  78. {
  79. }
  80.  
  81. void Controller_OnAfterSim(Vehicle_Controller controller)
  82. {
  83. }
  84.  
  85. void Controller_OnTeleport(Vehicle_Controller controller)
  86. {
  87. }
  88.  
  89. void Controller_OnSetVelocity(Vehicle_Controller controller)
  90. {
  91. }
  92.  
  93. string Controller_GetStringForVar(string varName)
  94. {
  95. return "";
  96. }
  97.  
  98. int Controller_GetIntForVar(string varName)
  99. {
  100. return 0;
  101. }
  102.  
  103. float Controller_GetFloatForVar(string varName)
  104. {
  105. return 0;
  106. }
  107.  
  108. bool Controller_GetBoolForVar(string varName)
  109. {
  110. return false;
  111. }
  112.  
  113. vector Controller_GetVectorForVar(string varName)
  114. {
  115. return ZeroVec;
  116. }
  117.  
  118. bool Controller_GetVehicleBroken()
  119. {
  120. return false;
  121. }
  122.  
  123. float Controller_GetListenerVolume()
  124. {
  125. return 1;
  126. }
  127.  
  128. float Controller_GetListenerSFXLerp()
  129. {
  130. return 0;
  131. }
  132.  
  133. string Controller_GetListenerSFXPath()
  134. {
  135. return "";
  136. }
  137.  
  138. bool Controller_GetOutOfFuel()
  139. {
  140. return false;
  141. }
  142.  
  143. bool Controller_Editor_GetCanSpawnFuel()
  144. {
  145. return false;
  146. }
  147.  
  148. void Controller_Editor_SpawnFuel()
  149. {
  150. }
  151.  
  152. void Controller_OnFullyInitialized()
  153. {
  154. }
  155.  
  156. void Controller_OnPartDamagedBy(Vehicle_Controller controller, Vehicle_Part part, float damage, int damagedByID)
  157. {
  158. }
  159.  
  160. void Controller_OnPartHandleDamage(Vehicle_Controller controller, Vehicle_Part part, float damage)
  161. {
  162. }
  163.  
  164. void Controller_OnBreakJoint(Vehicle_Controller controller, int jNum, bool breakFX, bool logLoss)
  165. {
  166. }
  167.  
  168. void Controller_OnDeletePart(Vehicle_Controller controller, Vehicle_Part part, int pNum)
  169. {
  170. }
  171.  
  172. void Controller_OnPress(Vehicle_Controller controller, Vehicle_Part part, bool end)
  173. {
  174. }
  175.  
  176. void Controller_OnUnPress(Vehicle_Controller controller, Vehicle_Part part, bool end)
  177. {
  178. }
  179.  
  180. void Controller_OnEvent(Vehicle_Controller controller, string eventName)
  181. {
  182. }
  183.  
  184. void Controller_OnEventWithForce(Vehicle_Controller controller, string eventName, vector pos, vector force)
  185. {
  186. }
  187.  
  188. void Controller_OnEventWithEntity(Vehicle_Controller controller, string eventName, _entity ent)
  189. {
  190. }
  191.  
  192. void Controller_OnEventWithUnit(Vehicle_Controller controller, string eventName, Vehicle_Handler unit)
  193. {
  194. }
  195.  
  196. void Controller_OnEventWithPart(Vehicle_Controller controller, string eventName, Vehicle_Part part)
  197. {
  198. }
  199.  
  200. void Controller_OnEventWithSoundParams(Vehicle_Controller controller, string eventName, SoundShader sndShdr, vector sndPos, float sndVol, int ownerID)
  201. {
  202. }
  203.  
  204. void Controller_OnEventWithInt(Vehicle_Controller controller, string eventName, int input)
  205. {
  206. }
  207.  
  208. void Controller_OnEventWithFloat(Vehicle_Controller controller, string eventName, float input)
  209. {
  210. }
  211.  
  212. void Controller_OnEventWithMatrix(Vehicle_Controller controller, string eventName, vector mat[])
  213. {
  214. }
  215.  
  216. void Controller_OnContact(Vehicle_Controller controller, Vehicle_Part contactPart, _entity other, Contact extra)
  217. {
  218. }
  219.  
  220. void Controller_SetCustomAnimation(string animPath, float tgtAnimSpeed, float tgtAnimFadeSpeed, bool noMove, bool mustComplete, bool lockView, float tgtFrame)
  221. {
  222. }
  223.  
  224. void Controller_OnCompleteCustomAnimation(string animPath)
  225. {
  226. }
  227.  
  228. void Controller_OnInventoryChanged(Vehicle_Controller controller)
  229. {
  230. }
  231.  
  232. void Controller_OnInventoryAccessing(Vehicle_Controller controller, Vehicle_Part part, widget rootWidget, float timeSlice)
  233. {
  234. }
  235.  
  236. // Called from a Ragdoll_Part entity if associated with this unit
  237. void Controller_OnRagdollContact(Vehicle_Controller controller, Ragdoll_Part contactPart, _entity other, Contact extra)
  238. {
  239. }
  240.  
  241. bool Controller_OnClick(Vehicle_Controller controller, widget w, int x, int y, int button)
  242. {
  243. return false;
  244. }
  245.  
  246. void OnEnterCar()
  247. {
  248. }
  249.  
  250. void OnEnterBBlockSeat()
  251. {
  252. }
  253.  
  254. // Called when fuel handler values should be stored (deletion of stored values handled automatically)
  255. void StoreFuelHandlerValues()
  256. {
  257. }
  258.  
  259. //! MULTIPLAYER: See comment in GameEntity class
  260. void OnNetObjectInitSend( PacketOutputAdapter output )
  261. {
  262. }
  263.  
  264. //! MULTIPLAYER: See comment in GameEntity class
  265. void OnNetObjectInitReceived( PacketInputAdapter input )
  266. {
  267. }
  268.  
  269. //! MULTIPLAYER: See comment in GameEntity class
  270. int NeedNetUpdate()
  271. {
  272. return 0; //no update
  273. }
  274.  
  275. //! MULTIPLAYER: See comment in GameEntity class
  276. void OnNetUpdate( PacketOutputAdapter output )
  277. {
  278. }
  279.  
  280. //! MULTIPLAYER: See comment in GameEntity class
  281. bool OnNetMessage( PacketInputAdapter input )
  282. {
  283. return true;
  284. }
  285.  
  286. //! MULTIPLAYER: See comment in GameEntity class
  287. bool OnRPC( int proc, PacketInputAdapter input )
  288. {
  289. return true;
  290. }
  291.  
  292. bool IsServer()
  293. {
  294. return g_Game.IsServer();
  295. }
  296.  
  297. bool IsClient()
  298. {
  299. return g_Game.IsClient();
  300. }
  301.  
  302. Vehicle_Part GetPartByCustomTitle(Vehicle_Controller controller, string customTitle)
  303. {
  304. return NULL;
  305. }
  306.  
  307. _entity GetEntityByCustomTitle(Vehicle_Controller controller, string customTitle)
  308. {
  309. return NULL;
  310. }
  311.  
  312. // Radiation
  313. float GetPartRadiationShieldingScale(Vehicle_Part part, int partNum)
  314. {
  315. return 1;
  316. }
  317.  
  318. // Communications
  319. vector GetPartCommsRange_Pos(Vehicle_Part part, int partNum)
  320. {
  321. return ZeroVec;
  322. }
  323.  
  324. float GetPartCommsRange_Near(Vehicle_Part part, int partNum)
  325. {
  326. return 0;
  327. }
  328.  
  329. float GetPartCommsRange_Far(Vehicle_Part part, int partNum)
  330. {
  331. return 0;
  332. }
  333.  
  334. bool GetCommsAlwaysVisibleOnMap()
  335. {
  336. return false;
  337. }
  338.  
  339. // Dynamic Atmo zone created - client only
  340. void OnDynamicAtmoZoneCreated(DynamicAtmoZone dynAtmoZone, int customID)
  341. {
  342. }
  343.  
  344. // Dynamic Atmo zone deleted - client only
  345. void OnDynamicAtmoZoneDeleted(DynamicAtmoZone dynAtmoZone, int customID)
  346. {
  347. }
  348.  
  349. float GetObjectViewPct(_entity ent)
  350. {
  351. return 0;
  352. }
  353.  
  354. AtmoZone GetAtmoZoneByName(string atmoZoneName)
  355. {
  356. return NULL;
  357. }
  358. };
  359.  
  360. class Vehicle_Controller
  361. {
  362. Vehicle_Handler ownerVehicle;
  363. ScriptModule scriptModule[CONTROL_VEHICLEMAX];
  364. Controller scriptController[CONTROL_VEHICLEMAX];
  365. int netUpdateFlags;
  366.  
  367. int numScript;
  368. float VInput_mX;
  369. float VInput_mY;
  370. float VInput_mW;
  371. float VInput_aF;
  372. float VInput_aB;
  373. float VInput_aL;
  374. float VInput_aR;
  375. float VInput_aU;
  376. float VInput_aD;
  377. float VInput_sF;
  378. float VInput_sB;
  379. float VInput_sL;
  380. float VInput_sR;
  381. float VInput_sU;
  382. float VInput_sD;
  383. float VInput_actJump;
  384. float VInput_actElev;
  385. float VInput_actRele;
  386.  
  387. void InitScripts();
  388. void PostInitScripts();
  389. void ProcessOnSelect();
  390. void ProcessOnUnselect();
  391. void ProcessOnFrm();
  392. void ProcessOnPFrm();
  393. void ProcessOnDeleteWidgets();
  394. void ProcessOnPreSim();
  395. void ProcessOnSim();
  396. void ProcessOnAfterSim();
  397. void ProcessOnTeleport();
  398. void ProcessOnSetVelocity();
  399. void ProcessOnPartDamagedBy(Vehicle_Part part, float damage, int damagedByID);
  400. void ProcessOnPartHandleDamage(Vehicle_Part part, float damage);
  401. void ProcessOnBreakJoint(int jNum, bool breakFX, bool logLoss);
  402. void ProcessOnDeletePart(Vehicle_Part part, int pNum);
  403. void ProcessOnPress(Vehicle_Part part, bool end);
  404. void ProcessOnUnPress(Vehicle_Part part, bool end);
  405. void ProcessOnEvent(string eventName);
  406. void ProcessOnEventWithForce(string eventName, vector pos, vector force);
  407. void ProcessOnEventWithEntity(string eventName, _entity ent);
  408. void ProcessOnEventWithUnit(string eventName, Vehicle_Handler unit);
  409. void ProcessOnEventWithPart(string eventName, Vehicle_Part part);
  410. void ProcessOnEventWithSoundParams(string eventName, SoundShader sndShdr, vector sndPos, float sndVol, int ownerID);
  411. void ProcessOnEventWithInt(string eventName, int input);
  412. void ProcessOnEventWithFloat(string eventName, float input);
  413. void ProcessOnEventWithMatrix(string eventName, vector mat[]);
  414. void ProcessOnContact(Vehicle_Part contactPart, _entity other, Contact extra);
  415. void ProcessSetCustomAnimation(string animPath, float tgtAnimSpeed, float tgtAnimFadeSpeed, bool noMove, bool mustComplete, bool lockView, float tgtFrame);
  416. void ProcessOnCompleteCustomAnimation(string animPath);
  417. void ProcessInventoryChanged();
  418. void ProcessInventoryAccessing(Vehicle_Part part, widget rootWidget, float timeSlice);
  419. void ProcessOnRagdollContact(Ragdoll_Part contactPart, _entity other, Contact extra);
  420. void ProcessOnClick(widget w, int x, int y, int button);
  421. Vehicle_Part GetPartByCustomTitle(string customTitle);
  422. _entity GetEntityByCustomTitle(string customTitle);
  423.  
  424. // Radiation
  425. float GetPartRadiationShieldingScale(Vehicle_Part part, int partNum);
  426.  
  427. // Communications
  428. vector GetPartCommsRange_Pos(Vehicle_Part part, int partNum);
  429. float GetPartCommsRange_Near(Vehicle_Part part, int partNum);
  430. float GetPartCommsRange_Far(Vehicle_Part part, int partNum);
  431. bool GetCommsAlwaysVisibleOnMap();
  432.  
  433. // Dynamic Atmo zones - client only
  434. void ProcessOnDynamicAtmoZone(DynamicAtmoZone dynAtmoZone, int customID);
  435. void ProcessDeleteDynamicAtmoZone(DynamicAtmoZone dynAtmoZone, int customID);
  436.  
  437. float GetObjectViewPct(_entity ent);
  438.  
  439. AtmoZone GetAtmoZoneByName(string atmoZoneName);
  440.  
  441. void AddScript(string scriptStr);
  442. void ExitScripts();
  443.  
  444. void OnEnterCar();
  445. void OnEnterBBlockSeat();
  446.  
  447. //! MULTIPLAYER: See comment in GameEntity class
  448. bool IsServer();
  449. bool IsClient();
  450. void OnNetObjectInitSend( PacketOutputAdapter output );
  451. void OnNetObjectInitReceived( PacketInputAdapter input );
  452. int NeedNetUpdate();
  453. void OnNetUpdate( PacketOutputAdapter output );
  454. bool OnNetMessage( PacketInputAdapter input );
  455. bool OnRPC( int proc, PacketInputAdapter input );
  456.  
  457. string GetStringForVar(string varName)
  458. {
  459. string result;
  460. for (int i = 0; i < numScript; i++)
  461. {
  462. Controller ctrl = scriptController[i];
  463. if (ctrl)
  464. {
  465. result = ctrl.Controller_GetStringForVar(varName);
  466. if (result != "")
  467. return result;
  468. }
  469. }
  470.  
  471. return "";
  472. }
  473. int GetIntForVar(string varName)
  474. {
  475. int result;
  476. for (int i = 0; i < numScript; i++)
  477. {
  478. Controller ctrl = scriptController[i];
  479. if (ctrl)
  480. {
  481. result = ctrl.Controller_GetIntForVar(varName);
  482. if (result != 0)
  483. return result;
  484. }
  485. }
  486.  
  487. return 0;
  488. }
  489. float GetFloatForVar(string varName)
  490. {
  491. float result;
  492. for (int i = 0; i < numScript; i++)
  493. {
  494. Controller ctrl = scriptController[i];
  495. if (ctrl)
  496. {
  497. result = ctrl.Controller_GetFloatForVar(varName);
  498. if (result != 0)
  499. return result;
  500. }
  501. }
  502.  
  503. return 0;
  504. }
  505. bool GetBoolForVar(string varName)
  506. {
  507. bool result;
  508. for (int i = 0; i < numScript; i++)
  509. {
  510. Controller ctrl = scriptController[i];
  511. if (ctrl)
  512. {
  513. result = ctrl.Controller_GetBoolForVar(varName);
  514. if (result)
  515. return result;
  516. }
  517. }
  518.  
  519. return false;
  520. }
  521. vector GetVectorForVar(string varName)
  522. {
  523. vector result;
  524. for (int i = 0; i < numScript; i++)
  525. {
  526. Controller ctrl = scriptController[i];
  527. if (ctrl)
  528. {
  529. result = ctrl.Controller_GetVectorForVar(varName);
  530. if (result != ZeroVec)
  531. return result;
  532. }
  533. }
  534.  
  535. return ZeroVec;
  536. }
  537.  
  538. bool GetVehicleBroken()
  539. {
  540. bool result;
  541. for (int i = 0; i < numScript; i++)
  542. {
  543. Controller ctrl = scriptController[i];
  544. if (ctrl)
  545. {
  546. result = ctrl.Controller_GetVehicleBroken();
  547. if (result)
  548. return result;
  549. }
  550. }
  551.  
  552. return false;
  553. }
  554.  
  555. float GetListenerVolume()
  556. {
  557. float result = 1;
  558. for (int i = 0; i < numScript; i++)
  559. {
  560. Controller ctrl = scriptController[i];
  561. if (ctrl)
  562. {
  563. result = ctrl.Controller_GetListenerVolume();
  564. if (result != 1)
  565. return result;
  566. }
  567. }
  568.  
  569. return 1;
  570. }
  571.  
  572. float GetListenerSFXLerp()
  573. {
  574. float result = 0;
  575. for (int i = 0; i < numScript; i++)
  576. {
  577. Controller ctrl = scriptController[i];
  578. if (ctrl)
  579. {
  580. result = ctrl.Controller_GetListenerSFXLerp();
  581. if (result != 0)
  582. return result;
  583. }
  584. }
  585.  
  586. return 0;
  587. }
  588.  
  589. string GetListenerSFXPath()
  590. {
  591. string result = "";
  592. for (int i = 0; i < numScript; i++)
  593. {
  594. Controller ctrl = scriptController[i];
  595. if (ctrl)
  596. {
  597. result = ctrl.Controller_GetListenerSFXPath();
  598. if (result != "")
  599. return result;
  600. }
  601. }
  602.  
  603. return "";
  604. }
  605.  
  606. bool GetOutOfFuel()
  607. {
  608. bool result;
  609. for (int i = 0; i < numScript; i++)
  610. {
  611. Controller ctrl = scriptController[i];
  612. if (ctrl)
  613. {
  614. result = ctrl.Controller_GetOutOfFuel();
  615. if (result)
  616. return result;
  617. }
  618. }
  619.  
  620. return false;
  621. }
  622.  
  623. bool Editor_GetCanSpawnFuel()
  624. {
  625. bool result;
  626. for (int i = 0; i < numScript; i++)
  627. {
  628. Controller ctrl = scriptController[i];
  629. if (ctrl)
  630. {
  631. result = ctrl.Controller_Editor_GetCanSpawnFuel();
  632. if (result)
  633. return result;
  634. }
  635. }
  636.  
  637. return false;
  638. }
  639.  
  640. void Editor_SpawnFuel()
  641. {
  642. for (int i = 0; i < numScript; i++)
  643. {
  644. Controller ctrl = scriptController[i];
  645. if (ctrl)
  646. ctrl.Controller_Editor_SpawnFuel();
  647. }
  648. }
  649.  
  650. void CallOnFullyInitialized()
  651. {
  652. for (int i = 0; i < numScript; i++)
  653. {
  654. Controller ctrl = scriptController[i];
  655. if (ctrl)
  656. ctrl.Controller_OnFullyInitialized();
  657. }
  658. }
  659.  
  660. void StoreFuelHandlerValues()
  661. {
  662. for (int i = 0; i < numScript; i++)
  663. {
  664. Controller ctrl = scriptController[i];
  665. if (ctrl)
  666. ctrl.StoreFuelHandlerValues();
  667. }
  668. }
  669.  
  670. void Vehicle_Controller()
  671. {
  672. ownerVehicle = NULL;
  673. numScript = 0;
  674. for (int i = 0; i < CONTROL_VEHICLEMAX; i++)
  675. {
  676. scriptModule[i] = NULL;
  677.  
  678. scriptController[i] = NULL;
  679. }
  680. }
  681.  
  682. void ~Vehicle_Controller()
  683. {
  684. ownerVehicle = NULL;
  685. numScript = 0;
  686. ScriptModule smodule;
  687. Controller controller;
  688.  
  689. for (int i = 0; i < CONTROL_VEHICLEMAX; i++)
  690. {
  691. if (scriptModule[i])
  692. {
  693. controller = scriptController[i];
  694. smodule = scriptModule[i];
  695.  
  696. if(controller)
  697. delete controller; //destroy before destroing module!
  698.  
  699. if (smodule)
  700. smodule.Release();
  701.  
  702. scriptModule[i] = NULL;
  703. }
  704. }
  705. }
  706. }
  707.  
  708. class Vehicle_Handler extends Vehicle_Part
  709. {
  710. World GetCurrentWorld(); // Returns the current world
  711.  
  712. NetPlayerTKOM netPlayer; //player which controls this vehicle
  713. VehicleObject storage; //vehicle object storage. exist always and is serializable. all vehicle/mission data that need be serialized, store to this!!!
  714. TraceContact VehicleTrcCon; // Pointer to the vehicle's TraceContact entity
  715. _entity VehicleTrcEnt; // Pointer to the traced entity (NOT SERIALIZED SO ENSURE RESET!)
  716. Vehicle_WidgetHandler widgetHandler; // The vehicle's widget handler
  717. Vehicle_Controller vehicleController; // The vehicle's controller
  718. widget widgetList[WIDGETS_VEHICLEMAX] // A list of widgets created on the vehicle
  719.  
  720. // Variables that should not be serialized
  721. // =============================================================================================
  722. bool delayDelete; // If true, the vehicle will delete itself the next frame
  723. bool isSelected; // True when the vehicle is selected
  724. bool lastSelected; // Stores the last selected state (for optimization)
  725. bool EnvData; // True if environmental data should be displayed
  726. bool EmergencyMode; // True if the vehicle is in emergency mode (for HUD)
  727. bool HasMovementInput; // True if the unit has some form of input
  728. bool HasTurboInput; // True if the unit has turbo input
  729. vector MovementInput; // Amount of input in units
  730. float PriPartSwitchTime; // Delay time for keyboard and analog controls for primary parts
  731. float SecPartSwitchTime; // Delay time for keyboard and analog controls for secondary parts
  732. float GodModeTime; // If above 0, the vehicle cannot get damaged and joints can't break. Decrements with time
  733. float PowerGenRate; // Stores the amount of power the vehicle is generating per hour
  734. float PowerDrainRate; // Stores the amount of power the vehicle is draining per hour
  735. float PowerStorageMax; // Stores the amount of power the vehicle can store
  736. float ChemBattLevel; // Stores the amount of power available in backup chemical batteries (for HUD)
  737. bool ChemBattUse; // Stores whether the chemical batteries are being actively used
  738. vector PowerTraces; // Stores the number of traces performed for solar panel simulation
  739. string CommandsHelpList[MAX_VEHICLES_COMMANDS_TYPES][MAX_VEHICLES_COMMANDS_TYPESMAX]; // Stores a list of commands that are available for the vehicle
  740. int CommandsHelpListNum;
  741. bool CommandsHelpListUpdated; // If false, tells the controllers to update the list
  742. bool NoHierarchyGripImpulseBreak; // If true, then impulses to gripped parts will not break the grip of other gripped parts
  743.  
  744. void QueueDelete();
  745.  
  746. // On fully initialized
  747. void OnFullyInitialized()
  748. {
  749. if( HasNetworkObject() ) //in multiplayer on server
  750. InitNetworkObject(); //we have to notify c++ side that entity is completely initialized!
  751.  
  752. if (vehicleController)
  753. vehicleController.CallOnFullyInitialized();
  754. }
  755.  
  756. // Radiation
  757. float GetPartRadiationShieldingScale(Vehicle_Part part, int partNum)
  758. {
  759. if (vehicleController)
  760. return vehicleController.GetPartRadiationShieldingScale(part, partNum);
  761.  
  762. return 1;
  763. }
  764.  
  765. // Communications
  766. vector GetPartCommsRange_Pos(Vehicle_Part part, int partNum)
  767. {
  768. if (vehicleController)
  769. return vehicleController.GetPartCommsRange_Pos(part, partNum);
  770.  
  771. return ZeroVec;
  772. }
  773.  
  774. float GetPartCommsRange_Near(Vehicle_Part part, int partNum)
  775. {
  776. if (vehicleController)
  777. return vehicleController.GetPartCommsRange_Near(part, partNum);
  778.  
  779. return 0;
  780. }
  781.  
  782. float GetPartCommsRange_Far(Vehicle_Part part, int partNum)
  783. {
  784. if (vehicleController)
  785. return vehicleController.GetPartCommsRange_Far(part, partNum);
  786.  
  787. return 0;
  788. }
  789.  
  790. bool GetCommsAlwaysVisibleOnMap()
  791. {
  792. if (vehicleController)
  793. return vehicleController.GetCommsAlwaysVisibleOnMap();
  794.  
  795. return false;
  796. }
  797.  
  798. // Object in view screen percent checking
  799. float GetObjectViewPct(_entity ent)
  800. {
  801. if (vehicleController)
  802. return vehicleController.GetObjectViewPct(ent);
  803.  
  804. return 0;
  805. }
  806.  
  807. // Get an atmospheric zone by name
  808. AtmoZone GetAtmoZoneByName(string atmoZoneName)
  809. {
  810. if (vehicleController)
  811. return vehicleController.GetAtmoZoneByName(atmoZoneName);
  812.  
  813. return NULL;
  814. }
  815.  
  816. // Joint pointers, block pointers etc
  817. dJoint joints_ents[VEHICLE_MAXJOINTS]; // Stores a pointer to each joint
  818. dBlock blocks_ents[VEHICLE_MAXBLOCKS]; // Stores a pointer to each collision blocker
  819. Vehicle_Part parts_ents[VEHICLE_MAXPARTS]; // Stores an entity pointer to each part
  820. int parts_interactionLayer[VEHICLE_MAXPARTS]; // Stores the physics interaction layer of each part for disabling collisions
  821. GUI3DWidgetHandler gui3dWidgetHandler[VEHICLE_MAXPARTS]; // Stores pointer to 3D GUI widget handler pointer
  822. #ifdef DEVELOPER
  823. float parts_lastGripTime[VEHICLE_MAXPARTS]; // Stores the last time the part gripped in MP
  824. #endif
  825.  
  826. // List of 3D GUI widget handlers for multiplayer synch
  827. GUI3DWidgetHandler MP_gui3dWidgetHandlerList[VEHICLE_MAXPARTS];
  828. int MP_gui3dWidgetHandlerListNum;
  829.  
  830. int Get3DGUIWidgetHandlerListPartNum(GUI3DWidgetHandler w3dguih)
  831. {
  832. for (int p = 0; p < MP_gui3dWidgetHandlerListNum; p++)
  833. {
  834. if (gui3dWidgetHandler[p] == w3dguih)
  835. return p;
  836. }
  837.  
  838. return -1;
  839. }
  840.  
  841. void Assign3DGUIWidgetHandlerToPart(int partNum, GUI3DWidgetHandler w3dguih)
  842. {
  843. if (gui3dWidgetHandler[partNum])
  844. {
  845. Print(String("VEHICLE_HANDLER::ASSIGN3DGUIWIDGETHANDLERTOPART() - Cannot assign 3D GUI widget handler to part " + itoa(partNum) + ", already one assigned!"));
  846. return;
  847. }
  848.  
  849. w3dguih.owner = this;
  850. w3dguih.id = partNum;
  851. gui3dWidgetHandler[partNum] = w3dguih;
  852. MP_gui3dWidgetHandlerList[MP_gui3dWidgetHandlerListNum] = w3dguih;
  853. MP_gui3dWidgetHandlerListNum++;
  854. }
  855.  
  856. void Unassign3DGUIWidgetHandlerFromPart(int partNum)
  857. {
  858. if (!gui3dWidgetHandler[partNum])
  859. return;
  860.  
  861. GUI3DWidgetHandler w3dguih_del = gui3dWidgetHandler[partNum];
  862. gui3dWidgetHandler[partNum] = NULL;
  863. bool found = false;
  864. for (int gui = 0; gui < MP_gui3dWidgetHandlerListNum; gui++)
  865. {
  866. GUI3DWidgetHandler w3dguih = MP_gui3dWidgetHandlerList[gui];
  867. if (w3dguih == w3dguih_del)
  868. found = true;
  869. if (found)
  870. {
  871. if (MP_gui3dWidgetHandlerListNum <= gui + 1)
  872. MP_gui3dWidgetHandlerList[gui] = NULL;
  873. else
  874. MP_gui3dWidgetHandlerList[gui] = MP_gui3dWidgetHandlerList[gui + 1];
  875. }
  876. }
  877. MP_gui3dWidgetHandlerListNum--;
  878. }
  879.  
  880. GUI3DHandler GetCurrent3DGUI();
  881. bool PlayerUsing3DGUI();
  882.  
  883. // Returns the vehicle's current power drain
  884. float GetTotalPowerDrain()
  885. {
  886. float result = 0;
  887. for (int i = 0; i < storage.parts_num; i++)
  888. {
  889. result += storage.parts_pwrdrain[i];
  890. }
  891.  
  892. return result;
  893. }
  894.  
  895. // Updates power level from drain, charge, and max storage
  896. void UpdatePower();
  897.  
  898. // Sends a popup message to the target player
  899. void SendPopupToOwner(bool noAlphaChange, bool clearPrevious, float time, string layout, string titStr, string descStr, string descStr2);
  900.  
  901. //! MULTIPLAYER: See comment in GameEntity class
  902. void OnNetObjectInitSend( PacketOutputAdapter output );
  903. void OnNetObjectInitReceived( PacketInputAdapter input );
  904. void OnNetObjectAfterInitSend( PacketOutputAdapter output );
  905. void OnNetObjectAfterInitReceived( PacketInputAdapter input );
  906.  
  907. int NeedNetUpdate();
  908. void OnNetUpdate( PacketOutputAdapter output );
  909. bool OnNetMessage( PacketInputAdapter input );
  910. bool OnRPC(int proc, PacketInputAdapter input);
  911.  
  912. void RP_SynchTeam(int team, bool isRemoteCall = false);
  913. void RP_SelectCameraMainMode(int mode, bool isRemoteCall = false);
  914.  
  915. bool EnterCar(Vehicle_Handler vehicle, int reachSeat);
  916. void RP_EnterCar(int vehicleID, int reachSeat, bool isRemoteCall = false);
  917.  
  918. bool EnterBBlockSeat(_entity bblockBase, int reachSeat);
  919. void RP_EnterBBlockSeat(int bblockID, int reachSeat, bool isRemoteCall = false);
  920.  
  921. void SelectCameraMainMode(int mode);
  922.  
  923. void SetNetPlayer(NetPlayerTKOM player);
  924. NetPlayer GetNetPlayer();
  925. bool IsControlledByLocalPlayer();
  926. bool IsControlledByLocalDriver();
  927. bool IsControlledByRemoteDriver();
  928. bool IsControlledByRemotePlayer();
  929. bool IsControlledByAnyPlayer();
  930. bool IsControlledByAnyDriver();
  931. float GetControllerValue(int eEvent);
  932. bool IsControlsReceiver();
  933. bool PlayerHasMouseCursorEnabled();
  934. void SetInteractionLayer(int layer);
  935.  
  936. Vehicle_Handler GetDriver();
  937. Vehicle_Handler GetPassenger(int iSeatNum);
  938.  
  939. // Returns the display name for the input type name
  940. string GetTypeDisplayName(string typeStr)
  941. {
  942. for (int i = 0; i < storage.parts_num; i++) {
  943. if (storage.parts_types[i] == typeStr)
  944. return storage.parts_title[i];
  945. }
  946. return "";
  947. }
  948.  
  949. // Returns the display name for the input sub-type name
  950. string GetSubTypeDisplayName(string subTypeStr)
  951. {
  952. for (int i = 0; i < storage.parts_num; i++) {
  953. if (storage.parts_subtypes[i] == subTypeStr)
  954. return storage.parts_title[i];
  955. }
  956. return "";
  957. }
  958.  
  959.  
  960. // Clear the commands help list
  961. void ClearCommandsHelpList()
  962. {
  963. CommandsHelpListUpdated = false;
  964. for (int i = 0; i < MAX_VEHICLES_COMMANDS_TYPES; i++) {
  965. for (int n = 0; n < MAX_VEHICLES_COMMANDS_TYPESMAX; n++) {
  966. CommandsHelpList[i][n] = "";
  967. }
  968. }
  969. CommandsHelpListNum = 0;
  970. }
  971.  
  972. // Adds a command to the help list
  973. void AddCommandToHelpList(string cmdStr1, string cmdStr2, string cmdStr3, string cmdStr4, string cmdStr5, string descStr)
  974. {
  975. if (CommandsHelpListNum >= MAX_VEHICLES_COMMANDS_TYPES)
  976. return;
  977.  
  978. CommandsHelpList[CommandsHelpListNum][0] = cmdStr1;
  979. CommandsHelpList[CommandsHelpListNum][1] = cmdStr2;
  980. CommandsHelpList[CommandsHelpListNum][2] = cmdStr3;
  981. CommandsHelpList[CommandsHelpListNum][3] = cmdStr4;
  982. CommandsHelpList[CommandsHelpListNum][4] = cmdStr5;
  983. CommandsHelpList[CommandsHelpListNum][5] = descStr;
  984. CommandsHelpListNum++;
  985. }
  986.  
  987. // Arcade input
  988. float input_arc_pri0;
  989. float input_arc_pri1;
  990. float input_arc_pri2;
  991. bool input_arc_prigui;
  992. float input_arc_sec0;
  993. float input_arc_sec1;
  994. float input_arc_sec2;
  995. bool input_arc_secgui;
  996. float input_mouse_X;
  997. float input_mouse_Y;
  998. float input_mouse_Whl;
  999.  
  1000. // Vehicle switch tab variables
  1001. bool tabs_update; // Read from the campaign to determine whether to update the tabs
  1002.  
  1003. // Vehicle camera display variables
  1004. const int CAMS_MAINCAMNUM = 4;
  1005. const int CAMS_FIRSTCAMNUM = 5;
  1006. int cams_alllist[VEHICLE_MAXPARTS];
  1007. int cams_allistpos; // Stores the camera PIP the comprehensive list should be generated for
  1008. bool cams_tookphoto; // If true will take photo from the main camera
  1009. bool cams_mainModeSwitch; // True when switch button pressed
  1010. int cams_switchsel; // 0 is null, 1-6 correspond to cams 1-6
  1011. vector cams_photoOffset; // Used for tracing to the camera taking the picture
  1012. bool cams_photoColor; // Used to determine if the correct camera is being used in photo framing
  1013. int cams_photoPart; // Used to determine which vehicle part took the photo, for disabling collision in traces
  1014.  
  1015. // Vehicle instrument display variables
  1016. int inst_alllist[VEHICLE_MAXPARTS]; //list of instruments indexes
  1017. int inst_alllistex[VEHICLE_MAXPARTS]; //list of instruments indexes including passive
  1018. float inst_invalidtime; // Stores how long the invalid target hint is shown for
  1019. int inst_invalidtype; // Stores the type of invalid target to show, 0 = null, 1 = out of range, 2 = wrong target type
  1020. bool inst_inrange; // Set from instruments, if true, a valid target is in range
  1021. string inst_hilite; // Set from instruments, text to display in the instrument HUD when mousing over use instrument
  1022. string inst_sample; // Set from instruments, text to display in the instrument HUD when the instrument is sampling
  1023. string inst_analyze; // Set from instruments, text to display in the instrument HUD when the instrument is analyzing
  1024.  
  1025. // Vehicle Radial Menu variables
  1026. bool radm_closed; // Read from controllers to determine whether the radial menu is closed
  1027. bool radm_disabled; // Read from controllers to determine whether the radial menu is disabled
  1028. bool radm_lastcursor; // Stores the state of the cursor prior to opening the radial menu
  1029. bool radm_reloadimg; // Set to true when the icons on the radial menu need to be reloaded
  1030. float radm_alpha; // Stores the alpha value (0 - 1) of the window
  1031. string radm_act[RADM_NUMSLOTS]; // Store the actions to be executed when the appropriate radial menu icon is selected
  1032. bool radm_used[RADM_NUMSLOTS]; // True when the assigned action should be executed
  1033.  
  1034. //Camera matrix in entity format
  1035. vector cameraMat[4];
  1036. vector cameraForcedMat[4];
  1037.  
  1038. // Camera Mode HUD variables
  1039. float camHUD_zoom; // Zoom level (-1 - 1)
  1040.  
  1041. // Vehicle part HUD status indicators
  1042. const int STAT_MAX = 10;
  1043. int stat_state[STAT_MAX]; // Used in controllers to indicate the status of important parts
  1044.  
  1045. // Returns the first free radial menu slot
  1046. int RadialMenuGetFreeSlot()
  1047. {
  1048. if (radm_act[RADM_UP] == "")
  1049. return RADM_UP;
  1050. if (radm_act[RADM_RT] == "")
  1051. return RADM_RT;
  1052. if (radm_act[RADM_DN] == "")
  1053. return RADM_DN;
  1054. if (radm_act[RADM_LT] == "")
  1055. return RADM_LT;
  1056.  
  1057. return RADM_NULL;
  1058. }
  1059.  
  1060. // Returns the radial menu position the action has been assigned to
  1061. int RadialMenuGetActionAssigned(string action)
  1062. {
  1063. if (radm_act[RADM_UP] == action)
  1064. return RADM_UP;
  1065. if (radm_act[RADM_DN] == action)
  1066. return RADM_DN;
  1067. if (radm_act[RADM_LT] == action)
  1068. return RADM_LT;
  1069. if (radm_act[RADM_RT] == action)
  1070. return RADM_RT;
  1071.  
  1072. return RADM_NULL;
  1073. }
  1074.  
  1075. // Associates an action to the desired icon, assigning the appropriate icon as well
  1076. void RadialMenuSetAction(int pos, string action, string image, string imageHi, string actionTitle)
  1077. {
  1078. widget wP = FindWidget(NULL, "HUDRoot_RadialMenu");
  1079. if (wP) {
  1080. string txt2 = "";
  1081. if (pos == RADM_UP && radm_act[RADM_UP] != action) {
  1082. radm_act[RADM_UP] = action;
  1083. radm_used[RADM_UP] = false;
  1084. txt2 = "up";
  1085. }
  1086. if (pos == RADM_DN && radm_act[RADM_DN] != action) {
  1087. radm_act[RADM_DN] = action;
  1088. radm_used[RADM_DN] = false;
  1089. txt2 = "down";
  1090. }
  1091. if (pos == RADM_LT && radm_act[RADM_LT] != action) {
  1092. radm_act[RADM_LT] = action;
  1093. radm_used[RADM_LT] = false;
  1094. txt2 = "left";
  1095. }
  1096. if (pos == RADM_RT && radm_act[RADM_RT] != action) {
  1097. radm_act[RADM_RT] = action;
  1098. radm_used[RADM_RT] = false;
  1099. txt2 = "right";
  1100. }
  1101. if (image != "" && imageHi != "") {
  1102. widget wIco = FindAnyWidget(wP, "icon_" + txt2 + "0");
  1103. widget wIcoHi = FindAnyWidget(wP, "icon_" + txt2 + "0_hi");
  1104. widget wTxt = FindAnyWidget(wP, "icon_" + txt2 + "1_hi");
  1105. if (wIco) {
  1106. if (action == "") {
  1107. if (widgetHandler) {
  1108. int id = widgetHandler.FindInList("icon_" + txt2 + "0");
  1109. if (id != -1)
  1110. SetWidgetColor(wIco, ARGBF(widgetHandler.HUDBtn_Color[id][0], widgetHandler.HUDBtn_Color[id][1], widgetHandler.HUDBtn_Color[id][2], widgetHandler.HUDBtn_Color[id][3]));
  1111. }
  1112. }
  1113. LoadWidgetImage(wIco, 1, image);
  1114. SetWidgetImage(wIco, 1);
  1115. }
  1116. if (wIcoHi) {
  1117. if (action == "")
  1118. SetWidgetColor(wIcoHi, ARGBF(0, 0, 0, 0));
  1119. else {
  1120. LoadWidgetImage(wIcoHi, 1, imageHi);
  1121. SetWidgetImage(wIcoHi, 1);
  1122. }
  1123. }
  1124. if (wTxt) {
  1125. if (action == "")
  1126. SetWidgetColor(wTxt, ARGBF(0, 0, 0, 0));
  1127. else
  1128. SetWidgetTextEx(wTxt, 0, 1, actionTitle);
  1129. }
  1130. }
  1131. }
  1132. }
  1133.  
  1134. // Tries to assign an action to the radial menu, if succeeds returns the slot
  1135. int RadialMenuAttemptAssignAction(string action, string image, string imageHi, string actionTitle)
  1136. {
  1137. int result = RadialMenuGetActionAssigned(action);
  1138. if (result == RADM_NULL) {
  1139. result = RadialMenuGetFreeSlot();
  1140. if (result != RADM_NULL)
  1141. RadialMenuSetAction(result, action, image, imageHi, actionTitle);
  1142. }
  1143.  
  1144. return result;
  1145. }
  1146.  
  1147. // Tries to reset a single radial menu action to none
  1148. void RadialMenuResetAction(int pos)
  1149. {
  1150. if (pos != RADM_NULL)
  1151. RadialMenuSetAction(pos, "", "gui/textures/radmenu/icon_none", "gui/textures/radmenu/icon_none", "#tkom_rdmac_none");
  1152. }
  1153.  
  1154. // Resets all radial menu actions to none
  1155. void RadialMenuResetActions()
  1156. {
  1157. radm_act[RADM_UP] = "RESET";
  1158. radm_act[RADM_DN] = "RESET";
  1159. radm_act[RADM_LT] = "RESET";
  1160. radm_act[RADM_RT] = "RESET";
  1161. RadialMenuSetAction(RADM_UP, "", "gui/textures/radmenu/icon_none", "gui/textures/radmenu/icon_none", "#tkom_rdmac_none");
  1162. RadialMenuSetAction(RADM_DN, "", "gui/textures/radmenu/icon_none", "gui/textures/radmenu/icon_none", "#tkom_rdmac_none");
  1163. RadialMenuSetAction(RADM_LT, "", "gui/textures/radmenu/icon_none", "gui/textures/radmenu/icon_none", "#tkom_rdmac_none");
  1164. RadialMenuSetAction(RADM_RT, "", "gui/textures/radmenu/icon_none", "gui/textures/radmenu/icon_none", "#tkom_rdmac_none");
  1165. }
  1166.  
  1167. // Enables/disables impact damage on parts (does not disable joint breaking!!)
  1168. void EnableImpactDamage(bool enable)
  1169. {
  1170. for (int i = 0; i < storage.parts_num; i++)
  1171. {
  1172. Vehicle_Part pEnt = parts_ents[i];
  1173. if (pEnt)
  1174. pEnt.ImpactDamageEnabled = enable;
  1175. }
  1176. }
  1177.  
  1178. // Checks whether a part is connected to the target part
  1179. bool CheckPartConnect(int partNum, int partParent)
  1180. {
  1181. if (partNum <= -1 || partParent <= -1)
  1182. return false;
  1183.  
  1184. Vehicle_Part pEnt = parts_ents[partNum];
  1185. if (pEnt) {
  1186. int pNum = partNum;
  1187. if (storage.parts_models[partNum] == "INTERNAL") // If internal part, then automatically assume its parent can only be part 0
  1188. pNum = 0;
  1189. else {
  1190. int numIterations = 0;
  1191. while(pNum != partParent && pNum != -1 && numIterations < VEHICLE_MAXPARTS) {
  1192. pEnt = parts_ents[pNum];
  1193. if (pEnt)
  1194. pNum = pEnt.ParentPartNum;
  1195. numIterations++;
  1196. }
  1197. if (numIterations == VEHICLE_MAXPARTS) {
  1198. pNum = -1;
  1199. Print(String("CHECKPARTCONNECT(): Vehicle '" + storage.name + "' got stuck in an infinite loop while checking connection from parent " + itoa(partParent) + " to child " + itoa(partNum) + "!"));
  1200. }
  1201. }
  1202. if (pNum == partParent)
  1203. return true;
  1204. }
  1205. return false;
  1206. }
  1207.  
  1208. // Checks whether a part is connected to a base part
  1209. bool CheckPartBaseConnect(int partNum)
  1210. {
  1211. if (partNum <= -1)
  1212. return false;
  1213.  
  1214. if (CheckPartConnect(partNum, 0)) // Part 0 is always a base
  1215. return true;
  1216.  
  1217. for (int i = 0; i < storage.ctrlbase_num; i++)
  1218. {
  1219. if (storage.ctrlbase_parts[i] > 0 && CheckPartConnect(partNum, storage.ctrlbase_parts[i]))
  1220. return true;
  1221. }
  1222. return false;
  1223. }
  1224.  
  1225. float GetSpringScale()
  1226. {
  1227. float sscale = 1 / phys_FixedTick - 60 / 60;
  1228. clamp sscale<0, 1>;
  1229. sscale = 1 - sscale * 1 + 1;
  1230.  
  1231. return sscale;
  1232. }
  1233.  
  1234. float GetSpringLinDampScale()
  1235. {
  1236. return 0.0001;
  1237. }
  1238.  
  1239. float GetSpringAngDampScale()
  1240. {
  1241. return 0.0001;
  1242. }
  1243.  
  1244. // Returns joint index that is connected to part. Careful, returns only first joint it finds!
  1245. int GetJointToPart(int partNum)
  1246. {
  1247. if (partNum <= -1)
  1248. return -1;
  1249.  
  1250. for (int i = 0; i < storage.joints_num; i++)
  1251. {
  1252. if (storage.joints_part2[i] == partNum)
  1253. return i;
  1254. }
  1255.  
  1256. return -1;
  1257. }
  1258.  
  1259. // Returns joint index that is connected between parts. Careful, returns only first joint it finds!
  1260. int GetJointBetweenParts(int parentPartNum, int partNum)
  1261. {
  1262. if (partNum <= -1)
  1263. return -1;
  1264.  
  1265. if (parentPartNum <= -1)
  1266. return -1;
  1267.  
  1268. for (int i = 0; i < storage.joints_num; i++)
  1269. {
  1270. if (storage.joints_part1[i] == parentPartNum && storage.joints_part2[i] == partNum)
  1271. return i;
  1272. }
  1273.  
  1274. return -1;
  1275. }
  1276.  
  1277. // Returns whether to use a lower LOD for the joint
  1278. bool GetUseLODJoint(int jointNum)
  1279. {
  1280. if (!IsClient() && storage.joints_isLODed[jointNum] && fsum(1 / phys_FixedTick) < 100)
  1281. return true;
  1282. else
  1283. return false;
  1284. }
  1285.  
  1286. // Returns the joint's type, taking into account joint LODs
  1287. int GetJointType(int jointNum)
  1288. {
  1289. int jointType = storage.joints_type[jointNum];
  1290. if (GetUseLODJoint(jointNum))
  1291. jointType = JOINT_FIXED;
  1292.  
  1293. return jointType;
  1294. }
  1295.  
  1296. // Returns the number of the target part type
  1297. int PartTypeGetNum(int pNum, string pType)
  1298. {
  1299. int result = 0;
  1300. for (int i = 0; i < storage.parts_num; i++)
  1301. {
  1302. if (parts_ents[i]) {
  1303. if (storage.parts_types[i] == pType)
  1304. result++;
  1305. }
  1306. if (i >= pNum)
  1307. break;
  1308. }
  1309. return result;
  1310. }
  1311.  
  1312. // Returns the number of the target part subtype
  1313. int PartSubTypeGetNum(int pNum, string pType)
  1314. {
  1315. int result = 0;
  1316. for (int i = 0; i < storage.parts_num; i++)
  1317. {
  1318. if (parts_ents[i]) {
  1319. if (storage.parts_subtypes[i] == pType)
  1320. result++;
  1321. }
  1322. if (i >= pNum)
  1323. break;
  1324. }
  1325. return result;
  1326. }
  1327.  
  1328. // Returns first part of set type
  1329. Vehicle_Part GetPartByType(string pType)
  1330. {
  1331. for (int i = 0; i < storage.parts_num; i++)
  1332. {
  1333. if (parts_ents[i] && storage.parts_types[i] == pType)
  1334. return parts_ents[i];
  1335. }
  1336. }
  1337.  
  1338. // Checks if a camera part is in the camera list
  1339. int CameraGetInList(int pNum)
  1340. {
  1341. int result = -1;
  1342. for (int i = 0; i < CAMS_MAX; i++) {
  1343. if (storage.cams_list[i] == pNum) {
  1344. result = i;
  1345. break;
  1346. }
  1347. }
  1348. return result;
  1349. }
  1350.  
  1351. // Adds a camera part to the camera list
  1352. void CameraAddToList(int pNum)
  1353. {
  1354. if (CameraGetInList(pNum) == -1) {
  1355. for (int i = 0; i < CAMS_MAX; i++) {
  1356. if (storage.cams_list[i] == -1) {
  1357. storage.cams_list[i] = pNum;
  1358. storage.cams_online[i] = true;
  1359. break;
  1360. }
  1361. }
  1362. }
  1363. }
  1364.  
  1365. // Removes a camera part from the camera list
  1366. void CameraRemoveFromList(int pNum)
  1367. {
  1368. bool removed = false;
  1369. for (int i = 0; i < CAMS_MAX; i++) {
  1370. if (storage.cams_list[i] == pNum) {
  1371. storage.cams_list[i] = -1;
  1372. storage.cams_online[i] = false;
  1373. removed = true;
  1374. }
  1375. }
  1376. if (removed) {
  1377. int cams_tmplist[CAMS_MAX];
  1378. bool cams_tmponline[CAMS_MAX];
  1379. int tmpNum = 0;
  1380. for (i = 0; i < CAMS_MAX; i++) {
  1381. if (storage.cams_list[i] != -1) {
  1382. cams_tmplist[tmpNum] = storage.cams_list[i];
  1383. cams_tmponline[tmpNum] = storage.cams_online[i];
  1384. tmpNum++;
  1385. }
  1386. }
  1387. for (i = 0; i < CAMS_MAX; i++) {
  1388. if (i < tmpNum) {
  1389. storage.cams_list[i] = cams_tmplist[i];
  1390. storage.cams_online[i] = cams_tmponline[i];
  1391. } else {
  1392. storage.cams_list[i] = -1;
  1393. storage.cams_online[i] = false;
  1394. }
  1395. }
  1396. }
  1397. }
  1398.  
  1399. // Clear Cams
  1400. void CameraClearList()
  1401. {
  1402. for (int i = 0; i < CAMS_MAX; i++) {
  1403. storage.cams_list[i] = -1;
  1404. }
  1405. }
  1406.  
  1407. // Clears the comprehensive list of cameras attached to the vehicle
  1408. void CameraClearFullList()
  1409. {
  1410. for (int i = 0; i < VEHICLE_MAXPARTS; i++)
  1411. {
  1412. cams_alllist[i] = -1;
  1413. }
  1414. }
  1415.  
  1416. // Generates the comprehensive list of cameras attached to the vehicle, but not being displayed currently
  1417. int CameraCreateFullList()
  1418. {
  1419. bool isCam;
  1420. CameraClearFullList();
  1421. // First generate a list of available camera types on the vehicle
  1422. string camTypeList[VEHICLE_MAXPARTS];
  1423. int numCTypes = 0;
  1424. for (int i = 0; i < VEHICLE_MAXPARTS; i++)
  1425. {
  1426. camTypeList[i] = "";
  1427. isCam = false;
  1428. if (storage.parts_types[i] == "Camera" || storage.parts_types[i] == "CameraBW")
  1429. isCam = true;
  1430.  
  1431. if (isCam && storage.parts_subtypes[i] != "")
  1432. {
  1433. bool subtypeKnown = false;
  1434. for (int t = 0; t < numCTypes; t++)
  1435. {
  1436. if (storage.parts_subtypes[i] == camTypeList[t]) {
  1437. subtypeKnown = true;
  1438. t = numCTypes;
  1439. }
  1440. }
  1441. if (!subtypeKnown) {
  1442. camTypeList[numCTypes] = storage.parts_subtypes[i];
  1443. numCTypes++;
  1444. }
  1445. }
  1446. }
  1447.  
  1448. int result = 0;
  1449. for (t = 0; t < numCTypes; t++)
  1450. {
  1451. for (i = 0; i < storage.parts_num; i++)
  1452. {
  1453. if (parts_ents[i]) {
  1454. if (result >= storage.parts_num) {
  1455. i = storage.parts_num;
  1456. t = numCTypes;
  1457. } else {
  1458. isCam = false;
  1459. if (storage.parts_types[i] == "Camera" || storage.parts_types[i] == "CameraBW")
  1460. isCam = true;
  1461. if (CheckPartBaseConnect(i) && isCam && storage.parts_subtypes[i] == camTypeList[t] && CameraGetInList(i) == -1) {
  1462. cams_alllist[result] = i;
  1463. result++;
  1464. }
  1465. }
  1466. }
  1467. }
  1468. }
  1469. return result;
  1470. }
  1471.  
  1472. // Generates the comprehensive list of all cameras attached to the vehicle
  1473. int GetTotalCameraCount()
  1474. {
  1475. int result = 0;
  1476.  
  1477. for (int i = 0; i < VEHICLE_MAXPARTS; i++)
  1478. {
  1479. if (storage.parts_types[i] == "Camera" || storage.parts_types[i] == "CameraBW")
  1480. result++
  1481. }
  1482.  
  1483. return result;
  1484. }
  1485.  
  1486. // Searches through all Science Targets and checks to see whether they are visible
  1487. void CameraTakePhoto(Vehicle_Part ignorePart, int camNum, vector camPos, bool color);
  1488.  
  1489. // Clears the comprehensive list of instruments attached to the vehicle
  1490. void InstrumentClearFullList()
  1491. {
  1492. for (int i = 0; i < VEHICLE_MAXPARTS; i++)
  1493. {
  1494. inst_alllist[i] = -1;
  1495. }
  1496. }
  1497.  
  1498. // Generates the comprehensive list of instruments attached to the vehicle
  1499. int InstrumentCreateFullList()
  1500. {
  1501. InstrumentClearFullList();
  1502. // First generate a list of available camera types on the vehicle
  1503. string instTypeList[VEHICLE_MAXPARTS];
  1504. int numCTypes = 0;
  1505. for (int i = 0; i < VEHICLE_MAXPARTS; i++)
  1506. {
  1507. instTypeList[i] = "";
  1508. if (storage.parts_types[i] == "Instrument" && storage.parts_subtypes[i] != "") {
  1509. bool subtypeKnown = false;
  1510. for (int t = 0; t < numCTypes; t++)
  1511. {
  1512. if (storage.parts_subtypes[i] == instTypeList[t]) {
  1513. subtypeKnown = true;
  1514. t = numCTypes;
  1515. }
  1516. }
  1517. if (!subtypeKnown) {
  1518. instTypeList[numCTypes] = storage.parts_subtypes[i];
  1519. numCTypes++;
  1520. }
  1521. }
  1522. }
  1523.  
  1524. int result = 0;
  1525. for (t = 0; t < numCTypes; t++)
  1526. {
  1527. for (i = 0; i < storage.parts_num; i++)
  1528. {
  1529. if (parts_ents[i]) {
  1530. if (result >= storage.parts_num) {
  1531. i = storage.parts_num;
  1532. t = numCTypes;
  1533. } else {
  1534. if (CheckPartBaseConnect(i) && storage.parts_types[i] == "Instrument" && storage.parts_subtypes[i] == instTypeList[t]) {
  1535. inst_alllist[result] = i;
  1536. result++;
  1537. }
  1538. }
  1539. }
  1540. }
  1541. }
  1542. return result;
  1543. }
  1544.  
  1545. // Clears the comprehensive list of instruments (inc. passive) attached to the vehicle
  1546. void InstrumentClearFullListEx()
  1547. {
  1548. for (int i = 0; i < VEHICLE_MAXPARTS; i++)
  1549. {
  1550. inst_alllistex[i] = -1;
  1551. }
  1552. }
  1553.  
  1554. // Generates the comprehensive list of instruments (inc. passive) attached to the vehicle
  1555. int InstrumentCreateFullListEx()
  1556. {
  1557. InstrumentClearFullList();
  1558.  
  1559. int i;
  1560. int index;
  1561.  
  1562. // First generate a list of available camera types on the vehicle
  1563. string instTypeList[VEHICLE_MAXPARTS];
  1564. int numCTypes = 0;
  1565.  
  1566. for (i = 0; i < VEHICLE_MAXPARTS; i++)
  1567. {
  1568. instTypeList[i] = "";
  1569. if (storage.parts_types[i] == "Instrument" || storage.parts_types[i] == "InstrumentPassive")
  1570. {
  1571. if (storage.parts_subtypes[i] != "")
  1572. {
  1573. bool subtypeKnown = false;
  1574. for (int t = 0; t < numCTypes; t++)
  1575. {
  1576. if (storage.parts_subtypes[i] == instTypeList[t])
  1577. {
  1578. subtypeKnown = true;
  1579. t = numCTypes;
  1580. }
  1581. }
  1582. if (!subtypeKnown)
  1583. {
  1584. instTypeList[numCTypes] = storage.parts_subtypes[i];
  1585. numCTypes++;
  1586. }
  1587. }
  1588. }
  1589. }
  1590.  
  1591. int result = 0;
  1592. for (t = 0; t < numCTypes; t++)
  1593. {
  1594. for (i = 0; i < storage.parts_num; i++)
  1595. {
  1596. if (parts_ents[i])
  1597. {
  1598. if (result >= storage.parts_num)
  1599. {
  1600. i = storage.parts_num;
  1601. t = numCTypes;
  1602. }
  1603. else
  1604. {
  1605. if (storage.parts_types[i] == "Instrument" || storage.parts_types[i] == "InstrumentPassive")
  1606. {
  1607. if (CheckPartBaseConnect(i) && storage.parts_subtypes[i] == instTypeList[t])
  1608. {
  1609. inst_alllistex[result] = i;
  1610. result++;
  1611. }
  1612. }
  1613. }
  1614. }
  1615. }
  1616. }
  1617.  
  1618. //Sort non passive instruments first
  1619.  
  1620. for (i = 0; i < result; i++)
  1621. {
  1622. if (storage.parts_types[inst_alllistex[i]] == "InstrumentPassive")
  1623. {
  1624. for (index = i; index < result; index++)
  1625. {
  1626. if (storage.parts_types[inst_alllistex[index]] == "Instrument")
  1627. {
  1628. int id = inst_alllistex[i] ;
  1629.  
  1630. inst_alllistex[i] = inst_alllistex[index]
  1631. inst_alllistex[index] = id;
  1632.  
  1633. break
  1634. }
  1635. }
  1636. }
  1637. }
  1638.  
  1639. return result;
  1640. }
  1641.  
  1642. // Searches through all Science Targets and determine's if they should be completed
  1643. void InstrumentAnalyze(Vehicle_Part ignorePart, string instSubType, int physMat, string specMat, vector pos);
  1644.  
  1645. // Vehicle part data clearing
  1646. void ClearData()
  1647. {
  1648. for (int i = 0; i < VEHICLE_MAXJOINTS; i++)
  1649. {
  1650. joints_ents[i] = NULL;
  1651. }
  1652. for (i = 0; i < VEHICLE_MAXBLOCKS; i++)
  1653. {
  1654. blocks_ents[i] = NULL;
  1655. }
  1656. for (i = 0; i < VEHICLE_MAXPARTS; i++)
  1657. {
  1658. parts_ents[i] = NULL;
  1659. gui3dWidgetHandler[i] = NULL;
  1660. #ifdef DEVELOPER
  1661. parts_lastGripTime[i] = 0;
  1662. #endif
  1663. MP_gui3dWidgetHandlerList[i] = NULL;
  1664. }
  1665. MP_gui3dWidgetHandlerListNum = 0;
  1666. }
  1667.  
  1668. // In multiplayer must be client vehicle without joints, but must have blockers of these joints
  1669. void AppendBlocksForAllJoints()
  1670. {
  1671. int i;
  1672.  
  1673. //find first free block index
  1674. int lastFreeBlockIndex = -1;
  1675. for (i = VEHICLE_MAXBLOCKS - 1; i >= 0; i--)
  1676. {
  1677. if(storage.blocks_part1[i] != -1 && storage.blocks_part2[i] != -1)
  1678. {
  1679. lastFreeBlockIndex = i + 1;
  1680. break;
  1681. }
  1682. }
  1683.  
  1684. if(lastFreeBlockIndex == -1)
  1685. lastFreeBlockIndex = 0;
  1686.  
  1687. if(lastFreeBlockIndex >= VEHICLE_MAXBLOCKS)
  1688. return; //cannot add next blockers
  1689.  
  1690. for (i = 0; i < VEHICLE_MAXJOINTS; i++)
  1691. {
  1692. int part1 = storage.joints_part1[i];
  1693. int part2 = storage.joints_part2[i];
  1694.  
  1695. if (storage.joints_type[i] == -1 || part1 == -1 || part2 == -1)
  1696. continue;
  1697.  
  1698. storage.blocks_part1[lastFreeBlockIndex] = part1;
  1699. storage.blocks_part2[lastFreeBlockIndex] = part2;
  1700. lastFreeBlockIndex++;
  1701. }
  1702. }
  1703.  
  1704. // Returns a vehicle part by input custom title
  1705. Vehicle_Part GetPartByCustomTitle(string customTitle)
  1706. {
  1707. if (vehicleController)
  1708. return vehicleController.GetPartByCustomTitle(customTitle);
  1709.  
  1710. return NULL;
  1711. }
  1712.  
  1713. // Returns an entity by input custom title
  1714. _entity GetEntityByCustomTitle(string customTitle)
  1715. {
  1716. if (vehicleController)
  1717. return vehicleController.GetEntityByCustomTitle(customTitle);
  1718.  
  1719. return NULL;
  1720. }
  1721.  
  1722. // Deletes a widgets created for the vehicle
  1723. void DeleteRootWidget(string rootwidget)
  1724. {
  1725. widget w = FindWidget(NULL, rootwidget);
  1726. if (w) {
  1727. for (int i = 0; i < WIDGETS_VEHICLEMAX; i++)
  1728. {
  1729. if (widgetList[i] == w) {
  1730. DestroyWidget(widgetList[i]);
  1731. widgetList[i] = NULL;
  1732. }
  1733. }
  1734. }
  1735. }
  1736.  
  1737. // Deletes widgets created for the vehicle (HUD etc)
  1738. void DeleteWidgets()
  1739. {
  1740. if (vehicleController)
  1741. vehicleController.ProcessOnDeleteWidgets();
  1742.  
  1743. for (int i = 0; i < WIDGETS_VEHICLEMAX; i++)
  1744. {
  1745. if (widgetList[i])
  1746. {
  1747. DestroyWidget(widgetList[i]);
  1748. widgetList[i] = NULL;
  1749. }
  1750. if (widgetHandler)
  1751. widgetHandler.ClearHUDButtons();
  1752. }
  1753. radm_closed = true;
  1754. RadialMenuResetActions();
  1755. }
  1756.  
  1757. // Checks if the specified root widget exists in the widget list
  1758. widget FindVehWidget(string rootwidget)
  1759. {
  1760. for (int i = 0; i < WIDGETS_VEHICLEMAX; i++)
  1761. {
  1762. widget w = widgetList[i];
  1763. if (w && w.GetName() == rootwidget)
  1764. return w;
  1765. }
  1766.  
  1767. return NULL;
  1768. }
  1769.  
  1770. // Creates a new layout for the vehicle and puts its main root into the widget list
  1771. bool CreateVehWidgetsFromFile(string layoutFile, string rootwidget)
  1772. {
  1773. if (FindVehWidget(rootwidget))
  1774. return false;
  1775. else
  1776. {
  1777. for (int i = 0; i < WIDGETS_VEHICLEMAX; i++)
  1778. {
  1779. if (!widgetList[i])
  1780. {
  1781. widget w = CreateWidgets(String(layoutFile), NULL);
  1782. if (!w)
  1783. {
  1784. Print(String("CREATEVEHWIDGETSFROMFILE: Could not create widgets from layout '" + layoutFile + "'!!!"));
  1785. return false;
  1786. }
  1787.  
  1788. widgetList[i] = w;
  1789. if (widgetHandler)
  1790. SetWidgetEventHandler(w, widgetHandler);
  1791.  
  1792. return true;
  1793. }
  1794. }
  1795. }
  1796.  
  1797. return false;
  1798. }
  1799.  
  1800. // Creates a new layout (without using the suffix) for the vehicle and puts its main root into the widget list
  1801. bool CreateVehWidgetsNoSuffix(string layout, string rootwidget)
  1802. {
  1803. if (FindVehWidget(rootwidget))
  1804. return false;
  1805. else
  1806. {
  1807. for (int i = 0; i < WIDGETS_VEHICLEMAX; i++)
  1808. {
  1809. if (!widgetList[i])
  1810. {
  1811. widget w = CreateWidgets(String(layout + ".layout"), NULL);
  1812. if (!w)
  1813. {
  1814. Print(String("CREATEVEHWIDGETSNOSUFFIX: Could not create widgets from layout '" + layout + ".layout'!!!"));
  1815. return false;
  1816. }
  1817.  
  1818. widgetList[i] = w;
  1819. if (widgetHandler)
  1820. SetWidgetEventHandler(w, widgetHandler);
  1821.  
  1822. return true;
  1823. }
  1824. }
  1825. }
  1826.  
  1827. return false;
  1828. }
  1829.  
  1830. // Creates a new layout for the vehicle and puts its main root into the widget list
  1831. bool CreateVehWidgets(string layout, string rootwidget)
  1832. {
  1833. if (FindVehWidget(rootwidget))
  1834. return false;
  1835. else
  1836. {
  1837. for (int i = 0; i < WIDGETS_VEHICLEMAX; i++)
  1838. {
  1839. if (!widgetList[i])
  1840. {
  1841. widget w = CreateWidgets(String(layout + ".layout"), NULL);
  1842. if (!w)
  1843. {
  1844. Print(String("CREATEVEHWIDGETS: Could not create widgets from layout '" + layout + ".layout'!!!"));
  1845. return false;
  1846. }
  1847.  
  1848. widgetList[i] = w;
  1849. if (widgetHandler)
  1850. SetWidgetEventHandler(w, widgetHandler);
  1851.  
  1852. return true;
  1853. }
  1854. }
  1855. }
  1856.  
  1857. return false;
  1858. }
  1859.  
  1860. // Returns the quantized world mins and maxs for the whole vehicle
  1861. void Vehicle_GetWorldBounds(vector fullBounds[])
  1862. {
  1863. vector mins, maxs;
  1864. GetCBoundBox(this, mins, maxs);
  1865. for (int n = 0; n < storage.parts_num; n++) {
  1866. Vehicle_Part vehPart = parts_ents[n];
  1867. if (vehPart) {
  1868. vector mins2, maxs2;
  1869. GetCBoundBox(vehPart, mins2, maxs2);
  1870. for (int a = 0; a < 3; a++) {
  1871. if (mins2[a] < mins[a])
  1872. mins[a] = mins2[a];
  1873. if (maxs2[a] > maxs[a])
  1874. maxs[a] = maxs2[a];
  1875. }
  1876. }
  1877. }
  1878. fullBounds[0] = mins;
  1879. fullBounds[1] = maxs;
  1880. }
  1881.  
  1882. // Returns the mins and maxs for the whole vehicle
  1883. void Vehicle_GetFullBounds(vector fullBounds[])
  1884. {
  1885. vector mins, maxs;
  1886. GetBoundBox(this, mins, maxs);
  1887. for (int n = 0; n < storage.parts_num; n++) {
  1888. Vehicle_Part vehPart = parts_ents[n];
  1889. if (vehPart) {
  1890. vector rotBounds[2], mins2, maxs2;
  1891. GetBoundBox(vehPart, mins2, maxs2);
  1892. GetRotatedBounds(storage.parts_pos[n], storage.parts_ang[n], mins2, maxs2, rotBounds);
  1893. mins2 = rotBounds[0];
  1894. maxs2 = rotBounds[1];
  1895. for (int a = 0; a < 3; a++) {
  1896. if (mins2[a] < mins[a])
  1897. mins[a] = mins2[a];
  1898. if (maxs2[a] > maxs[a])
  1899. maxs[a] = maxs2[a];
  1900. }
  1901. }
  1902. }
  1903. fullBounds[0] = mins;
  1904. fullBounds[1] = maxs;
  1905. }
  1906.  
  1907. // Returns the mins and maxs for the whole vehicle, limited to parts with physics
  1908. void Vehicle_GetFullPhysicsBounds(vector fullBounds[])
  1909. {
  1910. vector mins, maxs;
  1911. GetBoundBox(this, mins, maxs);
  1912. for (int n = 0; n < storage.parts_num; n++) {
  1913. Vehicle_Part vehPart = parts_ents[n];
  1914. if (vehPart && dBodyIsDynamic(vehPart)) {
  1915. vector rotBounds[2], mins2, maxs2;
  1916. GetBoundBox(vehPart, mins2, maxs2);
  1917. GetRotatedBounds(storage.parts_pos[n], storage.parts_ang[n], mins2, maxs2, rotBounds);
  1918. mins2 = rotBounds[0];
  1919. maxs2 = rotBounds[1];
  1920. for (int a = 0; a < 3; a++) {
  1921. if (mins2[a] < mins[a])
  1922. mins[a] = mins2[a];
  1923. if (maxs2[a] > maxs[a])
  1924. maxs[a] = maxs2[a];
  1925. }
  1926. }
  1927. }
  1928. fullBounds[0] = mins;
  1929. fullBounds[1] = maxs;
  1930. }
  1931.  
  1932. // Returns collective center of mass, can be set to return only for attached parts to the vehicle hull, and can be set to return in local coords
  1933. vector Vehicle_GetCollectiveCOM(bool onlyAttached, bool localCoords)
  1934. {
  1935. vector mat[4];
  1936. GetMatrix4(this, mat);
  1937. int numCounted = 0;
  1938. float totalMass = 0;
  1939.  
  1940. // First get the highest mass
  1941. for (int n = 0; n < storage.parts_num; n++) {
  1942. if (onlyAttached && !CheckPartConnect(n, 0))
  1943. continue;
  1944.  
  1945. Vehicle_Part vehPart = parts_ents[n];
  1946. if (vehPart) {
  1947. if (!dBodyIsDynamic(vehPart))
  1948. continue;
  1949.  
  1950. float mass = GetObjectMass(vehPart);
  1951. totalMass += mass;
  1952. }
  1953. }
  1954.  
  1955. if (totalMass == 0)
  1956. totalMass = 1;
  1957.  
  1958. vector result = ZeroVec;
  1959. for (n = 0; n < storage.parts_num; n++) {
  1960. if (onlyAttached && !CheckPartConnect(n, 0))
  1961. continue;
  1962.  
  1963. vehPart = parts_ents[n];
  1964. if (vehPart) {
  1965. if (!dBodyIsDynamic(vehPart))
  1966. continue;
  1967.  
  1968. GetMatrix4(vehPart, mat);
  1969. vector comPos = VectorMatrixMultiply4(mat, dBodyGetCenterOfMass(vehPart));
  1970. mass = GetObjectMass(vehPart);
  1971. float massScale = mass / totalMass;
  1972. result = comPos * massScale + result;
  1973. numCounted++;
  1974. }
  1975. }
  1976.  
  1977. if (localCoords)
  1978. result = CoordToLocal(result);
  1979.  
  1980. return result;
  1981. }
  1982.  
  1983. // Teleports the entire vehicle to the desired location
  1984. void TeleportVehicle(vector pos, vector ang, bool ignoreDetachedParts)
  1985. {
  1986. if (GodModeTime < TELEPORT_GODMODETIME)
  1987. GodModeTime = TELEPORT_GODMODETIME;
  1988. SetOrigin(this, pos);
  1989. SetAngles(this, ang);
  1990. for (int i = 0; i < storage.parts_num; i++)
  1991. {
  1992. bool isStatic = false;
  1993. for (int i2 = 0; i2 < storage.statcons_num; i2++)
  1994. {
  1995. int p2 = storage.statcons_part2[i2];
  1996. if (p2 == i) {
  1997. isStatic = true;
  1998. break;
  1999. }
  2000. }
  2001. bool ignorePart = false;
  2002. if (i > 0 && ignoreDetachedParts && !CheckPartBaseConnect(i))
  2003. ignorePart = true;
  2004.  
  2005. Vehicle_Part vPart = parts_ents[i];
  2006. if (vPart && storage.parts_models[i] != "INTERNAL" && !isStatic && !ignorePart) {
  2007. vector mat[4];
  2008. GetEntOffsetMatrix(this, storage.parts_pos[i], storage.parts_ang[i], mat);
  2009. SetMatrix(vPart, mat);
  2010. }
  2011. }
  2012.  
  2013. if (vehicleController)
  2014. vehicleController.ProcessOnTeleport();
  2015. }
  2016.  
  2017. // Teleports the entire vehicle to the desired location
  2018. void TeleportVehicleMat4(vector mat[], bool ignoreDetachedParts)
  2019. {
  2020. if (GodModeTime < TELEPORT_GODMODETIME)
  2021. GodModeTime = TELEPORT_GODMODETIME;
  2022. SetMatrix(this, mat);
  2023. for (int i = 0; i < storage.parts_num; i++)
  2024. {
  2025. bool isStatic = false;
  2026. for (int i2 = 0; i2 < storage.statcons_num; i2++)
  2027. {
  2028. int p2 = storage.statcons_part2[i2];
  2029. if (p2 == i) {
  2030. isStatic = true;
  2031. break;
  2032. }
  2033. }
  2034. bool ignorePart = false;
  2035. if (i > 0 && ignoreDetachedParts && !CheckPartBaseConnect(i))
  2036. ignorePart = true;
  2037.  
  2038. Vehicle_Part vPart = parts_ents[i];
  2039. if (vPart && storage.parts_models[i] != "INTERNAL" && !isStatic && !ignorePart) {
  2040. GetEntOffsetMatrix(this, storage.parts_pos[i], storage.parts_ang[i], mat);
  2041. SetMatrix(vPart, mat);
  2042. }
  2043. }
  2044.  
  2045. if (vehicleController)
  2046. vehicleController.ProcessOnTeleport();
  2047. }
  2048.  
  2049. // Sets linear velocity on all parts
  2050. void SetVehicleLinVelocity(vector linvel, bool ignoreDetachedParts)
  2051. {
  2052. for (int i = 0; i < storage.parts_num; i++)
  2053. {
  2054. if (i > 0 && ignoreDetachedParts && !CheckPartBaseConnect(i))
  2055. continue;
  2056.  
  2057. Vehicle_Part vPart = parts_ents[i];
  2058. if (vPart && dBodyIsDynamic(vPart))
  2059. SetVelocity(vPart, linvel);
  2060. }
  2061.  
  2062. if (vehicleController)
  2063. vehicleController.ProcessOnSetVelocity();
  2064. }
  2065.  
  2066. // Sets angular velocity on all parts
  2067. void SetVehicleAngVelocity(vector angvel, bool ignoreDetachedParts)
  2068. {
  2069. for (int i = 0; i < storage.parts_num; i++)
  2070. {
  2071. if (i > 0 && ignoreDetachedParts && !CheckPartBaseConnect(i))
  2072. continue;
  2073.  
  2074. Vehicle_Part vPart = parts_ents[i];
  2075. if (vPart && dBodyIsDynamic(vPart))
  2076. dBodySetAngularVelocity(vPart, angvel);
  2077. }
  2078.  
  2079. if (vehicleController)
  2080. vehicleController.ProcessOnSetVelocity();
  2081. }
  2082.  
  2083. // Returns false if the part is internal, or a static connection
  2084. bool GetCanCreatePhysicsForPart(int pNum)
  2085. {
  2086. if (storage.parts_models[pNum] == "INTERNAL")
  2087. return false;
  2088.  
  2089. for (int p = 0; p < VEHICLE_MAXPARTS; p++)
  2090. {
  2091. int pNum2 = storage.statcons_part2[p];
  2092. if (pNum == pNum2)
  2093. return false;
  2094. }
  2095.  
  2096. return true;
  2097. }
  2098.  
  2099. // Spawns a vehicle part and sets its parameters
  2100. Vehicle_Part Vehicle_SpawnPart(int partNum)
  2101. {
  2102. vector mat[4];
  2103. GetEntOffsetMatrix(this, storage.parts_pos[partNum], storage.parts_ang[partNum], mat);
  2104. vobject model;
  2105. if (storage.parts_models[partNum] != "INTERNAL")
  2106. model = GetObject(storage.parts_models[partNum]);
  2107.  
  2108. Vehicle_Part ent = this;
  2109. if (partNum != 0) {
  2110. ent = new Vehicle_Part(false);
  2111. //ent.SetSceneID(TKOMHighestEntID + 1);
  2112. }
  2113. ent.PartNum = partNum;
  2114. if (storage.parts_models[partNum] != "INTERNAL") {
  2115. SetFlags(ent, TFL_VISIBLE|TFL_ACTIVE|TFL_SOLID);
  2116. ent.SetObject(model, "");
  2117. SetMatrix(ent, mat);
  2118. }
  2119. if (storage.parts_conPtcSnd[partNum] != "")
  2120. ent.FXIndex = CreateFXType(storage.parts_conPtcSnd[partNum]);
  2121. ent.GenVec = storage.parts_genVec[partNum];
  2122. ent.GenVec2 = storage.parts_genVec2[partNum];
  2123. ent.GenVec3 = storage.parts_genVec3[partNum];
  2124. ent.GenVec4 = storage.parts_genVec4[partNum];
  2125. ent.GenVec5 = storage.parts_genVec5[partNum];
  2126. ent.GenVec6 = storage.parts_genVec6[partNum];
  2127. ent.Toughness = storage.parts_tough[partNum];
  2128. ent.ParentVehicle = this;
  2129.  
  2130. if (GetCanCreatePhysicsForPart(partNum))
  2131. {
  2132. dBodyCreateDynamic(ent, ZeroVec, 0xffffffff);
  2133. UpdateDampingOnEnt(ent, NULL, 1);
  2134. float sleepThreshold = GetGlobalizedSleepThreshold();
  2135. dBodySetSleepingTreshold(ent, sleepThreshold, sleepThreshold);
  2136. dBodySetMass(ent, storage.parts_mass[partNum]);
  2137. ent.UpdatePhysicalParams();
  2138. CreateNamedGeomBox(ent, GEOMNAME_AABB, COLLIDERLAYER_DYNAMIC_AABB);
  2139. dBodyInteractionLayerEx(ent, storage.interactionLayer);
  2140. }
  2141.  
  2142. if (storage.parts_models[partNum] != "INTERNAL" && model)
  2143. ReleaseObject(model, false);
  2144.  
  2145. /*if( IsClient() && storage.isCharacter )
  2146. ent.EnableGravity( false );//disable gravity for all dynamic objects on clients!!! this keeps movement prediction, but removes jumping
  2147. */
  2148. return ent;
  2149. }
  2150.  
  2151. // Constructs the vehicle from the part and joint data
  2152. void ConstructVehicle(vector pos, vector ang)
  2153. {
  2154. storage.joints_num = 0;
  2155. storage.blocks_num = 0;
  2156. storage.parts_num = 0;
  2157. storage.statcons_num = 0;
  2158.  
  2159. local int part1, part2;
  2160. vector rndVel = storage.ReentryVelocity;
  2161. storage.ReentryVelocity = ZeroVec;
  2162. if (storage.ReentryZone != ZeroVec) {
  2163. storage.LandingZone = storage.ReentryZone;
  2164. storage.LandingZone[2] = GetTerrainHeight(storage.LandingZone);
  2165. storage.ReentryZone[2] = storage.ReentryOffsetPos[2];
  2166. pos[0] = storage.ReentryZone[0] + storage.ReentryOffsetPos[0];
  2167. pos[1] = storage.ReentryZone[1] + storage.ReentryOffsetPos[1];
  2168. storage.ReentryZone[0] = pos[0];
  2169. storage.ReentryZone[1] = pos[1];
  2170. ang = storage.ReentryOffsetAng;
  2171. rndVel[0] = rndVel[0] * frand(0.95, 1.05);
  2172. rndVel[1] = rndVel[1] * frand(0.95, 1.05);
  2173. rndVel[2] = rndVel[2] * frand(0.95, 1.05);
  2174. }
  2175.  
  2176. SetOrigin(this, pos);
  2177. SetAngles(this, ZeroVec);
  2178.  
  2179. inst_inrange = false;
  2180. inst_hilite = "";
  2181. inst_sample = "";
  2182. inst_analyze = "";
  2183. PriPartSwitchTime = 0;
  2184. SecPartSwitchTime = 0;
  2185.  
  2186. // First create the static vehicle parts
  2187. for (local int i = 0; i < VEHICLE_MAXPARTS; i++)
  2188. {
  2189. if (storage.parts_models[i] == "")
  2190. continue;
  2191.  
  2192. if (GetCanCreatePhysicsForPart(i))
  2193. continue;
  2194.  
  2195. parts_ents[i] = Vehicle_SpawnPart(i);
  2196. if (storage.parts_num < i + 1)
  2197. storage.parts_num = i + 1;
  2198. }
  2199.  
  2200. // Now create the dynamic vehicle parts
  2201. for (i = 0; i < VEHICLE_MAXPARTS; i++)
  2202. {
  2203. if (storage.parts_models[i] == "")
  2204. continue;
  2205.  
  2206. if (!GetCanCreatePhysicsForPart(i))
  2207. continue;
  2208.  
  2209. parts_ents[i] = Vehicle_SpawnPart(i);
  2210. if (storage.parts_num < i + 1)
  2211. storage.parts_num = i + 1;
  2212. }
  2213.  
  2214. // Create the vehicle joints
  2215. for (i = 0; i < VEHICLE_MAXJOINTS; i++)
  2216. {
  2217. int jointType = GetJointType(i); // Get joint type taking into account LODed joints and physics tick
  2218. if (jointType != -1) {
  2219. if (storage.joints_num < i + 1)
  2220. storage.joints_num = i + 1;
  2221. vector jmat1[4], jmat2[4];
  2222. part1 = storage.joints_part1[i];
  2223. part2 = storage.joints_part2[i];
  2224. if (part1 == -1 || part2 == -1)
  2225. continue;
  2226.  
  2227. Vehicle_Part p1Ent = parts_ents[part1];
  2228. Vehicle_Part p2Ent = parts_ents[part2];
  2229. if (p1Ent && p2Ent)
  2230. {
  2231. // Create the joint's vehicle FX ent, if it doesn't exist
  2232. if (storage.joints_breakPtcSnd[i] != "")
  2233. storage.joints_FXIndex[i] = CreateFXType(storage.joints_breakPtcSnd[i]);
  2234.  
  2235. // Create joint connection matrix 1 from the joint angles, part2 position, subtracted part 1 and 2 angles and part 1 center of mass
  2236. /*RollPitchYawMatrix(storage.joints_angles[i] + storage.parts_ang[part2] - storage.parts_ang[part1], jmat1);
  2237. jmat1[3] = p1Ent.CoordToLocal(CoordToParent(storage.parts_pos[part2])) - dBodyGetCenterOfMass(p1Ent);
  2238.  
  2239. // Create joint connection matrix 2 from the joint angles, and part 2 center of mass
  2240. RollPitchYawMatrix(storage.joints_angles[i], jmat2);
  2241. jmat2[3] = ZeroVec - dBodyGetCenterOfMass(p2Ent);*/
  2242.  
  2243.  
  2244. p2Ent.ParentPartNum = part1; // Store in each part its parent
  2245. p1Ent.AddChildPart(part2); // Store each child
  2246.  
  2247. vector p1Mat[4], p2Mat[4];
  2248.  
  2249. /*if( IsClient() && storage.isCharacter ) //do not create joints in multiplayer on clients
  2250. joints_ents[i] = NULL;
  2251. else
  2252. {*/
  2253. GetMatrix4(p1Ent, p1Mat);
  2254. GetMatrix4(p2Ent, p2Mat);
  2255.  
  2256. // Get joint rotation matrices
  2257. vector jaMat1[3], jaMat2[3];
  2258. RollPitchYawMatrix(storage.joints_angles[i], jaMat1);
  2259. MatrixMultiply3(p2Mat, jaMat1, jaMat2);
  2260.  
  2261. MatrixInvMultiply3(p1Mat, jaMat2, jmat1);
  2262.  
  2263. MatrixInvMultiply3(p2Mat, jaMat2, jmat2);
  2264. if (jointType == JOINT_360MOTOR)
  2265. {
  2266. vector jaMat3601[3], jaMat3602[3];
  2267. RollPitchYawMatrix("180 -180 0", jaMat3601);
  2268.  
  2269. jaMat3602[0] = jmat2[0];
  2270. jaMat3602[1] = jmat2[1];
  2271. jaMat3602[2] = jmat2[2];
  2272. MatrixInvMultiply3(jaMat3602, jaMat3601, jmat2);
  2273. }
  2274.  
  2275. // Get joint positions
  2276. jmat1[3] = p1Ent.CoordToLocal(CoordToParent(storage.parts_pos[part2])) - dBodyGetCenterOfMass(p1Ent);
  2277. jmat2[3] = ZeroVec - dBodyGetCenterOfMass(p2Ent);
  2278.  
  2279. // Fixed joint - keeps the parts firmly locked together.
  2280. if (jointType == JOINT_FIXED)
  2281. {
  2282. //joints_ents[i] = dJointCreateFixed(p1Ent, p2Ent, jmat1[3], jmat2[3], true, -1);
  2283. joints_ents[i] = dJointCreate6DOF(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2284. dJoint6DOFSetLinearLimits(joints_ents[i], ZeroVec, ZeroVec);
  2285. dJoint6DOFSetAngularLimits(joints_ents[i], ZeroVec, ZeroVec);
  2286. continue;
  2287. }
  2288.  
  2289. // Hinge joint - rotates about a single axis. Ideal for suspension, for example.
  2290. if (jointType == JOINT_HINGE)
  2291. {
  2292. //joints_ents[i] = dJointCreateHinge2(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2293. /** Hinge Limits:
  2294. storage.joints_limits_lo[i][0] = Lower limit in degrees - the joint won't turn below this amount (eg. -90)
  2295. storage.joints_limits_hi[i][0] = Upper limit in degrees - the joint won't turn above this amount (eg. 90)
  2296. Note: If the Lower limit is higher than the Upper Limit, the axis is free to turn 360 Degrees
  2297. storage.joints_limits_lo[i][1] = Softness - % of limits where movement is free, above this the limit is gradually enforced (eg. 0.5)
  2298. storage.joints_limits_lo[i][2] = Bias Factor - the strength with which the constraint resists limit violations (eg. 0.3)
  2299. storage.joints_limits_hi[i][1] = Relaxation Factor - The lower the values, the less the constraint will fight velocities which
  2300. violate the angular limits (eg. 1)
  2301. **/
  2302. /*if (storage.joints_limits_lo[i][0] != 0 && storage.joints_limits_hi[i][0] != 0)
  2303. dJointHingeSetLimits(joints_ents[i], storage.joints_limits_lo[i][0] * DEG2RAD, storage.joints_limits_hi[i][0] * DEG2RAD, storage.joints_limits_lo[i][1], storage.joints_limits_lo[i][2], storage.joints_limits_hi[i][1]);*/
  2304.  
  2305. joints_ents[i] = dJointCreate6DOF(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2306. vector hingeang_min = Vector(0, 0, storage.joints_limits_lo[i][0] * -DEG2RAD);
  2307. vector hingeang_max = Vector(0, 0, storage.joints_limits_hi[i][0] * -DEG2RAD);
  2308. dJoint6DOFSetLinearLimits(joints_ents[i], ZeroVec, ZeroVec);
  2309. dJoint6DOFSetAngularLimits(joints_ents[i], hingeang_min, hingeang_max);
  2310. continue;
  2311. }
  2312.  
  2313. // Motor joint (slider joint with motor forces) - rotates about one axis, useful for wheels.
  2314. if (jointType == JOINT_MOTOR) {
  2315. joints_ents[i] = dJointCreateSlider(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2316. /** Motor Limits:
  2317. storage.joints_limits_lo[i][0] = Lower limit in degrees - the joint won't turn below this amount (eg. -90)
  2318. storage.joints_limits_hi[i][0] = Upper limit in degrees - the joint won't turn above this amount (eg. 90)
  2319. Note: If the Lower limit is higher than the Upper Limit, the axis is free to turn 360 Degrees
  2320. storage.joints_limits_hi[i][1] = Motor spin-up/down speed (used in controllers)
  2321. storage.joints_limits_lo[i][1] = Maximum motor velocity - the maximum speed the motor can turn at
  2322. storage.joints_limits_lo[i][2] = Maximum motor torque - the maximum force used to turn the motor with
  2323. **/
  2324. dJointSliderSetLinearLimits(joints_ents[i], 0, 0);
  2325. dJointSliderSetAngularLimits(joints_ents[i], storage.joints_limits_lo[i][0] * DEG2RAD, storage.joints_limits_hi[i][0] * DEG2RAD);
  2326. continue;
  2327. }
  2328.  
  2329. // Twist Motor joint (hinge2 joint with twist motor setting) - rotates about one axis, can be instructed to twist to a certain angle, useful for steering.
  2330. if (jointType == JOINT_TMOTOR) {
  2331. //joints_ents[i] = dJointCreateHinge2(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2332. /** Hinge Limits:
  2333. storage.joints_limits_lo[i][0] = Half limit in degrees - the joint won't turn beyond this amount in any direction (eg. 90)
  2334. Note: If the Lower limit is higher than the Upper Limit, the axis is free to turn 360 Degrees
  2335. storage.joints_limits_lo[i][1] = Maximum motor turn - the time it takes the motor to turn to the desired angle
  2336. storage.joints_limits_lo[i][2] = Maximum motor torque - the maximum force used to turn the motor with
  2337. storage.joints_limits_hi[i][0] = Softness - % of limits where movement is free, above this the limit is gradually enforced (eg. 0.5)
  2338. storage.joints_limits_hi[i][1] = Bias Factor - the strength with which the constraint resists limit violations (eg. 0.3)
  2339. storage.joints_limits_hi[i][2] = Relaxation Factor - The lower the values, the less the constraint will fight velocities which
  2340. violate the angular limits (eg. 1)
  2341. **/
  2342. /*if (storage.joints_limits_lo[i][0] != 0 && storage.joints_limits_hi[i][0] != 0)
  2343. dJointHingeSetLimits(joints_ents[i], storage.joints_limits_lo[i][0] * -DEG2RAD, storage.joints_limits_lo[i][0] * DEG2RAD, storage.joints_limits_hi[i][0], storage.joints_limits_hi[i][1], storage.joints_limits_hi[i][2]);*/
  2344. joints_ents[i] = dJointCreate6DOF(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2345. dJoint6DOFSetLinearLimits(joints_ents[i], ZeroVec, ZeroVec);
  2346. TKOMJoint180_SetAngle(joints_ents[i], 0);
  2347. continue;
  2348. }
  2349.  
  2350. // 360 Motor joint (hinge2 joint with rotational motor setting) - rotates about one axis, can be instructed to twist to a certain angle, useful for steering.
  2351. if (jointType == JOINT_360MOTOR) {
  2352. joints_ents[i] = dJointCreateHinge2(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2353. /** Hinge Limits:
  2354. storage.joints_limits_lo[i][0] = Forward limit in degrees - can be used to prevent the joint from turning beyond this amount (eg. 270)
  2355. storage.joints_limits_lo[i][1] = Maximum motor turn - the maximum speed the motor can turn at
  2356. storage.joints_limits_lo[i][2] = Maximum motor torque - the maximum force used to turn the motor with
  2357. storage.joints_limits_hi[i][0] = Softness - % of limits where movement is free, above this the limit is gradually enforced (eg. 0.5)
  2358. storage.joints_limits_hi[i][1] = Bias Factor - the strength with which the constraint resists limit violations (eg. 0.3)
  2359. storage.joints_limits_hi[i][2] = Relaxation Factor - The lower the values, the less the constraint will fight velocities which
  2360. violate the angular limits (eg. 1)
  2361. **/
  2362. if (storage.joints_limits_lo[i][0] != 0 && storage.joints_limits_hi[i][0] != 0)
  2363. dJointHingeSetLimits(joints_ents[i], -180 * DEG2RAD, 180 * DEG2RAD, 0.5, 0.7, 0.7);
  2364. //dJointHingeSetLimits(joints_ents[i], -180 * DEG2RAD, 180 * DEG2RAD, storage.joints_limits_hi[i][0], storage.joints_limits_hi[i][1], storage.joints_limits_hi[i][2]);
  2365.  
  2366. /*joints_ents[i] = dJointCreate6DOF(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2367. dJoint6DOFSetLinearLimits(joints_ents[i], ZeroVec, ZeroVec);*/
  2368. TKOMJoint360_SetAngle(joints_ents[i], 0);
  2369. continue;
  2370. }
  2371.  
  2372. // 6 Degrees Of Freedom joint - allows movement in all axes
  2373. if (jointType == JOINT_6DOF) {
  2374. joints_ents[i] = dJointCreate6DOF(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2375. /** 6DOF Limits:
  2376. storage.joints_limits_lo[i] = Linear limits in units (eg. "0 20 0")
  2377. storage.joints_limits_hi[i] = Angular limits in degrees (eg. "0 100 0")
  2378. **/
  2379. vector lim_lin = storage.joints_limits_lo[i];
  2380. vector lim_ang = storage.joints_limits_hi[i] * DEG2RAD;
  2381. dJoint6DOFSetLinearLimits(joints_ents[i], -lim_lin, lim_lin);
  2382. dJoint6DOFSetAngularLimits(joints_ents[i], -lim_ang, lim_ang);
  2383. continue;
  2384. }
  2385.  
  2386. // Piston joint (slider joint with linear motor forces) - extends/retracts along an axis, useful for pistons.
  2387. if (jointType == JOINT_PISTON) {
  2388. //joints_ents[i] = dJointCreateSlider(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2389. /** Motor Limits:
  2390. storage.joints_limits_lo[i][0] = Lower limit - the joint won't move below this amount in meters (eg. -1)
  2391. storage.joints_limits_hi[i][0] = Upper limit - the joint won't move above this amount in meters (eg. 1)
  2392. Note: If the Lower limit is higher than the Upper Limit, the axis is free to move
  2393. storage.joints_limits_lo[i][1] = Maximum motor velocity - the maximum speed the piston can move at
  2394. storage.joints_limits_lo[i][2] = Maximum motor force - the maximum force used to extend/retract the piston with
  2395. **/
  2396. /*dJointSliderSetLinearLimits(joints_ents[i], storage.joints_limits_lo[i][0], storage.joints_limits_hi[i][0]);
  2397. dJointSliderSetAngularLimits(joints_ents[i], 0, 0);*/
  2398. joints_ents[i] = dJointCreate6DOF(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2399. dJoint6DOFSetLinearLimits(joints_ents[i], ZeroVec, ZeroVec);
  2400. dJoint6DOFSetAngularLimits(joints_ents[i], ZeroVec, ZeroVec);
  2401. continue;
  2402. }
  2403.  
  2404. // Spring joint - allows movement in all axes
  2405. if (jointType == JOINT_SPRING) {
  2406. joints_ents[i] = dJointCreate6DOFSpring(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2407. /** Spring Limits:
  2408. storage.joints_limits_lo[i] = Linear limits in units (eg. "0 20 0")
  2409. storage.joints_limits_hi[i][0] = Stiffness of the spring (eg. 2000)
  2410. storage.joints_limits_hi[i][1] = Damping of the spring, lower values means more damping (eg. 0.5)
  2411. **/
  2412. vector sprlim_lin = storage.joints_limits_lo[i];
  2413. dJoint6DOFSetLinearLimits(joints_ents[i], -sprlim_lin, sprlim_lin);
  2414. dJoint6DOFSetAngularLimits(joints_ents[i], ZeroVec, ZeroVec);
  2415. dJoint6DOFSpringSetSpring(joints_ents[i], 0, storage.joints_limits_hi[i][0] * GetSpringScale(), storage.joints_limits_hi[i][1] * GetSpringLinDampScale());
  2416. dJoint6DOFSpringSetSpring(joints_ents[i], 1, storage.joints_limits_hi[i][0] * GetSpringScale(), storage.joints_limits_hi[i][1] * GetSpringLinDampScale());
  2417. dJoint6DOFSpringSetSpring(joints_ents[i], 2, storage.joints_limits_hi[i][0] * GetSpringScale(), storage.joints_limits_hi[i][1] * GetSpringLinDampScale());
  2418. continue;
  2419. }
  2420.  
  2421. // Angular Spring joint - allows rotation in all axes
  2422. if (jointType == JOINT_ANGSPRING) {
  2423. joints_ents[i] = dJointCreate6DOFSpring(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2424. /** Spring Limits:
  2425. storage.joints_limits_lo[i] = Angular limits in degrees (eg. "0 20 0")
  2426. storage.joints_limits_hi[i][0] = Stiffness of the spring (eg. 2000)
  2427. storage.joints_limits_hi[i][1] = Damping of the spring, lower values means more damping (eg. 0.5)
  2428. **/
  2429. vector sprlim_ang = storage.joints_limits_lo[i];
  2430. sprlim_ang[0] = sprlim_ang[0] * DEG2RAD;
  2431. sprlim_ang[1] = sprlim_ang[1] * DEG2RAD;
  2432. sprlim_ang[2] = sprlim_ang[2] * DEG2RAD;
  2433. dJoint6DOFSetLinearLimits(joints_ents[i], ZeroVec, ZeroVec);
  2434. dJoint6DOFSetAngularLimits(joints_ents[i], -sprlim_ang, sprlim_ang);
  2435. dJoint6DOFSpringSetSpring(joints_ents[i], 3, storage.joints_limits_hi[i][0] * GetSpringScale(), storage.joints_limits_hi[i][1] * GetSpringAngDampScale());
  2436. dJoint6DOFSpringSetSpring(joints_ents[i], 4, storage.joints_limits_hi[i][0] * GetSpringScale(), storage.joints_limits_hi[i][1] * GetSpringAngDampScale());
  2437. dJoint6DOFSpringSetSpring(joints_ents[i], 5, storage.joints_limits_hi[i][0] * GetSpringScale(), storage.joints_limits_hi[i][1] * GetSpringAngDampScale());
  2438. continue;
  2439. }
  2440.  
  2441. // Sphere Spring joint - allows movement in all axes, including rotation
  2442. if (jointType == JOINT_SPHERESPRING) {
  2443. joints_ents[i] = dJointCreate6DOFSpring(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2444. /** Spring Limits:
  2445. storage.joints_limits_lo[i][0] = Linear limits in units (eg. 20)
  2446. storage.joints_limits_lo[i][1] = Angular limits in degrees (eg. 10)
  2447. storage.joints_limits_hi[i][0] = Stiffness of the spring (eg. 2000)
  2448. storage.joints_limits_hi[i][1] = Damping of the spring, lower values means more damping (eg. 0.5)
  2449. **/
  2450. vector sphsprlim_lin = Vector(storage.joints_limits_lo[i][0], storage.joints_limits_lo[i][0], storage.joints_limits_lo[i][0]);
  2451. vector sphsprlim_ang = Vector(storage.joints_limits_lo[i][1] * DEG2RAD, storage.joints_limits_lo[i][1] * DEG2RAD, storage.joints_limits_lo[i][1] * DEG2RAD);
  2452. dJoint6DOFSetLinearLimits(joints_ents[i], -sphsprlim_lin, sphsprlim_lin);
  2453. dJoint6DOFSetAngularLimits(joints_ents[i], -sphsprlim_ang, sphsprlim_ang);
  2454. dJoint6DOFSpringSetSpring(joints_ents[i], 0, storage.joints_limits_hi[i][0] * GetSpringScale(), storage.joints_limits_hi[i][1] * GetSpringLinDampScale());
  2455. dJoint6DOFSpringSetSpring(joints_ents[i], 1, storage.joints_limits_hi[i][0] * GetSpringScale(), storage.joints_limits_hi[i][1] * GetSpringLinDampScale());
  2456. dJoint6DOFSpringSetSpring(joints_ents[i], 2, storage.joints_limits_hi[i][0] * GetSpringScale(), storage.joints_limits_hi[i][1] * GetSpringLinDampScale());
  2457. dJoint6DOFSpringSetSpring(joints_ents[i], 3, storage.joints_limits_hi[i][0] * GetSpringScale(), storage.joints_limits_hi[i][1] * GetSpringAngDampScale());
  2458. dJoint6DOFSpringSetSpring(joints_ents[i], 4, storage.joints_limits_hi[i][0] * GetSpringScale(), storage.joints_limits_hi[i][1] * GetSpringAngDampScale());
  2459. dJoint6DOFSpringSetSpring(joints_ents[i], 5, storage.joints_limits_hi[i][0] * GetSpringScale(), storage.joints_limits_hi[i][1] * GetSpringAngDampScale());
  2460. continue;
  2461. }
  2462.  
  2463. // 6 Degrees Of Freedom Hinge joint - allows rotation in all axes
  2464. if (jointType == JOINT_6DOFHINGE) {
  2465. joints_ents[i] = dJointCreate6DOF(p1Ent, p2Ent, jmat1, jmat2, true, -1);
  2466. /** 6DOF Hinge Limits:
  2467. storage.joints_limits_lo[i] = Minimum angular limits in units (eg. "0 20 0")
  2468. storage.joints_limits_hi[i] = Maximum angular limits in degrees (eg. "0 100 0")
  2469. **/
  2470. vector lim_ang_min = storage.joints_limits_lo[i] * DEG2RAD;
  2471. vector lim_ang_max = storage.joints_limits_hi[i] * DEG2RAD;
  2472. dJoint6DOFSetLinearLimits(joints_ents[i], ZeroVec, ZeroVec);
  2473. dJoint6DOFSetAngularLimits(joints_ents[i], lim_ang_min, lim_ang_max);
  2474. continue;
  2475. }
  2476. //}
  2477. } else {
  2478. string printStr = "VEHICLEHANDLER: Constructing vehicle joint but part";
  2479. if (p1Ent || p2Ent) {
  2480. if (!p1Ent)
  2481. printStr += " " + itoa(part1) + " does not exist!";
  2482. if (!p2Ent)
  2483. printStr += " " + itoa(part2) + " does not exist!";
  2484. } else
  2485. printStr += "s " + itoa(part1) + " and " + itoa(part2) + " do not exist!";
  2486. Print(String(printStr));
  2487. }
  2488. }
  2489. }
  2490.  
  2491. // Create the collision blockers
  2492. for (i = 0; i < VEHICLE_MAXBLOCKS; i++)
  2493. {
  2494. if (storage.blocks_part1[i] != -1 && storage.blocks_part2[i] != -1) {
  2495. if (storage.blocks_num < i + 1)
  2496. storage.blocks_num = i + 1;
  2497. part1 = storage.blocks_part1[i];
  2498. part2 = storage.blocks_part2[i];
  2499. p1Ent = parts_ents[part1];
  2500. p2Ent = parts_ents[part2];
  2501. if (p1Ent && p2Ent && dBodyIsSet(p1Ent) && dBodyIsSet(p2Ent))
  2502. blocks_ents[i] = dBodyCollisionBlock(p1Ent, p2Ent);
  2503. else {
  2504. if (!p1Ent || !p2Ent)
  2505. {
  2506. printStr = "VEHICLEHANDLER: Constructing vehicle collision blocker " + itoa(i) + " but part";
  2507. if (p1Ent || p2Ent) {
  2508. if (!p1Ent)
  2509. printStr += " " + itoa(part1) + " does not exist!";
  2510. if (!p2Ent)
  2511. printStr += " " + itoa(part2) + " does not exist!";
  2512. } else
  2513. printStr += "s " + itoa(part1) + " and " + itoa(part2) + " do not exist!";
  2514. Print(String(printStr));
  2515. if (p1Ent || p2Ent) {
  2516. if (!p1Ent)
  2517. Print(String("Model: '" + storage.parts_models[part1] + "'"));
  2518. if (!p2Ent)
  2519. Print(String("Model: '" + storage.parts_models[part2] + "'"));
  2520. } else {
  2521. Print(String("Model 1: '" + storage.parts_models[part1] + "'"));
  2522. Print(String("Model 2: '" + storage.parts_models[part2] + "'"));
  2523. }
  2524. }
  2525. else
  2526. {
  2527. printStr = "VEHICLEHANDLER: Constructing vehicle collision blocker " + itoa(i) + " but part";
  2528. if (dBodyIsSet(p1Ent) || dBodyIsSet(p2Ent)) {
  2529. if (!dBodyIsSet(p1Ent))
  2530. printStr += " " + itoa(part1) + " does not have physics set (static connection?)!";
  2531. if (!dBodyIsSet(p2Ent))
  2532. printStr += " " + itoa(part2) + " does not have physics set (static connection?)!";
  2533. } else
  2534. printStr += "s " + itoa(part1) + " and " + itoa(part2) + " do not have physics set (static connection?)!";
  2535. Print(String(printStr));
  2536. if (dBodyIsSet(p1Ent) || dBodyIsSet(p2Ent)) {
  2537. if (!dBodyIsSet(p1Ent))
  2538. Print(String("Model: '" + storage.parts_models[part1] + "'"));
  2539. if (!dBodyIsSet(p2Ent))
  2540. Print(String("Model: '" + storage.parts_models[part2] + "'"));
  2541. } else {
  2542. Print(String("Model 1: '" + storage.parts_models[part1] + "'"));
  2543. Print(String("Model 2: '" + storage.parts_models[part2] + "'"));
  2544. }
  2545. }
  2546. }
  2547. }
  2548. }
  2549.  
  2550. if (storage.ReentryZone != ZeroVec) {
  2551. TeleportVehicle(storage.ReentryZone, ang, false);
  2552. storage.ReentryZone = ZeroVec;
  2553. } else
  2554. TeleportVehicle(pos, ang, false);
  2555.  
  2556. // Move parts to world coordinates, if defined, and set previous parents
  2557. for (i = 0; i < VEHICLE_MAXPARTS; i++)
  2558. {
  2559. vector checkVec = storage.parts_wmat3[i];
  2560. if (parts_ents[i])
  2561. {
  2562. Vehicle_Part pEnt = parts_ents[i];
  2563.  
  2564. // if( IsClient() )
  2565. // dBodyInteractionLayer(pEnt, COLLIDERLAYER_NONE);
  2566.  
  2567. if (checkVec != ZeroVec)
  2568. {
  2569. vector mat[4];
  2570. mat[0] = storage.parts_wmat0[i];
  2571. mat[1] = storage.parts_wmat1[i];
  2572. mat[2] = storage.parts_wmat2[i];
  2573. mat[3] = storage.parts_wmat3[i];
  2574. SetMatrix(parts_ents[i], mat);
  2575. }
  2576. if (rndVel != ZeroVec)
  2577. SetVelocity(parts_ents[i], rndVel);
  2578. else
  2579. {
  2580. SetVelocity(parts_ents[i], storage.parts_velLin[i]);
  2581. dBodySetAngularVelocity(parts_ents[i], storage.parts_velAng[i]);
  2582. }
  2583. if (storage.parts_storedParent[i] >= -1) // If there is a stored parent data, use it
  2584. pEnt.ParentPartNum = storage.parts_storedParent[i];
  2585. }
  2586. }
  2587.  
  2588. // Create static connections
  2589. for (i = 0; i < VEHICLE_MAXPARTS; i++)
  2590. {
  2591. int p1 = storage.statcons_part1[i];
  2592. int p2 = storage.statcons_part2[i];
  2593. if (p1 > -1 && p2 > -1 && parts_ents[p1] && parts_ents[p2]) {
  2594. if (storage.statcons_num < i + 1)
  2595. storage.statcons_num = i + 1;
  2596. Vehicle_Part sp1Ent = parts_ents[p1];
  2597. Vehicle_Part sp2Ent = parts_ents[p2];
  2598.  
  2599. vector sp1Mat[4], sp2Mat[4], smodMat[4];
  2600. RollPitchYawMatrix(storage.parts_ang[p1], sp1Mat);
  2601. RollPitchYawMatrix(storage.parts_ang[p2], smodMat);
  2602. sp1Mat[3] = storage.parts_pos[p1];
  2603. smodMat[3] = storage.parts_pos[p2];
  2604. MatrixInvMultiply4(sp1Mat, smodMat, sp2Mat);
  2605.  
  2606. dBodyInteractionLayer(sp2Ent, COLLIDERLAYER_NONE);
  2607.  
  2608. AddChild(sp1Ent, sp2Ent, -1);
  2609. SetMatrix(sp2Ent, sp2Mat);
  2610. sp2Ent.ParentPartNum = p1;
  2611. sp1Ent.AddChildPart(p2); // Store each child
  2612. }
  2613. }
  2614.  
  2615. // Activate the vehicle handler's simulation
  2616. SetEventMask(this, EV_SIMULATE|EV_FRAME|EV_POSTFRAME);
  2617.  
  2618. // Create the vehicle's widget handler
  2619. if (!widgetHandler)
  2620. widgetHandler = new Vehicle_WidgetHandler(this);
  2621.  
  2622. // Create the vehicle's controller
  2623. if (!vehicleController)
  2624. vehicleController = new Vehicle_Controller();
  2625. if (vehicleController)
  2626. {
  2627. vehicleController.ownerVehicle = this;
  2628. for (i = 0; i < CONTROL_VEHICLEMAX; i++)
  2629. {
  2630. vehicleController.AddScript(storage.script_Path[i]);
  2631. }
  2632. vehicleController.InitScripts();
  2633. }
  2634.  
  2635. vector compatSpawnPos = storage.CompatibilitySpawnMat[3];
  2636. if (compatSpawnPos != ZeroVec)
  2637. TeleportVehicleMat4(storage.CompatibilitySpawnMat, false);
  2638.  
  2639. MatrixIdentity(storage.CompatibilitySpawnMat);
  2640. }
  2641.  
  2642. void UnitScriptsPostInit()
  2643. {
  2644. if (vehicleController)
  2645. vehicleController.PostInitScripts();
  2646. }
  2647.  
  2648. void DestroyController()
  2649. {
  2650. if(vehicleController)
  2651. {
  2652. vehicleController.ExitScripts();
  2653. delete vehicleController;
  2654. vehicleController = NULL;
  2655. }
  2656. }
  2657.  
  2658. void RemoveJointsBlockers()
  2659. {
  2660. World curWorld = GetCurrentWorld();
  2661. for (int i = 0; i < VEHICLE_MAXJOINTS; i++) {
  2662. dJoint killJoint = joints_ents[i];
  2663. if (killJoint)
  2664. {
  2665. dJointDestroy(killJoint);
  2666. joints_ents[i] = NULL;
  2667. }
  2668. }
  2669. for (i = 0; i < VEHICLE_MAXBLOCKS; i++) {
  2670. dBlock killBlock = blocks_ents[i];
  2671. if (killBlock && curWorld)
  2672. {
  2673. dBodyRemoveBlock(curWorld, killBlock);
  2674. blocks_ents[i] = NULL;
  2675. }
  2676. }
  2677. }
  2678.  
  2679. void RemoveStaticConnections()
  2680. {
  2681. if (storage) {
  2682. for (int i = 0; i < VEHICLE_MAXPARTS; i++)
  2683. {
  2684. int p1 = storage.statcons_part1[i];
  2685. int p2 = storage.statcons_part2[i];
  2686. if (p1 > -1 && p2 > -1 && parts_ents[p1] && parts_ents[p2])
  2687. RemoveChild(parts_ents[p1], parts_ents[p2]);
  2688. }
  2689. }
  2690. }
  2691.  
  2692. // Update world matrix for parts
  2693. void UpdatePartsWorldData()
  2694. {
  2695. for (int i = 0; i < storage.parts_num; i++)
  2696. {
  2697. Vehicle_Part partEnt = parts_ents[i];
  2698. if (partEnt) {
  2699. vector mat[4];
  2700. GetMatrix4(partEnt, mat);
  2701. storage.parts_wmat0[i] = mat[0];
  2702. storage.parts_wmat1[i] = mat[1];
  2703. storage.parts_wmat2[i] = mat[2];
  2704. storage.parts_wmat3[i] = mat[3];
  2705. if (noUpdate) {
  2706. storage.parts_velLin[i] = partEnt.noUpdate_velLin;
  2707. storage.parts_velAng[i] = partEnt.noUpdate_velAng;
  2708. } else {
  2709. storage.parts_velLin[i] = GetVelocity(partEnt);
  2710. storage.parts_velAng[i] = dBodyGetAngularVelocity(partEnt);
  2711. }
  2712. storage.parts_genVec[i] = partEnt.GenVec;
  2713. storage.parts_genVec2[i] = partEnt.GenVec2;
  2714. storage.parts_genVec3[i] = partEnt.GenVec3;
  2715. storage.parts_genVec4[i] = partEnt.GenVec4;
  2716. storage.parts_genVec5[i] = partEnt.GenVec5;
  2717. storage.parts_genVec6[i] = partEnt.GenVec6;
  2718. storage.parts_storedParent[i] = partEnt.ParentPartNum;
  2719. }
  2720. }
  2721. }
  2722.  
  2723. // Called when fuel handler values should be stored
  2724. void StoreFuelHandlerValues()
  2725. {
  2726. if(vehicleController)
  2727. vehicleController.StoreFuelHandlerValues();
  2728. }
  2729.  
  2730. void BrokeVehiclePart(string partType);
  2731.  
  2732. // Goes through attached children to the parent part and adds log entries of losses
  2733. void LogLosses(int parentPart)
  2734. {
  2735. if (storage.parts_title[parentPart] != "") {
  2736. if (storage.parts_subtypes[parentPart] != "")
  2737. storage.AddLogEntry("#tkom_log_malfloss " + storage.parts_title[parentPart] + " " + itoa(PartSubTypeGetNum(parentPart, storage.parts_subtypes[parentPart])));
  2738. else {
  2739. if (storage.parts_types[parentPart] != "")
  2740. storage.AddLogEntry("#tkom_log_malfloss " + storage.parts_title[parentPart] + " " + itoa(PartTypeGetNum(parentPart, storage.parts_types[parentPart])));
  2741. }
  2742. }
  2743. if (storage.parts_types[parentPart] != "")
  2744. BrokeVehiclePart(storage.parts_types[parentPart]);
  2745. for (int i = 0; i < storage.parts_num; i++)
  2746. {
  2747. if (i != parentPart && CheckPartConnect(i, parentPart)) {
  2748. if (storage.parts_title[i] != "") {
  2749. if (storage.parts_subtypes[i] != "")
  2750. storage.AddLogEntry("#tkom_log_malfloss " + storage.parts_title[i] + " " + itoa(PartSubTypeGetNum(i, storage.parts_subtypes[i])));
  2751. else {
  2752. if (storage.parts_types[i] != "")
  2753. storage.AddLogEntry("#tkom_log_malfloss " + storage.parts_title[i] + " " + itoa(PartTypeGetNum(i, storage.parts_types[i])));
  2754. }
  2755. }
  2756. if (storage.parts_types[i] != "")
  2757. BrokeVehiclePart(storage.parts_types[i]);
  2758. }
  2759. }
  2760. }
  2761.  
  2762. void OnInventoryChanged() // Called from inventories when items within them have changed
  2763. {
  2764. if (vehicleController)
  2765. vehicleController.ProcessInventoryChanged();
  2766. }
  2767.  
  2768. void CallCustomEvent(string eventName)
  2769. {
  2770. if (vehicleController)
  2771. vehicleController.ProcessOnEvent(eventName);
  2772. storage.InventoriesOnEvent(eventName);
  2773. }
  2774.  
  2775. void CallCustomEventWithEntity(string eventName, _entity ent)
  2776. {
  2777. if (vehicleController)
  2778. vehicleController.ProcessOnEventWithEntity(eventName, ent);
  2779. storage.InventoriesOnEventWithEntity(eventName, ent);
  2780. }
  2781.  
  2782. void CallCustomEventWithUnit(string eventName, Vehicle_Handler unit)
  2783. {
  2784. if (vehicleController)
  2785. vehicleController.ProcessOnEventWithUnit(eventName, unit);
  2786. storage.InventoriesOnEventWithUnit(eventName, unit);
  2787. }
  2788.  
  2789. void CallCustomEventWithPart(string eventName, Vehicle_Handler part)
  2790. {
  2791. if (vehicleController)
  2792. vehicleController.ProcessOnEventWithPart(eventName, part);
  2793. storage.InventoriesOnEventWithPart(eventName, part);
  2794. }
  2795.  
  2796. void CallCustomEventWithSoundParams(string eventName, SoundShader sndShdr, vector sndPos, float sndVol, int ownerID)
  2797. {
  2798. if (vehicleController)
  2799. vehicleController.ProcessOnEventWithSoundParams(eventName, sndShdr, sndPos, sndVol, ownerID);
  2800. storage.InventoriesOnEventWithSoundParams(eventName, sndShdr, sndPos, sndVol, ownerID);
  2801. }
  2802.  
  2803. void CallCustomEventWithInt(string eventName, int input)
  2804. {
  2805. if (vehicleController)
  2806. vehicleController.ProcessOnEventWithInt(eventName, input);
  2807. storage.InventoriesOnEventWithInt(eventName, input);
  2808. }
  2809.  
  2810. void CallCustomEventWithFloat(string eventName, float input)
  2811. {
  2812. if (vehicleController)
  2813. vehicleController.ProcessOnEventWithFloat(eventName, input);
  2814. storage.InventoriesOnEventWithFloat(eventName, input);
  2815. }
  2816.  
  2817. void CallCustomEventWithMatrix(string eventName, vector mat[])
  2818. {
  2819. if (vehicleController)
  2820. vehicleController.ProcessOnEventWithMatrix(eventName, mat);
  2821. storage.InventoriesOnEventWithMatrix(eventName, mat);
  2822. }
  2823.  
  2824. void CallCustomEventWithForce(string eventName, vector pos, vector force)
  2825. {
  2826. if (vehicleController)
  2827. vehicleController.ProcessOnEventWithForce(eventName, pos, force);
  2828. storage.InventoriesOnEventWithForce(eventName, pos, force);
  2829. }
  2830.  
  2831. bool GetVehicleBroken()
  2832. {
  2833. if (vehicleController)
  2834. return vehicleController.GetVehicleBroken();
  2835. }
  2836.  
  2837. bool GetOutOfFuel()
  2838. {
  2839. if (vehicleController)
  2840. return vehicleController.GetOutOfFuel();
  2841. }
  2842.  
  2843. bool Editor_GetCanSpawnFuel()
  2844. {
  2845. if (vehicleController)
  2846. return vehicleController.Editor_GetCanSpawnFuel();
  2847. }
  2848.  
  2849. void Editor_SpawnFuel()
  2850. {
  2851. if (vehicleController)
  2852. vehicleController.Editor_SpawnFuel();
  2853. }
  2854.  
  2855. bool GetOutOfPower()
  2856. {
  2857. float genVsDrain = PowerGenRate - PowerDrainRate;
  2858.  
  2859. if (genVsDrain > 0)
  2860. return false;
  2861.  
  2862. if (storage.LowPowerShutdown)
  2863. return true;
  2864. else
  2865. return false;
  2866. }
  2867.  
  2868. float GetListenerVolume()
  2869. {
  2870. if (vehicleController)
  2871. return vehicleController.GetListenerVolume();
  2872. }
  2873.  
  2874. float GetListenerSFXLerp()
  2875. {
  2876. if (vehicleController)
  2877. return vehicleController.GetListenerSFXLerp();
  2878. }
  2879.  
  2880. string GetListenerSFXPath()
  2881. {
  2882. if (vehicleController)
  2883. return vehicleController.GetListenerSFXPath();
  2884. }
  2885.  
  2886. // Enables custom gravity simulation
  2887. bool CustomGravityEnabled;
  2888. vector CustomGravity;
  2889. void EnableCustomGravity(bool enable, vector gravity)
  2890. {
  2891. CustomGravityEnabled = enable;
  2892. if (enable)
  2893. CustomGravity = gravity;
  2894. else
  2895. CustomGravity = ZeroVec;
  2896.  
  2897. for (int i = 0; i < storage.parts_num; i++)
  2898. {
  2899. Vehicle_Part partEnt = parts_ents[i];
  2900. if (partEnt && dBodyIsDynamic(partEnt))
  2901. {
  2902. if (enable)
  2903. dBodyEnableGravity(partEnt, false);
  2904. else
  2905. dBodyEnableGravity(partEnt, true);
  2906. }
  2907. }
  2908.  
  2909. CallCustomEvent("CHANGED_CUSTOMGRAVITY");
  2910. }
  2911.  
  2912. // Simulate custom gravity
  2913. void SimulateCustomGravity(float timeslice)
  2914. {
  2915. if (!CustomGravityEnabled)
  2916. return;
  2917.  
  2918. if (CustomGravity == ZeroVec)
  2919. return;
  2920.  
  2921. for (int i = 0; i < storage.parts_num; i++)
  2922. {
  2923. Vehicle_Part partEnt = parts_ents[i];
  2924. if (partEnt && dBodyIsDynamic(partEnt) && dBodyIsActive(partEnt)) {
  2925. float mass = dBodyGetMass(partEnt);
  2926. dBodyApplyImpulse(partEnt, CustomGravity * 32 * mass * timeslice);
  2927. }
  2928. }
  2929. }
  2930.  
  2931. // Dynamic atmo zone created - client only
  2932. void MP_CallCreated(GameEntity dynAtmoZoneBase, int customID)
  2933. {
  2934. if (!IsClient())
  2935. return;
  2936.  
  2937. if (!vehicleController)
  2938. return;
  2939.  
  2940. DynamicAtmoZone dynAtmoZone = (DynamicAtmoZone)dynAtmoZoneBase;
  2941. if (!dynAtmoZone)
  2942. return;
  2943.  
  2944. vehicleController.ProcessOnDynamicAtmoZone(dynAtmoZone, customID);
  2945. }
  2946.  
  2947. // Dynamic atmo zone deleted - client only
  2948. void MP_CallDeleted(GameEntity dynAtmoZoneBase, int customID)
  2949. {
  2950. if (!IsClient())
  2951. return;
  2952.  
  2953. if (!vehicleController)
  2954. return;
  2955.  
  2956. DynamicAtmoZone dynAtmoZone = (DynamicAtmoZone)dynAtmoZoneBase;
  2957. if (!dynAtmoZone)
  2958. return;
  2959.  
  2960. vehicleController.ProcessDeleteDynamicAtmoZone(dynAtmoZone, customID);
  2961. }
  2962.  
  2963. // Docking
  2964. void MPSafe_Dock(int dockNum, int otherID, int otherDockNum);
  2965. void Dock(int dockNum, int otherID, int otherDockNum);
  2966. void RP_Dock(int dockNum, int otherID, int otherDockNum, bool isRemoteCall);
  2967.  
  2968. // Undocking
  2969. void MPSafe_Undock(int dockNum, bool applyUndockForce);
  2970. void Undock(int dockNum, bool applyUndockForce);
  2971. void RP_Undock(int dockNum, bool applyUndockForce, bool isRemoteCall);
  2972.  
  2973. // Event to controller that a part was damaged by something else
  2974. void PartDamagedBy(Vehicle_Part part, float damage, int damagedByID)
  2975. {
  2976. if (vehicleController)
  2977. vehicleController.ProcessOnPartDamagedBy(part, damage, damagedByID);
  2978. }
  2979.  
  2980. // Event to controller that a part was damaged
  2981. void PartHandleDamage(Vehicle_Part part, float damage)
  2982. {
  2983. if (vehicleController)
  2984. vehicleController.ProcessOnPartHandleDamage(part, damage);
  2985. }
  2986.  
  2987. // Deletes a specific joint and spawns its particle effect
  2988. void MPSafe_BreakJoint(int jNum, bool breakFX, bool logLoss);
  2989. void RP_BreakJoint(int jNum, bool breakFX, bool logLoss, bool isRemoteCall);
  2990. void BreakJoint(int jNum, bool breakFX, bool logLoss);
  2991.  
  2992. // Deletes joints connecting to the specified part
  2993. void MPSafe_DeleteJointsToPart(int pNum, bool breakFX, bool logLoss, bool forceDelete);
  2994. void RP_DeleteJointsToPart(int pNum, bool breakFX, bool logLoss, bool forceDelete, bool isRemoteCall);
  2995. void DeleteJointsToPart(int pNum, bool breakFX, bool logLoss, bool forceDelete)
  2996. {
  2997. bool deleteBlockers = true;
  2998. World curWorld = GetCurrentWorld();
  2999. for (int i = 0; i < storage.joints_num; i++)
  3000. {
  3001. if (storage.joints_part1[i] == pNum || storage.joints_part2[i] == pNum) {
  3002. /*if (storage.joints_noDelete[i])
  3003. Print(String("Joint " + itoa(i) + " is set to no delete!"));
  3004. else
  3005. Print(String("Deleting joint " + itoa(i)));*/
  3006. if (forceDelete || !storage.joints_noDelete[i])
  3007. BreakJoint(i, breakFX, logLoss);
  3008. else
  3009. deleteBlockers = false;
  3010. }
  3011. }
  3012.  
  3013. if (!deleteBlockers)
  3014. return;
  3015.  
  3016. for (i = 0; i < storage.blocks_num; i++)
  3017. {
  3018. if (storage.blocks_part1[i] == pNum || storage.blocks_part2[i] == pNum) {
  3019. storage.blocks_part1[i] = -1; // Part 1 number
  3020. storage.blocks_part2[i] = -1; // Part 2 number
  3021. if (blocks_ents[i] && curWorld)
  3022. {
  3023. if (forceDelete || !storage.blocks_noDelete[i])
  3024. dBodyRemoveBlock(curWorld, blocks_ents[i]);
  3025. }
  3026. blocks_ents[i] = NULL;
  3027. }
  3028. }
  3029. }
  3030.  
  3031. // Deletes joints connecting the specified parts
  3032. void MPSafe_DeleteJointsBetweenParts(int pNum1, int pNum2, bool breakFX, bool logLoss, bool forceDelete);
  3033. void RP_DeleteJointsBetweenParts(int pNum1, int pNum2, bool breakFX, bool logLoss, bool forceDelete, bool isRemoteCall);
  3034. void DeleteJointsBetweenParts(int pNum1, int pNum2, bool breakFX, bool logLoss, bool forceDelete)
  3035. {
  3036. bool deleteBlockers = true;
  3037. bool del = false;
  3038. for (int i = 0; i < storage.joints_num; i++)
  3039. {
  3040. del = false;
  3041. if (storage.joints_part1[i] == pNum1 || storage.joints_part1[i] == pNum2) {
  3042. if (storage.joints_part2[i] == pNum1 || storage.joints_part2[i] == pNum2)
  3043. del = true;
  3044. }
  3045. if (del) {
  3046. if (forceDelete || !storage.joints_noDelete[i])
  3047. BreakJoint(i, breakFX, logLoss);
  3048. else
  3049. deleteBlockers = false;
  3050. }
  3051. }
  3052.  
  3053. if (!deleteBlockers)
  3054. return;
  3055.  
  3056. for (i = 0; i < storage.blocks_num; i++)
  3057. {
  3058. del = false;
  3059. if (storage.blocks_part1[i] == pNum1 || storage.blocks_part1[i] == pNum2) {
  3060. if (storage.blocks_part2[i] == pNum1 || storage.blocks_part2[i] == pNum2)
  3061. del = true;
  3062. }
  3063. if (del) {
  3064. World curWorld = GetCurrentWorld();
  3065. storage.blocks_part1[i] = -1; // Part 1 number
  3066. storage.blocks_part2[i] = -1; // Part 2 number
  3067. if (blocks_ents[i] && curWorld)
  3068. {
  3069. if (forceDelete || !storage.blocks_noDelete[i])
  3070. dBodyRemoveBlock(curWorld, blocks_ents[i]);
  3071. }
  3072. blocks_ents[i] = NULL;
  3073. }
  3074. }
  3075. }
  3076.  
  3077. // Docking stuff
  3078. void GetDockingPortMat(int dockPortIndex, vector mat[4]);
  3079. bool GetVehicleDockToDockStressOk(int dockNum, Vehicle_Part myDockPart, Vehicle_Handler otherVehicle, int otherVehicleDockNum, Vehicle_Part otherDockPart);
  3080. bool GetDocksAligned(vector myDockPortMat[4], vector otherDockPortMat[4]);
  3081. bool GetCanDockToVehicle(int dockNum, Vehicle_Handler otherVehicle, int otherVehicleDockNum);
  3082. void Update_TryDocking();
  3083. void ApplyUndockForce(int dockPortIndex);
  3084. void Update_DockPortForce();
  3085. void Update_DockPortStress();
  3086.  
  3087. // Permanently deletes a part
  3088. void DeletePart(local int pNum)
  3089. {
  3090. if (pNum == 0) // No deleting the main piece!
  3091. return;
  3092.  
  3093. DeleteJointsToPart(pNum, false, false, true);
  3094.  
  3095. // First check if it is a statically connected part
  3096. for (local int i = 0; i < VEHICLE_MAXPARTS; i++)
  3097. {
  3098. local int p1 = storage.statcons_part1[i];
  3099. local int p2 = storage.statcons_part2[i];
  3100. if (p1 > -1 && p2 > -1 && parts_ents[p1] && parts_ents[p2] && pNum == p2) {
  3101. RemoveChild(parts_ents[p1], parts_ents[p2]);
  3102. storage.statcons_part1[i] = -1;
  3103. storage.statcons_part2[i] = -1;
  3104. }
  3105. }
  3106.  
  3107. // Now check if it has a static part connected to it
  3108. for (i = 0; i < VEHICLE_MAXPARTS; i++)
  3109. {
  3110. p1 = storage.statcons_part1[i];
  3111. p2 = storage.statcons_part2[i];
  3112. if (p1 > -1 && p2 > -1 && parts_ents[p1] && parts_ents[p2] && pNum == p1)
  3113. DeletePart(p2);
  3114. }
  3115.  
  3116. // Now remove it and clear its data
  3117. storage.parts_pwrdrain[pNum] = 0;
  3118. storage.parts_damage[pNum] = -1;
  3119. storage.parts_tough[pNum] = 0;
  3120. storage.parts_mass[pNum] = -1;
  3121. storage.parts_models[pNum] = "";
  3122. storage.parts_types[pNum] = "";
  3123. storage.parts_subtypes[pNum] = "";
  3124. storage.parts_title[pNum] = "";
  3125. storage.parts_pos[pNum] = ZeroVec;
  3126. storage.parts_ang[pNum] = ZeroVec;
  3127. storage.parts_wmat0[pNum] = ZeroVec;
  3128. storage.parts_wmat1[pNum] = ZeroVec;
  3129. storage.parts_wmat2[pNum] = ZeroVec;
  3130. storage.parts_wmat3[pNum] = ZeroVec;
  3131. storage.parts_velLin[pNum] = ZeroVec;
  3132. storage.parts_velAng[pNum] = ZeroVec;
  3133. storage.parts_genVec[pNum] = ZeroVec;
  3134. storage.parts_genVec2[pNum] = ZeroVec;
  3135. storage.parts_genVec3[pNum] = ZeroVec;
  3136. storage.parts_genVec4[pNum] = ZeroVec;
  3137. storage.parts_genVec5[pNum] = ZeroVec;
  3138. storage.parts_genVec6[pNum] = ZeroVec;
  3139. storage.parts_conPtcSnd[pNum] = "";
  3140. storage.parts_storedParent[pNum] = -2;
  3141.  
  3142. if (vehicleController)
  3143. vehicleController.ProcessOnDeletePart(parts_ents[pNum], pNum);
  3144.  
  3145. if (parts_ents[pNum])
  3146. delete parts_ents[pNum];
  3147. parts_ents[pNum] = NULL;
  3148. }
  3149.  
  3150. // Delete part queue (to delete outside physics tick)
  3151. int DeletePartQueue[VEHICLE_MAXPARTS];
  3152. int DeletePartQueueNum;
  3153.  
  3154. bool GetPartDeleteQueueIndex(int p)
  3155. {
  3156. return IsInArray(DeletePartQueue, DeletePartQueueNum, p);
  3157. }
  3158.  
  3159. void AddPartToDeleteQueue(int p)
  3160. {
  3161. if (p <= -1)
  3162. return;
  3163.  
  3164. if (GetPartDeleteQueueIndex(p) != -1)
  3165. return;
  3166.  
  3167. Vehicle_Part pEnt = parts_ents[p];
  3168. if (!pEnt)
  3169. return;
  3170.  
  3171. parts_interactionLayer[p] = COLLIDERLAYER_NONE;
  3172. dBodyInteractionLayer(pEnt, COLLIDERLAYER_NONE);
  3173. ClearFlags(pEnt, TFL_VISIBLE);
  3174.  
  3175. DeletePartQueue[DeletePartQueueNum] = p;
  3176. DeletePartQueueNum++;
  3177. }
  3178.  
  3179. void ProcessDeletePartQueue()
  3180. {
  3181. for (local int p = 0; p < DeletePartQueueNum; p++)
  3182. {
  3183. local int pNum = DeletePartQueue[p];
  3184. DeletePart(pNum);
  3185. }
  3186. DeletePartQueueNum = 0;
  3187. }
  3188.  
  3189. // Queues a part for permanent deletion
  3190. void MPSafe_DeletePart(local int pNum);
  3191. void RP_DeletePart(local int pNum, bool isRemoteCall);
  3192. void QueueDeletePart(local int pNum)
  3193. {
  3194. if (pNum == 0) // No deleting the main piece!
  3195. return;
  3196.  
  3197. AddPartToDeleteQueue(pNum);
  3198. }
  3199.  
  3200. void Update_JointStress()
  3201. {
  3202. if (GodModeTime > 0)
  3203. return;
  3204.  
  3205. // Adjust for unreliable stress values in lower physics settings
  3206. float physTickScale = 1 / phys_FixedTick - 60 / 60;
  3207. clamp physTickScale<0, 1>;
  3208. physTickScale = 1 - physTickScale * 0.25 + 1;
  3209.  
  3210. for (int i = 0; i < storage.joints_num; i++)
  3211. {
  3212. if (!joints_ents[i])
  3213. continue;
  3214.  
  3215. if (storage.joints_noDelete[i])
  3216. continue;
  3217.  
  3218. int p1 = storage.joints_part1[i];
  3219. int p2 = storage.joints_part2[i];
  3220. Vehicle_Part vehPart1 = parts_ents[p1];
  3221. if (!vehPart1)
  3222. continue;
  3223. Vehicle_Part vehPart2 = parts_ents[p2];
  3224. if (!vehPart2)
  3225. continue;
  3226.  
  3227. float lStressMax = storage.joints_Lstress[i] * physTickScale;
  3228. float aStressMax = storage.joints_Astress[i] * physTickScale;
  3229. if (lStressMax < 0 && aStressMax < 0)
  3230. continue;
  3231.  
  3232. vector lv_p1, lv_p2, av_p1, av_p2;
  3233. lv_p1 = GetVelocity(vehPart1);
  3234. av_p1 = dBodyGetAngularVelocity(vehPart1);
  3235. lv_p2 = GetVelocity(vehPart2);
  3236. av_p2 = dBodyGetAngularVelocity(vehPart2);
  3237. lv_p1 = lv_p1 - lv_p2;
  3238. av_p1 = av_p1 - av_p2;
  3239. float lStress = VectorLength(lv_p1);
  3240. float aStress = VectorLength(av_p1);
  3241. if (lStress >= lStressMax && lStressMax >= 0)
  3242. MPSafe_BreakJoint(i, true, true);
  3243. else
  3244. {
  3245. if (aStress >= aStressMax && aStressMax >= 0)
  3246. MPSafe_BreakJoint(i, true, true);
  3247. }
  3248. }
  3249. }
  3250.  
  3251. // Updates the status text (failure etc)
  3252. /*void Update_PartStatus(int partNum, float damage)
  3253. {
  3254. storage.parts_detailsStatus[i]
  3255. }*/
  3256.  
  3257. // Checks parts for any AddDamage value and adds it to the part's total damage value, breaking joints to the part if it is 1.0
  3258. void Update_PartDamage()
  3259. {
  3260. for (int i = 0; i < storage.parts_num; i++) {
  3261. Vehicle_Part pEnt = parts_ents[i];
  3262. if (pEnt) {
  3263. if (GodModeTime == 0) {
  3264. float dmg = storage.parts_damage[i] + pEnt.AddDamage;
  3265. bool doBreak = false;
  3266. if (dmg >= 1 && storage.parts_damage[i] < 1)
  3267. doBreak = true;
  3268.  
  3269. clamp dmg<0, 1>;
  3270. storage.parts_damage[i] = dmg;
  3271. //if (dmg > 0)
  3272. //Print(String("Part " + itoa(i) + " damaged, total: " + ftoa(dmg) + ", Toughness: " + itoa(storage.parts_tough[i])));
  3273. // Destroyed, break off
  3274. if (doBreak) {
  3275. MPSafe_DeleteJointsToPart(i, true, true, false);
  3276. //Print(String("Part " + itoa(i) + " is destroyed, breaking joints..."));
  3277. }
  3278. }
  3279. pEnt.AddDamage = 0;
  3280. }
  3281. //Update_PartStatus(i);
  3282. }
  3283. }
  3284.  
  3285. // Checks if any part has the bool GripImpulse set to true, if so, then any gripped parts are ungripped unless NoHierarchyGripImpulseBreak set to true
  3286. void Update_PartGrip()
  3287. {
  3288. int i;
  3289. Vehicle_Part pEnt;
  3290.  
  3291. if (NoHierarchyGripImpulseBreak) {
  3292. for (i = 0; i < storage.parts_num; i++) {
  3293. pEnt = parts_ents[i];
  3294. if (pEnt && pEnt.GripImpulse)
  3295. pEnt.GripImpulse = false;
  3296. }
  3297. return;
  3298. }
  3299.  
  3300. bool breakGrips = false;
  3301. // First run through the list and pass any grip impulses to the highest parent
  3302. for (i = 0; i < storage.parts_num; i++) {
  3303. pEnt = parts_ents[i];
  3304. if (pEnt && pEnt.GripImpulse) {
  3305. breakGrips = true;
  3306. pEnt.GripImpulse = false;
  3307. int pNum = pEnt.ParentPartNum;
  3308. if (pNum == -1)
  3309. pEnt.GripImpulse = true;
  3310. else {
  3311. int numIterations = 0;
  3312. while(pNum != -1 && numIterations < VEHICLE_MAXPARTS) {
  3313. pEnt = parts_ents[pNum];
  3314. if (pEnt) {
  3315. pEnt.GripImpulse = false;
  3316. pNum = pEnt.ParentPartNum;
  3317. if (pNum == -1)
  3318. pEnt.GripImpulse = true;
  3319. }
  3320. numIterations++;
  3321. }
  3322. if (numIterations == VEHICLE_MAXPARTS)
  3323. Print(String("UPDATE_PARTSGRIP(): Vehicle '" + storage.name + "' got stuck in an infinite loop while checking connection!"));
  3324. }
  3325. }
  3326. }
  3327. // Now, if there were any grip impulses, run through each part and check up to its highest parent for grip impulses
  3328. if (breakGrips) {
  3329. for (i = 0; i < storage.parts_num; i++) {
  3330. pEnt = parts_ents[i];
  3331. if (pEnt) {
  3332. pNum = pEnt.ParentPartNum;
  3333. if (pNum != -1) {
  3334. numIterations = 0;
  3335. while(pNum != -1 && numIterations < VEHICLE_MAXPARTS) {
  3336. Vehicle_Part pEnt2 = parts_ents[pNum];
  3337. if (pEnt2) {
  3338. if (pEnt2.GripImpulse)
  3339. pEnt.GripImpulse = true;
  3340. pNum = pEnt2.ParentPartNum;
  3341. }
  3342. numIterations++;
  3343. }
  3344. if (numIterations == VEHICLE_MAXPARTS)
  3345. Print(String("UPDATE_PARTSGRIP(): Vehicle '" + storage.name + "' got stuck in an infinite loop while checking connection!"));
  3346. }
  3347.  
  3348. if (pEnt.GripImpulse && pEnt.Gripped)
  3349. pEnt.MPSafe_Grip(false);
  3350. }
  3351. }
  3352. // Finally, run through again and remove any grip impulses
  3353. for (i = 0; i < storage.parts_num; i++) {
  3354. pEnt = parts_ents[i];
  3355. if (pEnt && pEnt.GripImpulse)
  3356. pEnt.GripImpulse = false;
  3357. }
  3358. }
  3359. }
  3360.  
  3361. // Returns the total mass of the objects connected to the target part
  3362. float GetPayloadMass(int payloadParent)
  3363. {
  3364. float result = 0;
  3365. for (int i = 0; i < storage.parts_num; i++) {
  3366. if (CheckPartConnect(i, payloadParent))
  3367. result += storage.parts_mass[i];
  3368. }
  3369. return result;
  3370. }
  3371.  
  3372. // Returns number of a type of part attached to the vehicle
  3373. int GetNumPartType(string partType)
  3374. {
  3375. int result = 0;
  3376. for (int i = 0; i < storage.parts_num; i++) {
  3377. if (storage.parts_types[i] == partType && CheckPartBaseConnect(i))
  3378. result++;
  3379. }
  3380. return result;
  3381. }
  3382.  
  3383. void ClearInput(bool secondary)
  3384. {
  3385. if( !IsControlsReceiver() )
  3386. {
  3387. if (!secondary) {
  3388. input_arc_pri0 = 0;
  3389. input_arc_pri1 = 0;
  3390. input_arc_pri2 = 0;
  3391. input_arc_prigui = false;
  3392. } else {
  3393. input_arc_sec0 = 0;
  3394. input_arc_sec1 = 0;
  3395. input_arc_sec2 = 0;
  3396. input_arc_secgui = false;
  3397. }
  3398. }
  3399. }
  3400.  
  3401. void SelectNextPart(bool previous, bool secondary, bool force)
  3402. {
  3403. int curPart;
  3404. int result;
  3405. bool switchPart = false;
  3406. if (!secondary) {
  3407. curPart = storage.CurrentPriPart;
  3408. result = storage.CurrentPriPart;
  3409. if (GetMissionTime(1) > PriPartSwitchTime || PriPartSwitchTime < GetMissionTime(1) || force) {
  3410. PriPartSwitchTime = GetMissionTime(1) + 0.25;
  3411. switchPart = true;
  3412. }
  3413. } else {
  3414. curPart = storage.CurrentSecPart;
  3415. result = storage.CurrentSecPart;
  3416. if (GetMissionTime(1) > SecPartSwitchTime || SecPartSwitchTime < GetMissionTime(1) || force) {
  3417. SecPartSwitchTime = GetMissionTime(1) + 0.25;
  3418. switchPart = true;
  3419. }
  3420. }
  3421. if (switchPart) {
  3422. ClearInput(secondary);
  3423. int numChecks = 0;
  3424. while (result == curPart && numChecks < storage.parts_num) {
  3425. if (previous)
  3426. result--;
  3427. else
  3428. result++;
  3429. if (result >= storage.parts_num)
  3430. result = 0;
  3431. if (result < 0)
  3432. result = storage.parts_num - 1;
  3433. bool isControlable = false;
  3434. for (int i = 0; i < storage.ctrl_num; i++) {
  3435. if (storage.parts_types[result] == storage.ctrl_types[i])
  3436. isControlable = true;
  3437. }
  3438. if (isControlable && CheckPartBaseConnect(result))
  3439. curPart = -1;
  3440. else
  3441. curPart = result;
  3442. numChecks++;
  3443. }
  3444. if (!secondary)
  3445. storage.CurrentPriPart = result;
  3446. else
  3447. storage.CurrentSecPart = result;
  3448. }
  3449. }
  3450.  
  3451. void SelectPart(int num, bool secondary)
  3452. {
  3453. bool isControlable = false;
  3454. for (int i = 0; i < storage.ctrl_num; i++) {
  3455. if (storage.parts_types[num] == storage.ctrl_types[i])
  3456. isControlable = true;
  3457. }
  3458. if (isControlable) {
  3459. if (secondary)
  3460. storage.CurrentPriPart = num;
  3461. else
  3462. storage.CurrentSecPart = num;
  3463. }
  3464. ClearInput(secondary);
  3465. }
  3466.  
  3467. // Sets/resets physics interaction layer of the vehicle for collision sweep tests
  3468. void EnablePhysicsInteraction(bool enable)
  3469. {
  3470. for (int i = 0; i < storage.parts_num; i++) {
  3471. Vehicle_Part vPart = parts_ents[i];
  3472. if (vPart) {
  3473. int intLayer = parts_interactionLayer[i];
  3474. if (enable)
  3475. {
  3476. if (intLayer > 0)
  3477. dBodyInteractionLayerEx(vPart, intLayer);
  3478. parts_interactionLayer[i] = 0;
  3479. }
  3480. else
  3481. {
  3482. if (intLayer <= 0)
  3483. parts_interactionLayer[i] = dBodyGetGeomInteractionLayer(vPart, 0);
  3484. dBodyInteractionLayer(vPart, COLLIDERLAYER_NONE);
  3485. }
  3486. }
  3487. }
  3488. }
  3489.  
  3490. // Enables/disables solidity of the vehicle for traces
  3491. void EnableSolidity(bool enable)
  3492. {
  3493. for (int i = 0; i < storage.parts_num; i++) {
  3494. Vehicle_Part vPart = parts_ents[i];
  3495. if (vPart) {
  3496. if (enable)
  3497. SetFlags(vPart, TFL_SOLID);
  3498. else
  3499. ClearFlags(vPart, TFL_SOLID);
  3500. }
  3501. }
  3502. }
  3503.  
  3504. // Enables/disables solidity of the vehicle's passengers for traces
  3505. bool EnablePassengersSolidity(bool enable)
  3506. {
  3507. for (int i = 0; i < storage.passengerSeat_num; i++)
  3508. {
  3509. CharacterObject passenger = storage.passengers[i];
  3510. if (passenger) {
  3511. Vehicle_Handler passengerHandler = passenger.vehicleHandler;
  3512. if (passengerHandler)
  3513. passengerHandler.EnableSolidity(enable);
  3514. }
  3515. }
  3516. }
  3517.  
  3518. // Traces forward from the part and returns the distance
  3519. float TracePart(vector mat[4], float minDist, float maxDist, Vehicle_Part ignorePart)
  3520. {
  3521. VehicleTrcEnt = NULL;
  3522. _entity t_ent = NULL;
  3523. float t_plane[4];
  3524. int t_surfparm;
  3525. vector start = mat[0] * minDist + mat[3];
  3526. vector end = mat[0] * maxDist + mat[3];
  3527.  
  3528. if (ignorePart)
  3529. ClearFlags(ignorePart, TFL_SOLID);
  3530.  
  3531. float result = TraceLineExEx(start, end, ZeroVec, ZeroVec, t_ent, t_plane, 0, t_surfparm, TRACE_WORLD|TRACE_ENTS|TRACE_LINE|TRACE_ONLY_PHYSICS|TRACE_RAGDOLLS, NULL, COLLIDERLAYER_DYNAMIC);
  3532. if (VehicleTrcCon) {
  3533. VehicleTrcCon.Shader = "";
  3534. VehicleTrcCon.Surfparm = -1;
  3535. }
  3536. /*const vector TRCVEC = "0.5 0.5 0.5";
  3537. AddDShape(SHAPE_DIAMOND, COLOR_GREEN, SS_ONCE, end - TRCVEC, end + TRCVEC);*/
  3538.  
  3539. vector t_ent_mins = ZeroVec;
  3540. vector t_ent_maxs = ZeroVec;
  3541. float size = 0;
  3542. if (t_ent) {
  3543. GetBoundBox(t_ent, t_ent_mins, t_ent_maxs);
  3544. size = VectorLength(t_ent_maxs - t_ent_mins);
  3545. }
  3546. if (result < 1 && t_ent && t_ent != GetCurrentWorld() && VehicleTrcCon && size != 0) {
  3547. VehicleTrcEnt = t_ent;
  3548. start = mat[0] * minDist + mat[3];
  3549. end = mat[0] * maxDist + mat[3];
  3550. bool traced = TraceLineToEntity(t_ent, start, end, VehicleTrcCon);
  3551. }
  3552. if (VehicleTrcCon && result < 1)
  3553. VehicleTrcCon.Surfparm = t_surfparm;
  3554.  
  3555. if (ignorePart)
  3556. SetFlags(ignorePart, TFL_SOLID);
  3557.  
  3558. return result;
  3559. }
  3560.  
  3561. // Traces forward from the part and returns the distance, ignoring tracing faces
  3562. float TracePartNoFaces(vector mat[4], float minDist, float maxDist, Vehicle_Part ignorePart)
  3563. {
  3564. _entity t_ent = NULL;
  3565. float t_plane[4];
  3566. int t_surfparm;
  3567. vector start = mat[0] * minDist + mat[3];
  3568. vector end = mat[0] * maxDist + mat[3];
  3569.  
  3570. if (ignorePart)
  3571. ClearFlags(ignorePart, TFL_SOLID);
  3572.  
  3573. float result = TraceLineExEx(start, end, ZeroVec, ZeroVec, t_ent, t_plane, 0, t_surfparm, TRACE_WORLD|TRACE_ENTS|TRACE_LINE|TRACE_ONLY_PHYSICS|TRACE_RAGDOLLS, NULL, COLLIDERLAYER_DYNAMIC);
  3574. /*const vector TRCVEC = "0.5 0.5 0.5";
  3575. AddDShape(SHAPE_DIAMOND, COLOR_GREEN, SS_ONCE, end - TRCVEC, end + TRCVEC);*/
  3576.  
  3577. if (ignorePart)
  3578. SetFlags(ignorePart, TFL_SOLID);
  3579.  
  3580. return result;
  3581. }
  3582.  
  3583. bool getSolidGround_worldBoundsClamp;
  3584. float getSolidGround_worldBoundsOffset;
  3585. float GetSolidGroundHeight(_entity optEnt);
  3586. float GetSolidGroundHeightEx(_entity optEnt, vector offset, vector dir, float dist);
  3587. float GetSolidGroundDist(_entity optEnt, vector dir);
  3588.  
  3589. float GetTotalHeatVolume()
  3590. {
  3591. float result = 0;
  3592. for (int i = 0; i < storage.parts_num; i++)
  3593. {
  3594. Vehicle_Part vehPart = parts_ents[i];
  3595. if (vehPart)
  3596. result += vehPart.heatValue * vehPart.PartMass;
  3597. }
  3598.  
  3599. return result;
  3600. }
  3601.  
  3602. vector Trace3rdCam_normal;
  3603. // Traces forward from the 3rd persp. cam and returns the distance
  3604. float Trace3rdCam(vector mat[4], float minDist, float maxDist, int layerMask)
  3605. {
  3606. _entity t_ent = NULL;
  3607. float t_plane[4];
  3608. int t_surfparm;
  3609. vector start = mat[0] * minDist + mat[3];
  3610. vector end = mat[0] * maxDist + mat[3];
  3611.  
  3612. EnableSolidity(false);
  3613.  
  3614. float result = TraceLineExEx(start, end, ZeroVec, ZeroVec, t_ent, t_plane, 0, t_surfparm, TRACE_WORLD|TRACE_ENTS|TRACE_LINE|TRACE_ONLY_PHYSICS|TRACE_RAGDOLLS, NULL, layerMask);
  3615.  
  3616. EnableSolidity(true);
  3617.  
  3618. Trace3rdCam_normal = Vector(t_plane[0], t_plane[1], t_plane[2]);
  3619.  
  3620. return result;
  3621. }
  3622.  
  3623. // Selects the next valid base part (or a specified part) for the 3rd person cam
  3624. void Select3rdTargetPart(int optPart)
  3625. {
  3626. int cP, cPIndex;
  3627. int lastPart = storage.cams_3rdPart;
  3628. if (optPart != -1)
  3629. storage.cams_3rdPart = optPart;
  3630. else {
  3631. if (storage.cams_3rdPart == 0) { // Part 0 selected, so cycle through valid base parts and select a valid one
  3632. for (cP = 0; cP < storage.ctrlbase_num; cP++) {
  3633. cPIndex = storage.ctrlbase_parts[cP];
  3634. if (cPIndex != -1 && parts_ents[cPIndex]) {
  3635. storage.cams_3rdPart = cPIndex;
  3636. break;
  3637. }
  3638. }
  3639. } else {
  3640. int curBasePartNum = -1;
  3641. for (cP = 0; cP < storage.ctrlbase_num; cP++) { // Find which base part we are using
  3642. cPIndex = storage.ctrlbase_parts[cP];
  3643. if (cPIndex != -1 && parts_ents[cPIndex] && storage.cams_3rdPart == cPIndex) {
  3644. curBasePartNum = cP + 1;
  3645. break;
  3646. }
  3647. }
  3648. if (curBasePartNum != -1 && curBasePartNum < storage.ctrlbase_num)
  3649. storage.cams_3rdPart = storage.ctrlbase_parts[curBasePartNum];
  3650. else
  3651. storage.cams_3rdPart = 0;
  3652. }
  3653. }
  3654. int curPart = storage.cams_3rdPart;
  3655. if (lastPart != curPart) {
  3656. Vehicle_Part lastPEnt = parts_ents[lastPart];
  3657. Vehicle_Part curPEnt = parts_ents[curPart];
  3658. if (storage.cams_mainMode == 1)
  3659. storage.cams_3rdPosition = GetOrigin(lastPEnt) - GetOrigin(curPEnt) + storage.cams_3rdPosition;
  3660. if (storage.cams_mainMode == 2)
  3661. storage.cams_3rdPosition2 = GetOrigin(lastPEnt) - GetOrigin(curPEnt) + storage.cams_3rdPosition2;
  3662. }
  3663. }
  3664.  
  3665. //assign location storage object. exist always, and is serializable
  3666. void SetStorage(VehicleObject vehicle)
  3667. {
  3668. if (!vehicle)
  3669. return;
  3670.  
  3671. storage = vehicle;
  3672. storage.vehicleHandler = this;
  3673. }
  3674.  
  3675. //create default storage object
  3676. void CreateDefaultStorage();
  3677. void CreateDefaultCharacterStorage();
  3678.  
  3679. // Delete storage, if exists
  3680. void DeleteStorage();
  3681.  
  3682. bool NewFrame; // For use in OnSimulate to determine whether we have a new frame
  3683. float LastFrameTime;
  3684. float FrameTimeDiff;
  3685.  
  3686. void OnPreSimulate()
  3687. {
  3688. if (!noUpdate)
  3689. {
  3690. if (!IsClient())
  3691. {
  3692. Update_JointStress();
  3693. Update_DockPortStress();
  3694. Update_PartDamage();
  3695. Update_PartGrip();
  3696. }
  3697. if (vehicleController)
  3698. vehicleController.ProcessOnPreSim();
  3699. }
  3700. }
  3701.  
  3702. private void EOnSimulate(_entity other, float dt)
  3703. {
  3704. if (!noUpdate) {
  3705. Update_DockPortForce();
  3706.  
  3707. if (!IsClient() || IsLagging())
  3708. SimulateCustomGravity(phys_FixedTick);
  3709. if (vehicleController)
  3710. vehicleController.ProcessOnSim();
  3711. storage.InventoriesOnSimulate();
  3712. GodModeTime -= phys_FixedTick;
  3713. if (GodModeTime < 0)
  3714. GodModeTime = 0;
  3715. storage.UpdateCommandSequence(phys_FixedTick);
  3716. }
  3717. NewFrame = false;
  3718.  
  3719. if (delayDelete)
  3720. SetInteractionLayer(COLLIDERLAYER_NONE);
  3721. }
  3722.  
  3723. void OnAfterSimulate()
  3724. {
  3725. if (!noUpdate)
  3726. {
  3727. if (vehicleController)
  3728. vehicleController.ProcessOnAfterSim();
  3729. }
  3730. }
  3731.  
  3732. int lastTeam;
  3733. event private void EOnFrame(_entity other, int extra)
  3734. {
  3735. Update_TryDocking();
  3736.  
  3737. UpdatePower();
  3738.  
  3739. // Send view/body matrix to storage UnitMapMatrix, used for map icons
  3740. if (storage)
  3741. {
  3742. if (storage.isCharacter)
  3743. {
  3744. vector camPos = cameraMat[3];
  3745. if (camPos == ZeroVec)
  3746. GetMatrix4(this, storage.UnitMapMatrix);
  3747. else
  3748. {
  3749. storage.UnitMapMatrix[0] = cameraMat[0];
  3750. storage.UnitMapMatrix[1] = cameraMat[1];
  3751. storage.UnitMapMatrix[2] = cameraMat[2];
  3752. storage.UnitMapMatrix[3] = cameraMat[3];
  3753. }
  3754. }
  3755. else
  3756. GetMatrix4(this, storage.UnitMapMatrix);
  3757. }
  3758.  
  3759. if (IsServer() && !delayDelete && storage && storage.Team != lastTeam)
  3760. {
  3761. lastTeam = storage.Team;
  3762. RP_SynchTeam(storage.Team, false);
  3763. }
  3764.  
  3765. if (!delayDelete && !noUpdate && vehicleController)
  3766. {
  3767. vehicleController.ProcessOnFrm();
  3768. storage.InventoriesOnFrame();
  3769. }
  3770.  
  3771. if (delayDelete)
  3772. {
  3773. DeleteStorage();
  3774. delete this;
  3775. }
  3776. }
  3777.  
  3778. vector threeFrame_mX;
  3779. vector threeFrame_mY;
  3780. int threeFrameNum;
  3781. event private void EOnPostFrame(_entity other, int extra)
  3782. {
  3783. ProcessDeletePartQueue();
  3784.  
  3785. if (delayDelete)
  3786. return;
  3787.  
  3788. NewFrame = true;
  3789.  
  3790. float CurFrameTime = GetMissionTime(1);
  3791. if (LastFrameTime == 0 || CurFrameTime < LastFrameTime)
  3792. LastFrameTime = CurFrameTime;
  3793. FrameTimeDiff = CurFrameTime - LastFrameTime;
  3794. if (!noUpdate && vehicleController)
  3795. {
  3796. storage.UpdateGeneratedMission(FrameTimeDiff, GetOrigin(this)); // Update the vehicle's generated mission
  3797.  
  3798. if (widgetHandler) {
  3799. if (widgetHandler.wUpdateTime > CurFrameTime || widgetHandler.wUpdateTime < CurFrameTime - 1)
  3800. widgetHandler.wUpdateTime = CurFrameTime;
  3801. widgetHandler.UpdateHUDButtons(CurFrameTime - widgetHandler.wUpdateTime);
  3802. widgetHandler.wUpdateTime = CurFrameTime;
  3803. }
  3804. if (!isSelected)
  3805. {
  3806. if (lastSelected)
  3807. {
  3808. DeleteWidgets();
  3809.  
  3810. if( !IsControlsReceiver() )
  3811. {
  3812. input_mouse_X = 0;
  3813. input_mouse_Y = 0;
  3814. input_mouse_Whl = 0;
  3815. }
  3816. lastSelected = false;
  3817. }
  3818. }
  3819. else
  3820. {
  3821. lastSelected = true;
  3822.  
  3823. if( !IsControlsReceiver() && !g_Game.IsMainMenuVisible() )
  3824. {
  3825. // Handle mouse-controls
  3826. if (!Cursor_Enable)
  3827. {
  3828. float scaleDown = FrameTimeDiff * 10;
  3829. if (!Options_FluidFreeFly)
  3830. scaleDown = FrameTimeDiff * 30;
  3831. clamp scaleDown<0, 1>;
  3832. input_mouse_X *= 1 - scaleDown;
  3833. input_mouse_Y *= 1 - scaleDown;
  3834.  
  3835. vehicleController.VInput_mX = g_Controller.GetDeltaHorizontal();
  3836. vehicleController.VInput_mY = g_Controller.GetDeltaVertical();
  3837. clamp vehicleController.VInput_mX<-600, 600>;
  3838. clamp vehicleController.VInput_mY<-600, 600>;
  3839. if (!Options_FluidFreeFly) {
  3840. vehicleController.VInput_mX *= 5;
  3841. vehicleController.VInput_mY *= 5;
  3842. }
  3843. input_mouse_X += vehicleController.VInput_mX * fabs(1/200);
  3844. input_mouse_Y += vehicleController.VInput_mY * fabs(1/200);
  3845. if (input_mouse_X < 0.001 && input_mouse_X > -0.001)
  3846. input_mouse_X = 0;
  3847. if (input_mouse_Y < 0.001 && input_mouse_Y > -0.001)
  3848. input_mouse_Y = 0;
  3849. /*threeFrameNum++;
  3850. if (threeFrameNum > 2)
  3851. threeFrameNum = 0;
  3852.  
  3853. if (Options_FluidFreeFly) {
  3854. float scaleDown = FrameTimeDiff * 10;
  3855. clamp scaleDown<0, 1>;
  3856. input_mouse_X *= 1 - scaleDown;
  3857. input_mouse_Y *= 1 - scaleDown;
  3858. }
  3859.  
  3860. vehicleController.VInput_mX = g_Controller.GetDeltaHorizontal();
  3861. vehicleController.VInput_mY = g_Controller.GetDeltaVertical();
  3862. clamp vehicleController.VInput_mX<-600, 600>;
  3863. clamp vehicleController.VInput_mY<-600, 600>;
  3864. if (Options_FluidFreeFly) {
  3865. input_mouse_X += vehicleController.VInput_mX * fabs(1/200);
  3866. input_mouse_Y += vehicleController.VInput_mY * fabs(1/200);
  3867. if (input_mouse_X < 0.001 && input_mouse_X > -0.001)
  3868. input_mouse_X = 0;
  3869. if (input_mouse_Y < 0.001 && input_mouse_Y > -0.001)
  3870. input_mouse_Y = 0;
  3871. } else {
  3872. threeFrame_mX[threeFrameNum] = vehicleController.VInput_mX * fabs(1/20);
  3873. threeFrame_mY[threeFrameNum] = vehicleController.VInput_mY * fabs(1/20);
  3874. int fnum = threeFrameNum + 1;
  3875. if (fnum > 2)
  3876. fnum = 0;
  3877. if (fabs(threeFrame_mX[threeFrameNum]) < fabs(threeFrame_mX[fnum])
  3878. input_mouse_X = threeFrame_mX[0] + threeFrame_mX[1] + threeFrame_mX[2] + threeFrame_mX[fnum] + threeFrame_mX[fnum] / 5;
  3879. else
  3880. input_mouse_X = threeFrame_mX[0] + threeFrame_mX[1] + threeFrame_mX[2] + threeFrame_mX[threeFrameNum] + threeFrame_mX[threeFrameNum] / 5;
  3881.  
  3882. if (fabs(threeFrame_mY[threeFrameNum]) < fabs(threeFrame_mY[fnum])
  3883. input_mouse_Y = threeFrame_mY[0] + threeFrame_mY[1] + threeFrame_mY[2] + threeFrame_mY[fnum] + threeFrame_mY[fnum] / 5;
  3884. else
  3885. input_mouse_Y = threeFrame_mY[0] + threeFrame_mY[1] + threeFrame_mY[2] + threeFrame_mY[threeFrameNum] + threeFrame_mY[threeFrameNum] / 5;
  3886. }*/
  3887. if (!storage.isCharacter && storage.cams_mainMode == 0) {
  3888. clamp input_mouse_X<-2, 2>;
  3889. clamp input_mouse_Y<-2, 2>;
  3890. }
  3891.  
  3892. vehicleController.VInput_mW = UniversalGetControllerValue(AC_WHEEL_UP);
  3893. vehicleController.VInput_mW -= UniversalGetControllerValue(AC_WHEEL_DOWN);
  3894. input_mouse_Whl += vehicleController.VInput_mW * 0.25;
  3895. if (vehicleController.VInput_mW == 0)
  3896. input_mouse_Whl *= 1 - fabs(FrameTimeDiff * 4);
  3897. if (input_mouse_Whl < 0.001 && input_mouse_Whl > -0.001)
  3898. input_mouse_Whl = 0;
  3899. clamp input_mouse_Whl<-10, 10>;
  3900. }
  3901. else
  3902. {
  3903. input_mouse_X = 0;
  3904. input_mouse_Y = 0;
  3905. input_mouse_Whl = 0;
  3906. }
  3907.  
  3908. // Update input controls
  3909.  
  3910. vehicleController.VInput_aF = UniversalGetControllerValue(AC_FORWARD);
  3911. vehicleController.VInput_aB = UniversalGetControllerValue(AC_BACKWARD);
  3912. vehicleController.VInput_aL = UniversalGetControllerValue(AC_LEFT);
  3913. vehicleController.VInput_aR = UniversalGetControllerValue(AC_RIGHT);
  3914. vehicleController.VInput_aU = UniversalGetControllerValue(AC_UP);
  3915. vehicleController.VInput_aD = UniversalGetControllerValue(AC_DOWN);
  3916. vehicleController.VInput_sF = UniversalGetControllerValue(AC_SEC_FORWARD);
  3917. vehicleController.VInput_sB = UniversalGetControllerValue(AC_SEC_BACKWARD);
  3918. vehicleController.VInput_sL = UniversalGetControllerValue(AC_SEC_LEFT);
  3919. vehicleController.VInput_sR = UniversalGetControllerValue(AC_SEC_RIGHT);
  3920. vehicleController.VInput_sU = UniversalGetControllerValue(AC_SEC_UP);
  3921. vehicleController.VInput_sD = UniversalGetControllerValue(AC_SEC_DOWN);
  3922. vehicleController.VInput_actJump = UniversalGetControllerValue(AC_HUMAN_JUMP);
  3923. vehicleController.VInput_actElev = UniversalGetControllerValue(AC_ELEVATE);
  3924. vehicleController.VInput_actRele = UniversalGetControllerValue(AC_RELEGATE);
  3925.  
  3926. input_arc_pri0 = vehicleController.VInput_aF - vehicleController.VInput_aB;
  3927. input_arc_pri1 = vehicleController.VInput_aR - vehicleController.VInput_aL;
  3928. input_arc_pri2 = vehicleController.VInput_aU - vehicleController.VInput_aD;
  3929. input_arc_sec0 = vehicleController.VInput_sF - vehicleController.VInput_sB;
  3930. input_arc_sec1 = vehicleController.VInput_sR - vehicleController.VInput_sL;
  3931. input_arc_sec2 = vehicleController.VInput_sU - vehicleController.VInput_sD;
  3932. }
  3933. }
  3934. if (!CommandsHelpListUpdated) {
  3935. AddCommandToHelpList("CLEAR", "", "", "", "", "#tkom_vehcmddesc_clear");
  3936. AddCommandToHelpList("", "", "", "", "", "");
  3937. AddCommandToHelpList("WAIT", "(num)", "H/M/S", "", "", "#tkom_vehcmddesc_wait");
  3938. AddCommandToHelpList("", "", "", "", "", "");
  3939. }
  3940.  
  3941. vehicleController.ProcessOnPFrm();
  3942. storage.InventoriesOnPostFrame();
  3943.  
  3944. if (!CommandsHelpListUpdated)
  3945. CommandsHelpListUpdated = true;
  3946. }
  3947. LastFrameTime = CurFrameTime;
  3948. }
  3949.  
  3950. // Called when unit is unselected
  3951. void OnUnselect()
  3952. {
  3953. isSelected = false;
  3954.  
  3955. if (vehicleController)
  3956. vehicleController.ProcessOnUnselect();
  3957.  
  3958. DeleteWidgets();
  3959. }
  3960.  
  3961. // Called when unit is selected
  3962. void OnSelect()
  3963. {
  3964. isSelected = true;
  3965.  
  3966. if (vehicleController)
  3967. vehicleController.ProcessOnSelect();
  3968. }
  3969.  
  3970. //send and receive message to construct vehicle on server/clients
  3971. // void SendConstructMessage();
  3972. // void OnReceiveConstructMessage( PacketInputAdapter input );
  3973.  
  3974. // Creates static objects at the position of the vehicle parts
  3975. void CreateStaticsFromParts();
  3976.  
  3977. //----------------------------------------------------------
  3978. void SetSceneID(int id)
  3979. {
  3980. SetID( id ); //set unique ID for fast finding using FindEntityByID
  3981. storage.Store_ID = id;
  3982. if (id > TKOMHighestEntID)
  3983. TKOMHighestEntID = id;
  3984. }
  3985.  
  3986. void Vehicle_Handler(bool character, bool netEnt);
  3987. void ~Vehicle_Handler();
  3988. }
  3989. /****************************************************************************
  3990. ***************************************************************************/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement