TransportContain.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  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: TransportContain.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/Player.h"
  30. #include "Common/ThingTemplate.h"
  31. #include "Common/ThingFactory.h"
  32. #include "Common/Xfer.h"
  33. #include "GameClient/Drawable.h"
  34. #include "GameLogic/AI.h"
  35. #include "GameLogic/AIPathfind.h"
  36. #include "GameLogic/Locomotor.h"
  37. #include "GameLogic/Module/AIUpdate.h"
  38. #include "GameLogic/Module/BodyModule.h"
  39. #include "GameLogic/Module/PhysicsUpdate.h"
  40. #include "GameLogic/Module/StealthUpdate.h"
  41. #include "GameLogic/Module/TransportContain.h"
  42. #include "GameLogic/Object.h"
  43. #include "GameLogic/Weapon.h"
  44. #ifdef _INTERNAL
  45. // for occasional debugging...
  46. //#pragma optimize("", off)
  47. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  48. #endif
  49. // ------------------------------------------------------------------------------------------------
  50. // ------------------------------------------------------------------------------------------------
  51. TransportContainModuleData::TransportContainModuleData()
  52. {
  53. m_slotCapacity = 0;
  54. m_scatterNearbyOnExit = true;
  55. m_orientLikeContainerOnExit = false;
  56. m_keepContainerVelocityOnExit = false;
  57. m_goAggressiveOnExit = FALSE;
  58. m_armedRidersUpgradeWeaponSet = FALSE;
  59. m_resetMoodCheckTimeOnExit = true;
  60. m_destroyRidersWhoAreNotFreeToExit = false;
  61. m_exitPitchRate = 0.0f;
  62. m_initialPayload.count = 0;
  63. m_healthRegen = 0.0f;
  64. m_exitDelay = 0;
  65. m_isDelayExitInAir = FALSE;
  66. //
  67. // by default we say that transports can have infantry inside them, this will be totally
  68. // overwritten by any data provided from the INI entry tho
  69. //
  70. m_allowInsideKindOf = MAKE_KINDOF_MASK( KINDOF_INFANTRY );
  71. }
  72. // ------------------------------------------------------------------------------------------------
  73. // ------------------------------------------------------------------------------------------------
  74. void TransportContainModuleData::parseInitialPayload( INI* ini, void *instance, void *store, const void* /*userData*/ )
  75. {
  76. TransportContainModuleData* self = (TransportContainModuleData*)instance;
  77. const char* name = ini->getNextToken();
  78. const char* countStr = ini->getNextTokenOrNull();
  79. Int count = countStr ? INI::scanInt(countStr) : 1;
  80. self->m_initialPayload.name.set(name);
  81. self->m_initialPayload.count = count;
  82. }
  83. // ------------------------------------------------------------------------------------------------
  84. // ------------------------------------------------------------------------------------------------
  85. void TransportContainModuleData::buildFieldParse(MultiIniFieldParse& p)
  86. {
  87. OpenContainModuleData::buildFieldParse(p);
  88. static const FieldParse dataFieldParse[] =
  89. {
  90. { "Slots", INI::parseInt, NULL, offsetof( TransportContainModuleData, m_slotCapacity ) },
  91. { "ScatterNearbyOnExit", INI::parseBool, NULL, offsetof( TransportContainModuleData, m_scatterNearbyOnExit ) },
  92. { "OrientLikeContainerOnExit", INI::parseBool, NULL, offsetof( TransportContainModuleData, m_orientLikeContainerOnExit ) },
  93. { "KeepContainerVelocityOnExit", INI::parseBool, NULL, offsetof( TransportContainModuleData, m_keepContainerVelocityOnExit ) },
  94. { "GoAggressiveOnExit", INI::parseBool, NULL, offsetof( TransportContainModuleData, m_goAggressiveOnExit ) },
  95. { "ResetMoodCheckTimeOnExit", INI::parseBool, NULL, offsetof( TransportContainModuleData, m_resetMoodCheckTimeOnExit ) },
  96. { "DestroyRidersWhoAreNotFreeToExit", INI::parseBool, NULL, offsetof( TransportContainModuleData, m_destroyRidersWhoAreNotFreeToExit ) },
  97. { "ExitBone", INI::parseAsciiString, NULL, offsetof( TransportContainModuleData, m_exitBone ) },
  98. { "ExitPitchRate", INI::parseAngularVelocityReal, NULL, offsetof( TransportContainModuleData, m_exitPitchRate ) },
  99. { "InitialPayload", parseInitialPayload, NULL, 0 },
  100. { "HealthRegen%PerSec", INI::parseReal, NULL, offsetof( TransportContainModuleData, m_healthRegen ) },
  101. { "ExitDelay", INI::parseDurationUnsignedInt, NULL, offsetof( TransportContainModuleData, m_exitDelay ) },
  102. { "ArmedRidersUpgradeMyWeaponSet", INI::parseBool, NULL, offsetof( TransportContainModuleData, m_armedRidersUpgradeWeaponSet ) },
  103. { "DelayExitInAir", INI::parseBool, NULL, offsetof( TransportContainModuleData, m_isDelayExitInAir ) },
  104. { 0, 0, 0, 0 }
  105. };
  106. p.add(dataFieldParse);
  107. }
  108. // PRIVATE ////////////////////////////////////////////////////////////////////////////////////////
  109. //-------------------------------------------------------------------------------------------------
  110. //-------------------------------------------------------------------------------------------------
  111. Int TransportContain::getContainMax( void ) const
  112. {
  113. if (getTransportContainModuleData())
  114. return getTransportContainModuleData()->m_slotCapacity;
  115. return 0;
  116. }
  117. // PUBLIC /////////////////////////////////////////////////////////////////////////////////////////
  118. //-------------------------------------------------------------------------------------------------
  119. //-------------------------------------------------------------------------------------------------
  120. TransportContain::TransportContain( Thing *thing, const ModuleData *moduleData ) :
  121. OpenContain( thing, moduleData )
  122. {
  123. m_extraSlotsInUse = 0;
  124. m_frameExitNotBusy = 0;
  125. }
  126. //-------------------------------------------------------------------------------------------------
  127. //-------------------------------------------------------------------------------------------------
  128. TransportContain::~TransportContain( void )
  129. {
  130. }
  131. //-------------------------------------------------------------------------------------------------
  132. //-------------------------------------------------------------------------------------------------
  133. /**
  134. can this container contain this kind of object?
  135. and, if checkCapacity is TRUE, does this container have enough space left to hold the given unit?
  136. */
  137. Bool TransportContain::isValidContainerFor(const Object* rider, Bool checkCapacity) const
  138. {
  139. // sanity
  140. if (!rider)
  141. return false;
  142. // The point of this new code is to determine when something is a "fake" container, to
  143. // look at the object inside of it to use that as the valid check. There is a case, when a
  144. // paratrooper (an infantry contained in a parachute). In this case, when we pass this object
  145. // to contain in a transport plane, we want to check the infantry, not the parachute.
  146. if (rider->getContain() && rider->getContain()->isSpecialZeroSlotContainer())
  147. {
  148. // Report the first thing inside it!
  149. const ContainedItemsList *items = rider->getContain()->getContainedItemsList();
  150. if (items && !items->empty())
  151. {
  152. if (items->front())
  153. {
  154. // Replace the object we are checking with the *first* object contained within it.
  155. rider = items->front();
  156. }
  157. }
  158. }
  159. // extend functionality
  160. if( OpenContain::isValidContainerFor( rider, checkCapacity ) == false )
  161. return false;
  162. // // only allied objects can be transported.
  163. // // order matters: we want to know if I consider it to be an ally, not vice versa
  164. // if (getObject()->getRelationship(rider) != ALLIES)
  165. // return false;
  166. // no... actually, only OUR OWN units can be transported.
  167. if (rider->getControllingPlayer() != getObject()->getControllingPlayer())
  168. return false;
  169. Int transportSlotCount = rider->getTransportSlotCount();
  170. // if 0, this object isn't transportable.
  171. if (transportSlotCount == 0)
  172. return false;
  173. if (checkCapacity)
  174. {
  175. Int containMax = getContainMax();
  176. Int containCount = getContainCount();
  177. return (m_extraSlotsInUse + containCount + transportSlotCount <= containMax);
  178. }
  179. else
  180. {
  181. return true;
  182. }
  183. }
  184. //-------------------------------------------------------------------------------------------------
  185. //-------------------------------------------------------------------------------------------------
  186. void TransportContain::letRidersUpgradeWeaponSet( void )
  187. {
  188. const TransportContainModuleData * d = getTransportContainModuleData();
  189. if ( ! d->m_armedRidersUpgradeWeaponSet )
  190. return;
  191. Object *self = getObject();
  192. if ( self == NULL )
  193. return;
  194. Bool anyRiderHasViableWeapon = FALSE;
  195. const ContainedItemsList* riderList = getContainedItemsList();
  196. if( riderList )
  197. {
  198. ContainedItemsList::const_iterator it;
  199. it = riderList->begin();
  200. while( *it )
  201. {
  202. Object *rider = *it;
  203. //Advance to the next iterator
  204. it++;
  205. if ( rider )
  206. {
  207. if(rider->isKindOf(KINDOF_INFANTRY) == false)
  208. continue;
  209. Weapon *weapon = NULL;
  210. for ( Int w = PRIMARY_WEAPON; w < WEAPONSLOT_COUNT; ++ w )
  211. {
  212. weapon = rider->getWeaponInWeaponSlot( (WeaponSlotType)w );
  213. if ( weapon )
  214. {
  215. if ( weapon->getTemplate()->isContactWeapon() == FALSE && weapon->isDamageWeapon() == TRUE ) // THIS MAY NEED TO CHECK MORE WEAPON ATTRIBUTES TO WORK BEST
  216. {
  217. anyRiderHasViableWeapon = TRUE;
  218. break;
  219. }
  220. }
  221. }
  222. }//end if rider
  223. }
  224. }
  225. if ( anyRiderHasViableWeapon )
  226. self->setWeaponSetFlag( WEAPONSET_PLAYER_UPGRADE );
  227. else
  228. self->clearWeaponSetFlag( WEAPONSET_PLAYER_UPGRADE );
  229. }
  230. //-------------------------------------------------------------------------------------------------
  231. //-------------------------------------------------------------------------------------------------
  232. void TransportContain::onContaining( Object *rider, Bool wasSelected )
  233. {
  234. OpenContain::onContaining( rider, wasSelected );
  235. // objects inside a transport are held
  236. rider->setDisabled( DISABLED_HELD );
  237. Int transportSlotCount = rider->getTransportSlotCount();
  238. DEBUG_ASSERTCRASH(transportSlotCount > 0, ("Hmm, this object isnt transportable"));
  239. m_extraSlotsInUse += transportSlotCount - 1;
  240. DEBUG_ASSERTCRASH(m_extraSlotsInUse >= 0 && m_extraSlotsInUse + getContainCount() <= getContainMax(), ("Hmm, bad slot count"));
  241. //
  242. // when we go from holding nothing to holding something we have a model condition
  243. // to visually show the change
  244. //
  245. if( getContainCount() == 1 )
  246. {
  247. Drawable *draw = getObject()->getDrawable();
  248. if( draw )
  249. draw->setModelConditionState( MODELCONDITION_LOADED );
  250. } // end if
  251. if ( getTransportContainModuleData()->m_armedRidersUpgradeWeaponSet )
  252. letRidersUpgradeWeaponSet();
  253. //Kris: October 20, 2003 - Patch 1.01
  254. //Force Jarmen Kell to transfer weapon timer for snipe to and from the combat bike.
  255. if( getObject()->isKindOf( KINDOF_CLIFF_JUMPER ) && rider->isKindOf( KINDOF_HERO ) && rider->isKindOf( KINDOF_SALVAGER ) )
  256. {
  257. //Admittedly brutal hack, but considering the state of the game (post-ship), this is a particularly surgical fix.
  258. Weapon *bikeWeapon = getObject()->getWeaponInWeaponSlot( SECONDARY_WEAPON );
  259. Weapon *riderWeapon = rider->getWeaponInWeaponSlot( SECONDARY_WEAPON );
  260. if( bikeWeapon && riderWeapon )
  261. {
  262. //Transfer the reload time from the rider to the bike
  263. bikeWeapon->transferNextShotStatsFrom( *riderWeapon );
  264. }
  265. }
  266. }
  267. //-------------------------------------------------------------------------------------------------
  268. //-------------------------------------------------------------------------------------------------
  269. void TransportContain::onRemoving( Object *rider )
  270. {
  271. OpenContain::onRemoving(rider);
  272. // object is no longer held inside a transport
  273. rider->clearDisabled( DISABLED_HELD );
  274. const TransportContainModuleData* d = getTransportContainModuleData();
  275. if (!d->m_exitBone.isEmpty())
  276. {
  277. Drawable* draw = getObject()->getDrawable();
  278. if (draw)
  279. {
  280. Coord3D bonePos, worldPos;
  281. if (draw->getPristineBonePositions(d->m_exitBone.str(), 0, &bonePos, NULL, 1) == 1)
  282. {
  283. getObject()->convertBonePosToWorldPos(&bonePos, NULL, &worldPos, NULL);
  284. rider->setPosition(&worldPos);
  285. }
  286. }
  287. }
  288. if (d->m_orientLikeContainerOnExit)
  289. {
  290. rider->setOrientation(getObject()->getOrientation());
  291. }
  292. if (d->m_keepContainerVelocityOnExit)
  293. {
  294. PhysicsBehavior* parent = getObject()->getPhysics();
  295. PhysicsBehavior* child = rider->getPhysics();
  296. if (parent && child)
  297. {
  298. Coord3D startingForce = *parent->getVelocity();
  299. Real mass = child->getMass();
  300. startingForce.x *= mass;
  301. startingForce.y *= mass;
  302. startingForce.z *= mass;
  303. child->applyMotiveForce( &startingForce );
  304. Real pitchRate = child->getCenterOfMassOffset() * d->m_exitPitchRate;
  305. child->setPitchRate( pitchRate );
  306. }
  307. }
  308. Int transportSlotCount = rider->getTransportSlotCount();
  309. DEBUG_ASSERTCRASH(transportSlotCount > 0, ("Hmm, this object isnt transportable"));
  310. m_extraSlotsInUse -= transportSlotCount - 1;
  311. #if (defined(_DEBUG) || defined(_INTERNAL))
  312. UnsignedInt containCount = getContainCount();
  313. UnsignedInt containMax = getContainMax();
  314. DEBUG_ASSERTCRASH(m_extraSlotsInUse >= 0 && m_extraSlotsInUse + containCount <= containMax, ("Hmm, bad slot count"));
  315. #endif
  316. // when we are empty again, clear the model condition for loaded
  317. if( getContainCount() == 0 )
  318. {
  319. Drawable *draw = getObject()->getDrawable();
  320. if( draw )
  321. draw->clearModelConditionState( MODELCONDITION_LOADED );
  322. } // end if
  323. if (getObject()->isAboveTerrain())
  324. {
  325. // temporarily mark the guy as being allowed to fall
  326. // (overriding his locomotor's stick-to-ground attribute).
  327. // this will be reset (by PhysicsBehavior) when he touches the ground.
  328. PhysicsBehavior* physics = rider->getPhysics();
  329. if (physics)
  330. physics->setAllowToFall(true);
  331. }
  332. // AI might need help using this transport in a good way. Make the passengers aggressive.
  333. //There is no computer player check since Aggressive only means something for computer players anyway
  334. if( d->m_goAggressiveOnExit && rider->getAI() )
  335. {
  336. rider->getAI()->setAttitude( AI_AGGRESSIVE );
  337. }
  338. if (getObject()->isEffectivelyDead()) {
  339. scatterToNearbyPosition(rider);
  340. }
  341. if( d->m_resetMoodCheckTimeOnExit && rider->getAI() )
  342. {
  343. rider->getAI()->wakeUpAndAttemptToTarget();
  344. }
  345. m_frameExitNotBusy = TheGameLogic->getFrame() + d->m_exitDelay;
  346. if ( d->m_armedRidersUpgradeWeaponSet )
  347. letRidersUpgradeWeaponSet();
  348. //Kris: October 20, 2003 - Patch 1.01
  349. //Force Jarmen Kell to transfer weapon timer for snipe to and from the combat bike.
  350. if( getObject()->isKindOf( KINDOF_CLIFF_JUMPER ) && rider->isKindOf( KINDOF_HERO ) && rider->isKindOf( KINDOF_SALVAGER ) )
  351. {
  352. //Admittedly brutal hack, but considering the state of the game (post-ship), this is a particularly surgical fix.
  353. Weapon *bikeWeapon = getObject()->getWeaponInWeaponSlot( SECONDARY_WEAPON );
  354. Weapon *riderWeapon = rider->getWeaponInWeaponSlot( SECONDARY_WEAPON );
  355. if( bikeWeapon && riderWeapon )
  356. {
  357. //Transfer the reload time from the bike to the rider
  358. riderWeapon->transferNextShotStatsFrom( *bikeWeapon );
  359. }
  360. }
  361. }
  362. // ------------------------------------------------------------------------------------------------
  363. // ------------------------------------------------------------------------------------------------
  364. void TransportContain::createPayload()
  365. {
  366. TransportContainModuleData* self = (TransportContainModuleData*)getTransportContainModuleData();
  367. Int count = self->m_initialPayload.count;
  368. const ThingTemplate* payloadTemplate = TheThingFactory->findTemplate( self->m_initialPayload.name );
  369. Object* object = getObject();
  370. ContainModuleInterface *contain = object->getContain();
  371. if( contain )
  372. {
  373. contain->enableLoadSounds( FALSE );
  374. for( int i = 0; i < count; i++ )
  375. {
  376. //We are creating a transport that comes with a initial payload, so add it now!
  377. Object* payload = TheThingFactory->newObject( payloadTemplate, object->getControllingPlayer()->getDefaultTeam() );
  378. if( contain->isValidContainerFor( payload, true ) )
  379. {
  380. contain->addToContain( payload );
  381. }
  382. else
  383. {
  384. DEBUG_CRASH( ( "DeliverPayload: PutInContainer %s is full, or not valid for the payload %s!", object->getName().str(), self->m_initialPayload.name.str() ) );
  385. }
  386. }
  387. contain->enableLoadSounds( TRUE );
  388. }
  389. m_payloadCreated = TRUE;
  390. }
  391. // ------------------------------------------------------------------------------------------------
  392. // ------------------------------------------------------------------------------------------------
  393. UpdateSleepTime TransportContain::update()
  394. {
  395. const TransportContainModuleData *moduleData = getTransportContainModuleData();
  396. if( m_payloadCreated == FALSE )
  397. createPayload();
  398. if( moduleData && moduleData->m_healthRegen )
  399. {
  400. ContainModuleInterface *contain = getObject()->getContain();
  401. if( contain )
  402. {
  403. //This transport has a health regeneration value, so go through and heal all inside.
  404. const ContainedItemsList* items = contain->getContainedItemsList();
  405. if( items )
  406. {
  407. ContainedItemsList::const_iterator it;
  408. it = items->begin();
  409. while( *it )
  410. {
  411. Object *object = *it;
  412. //Advance to the next iterator
  413. it++;
  414. //Determine if we need healing or not.
  415. BodyModuleInterface *body = object->getBodyModule();
  416. if( body->getHealth() < body->getMaxHealth() )
  417. {
  418. //Calculate the health to be regenerated on each unit.
  419. Real regen = body->getMaxHealth() * moduleData->m_healthRegen / 100.0f * SECONDS_PER_LOGICFRAME_REAL;
  420. //Perform the actual healing for this frame.
  421. // DamageInfo damageInfo;
  422. // damageInfo.in.m_damageType = DAMAGE_HEALING;
  423. // damageInfo.in.m_deathType = DEATH_NONE;
  424. // damageInfo.in.m_sourceID = getObject()->getID();
  425. // damageInfo.in.m_amount = regen;
  426. // object->attemptDamage( &damageInfo );
  427. object->attemptHealing( regen, getObject() );
  428. }
  429. }
  430. }
  431. }
  432. }
  433. return OpenContain::update(); //extend
  434. }
  435. // ------------------------------------------------------------------------------------------------
  436. // ------------------------------------------------------------------------------------------------
  437. void TransportContain::unreserveDoorForExit( ExitDoorType exitDoor )
  438. {
  439. /* nothing */
  440. }
  441. // ------------------------------------------------------------------------------------------------
  442. // ------------------------------------------------------------------------------------------------
  443. void TransportContain::killRidersWhoAreNotFreeToExit()
  444. {
  445. const TransportContainModuleData* d = getTransportContainModuleData();
  446. ContainedItemsList::const_iterator it = getContainList().begin();
  447. while( it != getContainList().end() )
  448. {
  449. // get the object
  450. Object *obj = *it;
  451. // increment the iterator, since death will pull this guy from the list somewhere else
  452. ++it;
  453. if (!isSpecificRiderFreeToExit(obj)) // only TransportContain has a meaningful failure for isFreeToExit
  454. {
  455. // If we cannot exit this guy legally, kill the bastard before removeAllContained forces him out.
  456. if (d->m_destroyRidersWhoAreNotFreeToExit)
  457. TheGameLogic->destroyObject(obj);
  458. else
  459. obj->kill();
  460. }
  461. }
  462. }
  463. // ------------------------------------------------------------------------------------------------
  464. // ------------------------------------------------------------------------------------------------
  465. Bool TransportContain::isSpecificRiderFreeToExit(Object* specificObject)
  466. {
  467. if( specificObject == NULL )
  468. return TRUE; // I can, in general, exit people.
  469. // This is a override, not an extend. I will check for game legality for
  470. // okaying the call to exitObjectViaDoor.
  471. const Object* me = getObject();
  472. // this is present solely for some transports to override, so that they can land before
  473. // allowing people to exit...
  474. const AIUpdateInterface* ai = me->getAIUpdateInterface();
  475. if (ai && ai->getAiFreeToExit(specificObject) != FREE_TO_EXIT)
  476. return FALSE;
  477. // I can always kick people out if I am in the air, I know what I'm doing
  478. if (me->isUsingAirborneLocomotor())
  479. return TRUE;
  480. const Coord3D *myPosition = me->getPosition();
  481. if (!specificObject->getAIUpdateInterface())
  482. return FALSE;
  483. const Locomotor *hisLocomotor = specificObject->getAIUpdateInterface()->getCurLocomotor();
  484. if( hisLocomotor == FALSE )
  485. return FALSE;
  486. // He can't get to this spot naturally, so I can't force him there. (amphib transport)
  487. if (!TheAI->pathfinder()->validMovementTerrain(me->getLayer(), hisLocomotor, myPosition))
  488. return FALSE;
  489. return TRUE;
  490. }
  491. Bool TransportContain::isPassengerAllowedToFire( ObjectID id ) const
  492. {
  493. Object *passenger = TheGameLogic->findObjectByID(id);
  494. if( passenger != NULL )
  495. {
  496. //only allow infantry, and turrets and such. no vehicles.
  497. if( passenger->isKindOf(KINDOF_INFANTRY) == FALSE )
  498. return FALSE;
  499. }
  500. if ( ! getObject() )
  501. return FALSE;
  502. // but wait! I may be riding on an Overlord
  503. // This code detects the case of whether the contained passenger is in a bunker riding on an overlord, inside a helix!
  504. // Oh my God.
  505. const Object *heWhoContainsMe = getObject()->getContainedBy();
  506. if ( heWhoContainsMe)
  507. {
  508. ContainModuleInterface *hisContain = heWhoContainsMe->getContain();
  509. DEBUG_ASSERTCRASH( hisContain,("TransportContain::isPassengerAllowedToFire()... CONTAINER WITHOUT A CONTAIN! AARRGH!") );
  510. if ( hisContain && hisContain->isSpecialOverlordStyleContainer() )
  511. return hisContain->isPassengerAllowedToFire( id );
  512. }
  513. return OpenContain::isPassengerAllowedToFire();
  514. }
  515. // ------------------------------------------------------------------------------------------------
  516. // ------------------------------------------------------------------------------------------------
  517. ExitDoorType TransportContain::reserveDoorForExit( const ThingTemplate* objType, Object *specificObject )
  518. {
  519. return isSpecificRiderFreeToExit(specificObject) ? DOOR_1 : DOOR_NONE_AVAILABLE;
  520. }
  521. // ------------------------------------------------------------------------------------------------
  522. // ------------------------------------------------------------------------------------------------
  523. Bool TransportContain::isExitBusy() const ///< Contain style exiters are getting the ability to space out exits, so ask this before reserveDoor as a kind of no-commitment check.
  524. {
  525. const TransportContainModuleData *data = getTransportContainModuleData();
  526. if( data->m_isDelayExitInAir && getObject()->isAboveTerrain() )
  527. return TRUE;
  528. return TheGameLogic->getFrame() < m_frameExitNotBusy;
  529. }
  530. // ------------------------------------------------------------------------------------------------
  531. // ------------------------------------------------------------------------------------------------
  532. void TransportContain::onCapture( Player *oldOwner, Player *newOwner )
  533. {
  534. if( oldOwner != newOwner )
  535. {
  536. if( getObject()->isDisabledByType( DISABLED_UNMANNED ) )
  537. {
  538. //If this vehicle was sniped, then instantly eject everyone (otherwise, the next guy to eject will recapture it).
  539. removeAllContained();
  540. }
  541. else
  542. {
  543. //Use standard
  544. orderAllPassengersToExit( CMD_FROM_AI, FALSE );
  545. }
  546. }
  547. }
  548. // ------------------------------------------------------------------------------------------------
  549. /** CRC */
  550. // ------------------------------------------------------------------------------------------------
  551. void TransportContain::crc( Xfer *xfer )
  552. {
  553. // extend base class
  554. OpenContain::crc( xfer );
  555. } // end crc
  556. // ------------------------------------------------------------------------------------------------
  557. /** Xfer method
  558. * Version Info:
  559. * 1: Initial version */
  560. // ------------------------------------------------------------------------------------------------
  561. void TransportContain::xfer( Xfer *xfer )
  562. {
  563. // version
  564. XferVersion currentVersion = 1;
  565. XferVersion version = currentVersion;
  566. xfer->xferVersion( &version, currentVersion );
  567. // extend base class
  568. OpenContain::xfer( xfer );
  569. // payload created
  570. xfer->xferBool( &m_payloadCreated );
  571. // extra slots in use
  572. xfer->xferInt( &m_extraSlotsInUse );
  573. // frame exit not busy
  574. xfer->xferUnsignedInt( &m_frameExitNotBusy );
  575. } // end xfer
  576. // ------------------------------------------------------------------------------------------------
  577. /** Load post process */
  578. // ------------------------------------------------------------------------------------------------
  579. void TransportContain::loadPostProcess( void )
  580. {
  581. // extend base class
  582. OpenContain::loadPostProcess();
  583. } // end loadPostProcess