ParachuteContain.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: ParachuteContain.cpp //////////////////////////////////////////////////////////////////////
  24. // Author: Steven Johnson, March 2002
  25. // Desc: Contain module for transport units.
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. // USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
  28. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  29. #include "Common/CRCDebug.h"
  30. #include "Common/Player.h"
  31. #include "Common/RandomValue.h"
  32. #include "Common/ThingTemplate.h"
  33. #include "Common/Xfer.h"
  34. #include "GameLogic/AIPathfind.h"
  35. #include "GameLogic/Locomotor.h"
  36. #include "GameLogic/Module/AIUpdate.h"
  37. #include "GameLogic/Module/ParachuteContain.h"
  38. #include "GameLogic/Module/PhysicsUpdate.h"
  39. #include "GameLogic/Object.h"
  40. #include "GameLogic/PartitionManager.h"
  41. #include "GameClient/Drawable.h"
  42. const Real NO_START_Z = 1e10;
  43. #ifdef _INTERNAL
  44. // for occasional debugging...
  45. //#pragma optimize("", off)
  46. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  47. #endif
  48. // PRIVATE ////////////////////////////////////////////////////////////////////////////////////////
  49. //-------------------------------------------------------------------------------------------------
  50. ParachuteContainModuleData::ParachuteContainModuleData() :
  51. m_pitchRateMax(0),
  52. m_rollRateMax(0),
  53. m_lowAltitudeDamping(0.2f),
  54. m_paraOpenDist(0.0f),
  55. m_freeFallDamagePercent(0.5f),
  56. m_killWhenLandingInWaterSlop(10.0f)
  57. {
  58. }
  59. //-------------------------------------------------------------------------------------------------
  60. void ParachuteContainModuleData::buildFieldParse(MultiIniFieldParse& p)
  61. {
  62. OpenContainModuleData::buildFieldParse(p);
  63. static const FieldParse dataFieldParse[] =
  64. {
  65. { "PitchRateMax", INI::parseAngularVelocityReal, NULL, offsetof( ParachuteContainModuleData, m_pitchRateMax ) },
  66. { "RollRateMax", INI::parseAngularVelocityReal, NULL, offsetof( ParachuteContainModuleData, m_rollRateMax ) },
  67. { "LowAltitudeDamping", INI::parseReal, NULL, offsetof( ParachuteContainModuleData, m_lowAltitudeDamping ) },
  68. { "ParachuteOpenDist", INI::parseReal, NULL, offsetof( ParachuteContainModuleData, m_paraOpenDist ) },
  69. { "KillWhenLandingInWaterSlop", INI::parseReal, NULL, offsetof( ParachuteContainModuleData, m_killWhenLandingInWaterSlop ) },
  70. { "FreeFallDamagePercent", INI::parsePercentToReal, NULL, offsetof( ParachuteContainModuleData, m_freeFallDamagePercent ) },
  71. { "ParachuteOpenSound", INI::parseAudioEventRTS, NULL, offsetof( ParachuteContainModuleData, m_parachuteOpenSound ) },
  72. { 0, 0, 0, 0 }
  73. };
  74. p.add(dataFieldParse);
  75. }
  76. // PUBLIC /////////////////////////////////////////////////////////////////////////////////////////
  77. //-------------------------------------------------------------------------------------------------
  78. //-------------------------------------------------------------------------------------------------
  79. ParachuteContain::ParachuteContain( Thing *thing, const ModuleData *moduleData ) :
  80. OpenContain( thing, moduleData )
  81. {
  82. m_opened = false;
  83. m_needToUpdateParaBones = true;
  84. m_needToUpdateRiderBones = true;
  85. m_pitch = 0;
  86. m_roll = 0;
  87. m_pitchRate = 0;
  88. m_rollRate = 0;
  89. m_isLandingOverrideSet = FALSE;
  90. m_startZ = NO_START_Z;
  91. //Added By Sadullah Nader
  92. //Initializations
  93. m_landingOverride.zero();
  94. m_paraAttachBone.zero();
  95. m_paraAttachOffset.zero();
  96. m_paraSwayBone.zero();
  97. m_paraSwayOffset.zero();
  98. m_riderAttachBone.zero();
  99. m_riderAttachOffset.zero();
  100. m_riderSwayBone.zero();
  101. m_riderSwayOffset.zero();
  102. //
  103. const ParachuteContainModuleData* d = getParachuteContainModuleData();
  104. if (d)
  105. {
  106. m_pitchRate = GameLogicRandomValueReal(-d->m_pitchRateMax, d->m_pitchRateMax);
  107. m_rollRate = GameLogicRandomValueReal(-d->m_rollRateMax, d->m_rollRateMax);
  108. }
  109. getObject()->setStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_PARACHUTING ) );
  110. }
  111. //-------------------------------------------------------------------------------------------------
  112. //-------------------------------------------------------------------------------------------------
  113. ParachuteContain::~ParachuteContain( void )
  114. {
  115. }
  116. //-------------------------------------------------------------------------------------------------
  117. /**
  118. this is called whenever a drawable is bound to the object.
  119. drawable is NOT guaranteed to be non-null.
  120. */
  121. void ParachuteContain::onDrawableBoundToObject()
  122. {
  123. Drawable* draw = getObject()->getDrawable();
  124. if (draw)
  125. draw->setDrawableHidden(!m_opened);
  126. }
  127. //-------------------------------------------------------------------------------------------------
  128. void ParachuteContain::calcSwayMtx(const Coord3D* offset, Matrix3D* mtx)
  129. {
  130. mtx->Make_Identity();
  131. mtx->Translate(offset->x, offset->y, offset->z);
  132. mtx->In_Place_Pre_Rotate_X(m_roll);
  133. mtx->In_Place_Pre_Rotate_Y(m_pitch);
  134. mtx->Translate(-offset->x, -offset->y, -offset->z);
  135. }
  136. //-------------------------------------------------------------------------------------------------
  137. void ParachuteContain::updateBonePositions()
  138. {
  139. if (m_needToUpdateParaBones)
  140. {
  141. m_needToUpdateParaBones = false; // yeah, even if not found.
  142. Drawable* parachuteDraw = getObject()->getDrawable();
  143. if (parachuteDraw)
  144. {
  145. if (parachuteDraw->getPristineBonePositions( "PARA_COG", 0, &m_paraSwayBone, NULL, 1) != 1)
  146. {
  147. DEBUG_CRASH(("PARA_COG not found\n"));
  148. m_paraSwayBone.zero();
  149. }
  150. if (parachuteDraw->getPristineBonePositions( "PARA_ATTCH", 0, &m_paraAttachBone, NULL, 1 ) != 1)
  151. {
  152. DEBUG_CRASH(("PARA_ATTCH not found\n"));
  153. m_paraAttachBone.zero();
  154. }
  155. }
  156. //DEBUG_LOG(("updating para bone positions %d...\n",TheGameLogic->getFrame()));
  157. }
  158. if (m_needToUpdateRiderBones)
  159. {
  160. m_needToUpdateRiderBones = false; // yeah, even if not found.
  161. Object* rider = (getContainCount() > 0) ? getContainList().front() : NULL;
  162. Drawable* riderDraw = rider ? rider->getDrawable() : NULL;
  163. if (riderDraw)
  164. {
  165. if (riderDraw->getPristineBonePositions( "PARA_MAN", 0, &m_riderAttachBone, NULL, 1) != 1)
  166. {
  167. //DEBUG_LOG(("*** No parachute-attach bone... using object height!\n"));
  168. m_riderAttachBone.zero();
  169. m_riderAttachBone.z += riderDraw->getDrawableGeometryInfo().getMaxHeightAbovePosition();
  170. }
  171. }
  172. //DEBUG_LOG(("updating rider bone positions %d...\n",TheGameLogic->getFrame()));
  173. }
  174. }
  175. //-------------------------------------------------------------------------------------------------
  176. void ParachuteContain::updateOffsetsFromBones()
  177. {
  178. const Coord3D* objPos = getObject()->getPosition();
  179. getObject()->convertBonePosToWorldPos(&m_paraSwayBone, NULL, &m_paraSwayOffset, NULL);
  180. m_paraSwayOffset.x -= objPos->x;
  181. m_paraSwayOffset.y -= objPos->y;
  182. m_paraSwayOffset.z -= objPos->z;
  183. getObject()->convertBonePosToWorldPos(&m_paraAttachBone, NULL, &m_paraAttachOffset, NULL);
  184. m_paraAttachOffset.x -= objPos->x;
  185. m_paraAttachOffset.y -= objPos->y;
  186. m_paraAttachOffset.z -= objPos->z;
  187. Object* rider = (getContainCount() > 0) ? getContainList().front() : NULL;
  188. if (rider)
  189. {
  190. const Coord3D* riderPos = rider->getPosition();
  191. rider->convertBonePosToWorldPos(&m_riderAttachBone, NULL, &m_riderAttachOffset, NULL);
  192. m_riderAttachOffset.x -= riderPos->x;
  193. m_riderAttachOffset.y -= riderPos->y;
  194. m_riderAttachOffset.z -= riderPos->z;
  195. m_riderAttachOffset.x = m_paraAttachOffset.x - m_riderAttachOffset.x;
  196. m_riderAttachOffset.y = m_paraAttachOffset.y - m_riderAttachOffset.y;
  197. m_riderAttachOffset.z = m_paraAttachOffset.z - m_riderAttachOffset.z;
  198. m_riderSwayOffset.x = m_paraSwayOffset.x - m_riderAttachOffset.x;
  199. m_riderSwayOffset.y = m_paraSwayOffset.y - m_riderAttachOffset.y;
  200. m_riderSwayOffset.z = m_paraSwayOffset.z - m_riderAttachOffset.z;
  201. }
  202. }
  203. //-------------------------------------------------------------------------------------------------
  204. //-------------------------------------------------------------------------------------------------
  205. /**
  206. can this container contain this kind of object?
  207. and, if checkCapacity is TRUE, does this container have enough space left to hold the given unit?
  208. */
  209. Bool ParachuteContain::isValidContainerFor(const Object* rider, Bool checkCapacity) const
  210. {
  211. if (!rider)
  212. return false;
  213. // extend functionality
  214. if( OpenContain::isValidContainerFor( rider, checkCapacity ) == false )
  215. return false;
  216. Int transportSlotCount = rider->getTransportSlotCount();
  217. // if 0, this object isn't transportable.
  218. // (exception: infantry are always transportable by parachutes, regardless
  219. // of this.... this allows us to paradrop pilots, but not transport them
  220. // by other means)
  221. if (transportSlotCount == 0 && !rider->isKindOf(KINDOF_INFANTRY) && !rider->isKindOf(KINDOF_PARACHUTABLE))
  222. return false;
  223. // we can only "hold" one item at a time.
  224. if (getContainCount() > 0)
  225. return false;
  226. return true;
  227. }
  228. //-------------------------------------------------------------------------------------------------
  229. //-------------------------------------------------------------------------------------------------
  230. void ParachuteContain::containReactToTransformChange()
  231. {
  232. // a bit of a cheese festival here... hidden is a flag, not a counter, so when we are dumped
  233. // from a plane, we might get drawn for a frame before our update is called, meaning we
  234. // should be briefly visible. put this here to ensure we stay hidden appropriately.
  235. Drawable* draw = getObject()->getDrawable();
  236. if (draw)
  237. draw->setDrawableHidden(!m_opened);
  238. }
  239. //-------------------------------------------------------------------------------------------------
  240. //-------------------------------------------------------------------------------------------------
  241. UpdateSleepTime ParachuteContain::update( void )
  242. {
  243. OpenContain::update();
  244. Object* parachute = getObject();
  245. if( parachute->isDisabledByType( DISABLED_HELD ) )
  246. {
  247. return UPDATE_SLEEP_NONE; // my, that was easy
  248. }
  249. AIUpdateInterface *parachuteAI = parachute->getAI();
  250. Drawable* draw = parachute->getDrawable();
  251. const ParachuteContainModuleData* d = getParachuteContainModuleData();
  252. Object* rider = (getContainCount() > 0) ? getContainList().front() : NULL;
  253. if (m_startZ == NO_START_Z) {
  254. m_startZ = parachute->getPosition()->z;
  255. Real groundHeight = TheTerrainLogic->getGroundHeight(parachute->getPosition()->x, parachute->getPosition()->y);
  256. if (m_startZ-groundHeight < 2*d->m_paraOpenDist) {
  257. // Oh dear - we ejected too close to the ground, and there isn't enough
  258. // room to open the chute. Well, since it's only a game, we'll fudge
  259. // a little so that the pilot doesn't slam into the ground & stick.
  260. m_startZ = groundHeight+2*d->m_paraOpenDist;
  261. }
  262. }
  263. if (!m_opened)
  264. {
  265. // see if we need to open.
  266. if (fabs(m_startZ - parachute->getPosition()->z) >= d->m_paraOpenDist)
  267. {
  268. m_opened = true;
  269. parachute->clearAndSetModelConditionState(MODELCONDITION_FREEFALL, MODELCONDITION_PARACHUTING);
  270. m_needToUpdateParaBones = true;
  271. if (rider)
  272. {
  273. rider->clearAndSetModelConditionState(MODELCONDITION_FREEFALL, MODELCONDITION_PARACHUTING);
  274. m_needToUpdateRiderBones = true;
  275. AudioEventRTS soundToPlay = d->m_parachuteOpenSound;
  276. soundToPlay.setObjectID( rider->getID() );
  277. TheAudio->addAudioEvent( &soundToPlay );
  278. }
  279. // When a parachute opens, it should look for a good place to land. This could be explicitly set
  280. // by a DeliverPayload, otherwise any place clear is good.
  281. if( parachuteAI )
  282. {
  283. Coord3D target = *parachute->getPosition();
  284. if( m_isLandingOverrideSet )
  285. {
  286. target = m_landingOverride;
  287. if( parachuteAI->getCurLocomotor() )
  288. parachuteAI->getCurLocomotor()->setUltraAccurate( TRUE );
  289. }
  290. else
  291. {
  292. FindPositionOptions fpOptions;
  293. fpOptions.minRadius = 0.0f;
  294. fpOptions.maxRadius = 100.0f;
  295. fpOptions.relationshipObject = NULL;
  296. fpOptions.flags = FPF_NONE;
  297. ThePartitionManager->findPositionAround( &target, &fpOptions, &target );
  298. }
  299. parachuteAI->aiMoveToPosition( &target, CMD_FROM_AI );
  300. }
  301. }
  302. else if ( rider )
  303. rider->clearAndSetModelConditionState( MODELCONDITION_PARACHUTING, MODELCONDITION_FREEFALL );
  304. }
  305. draw->setDrawableHidden(!m_opened);
  306. if (!m_opened || getContainCount() == 0)
  307. {
  308. // unopened, or empty, chutes, don't collide with anything, to simplify
  309. // ejections, paradrops, landings, etc...
  310. parachute->setStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_NO_COLLISIONS ) );
  311. if (rider)
  312. rider->setStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_NO_COLLISIONS ) );
  313. }
  314. else
  315. {
  316. // opened/nonempty chutes DO collide...
  317. parachute->clearStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_NO_COLLISIONS ) );
  318. if (rider)
  319. rider->clearStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_NO_COLLISIONS ) );
  320. }
  321. AIUpdateInterface* ai = parachute->getAIUpdateInterface();
  322. if (ai && !parachute->isEffectivelyDead())
  323. {
  324. ai->chooseLocomotorSet(m_opened ? LOCOMOTORSET_NORMAL : LOCOMOTORSET_FREEFALL);
  325. Locomotor* locomotor = ai->getCurLocomotor();
  326. if (locomotor)
  327. {
  328. // damp the swaying a bunch when we get close, so that things land vertically (or nearly so)
  329. Real altitudeDamping = 0;
  330. if (getContainCount() > 0)
  331. {
  332. Object* rider = getContainList().front();
  333. const Real ALTITUDE_DAMP_START = 20.0f;
  334. if (rider->getHeightAboveTerrain() <= ALTITUDE_DAMP_START)
  335. altitudeDamping = d->m_lowAltitudeDamping;
  336. }
  337. if (m_opened)
  338. {
  339. const Real PITCH_STIFFNESS = locomotor->getPitchStiffness();
  340. const Real ROLL_STIFFNESS = locomotor->getRollStiffness();
  341. const Real PITCH_DAMPING = locomotor->getPitchDamping() + altitudeDamping;
  342. const Real ROLL_DAMPING = locomotor->getRollDamping() + altitudeDamping;
  343. m_pitchRate += ((-PITCH_STIFFNESS * m_pitch) + (-PITCH_DAMPING * m_pitchRate)); // spring/damper
  344. m_rollRate += ((-ROLL_STIFFNESS * m_roll) + (-ROLL_DAMPING * m_rollRate)); // spring/damper
  345. m_pitch += m_pitchRate;
  346. m_roll += m_rollRate;
  347. if( m_isLandingOverrideSet )
  348. {
  349. // Need to wait until after opening to do this, or else we are sending the message to the Freefall locomotor.
  350. locomotor->setCloseEnoughDist( 10.0 );
  351. locomotor->setCloseEnoughDist3D( FALSE );
  352. }
  353. }
  354. if (draw)
  355. {
  356. updateBonePositions();
  357. updateOffsetsFromBones();
  358. Matrix3D tmp;
  359. calcSwayMtx(&m_paraSwayOffset, &tmp);
  360. draw->setInstanceMatrix(&tmp);
  361. }
  362. positionContainedObjectsRelativeToContainer();
  363. }
  364. }
  365. // allow us to land on bridges!
  366. const Coord3D* paraPos = getObject()->getPosition();
  367. PathfindLayerEnum newLayer = TheTerrainLogic->getHighestLayerForDestination(paraPos);
  368. getObject()->setLayer(newLayer);
  369. if (rider)
  370. rider->setLayer(newLayer);
  371. // If we have lost our passenger for whatever reason, die early. Otherwise we just sit around forever.
  372. if( getContainCount() == 0 )
  373. getObject()->kill();
  374. // the collide system doesn't always collide us with the ground if we fall into water.
  375. // so force the issue.
  376. Real waterZ;
  377. if (!getObject()->isEffectivelyDead()
  378. && getObject()->getLayer() == LAYER_GROUND
  379. && TheTerrainLogic->isUnderwater(paraPos->x, paraPos->y, &waterZ)
  380. && (paraPos->z - waterZ) < d->m_killWhenLandingInWaterSlop)
  381. {
  382. getObject()->kill();
  383. }
  384. return UPDATE_SLEEP_NONE;
  385. }
  386. //-------------------------------------------------------------------------------------------------
  387. //-------------------------------------------------------------------------------------------------
  388. void ParachuteContain::onContaining( Object *rider, Bool wasSelected )
  389. {
  390. OpenContain::onContaining( rider, wasSelected );
  391. // objects inside a transport are held
  392. rider->setDisabled( DISABLED_HELD );
  393. rider->setStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_PARACHUTING ) );
  394. rider->clearAndSetModelConditionState(MODELCONDITION_PARACHUTING, MODELCONDITION_FREEFALL);
  395. m_needToUpdateRiderBones = true;
  396. // position him correctly.
  397. positionRider(rider);
  398. }
  399. //-------------------------------------------------------------------------------------------------
  400. //-------------------------------------------------------------------------------------------------
  401. void ParachuteContain::onRemoving( Object *rider )
  402. {
  403. OpenContain::onRemoving(rider);
  404. const ParachuteContainModuleData* d = getParachuteContainModuleData();
  405. // object is no longer held inside a transport
  406. rider->clearDisabled( DISABLED_HELD );
  407. rider->clearStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_PARACHUTING ) );
  408. // mark parachute as "no-collisions"... it is just ephemeral at this point,
  409. // and having the chute collide with the soldier (and both bounce apart) is
  410. // just dumb-lookin'...
  411. getObject()->setStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_NO_COLLISIONS ) );
  412. // position him correctly.
  413. positionRider(rider);
  414. rider->clearModelConditionFlags(MAKE_MODELCONDITION_MASK2(MODELCONDITION_FREEFALL, MODELCONDITION_PARACHUTING));
  415. m_needToUpdateRiderBones = true;
  416. // temporarily mark the guy as being allowed to fall
  417. // (overriding his locomotor's stick-to-ground attribute).
  418. // this will be reset (by PhysicsBehavior) when he touches the ground.
  419. PhysicsBehavior* physics = rider->getPhysics();
  420. if (physics)
  421. {
  422. physics->setAllowToFall(true);
  423. Coord3D force;
  424. force.zero();
  425. physics->applyForce(&force); // force its physics to wake up... should be done when DISABLED_HELD is cleared, but it not, and scared to do it now.
  426. }
  427. AIUpdateInterface* riderAI = rider->getAIUpdateInterface();
  428. if (riderAI)
  429. {
  430. Player* controller = rider->getControllingPlayer();
  431. if (controller && controller->isSkirmishAIPlayer())
  432. {
  433. riderAI->aiHunt(CMD_FROM_AI); // hunt, as per Dustin's request.
  434. }
  435. else
  436. {
  437. bool hasRallyPoint = false;
  438. // Get the transport of the rider
  439. Object *transport = TheGameLogic->findObjectByID(rider->getProducerID());
  440. if (transport)
  441. {
  442. // Get the building that produced the transport
  443. Object *transportProducer = TheGameLogic->findObjectByID(transport->getProducerID());
  444. if (transportProducer)
  445. {
  446. // See if we need to set a rally point for the object being parachuted
  447. ExitInterface* exitInterface = transportProducer->getObjectExitInterface();
  448. if (exitInterface && exitInterface->useSpawnRallyPoint())
  449. {
  450. exitInterface->exitObjectViaDoor(rider, DOOR_1);
  451. hasRallyPoint = true;
  452. }
  453. }
  454. }
  455. if (!hasRallyPoint)
  456. riderAI->aiIdle(CMD_FROM_AI); // become idle.
  457. }
  458. }
  459. // if we land in the water, we die. alas.
  460. const Coord3D* riderPos = rider->getPosition();
  461. Real waterZ, terrainZ;
  462. if (TheTerrainLogic->isUnderwater(riderPos->x, riderPos->y, &waterZ, &terrainZ)
  463. && riderPos->z <= waterZ + d->m_killWhenLandingInWaterSlop
  464. && rider->getLayer() == LAYER_GROUND)
  465. {
  466. // don't call kill(); do it manually, so we can specify DEATH_FLOODED
  467. DamageInfo damageInfo;
  468. damageInfo.in.m_damageType = DAMAGE_WATER; // use this instead of UNRESISTABLE so we don't get a dusty damage effect
  469. damageInfo.in.m_deathType = DEATH_FLOODED;
  470. damageInfo.in.m_sourceID = INVALID_ID;
  471. damageInfo.in.m_amount = HUGE_DAMAGE_AMOUNT;
  472. rider->attemptDamage( &damageInfo );
  473. }
  474. // Kill if we landed on impassable ground
  475. Int cellX = REAL_TO_INT( rider->getPosition()->x / PATHFIND_CELL_SIZE );
  476. Int cellY = REAL_TO_INT( rider->getPosition()->y / PATHFIND_CELL_SIZE );
  477. PathfindCell* cell = TheAI->pathfinder()->getCell( rider->getLayer(), cellX, cellY );
  478. PathfindCell::CellType cellType = cell ? cell->getType() : PathfindCell::CELL_IMPASSABLE;
  479. // If we land outside the map from a faulty parachute, we die too.
  480. // Otherwise we exist outside the PartitionManger like a cheater.
  481. if( rider->isOffMap()
  482. || (cellType == PathfindCell::CELL_CLIFF)
  483. || (cellType == PathfindCell::CELL_WATER)
  484. || (cellType == PathfindCell::CELL_IMPASSABLE) )
  485. {
  486. // The Paradrop command was legal, the parachute destination was legal, but the parachute
  487. // can still fail to adjust back on the map. SO this is the place to cap the cheater.
  488. rider->kill();
  489. }
  490. // Note: for future enhancement of this feature, we should test the object against the cell type he is on,
  491. // using obj->getAI()->hasLocomotorForSurface( __ ). We cshould not assume here that the parachutist can not
  492. // find happiness on cliffs or water or whatever.
  493. }
  494. //-------------------------------------------------------------------------------------------------
  495. void ParachuteContain::positionRider(Object* rider)
  496. {
  497. updateBonePositions();
  498. updateOffsetsFromBones();
  499. Coord3D pos = *getObject()->getPosition();
  500. ///DUMPCOORD3D(&pos);
  501. pos.x += m_riderAttachOffset.x;
  502. pos.y += m_riderAttachOffset.y;
  503. pos.z += m_riderAttachOffset.z;
  504. //DUMPCOORD3D(&pos);
  505. rider->setPosition(&pos);
  506. Real alt = rider->getHeightAboveTerrain();
  507. if (alt < 0.0f)
  508. {
  509. // don't let him go below ground.
  510. pos.z -= alt;
  511. rider->setPosition(&pos);
  512. }
  513. rider->setOrientation(getObject()->getOrientation());
  514. Drawable* draw = rider->getDrawable();
  515. if (draw)
  516. {
  517. if( rider->isDisabledByType( DISABLED_HELD ) )
  518. {
  519. Matrix3D tmp;
  520. calcSwayMtx(&m_riderSwayOffset, &tmp);
  521. draw->setInstanceMatrix(&tmp);
  522. }
  523. else
  524. {
  525. draw->setInstanceMatrix(NULL);
  526. }
  527. }
  528. }
  529. //-------------------------------------------------------------------------------------------------
  530. void ParachuteContain::positionContainedObjectsRelativeToContainer()
  531. {
  532. for(ContainedItemsList::const_iterator it = getContainList().begin(); it != getContainList().end(); ++it)
  533. {
  534. positionRider(*it);
  535. }
  536. }
  537. //-------------------------------------------------------------------------------------------------
  538. void ParachuteContain::setOverrideDestination( const Coord3D *override )
  539. {
  540. // Instead of trying to float straight down, I am going to nail this spot.
  541. m_landingOverride = *override;
  542. m_isLandingOverrideSet = TRUE;
  543. }
  544. //-------------------------------------------------------------------------------------------------
  545. void ParachuteContain::onDie( const DamageInfo * damageInfo )
  546. {
  547. // if we are airborne when killed, the guy falls screaming to his death...
  548. if (getObject()->isSignificantlyAboveTerrain())
  549. {
  550. Object* rider = (getContainCount() > 0) ? getContainList().front() : NULL;
  551. if (rider)
  552. {
  553. removeAllContained();
  554. const ParachuteContainModuleData* d = getParachuteContainModuleData();
  555. if (d->m_freeFallDamagePercent > 0.0f)
  556. {
  557. // do some damage just for losing your parachute.
  558. // not very realistic, but practical to help ensure that
  559. // you really do die from going "splat" on the ground.
  560. DamageInfo extraDamageInfo;
  561. extraDamageInfo.in.m_damageType = DAMAGE_FALLING;
  562. extraDamageInfo.in.m_deathType = DEATH_SPLATTED;
  563. extraDamageInfo.in.m_sourceID = damageInfo->in.m_sourceID;
  564. extraDamageInfo.in.m_amount = rider->getBodyModule()->getMaxHealth() * d->m_freeFallDamagePercent;
  565. rider->attemptDamage(&extraDamageInfo);
  566. }
  567. PhysicsBehavior* physics = rider->getPhysics();
  568. if (physics)
  569. {
  570. physics->setAllowToFall(true);
  571. physics->setIsInFreeFall(true); // bwah ha ha
  572. Coord3D force;
  573. force.zero();
  574. physics->applyForce(&force); // force its physics to wake up... should be done when DISABLED_HELD is cleared, but it not, and scared to do it now.
  575. }
  576. }
  577. }
  578. OpenContain::onDie(damageInfo);
  579. }
  580. //-------------------------------------------------------------------------------------------------
  581. void ParachuteContain::onCollide( Object *other, const Coord3D *loc, const Coord3D *normal )
  582. {
  583. // Note that other == null means "collide with ground"
  584. if( other == NULL )
  585. {
  586. // if we're in a container (eg, a transport plane), just ignore this...
  587. if( getObject()->getContainedBy() != NULL )
  588. return;
  589. removeAllContained();
  590. // TheGameLogic->destroyObject(obj);
  591. // kill it, so that the chute's SlowDeath will trigger!
  592. getObject()->kill();
  593. }
  594. }
  595. // ------------------------------------------------------------------------------------------------
  596. /** CRC */
  597. // ------------------------------------------------------------------------------------------------
  598. void ParachuteContain::crc( Xfer *xfer )
  599. {
  600. // extend base class
  601. OpenContain::crc( xfer );
  602. } // end crc
  603. // ------------------------------------------------------------------------------------------------
  604. /** Xfer method
  605. * Version Info:
  606. * 1: Initial version */
  607. // ------------------------------------------------------------------------------------------------
  608. void ParachuteContain::xfer( Xfer *xfer )
  609. {
  610. // version
  611. XferVersion currentVersion = 1;
  612. XferVersion version = currentVersion;
  613. xfer->xferVersion( &version, currentVersion );
  614. // extend base class
  615. OpenContain::xfer( xfer );
  616. // pitch
  617. xfer->xferReal( &m_pitch );
  618. // roll
  619. xfer->xferReal( &m_roll );
  620. // pitch rage
  621. xfer->xferReal( &m_pitchRate );
  622. // roll rate
  623. xfer->xferReal( &m_rollRate );
  624. // start Z
  625. xfer->xferReal( &m_startZ );
  626. // is landing override set
  627. xfer->xferBool( &m_isLandingOverrideSet );
  628. // landing override
  629. xfer->xferCoord3D( &m_landingOverride );
  630. // rider attach bone
  631. xfer->xferCoord3D( &m_riderAttachBone );
  632. // rider sway bone
  633. xfer->xferCoord3D( &m_riderSwayBone );
  634. // para attach bone
  635. xfer->xferCoord3D( &m_paraAttachBone );
  636. // para sway bone
  637. xfer->xferCoord3D( &m_paraSwayBone );
  638. // rider attach offset
  639. xfer->xferCoord3D( &m_riderAttachOffset );
  640. // rider sway offset
  641. xfer->xferCoord3D( &m_riderSwayOffset );
  642. // para attach offset
  643. xfer->xferCoord3D( &m_paraAttachOffset );
  644. // para sway offset
  645. xfer->xferCoord3D( &m_paraSwayOffset );
  646. // need to update rider bones
  647. xfer->xferBool( &m_needToUpdateRiderBones );
  648. // need to update para bones
  649. xfer->xferBool( &m_needToUpdateParaBones );
  650. // opened
  651. xfer->xferBool( &m_opened );
  652. } // end xfer
  653. // ------------------------------------------------------------------------------------------------
  654. /** Load post process */
  655. // ------------------------------------------------------------------------------------------------
  656. void ParachuteContain::loadPostProcess( void )
  657. {
  658. // extend base class
  659. OpenContain::loadPostProcess();
  660. } // end loadPostProcess