transport.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. /*!
  2. Base native class of all vehicles in game.
  3. */
  4. #ifdef FEATURE_NETWORK_RECONCILIATION
  5. class TransportOwnerState : PawnOwnerState
  6. {
  7. proto native void SetWorldTransform(vector transform[4]);
  8. proto native void GetWorldTransform(out vector transform[4]);
  9. proto native void SetLinearVelocity(vector value);
  10. proto native void GetLinearVelocity(out vector value);
  11. proto native void SetAngularVelocity(vector value);
  12. proto native void GetAngularVelocity(out vector value);
  13. proto native void SetBuoyancySubmerged(float value);
  14. proto native float GetBuoyancySubmerged();
  15. #ifdef DIAG_DEVELOPER
  16. override event void GetTransform(inout vector transform[4])
  17. {
  18. GetWorldTransform(transform);
  19. }
  20. #endif
  21. };
  22. class TransportMove : PawnMove
  23. {
  24. proto native void SetWorldTransform(vector transform[4]);
  25. proto native void GetWorldTransform(out vector transform[4]);
  26. proto native void SetLinearVelocity(vector value);
  27. proto native void GetLinearVelocity(out vector value);
  28. proto native void SetAngularVelocity(vector value);
  29. proto native void GetAngularVelocity(out vector value);
  30. #ifdef DIAG_DEVELOPER
  31. override event void GetTransform(inout vector transform[4])
  32. {
  33. GetWorldTransform(transform);
  34. }
  35. #endif
  36. };
  37. //! Uses NetworkMoveStrategy.NONE
  38. class Transport extends Pawn
  39. #else
  40. class Transport extends EntityAI
  41. #endif
  42. {
  43. //! Shared context across all vehicles for flipping
  44. private static ref VehicleFlippedContext m_FlippedContext;
  45. ref TIntArray m_SingleUseActions;
  46. ref TIntArray m_ContinuousActions;
  47. ref TIntArray m_InteractActions;
  48. protected bool m_EngineZoneReceivedHit;
  49. protected vector m_fuelPos;
  50. protected ref set<int> m_UnconsciousCrewMemberIndices;
  51. protected ref set<int> m_DeadCrewMemberIndices;
  52. void Transport()
  53. {
  54. RegisterNetSyncVariableBool("m_EngineZoneReceivedHit");
  55. if ( MemoryPointExists("refill") )
  56. m_fuelPos = GetMemoryPointPos("refill");
  57. else
  58. m_fuelPos = "0 0 0";
  59. m_UnconsciousCrewMemberIndices = new set<int>();
  60. m_DeadCrewMemberIndices = new set<int>();
  61. }
  62. override void EEHitBy(TotalDamageResult damageResult, int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos, float speedCoef)
  63. {
  64. super.EEHitBy(damageResult, damageType, source, component, dmgZone, ammo, modelPos, speedCoef);
  65. SetEngineZoneReceivedHit(dmgZone == "Engine");
  66. }
  67. override int GetMeleeTargetType()
  68. {
  69. return EMeleeTargetType.NONALIGNABLE;
  70. }
  71. //!
  72. protected override event typename GetOwnerStateType()
  73. {
  74. return TransportOwnerState;
  75. }
  76. //!
  77. protected override event typename GetMoveType()
  78. {
  79. return TransportMove;
  80. }
  81. //! Synchronizes car's state in case the simulation is not running.
  82. proto native void Synchronize();
  83. //! Returns crew capacity of this vehicle.
  84. proto native int CrewSize();
  85. //! Returns crew member index based on action component index.
  86. //! -1 is returned when no crew position corresponds to given component index.
  87. proto native int CrewPositionIndex( int componentIdx );
  88. //! Returns crew member index based on player's instance.
  89. //! -1 is returned when the player is not isnide.
  90. proto native int CrewMemberIndex( Human player );
  91. //! Returns crew member based on position index.
  92. //! Null can be returned if no Human is present on the given position.
  93. proto native Human CrewMember( int posIdx );
  94. //! Returns the driver
  95. //! Null can be returned if no Human is present.
  96. proto native Human CrewDriver();
  97. //! Reads entry point and direction into vehicle on given position in model space.
  98. proto void CrewEntry( int posIdx, out vector pos, out vector dir );
  99. //! Reads entry point and direction into vehicle on given position in world space.
  100. proto void CrewEntryWS( int posIdx, out vector pos, out vector dir );
  101. //! Returns crew transformation indside vehicle in model space
  102. proto void CrewTransform( int posIdx, out vector mat[4] );
  103. //! Returns crew transformation indside vehicle in world space
  104. proto void CrewTransformWS( int posIdx, out vector mat[4] );
  105. //! Performs transfer of player from world into vehicle on given position.
  106. proto native void CrewGetIn( Human player, int posIdx );
  107. //! Performs transfer of player from vehicle into world from given position.
  108. proto native Human CrewGetOut( int posIdx );
  109. //! Handles death of player in vehicle and awakes its physics if needed
  110. proto native void CrewDeath( int posIdx );
  111. override bool IsTransport()
  112. {
  113. return true;
  114. }
  115. override bool IsIgnoredByConstruction()
  116. {
  117. return false;
  118. }
  119. override bool IsHealthVisible()
  120. {
  121. return true;
  122. }
  123. override bool ShowZonesHealth()
  124. {
  125. return true;
  126. }
  127. override int GetHideIconMask()
  128. {
  129. return EInventoryIconVisibility.HIDE_VICINITY;
  130. }
  131. float GetMomentum()
  132. {
  133. return GetVelocity(this).Length() * dBodyGetMass(this);
  134. }
  135. bool IsVitalSparkPlug()
  136. {
  137. return true;
  138. }
  139. string GetVehicleType()
  140. {
  141. return "VehicleTypeUndefined";
  142. }
  143. string GetActionCompNameFuel()
  144. {
  145. return "refill";
  146. }
  147. float GetActionDistanceFuel()
  148. {
  149. return 1.5;
  150. }
  151. vector GetRefillPointPosWS()
  152. {
  153. return ModelToWorld( m_fuelPos );
  154. }
  155. protected /*sealed*/ VehicleFlippedContext GetFlipContext()
  156. {
  157. if (!m_FlippedContext)
  158. {
  159. m_FlippedContext = new VehicleFlippedContext();
  160. }
  161. #ifdef DIAG_DEVELOPER
  162. m_FlippedContext.Reset(DiagMenu.GetBool(DiagMenuIDs.VEHICLE_DRAW_FLIP_CONTEXT));
  163. #endif
  164. return m_FlippedContext;
  165. }
  166. protected bool DetectFlippedUsingSurface(VehicleFlippedContext ctx, float angleTolerance)
  167. {
  168. vector corners[4];
  169. GetTightlyPackedCorners(ETransformationAxis.BOTTOM, corners);
  170. // compute the average position to find the lowest "center-most" position
  171. vector avgPosition = vector.Zero;
  172. for (int i = 0; i < 4; i++)
  173. {
  174. avgPosition = avgPosition + corners[i];
  175. }
  176. avgPosition = avgPosition * 0.25;
  177. // get depth of the water to determine if we should use the roadway surface normal or just up vector
  178. float depth = GetGame().GetWaterDepth(avgPosition);
  179. vector normal = vector.Up;
  180. vector dirUp = GetDirectionUp();
  181. bool testLand = depth < -1.0;
  182. // iterate over the corners to find the average normal
  183. if (testLand)
  184. {
  185. // trace roadway, incase the vehicle is on a rock, or bridge
  186. ctx.m_SurfaceParams.type = SurfaceDetectionType.Roadway;
  187. // ignore expensive water computation, we already know we are above land
  188. ctx.m_SurfaceParams.includeWater = false;
  189. // ignore this vehicle, it may have a roadway LOD
  190. ctx.m_SurfaceParams.ignore = this;
  191. // detect closest to the given point
  192. ctx.m_SurfaceParams.rsd = RoadSurfaceDetection.CLOSEST;
  193. for (i = 0; i < 4; i++)
  194. {
  195. ctx.m_SurfaceParams.position = corners[i];
  196. GetGame().GetSurface(ctx.m_SurfaceParams, ctx.m_SurfaceResult);
  197. corners[i][1] = ctx.m_SurfaceResult.height;
  198. }
  199. vector d0 = vector.Direction(corners[0], corners[1]);
  200. vector d1 = vector.Direction(corners[0], corners[2]);
  201. d0.Normalize();
  202. d1.Normalize();
  203. // cross product the two directions to get the normal vector of the land
  204. normal = d0 * d1;
  205. }
  206. bool isFlipped = vector.Dot(normal, dirUp) < Math.Cos(angleTolerance * Math.DEG2RAD);
  207. #ifdef DIAG_DEVELOPER
  208. if (ctx.IsDebug())
  209. {
  210. int color = 0xFF00FF00;
  211. if (isFlipped)
  212. color = 0xFFFF0000;
  213. ctx.AddShape(Shape.Create(ShapeType.LINE, color, ShapeFlags.NOZBUFFER, corners[0], corners[0] + normal));
  214. ctx.AddShape(Shape.Create(ShapeType.LINE, color, ShapeFlags.NOZBUFFER, corners[1], corners[1] + normal));
  215. ctx.AddShape(Shape.Create(ShapeType.LINE, color, ShapeFlags.NOZBUFFER, corners[2], corners[2] + normal));
  216. ctx.AddShape(Shape.Create(ShapeType.LINE, color, ShapeFlags.NOZBUFFER, corners[3], corners[3] + normal));
  217. }
  218. #endif
  219. return isFlipped;
  220. }
  221. //! Override based on vehicle implementation (Car, Boat, modded, etc.)
  222. protected bool DetectFlipped(VehicleFlippedContext ctx)
  223. {
  224. return false;
  225. }
  226. //! Don't override, may change to native for caching 'DetectFlipped' in the future based on active-ness (i.e. only updated when vehicle changes active state)
  227. /*sealed*/ bool IsFlipped()
  228. {
  229. VehicleFlippedContext ctx = GetFlipContext();
  230. ctx.m_bIsAction = false;
  231. ctx.m_ActionPlayer = null;
  232. return DetectFlipped(ctx);
  233. }
  234. //! Don't override, may change to native for caching 'DetectFlipped' in the future based on active-ness (i.e. only updated when vehicle changes active state)
  235. /*sealed*/ bool IsActionFlipped(Man player)
  236. {
  237. VehicleFlippedContext ctx = GetFlipContext();
  238. ctx.m_bIsAction = true;
  239. ctx.m_ActionPlayer = player;
  240. return DetectFlipped(ctx);
  241. }
  242. bool IsAnyCrewPresent()
  243. {
  244. for (int index = 0; index < CrewSize(); ++index)
  245. {
  246. if (CrewMember(index) != null)
  247. return true;
  248. }
  249. return false;
  250. }
  251. float GetTransportCameraDistance()
  252. {
  253. return 4.0;
  254. }
  255. void MarkCrewMemberUnconscious(int crewMemberIndex)
  256. {
  257. set<int> crewMemberIndicesCopy = new set<int>();
  258. crewMemberIndicesCopy.Copy(m_UnconsciousCrewMemberIndices);
  259. crewMemberIndicesCopy.Insert(crewMemberIndex);
  260. m_UnconsciousCrewMemberIndices = crewMemberIndicesCopy;
  261. }
  262. void MarkCrewMemberDead(int crewMemberIndex)
  263. {
  264. set<int> crewMemberIndicesCopy = new set<int>();
  265. crewMemberIndicesCopy.Copy(m_DeadCrewMemberIndices);
  266. crewMemberIndicesCopy.Insert(crewMemberIndex);
  267. m_DeadCrewMemberIndices = crewMemberIndicesCopy;
  268. }
  269. protected void HandleByCrewMemberState(ECrewMemberState state);
  270. vector GetTransportCameraOffset()
  271. {
  272. return "0 1.3 0";
  273. }
  274. int GetAnimInstance()
  275. {
  276. #ifndef CFGMODS_DEFINE_TEST
  277. Error("GetAnimInstance() not implemented");
  278. return 0;
  279. #else
  280. return 2;
  281. #endif
  282. }
  283. int GetSeatAnimationType( int posIdx )
  284. {
  285. #ifndef CFGMODS_DEFINE_TEST
  286. Error("GetSeatAnimationType() not implemented");
  287. #endif
  288. return 0;
  289. }
  290. int Get3rdPersonCameraType()
  291. {
  292. #ifndef CFGMODS_DEFINE_TEST
  293. Error("Get3rdPersonCameraType() not implemented");
  294. return 0;
  295. #else
  296. return 31;
  297. #endif
  298. }
  299. bool CrewCanGetThrough( int posIdx )
  300. {
  301. #ifndef CFGMODS_DEFINE_TEST
  302. return false;
  303. #else
  304. return true;
  305. #endif
  306. }
  307. bool CanReachSeatFromSeat( int currentSeat, int nextSeat )
  308. {
  309. #ifndef CFGMODS_DEFINE_TEST
  310. return false;
  311. #else
  312. return true;
  313. #endif
  314. }
  315. bool CanReachSeatFromDoors( string pSeatSelection, vector pFromPos, float pDistance = 1.0 )
  316. {
  317. #ifndef CFGMODS_DEFINE_TEST
  318. return false;
  319. #else
  320. return true;
  321. #endif
  322. }
  323. bool CanReachDoorsFromSeat( string pDoorsSelection, int pCurrentSeat )
  324. {
  325. #ifndef CFGMODS_DEFINE_TEST
  326. return false;
  327. #else
  328. return true;
  329. #endif
  330. }
  331. int GetSeatIndexFromDoor( string pDoorSelection )
  332. {
  333. //Potientially could be fixed some other way, currently follows the unfortunate pattern that CanReachDoorsFromSeat has created
  334. switch (pDoorSelection)
  335. {
  336. case "DoorsDriver":
  337. return 0;
  338. break;
  339. case "DoorsCoDriver":
  340. return 1;
  341. break;
  342. case "DoorsCargo1":
  343. return 2;
  344. break;
  345. case "DoorsCargo2":
  346. return 3;
  347. break;
  348. }
  349. return -1;
  350. }
  351. bool IsIgnoredObject( Object o )
  352. {
  353. if (!o)
  354. return false;
  355. //! If the player can't interact (hint: collide) with the object, then it is ignored
  356. int layer = dBodyGetInteractionLayer(o);
  357. bool interacts = dGetInteractionLayer(this, PhxInteractionLayers.CHARACTER, layer);
  358. if (!interacts)
  359. {
  360. return true;
  361. }
  362. DayZPlayer player;
  363. if (Class.CastTo(player, o))
  364. {
  365. //! Ignore any player that is currently in this vehicle
  366. HumanCommandVehicle hcv = player.GetCommand_Vehicle();
  367. if (hcv && hcv.GetTransport() == this)
  368. {
  369. return true;
  370. }
  371. }
  372. EntityAI e = EntityAI.Cast(o);
  373. // CanBeSkinned means it is a dead entity which should not block the door
  374. return ( ( e && (e.IsZombie() || e.IsHologram()) ) || o.CanBeSkinned() || o.IsBush() || o.IsTree() );
  375. }
  376. void SetEngineZoneReceivedHit(bool pState)
  377. {
  378. m_EngineZoneReceivedHit = pState;
  379. SetSynchDirty();
  380. }
  381. bool HasEngineZoneReceivedHit()
  382. {
  383. return m_EngineZoneReceivedHit;
  384. }
  385. bool IsAreaAtDoorFree( int currentSeat, float maxAllowedObjHeight, inout vector extents, out vector transform[4] )
  386. {
  387. GetTransform(transform);
  388. vector crewPos;
  389. vector crewDir;
  390. CrewEntry( currentSeat, crewPos, crewDir );
  391. vector entry[4];
  392. entry[2] = crewDir;
  393. entry[0] = vector.Up * crewDir;
  394. entry[1] = entry[2] * entry[0];
  395. entry[3] = crewPos;
  396. Math3D.MatrixMultiply4( transform, entry, transform );
  397. vector position = transform[3];
  398. vector orientation = Math3D.MatrixToAngles(transform);
  399. position[1] = position[1] + maxAllowedObjHeight + (extents[1] * 0.5);
  400. array<Object> excluded = new array<Object>;
  401. array<Object> collided = new array<Object>;
  402. excluded.Insert(this);
  403. GetGame().IsBoxColliding(position, orientation, extents, excluded, collided);
  404. orientation.RotationMatrixFromAngles(transform);
  405. transform[3] = position;
  406. foreach (Object o : collided)
  407. {
  408. EntityAI e = EntityAI.Cast(o);
  409. if (IsIgnoredObject(o))
  410. continue;
  411. vector minmax[2];
  412. if (o.GetCollisionBox(minmax))
  413. return false;
  414. }
  415. return true;
  416. }
  417. bool IsAreaAtDoorFree( int currentSeat, float maxAllowedObjHeight = 0.5, float horizontalExtents = 0.5, float playerHeight = 1.7 )
  418. {
  419. vector transform[4];
  420. vector extents;
  421. extents[0] = horizontalExtents;
  422. extents[1] = playerHeight;
  423. extents[2] = horizontalExtents;
  424. return IsAreaAtDoorFree( currentSeat, maxAllowedObjHeight, extents, transform );
  425. }
  426. Shape DebugFreeAreaAtDoor( int currentSeat, float maxAllowedObjHeight = 0.5, float horizontalExtents = 0.5, float playerHeight = 1.7 )
  427. {
  428. int color = ARGB(20, 0, 255, 0);
  429. vector transform[4];
  430. vector extents;
  431. extents[0] = horizontalExtents;
  432. extents[1] = playerHeight;
  433. extents[2] = horizontalExtents;
  434. if (!IsAreaAtDoorFree( currentSeat, maxAllowedObjHeight, extents, transform ))
  435. {
  436. color = ARGB(20, 255, 0, 0);
  437. }
  438. Shape shape = Debug.DrawBox(-extents * 0.5, extents * 0.5, color);
  439. shape.SetMatrix(transform);
  440. return shape;
  441. }
  442. };
  443. class VehicleContactData
  444. {
  445. vector m_LocalPos;
  446. IEntity m_Other;
  447. float m_Impulse;
  448. void SetData(vector localPos, IEntity other, float impulse)
  449. {
  450. m_LocalPos = localPos;
  451. m_Other = other;
  452. m_Impulse = impulse;
  453. }
  454. };
  455. class VehicleFlippedContext
  456. {
  457. bool m_bIsAction = false;
  458. Man m_ActionPlayer;
  459. ref SurfaceDetectionParameters m_SurfaceParams = new SurfaceDetectionParameters();
  460. ref SurfaceDetectionResult m_SurfaceResult = new SurfaceDetectionResult();
  461. #ifdef DIAG_DEVELOPER
  462. private ref array<Shape> m_DebugShapes;
  463. private bool m_bIsDebug;
  464. void VehicleFlippedContext()
  465. {
  466. m_DebugShapes = new array<Shape>();
  467. }
  468. void ~VehicleFlippedContext()
  469. {
  470. Reset();
  471. }
  472. void Reset(bool isDebug = false)
  473. {
  474. foreach (Shape shape : m_DebugShapes)
  475. {
  476. shape.Destroy();
  477. }
  478. m_DebugShapes.Clear();
  479. m_bIsDebug = isDebug;
  480. }
  481. void AddShape(Shape shape)
  482. {
  483. m_DebugShapes.Insert(shape);
  484. }
  485. bool IsDebug()
  486. {
  487. return m_bIsDebug;
  488. }
  489. #endif
  490. };