TunnelContain.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  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: TunnelContain.cpp ////////////////////////////////////////////////////////////////////////////
  24. // Author: Graham Smallwood, March 2002
  25. // Desc: A version of OpenContain that overrides where the passengers are stored: the Owning Player's
  26. // TunnelTracker. All queries about capacity and contents are also redirected.
  27. ///////////////////////////////////////////////////////////////////////////////////////////////////
  28. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  29. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  30. #include "Common/Player.h"
  31. #include "Common/RandomValue.h"
  32. #include "Common/ThingTemplate.h"
  33. #include "Common/TunnelTracker.h"
  34. #include "Common/Xfer.h"
  35. #include "GameClient/Drawable.h"
  36. #include "GameLogic/Module/AIUpdate.h"
  37. #include "GameLogic/Module/OpenContain.h"
  38. #include "GameLogic/Module/TunnelContain.h"
  39. #include "GameLogic/Object.h"
  40. #include "GameLogic/PartitionManager.h"
  41. #ifdef _INTERNAL
  42. // for occasional debugging...
  43. //#pragma optimize("", off)
  44. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  45. #endif
  46. ///////////////////////////////////////////////////////////////////////////////////////////////////
  47. // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
  48. ///////////////////////////////////////////////////////////////////////////////////////////////////
  49. //-------------------------------------------------------------------------------------------------
  50. //-------------------------------------------------------------------------------------------------
  51. TunnelContain::TunnelContain( Thing *thing, const ModuleData* moduleData ) : OpenContain( thing, moduleData )
  52. {
  53. m_needToRunOnBuildComplete = true;
  54. m_isCurrentlyRegistered = FALSE;
  55. }
  56. //-------------------------------------------------------------------------------------------------
  57. //-------------------------------------------------------------------------------------------------
  58. TunnelContain::~TunnelContain()
  59. {
  60. }
  61. void TunnelContain::addToContainList( Object *obj )
  62. {
  63. Player *owningPlayer = getObject()->getControllingPlayer();
  64. owningPlayer->getTunnelSystem()->addToContainList( obj );
  65. }
  66. //-------------------------------------------------------------------------------------------------
  67. /** Remove 'obj' from the m_containList of objects in this module.
  68. * This will trigger an onRemoving event for the object that this module
  69. * is a part of and an onRemovedFrom event for the object being removed */
  70. //-------------------------------------------------------------------------------------------------
  71. void TunnelContain::removeFromContain( Object *obj, Bool exposeStealthUnits )
  72. {
  73. // sanity
  74. if( obj == NULL )
  75. return;
  76. // trigger an onRemoving event for 'm_object' no longer containing 'itemToRemove->m_object'
  77. if( getObject()->getContain() )
  78. {
  79. getObject()->getContain()->onRemoving( obj );
  80. }
  81. // trigger an onRemovedFrom event for 'remove'
  82. obj->onRemovedFrom( getObject() );
  83. //
  84. // we can only remove this object from the contains list of this module if
  85. // it is actually contained by this module
  86. //
  87. Player *owningPlayer = getObject()->getControllingPlayer();
  88. if( owningPlayer == NULL )
  89. return; //game tear down. We do the onRemove* stuff first because this is allowed to fail but that still needs to be done
  90. if( ! owningPlayer->getTunnelSystem()->isInContainer( obj ) )
  91. {
  92. return;
  93. }
  94. owningPlayer->getTunnelSystem()->removeFromContain( obj, exposeStealthUnits );
  95. }
  96. //--------------------------------------------------------------------------------------------------------
  97. /** Force all contained objects in the contained list to exit, and kick them in the pants on the way out*/
  98. //--------------------------------------------------------------------------------------------------------
  99. void TunnelContain::harmAndForceExitAllContained( DamageInfo *info )
  100. {
  101. Player *owningPlayer = getObject()->getControllingPlayer();
  102. const ContainedItemsList *fullList = owningPlayer->getTunnelSystem()->getContainedItemsList();
  103. Object *obj;
  104. ContainedItemsList::const_iterator it;
  105. //Kris: Patch 1.01 -- November 6, 2003
  106. //No longer advances the iterator and saves it. The iterator is fetched from the beginning after
  107. //each loop. This is to prevent a crash where dropping a bunker buster on a tunnel network containing
  108. //multiple units (if they have the suicide bomb upgrade - demo general). In this case, multiple bunker
  109. //busters would hit the tunnel network in close succession. Missile #1 would iterate the list, killing
  110. //infantry #1. Infantry #1 would explode and destroy Missile #2. Missile #2 would start iterating the
  111. //same list, killing the remaining units. When Missile #1 picked up and continued processing the list
  112. //it would crash because it's iterator was deleted from under it.
  113. it = (*fullList).begin();
  114. while( it != (*fullList).end() )
  115. {
  116. obj = *it;
  117. removeFromContain( obj, true );
  118. obj->attemptDamage( info );
  119. it = (*fullList).begin();
  120. } // end while
  121. } // end removeAllContained
  122. //-------------------------------------------------------------------------------------------------
  123. /** Remove all contained objects from the contained list */
  124. //-------------------------------------------------------------------------------------------------
  125. void TunnelContain::killAllContained( void )
  126. {
  127. Player *owningPlayer = getObject()->getControllingPlayer();
  128. const ContainedItemsList *fullList = owningPlayer->getTunnelSystem()->getContainedItemsList();
  129. Object *obj;
  130. ContainedItemsList::const_iterator it;
  131. it = (*fullList).begin();
  132. while( it != (*fullList).end() )
  133. {
  134. obj = *it;
  135. it++;
  136. removeFromContain( obj, true );
  137. obj->kill();
  138. }
  139. }
  140. //-------------------------------------------------------------------------------------------------
  141. /** Remove all contained objects from the contained list */
  142. //-------------------------------------------------------------------------------------------------
  143. void TunnelContain::removeAllContained( Bool exposeStealthUnits )
  144. {
  145. Player *owningPlayer = getObject()->getControllingPlayer();
  146. const ContainedItemsList *fullList = owningPlayer->getTunnelSystem()->getContainedItemsList();
  147. Object *obj;
  148. ContainedItemsList::const_iterator it;
  149. it = (*fullList).begin();
  150. while( it != (*fullList).end() )
  151. {
  152. obj = *it;
  153. it++;
  154. removeFromContain( obj, exposeStealthUnits );
  155. }
  156. }
  157. //-------------------------------------------------------------------------------------------------
  158. /** Iterate the contained list and call the callback on each of the objects */
  159. //-------------------------------------------------------------------------------------------------
  160. void TunnelContain::iterateContained( ContainIterateFunc func, void *userData, Bool reverse )
  161. {
  162. Player *owningPlayer = getObject()->getControllingPlayer();
  163. owningPlayer->getTunnelSystem()->iterateContained( func, userData, reverse );
  164. }
  165. //-------------------------------------------------------------------------------------------------
  166. void TunnelContain::onContaining( Object *obj, Bool wasSelected )
  167. {
  168. OpenContain::onContaining( obj, wasSelected );
  169. // objects inside a building are held
  170. obj->setDisabled( DISABLED_HELD );
  171. obj->getControllingPlayer()->getAcademyStats()->recordUnitEnteredTunnelNetwork();
  172. obj->handlePartitionCellMaintenance();
  173. }
  174. //-------------------------------------------------------------------------------------------------
  175. void TunnelContain::onRemoving( Object *obj )
  176. {
  177. OpenContain::onRemoving(obj);
  178. // object is no longer held inside a garrisoned building
  179. obj->clearDisabled( DISABLED_HELD );
  180. /// place the object in the world at position of the container m_object
  181. ThePartitionManager->registerObject( obj );
  182. obj->setPosition( getObject()->getPosition() );
  183. if( obj->getDrawable() )
  184. {
  185. obj->setSafeOcclusionFrame(TheGameLogic->getFrame()+obj->getTemplate()->getOcclusionDelay());
  186. obj->getDrawable()->setDrawableHidden( false );
  187. }
  188. doUnloadSound();
  189. }
  190. //-------------------------------------------------------------------------------------------------
  191. void TunnelContain::onSelling()
  192. {
  193. // A TunnelContain tells everyone to leave if this is the last tunnel
  194. Player *owningPlayer = getObject()->getControllingPlayer();
  195. if( owningPlayer == NULL )
  196. return;
  197. TunnelTracker *tunnelTracker = owningPlayer->getTunnelSystem();
  198. if( tunnelTracker == NULL )
  199. return;
  200. // We are the last tunnel, so kick everyone out. This makes tunnels act like Palace and Bunker
  201. // rather than killing the occupants as if the last tunnel died.
  202. if( tunnelTracker->friend_getTunnelCount() == 1 )
  203. removeAllContained(FALSE);// Can't be order to exit, as I have no time to organize their exits.
  204. // If they don't go right now, I will delete them in a moment
  205. // Unregister after the kick out, or else the unregistering will activate a cavein-kill.
  206. // We need to do this in case someone sells their last two tunnels at the same time.
  207. if( m_isCurrentlyRegistered )
  208. {
  209. tunnelTracker->onTunnelDestroyed( getObject() );
  210. m_isCurrentlyRegistered = FALSE;
  211. }
  212. }
  213. //-------------------------------------------------------------------------------------------------
  214. Bool TunnelContain::isValidContainerFor(const Object* obj, Bool checkCapacity) const
  215. {
  216. Player *owningPlayer = getObject()->getControllingPlayer();
  217. return owningPlayer->getTunnelSystem()->isValidContainerFor( obj, checkCapacity );
  218. }
  219. UnsignedInt TunnelContain::getContainCount() const
  220. {
  221. Player *owningPlayer = getObject()->getControllingPlayer();
  222. if( owningPlayer && owningPlayer->getTunnelSystem() )
  223. {
  224. return owningPlayer->getTunnelSystem()->getContainCount();
  225. }
  226. return 0;
  227. }
  228. Int TunnelContain::getContainMax( void ) const
  229. {
  230. Player *owningPlayer = getObject()->getControllingPlayer();
  231. return owningPlayer->getTunnelSystem()->getContainMax();
  232. }
  233. const ContainedItemsList* TunnelContain::getContainedItemsList() const
  234. {
  235. Player *owningPlayer = getObject()->getControllingPlayer();
  236. return owningPlayer->getTunnelSystem()->getContainedItemsList();
  237. }
  238. ///////////////////////////////////////////////////////////////////////////////////////////////////
  239. // PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////////////////////
  240. ///////////////////////////////////////////////////////////////////////////////////////////////////
  241. //-------------------------------------------------------------------------------------------------
  242. void TunnelContain::scatterToNearbyPosition(Object* obj)
  243. {
  244. Object *theContainer = getObject();
  245. //
  246. // for now we will just set the position of the object that is being removed from us
  247. // at a random angle away from our center out some distance
  248. //
  249. //
  250. // pick an angle that is in the view of the current camera position so that
  251. // the thing will come out "toward" the player and they can see it
  252. // NOPE, can't do that ... all players screen angles will be different, unless
  253. // we maintain the angle of each players screen in the player structure or something
  254. //
  255. Real angle = GameLogicRandomValueReal( 0.0f, 2.0f * PI );
  256. // angle = TheTacticalView->getAngle();
  257. // angle -= GameLogicRandomValueReal( PI / 3.0f, 2.0f * (PI / 3.0F) );
  258. Real minRadius = theContainer->getGeometryInfo().getBoundingCircleRadius();
  259. Real maxRadius = minRadius + minRadius / 2.0f;
  260. const Coord3D *containerPos = theContainer->getPosition();
  261. Real dist = GameLogicRandomValueReal( minRadius, maxRadius );
  262. Coord3D pos;
  263. pos.x = dist * Cos( angle ) + containerPos->x;
  264. pos.y = dist * Sin( angle ) + containerPos->y;
  265. pos.z = TheTerrainLogic->getGroundHeight( pos.x, pos.y );
  266. // set orientation
  267. obj->setOrientation( angle );
  268. AIUpdateInterface *ai = obj->getAIUpdateInterface();
  269. if( ai )
  270. {
  271. // set position of the object at center of building and move them toward pos
  272. obj->setPosition( theContainer->getPosition() );
  273. ai->ignoreObstacle(theContainer);
  274. ai->aiMoveToPosition( &pos, CMD_FROM_AI );
  275. } // end if
  276. else
  277. {
  278. // no ai, just set position at the target pos
  279. obj->setPosition( &pos );
  280. } // end else
  281. }
  282. //-------------------------------------------------------------------------------------------------
  283. /** The die callback. */
  284. //-------------------------------------------------------------------------------------------------
  285. void TunnelContain::onDie( const DamageInfo * damageInfo )
  286. {
  287. // override the onDie we inherit from OpenContain. no super call.
  288. if (!getTunnelContainModuleData()->m_dieMuxData.isDieApplicable(getObject(), damageInfo))
  289. return;
  290. if( !m_isCurrentlyRegistered )
  291. return;//it isn't registered as a tunnel
  292. Player *owningPlayer = getObject()->getControllingPlayer();
  293. if( owningPlayer == NULL )
  294. return;
  295. TunnelTracker *tunnelTracker = owningPlayer->getTunnelSystem();
  296. if( tunnelTracker == NULL )
  297. return;
  298. tunnelTracker->onTunnelDestroyed( getObject() );
  299. m_isCurrentlyRegistered = FALSE;
  300. }
  301. //-------------------------------------------------------------------------------------------------
  302. void TunnelContain::onDelete( void )
  303. {
  304. // Being sold is a straight up delete. no death
  305. if( !m_isCurrentlyRegistered )
  306. return;//it isn't registered as a tunnel
  307. Player *owningPlayer = getObject()->getControllingPlayer();
  308. if( owningPlayer == NULL )
  309. return;
  310. TunnelTracker *tunnelTracker = owningPlayer->getTunnelSystem();
  311. if( tunnelTracker == NULL )
  312. return;
  313. tunnelTracker->onTunnelDestroyed( getObject() );
  314. m_isCurrentlyRegistered = FALSE;
  315. }
  316. //-------------------------------------------------------------------------------------------------
  317. void TunnelContain::onCreate( void )
  318. {
  319. }
  320. //-------------------------------------------------------------------------------------------------
  321. void TunnelContain::onObjectCreated()
  322. {
  323. //Kris: July 29, 2003
  324. //Added this function to support the sneak attack (which doesn't call onBuildComplete).
  325. if( ! shouldDoOnBuildComplete() )
  326. return;
  327. m_needToRunOnBuildComplete = false;
  328. Player *owningPlayer = getObject()->getControllingPlayer();
  329. if( owningPlayer == NULL )
  330. return;
  331. TunnelTracker *tunnelTracker = owningPlayer->getTunnelSystem();
  332. if( tunnelTracker == NULL )
  333. return;
  334. tunnelTracker->onTunnelCreated( getObject() );
  335. m_isCurrentlyRegistered = TRUE;
  336. }
  337. //-------------------------------------------------------------------------------------------------
  338. void TunnelContain::onBuildComplete( void )
  339. {
  340. //Kris: July 29, 2003
  341. //Obsolete -- onObjectCreated handles it before this function gets called.
  342. /*
  343. if( ! shouldDoOnBuildComplete() )
  344. return;
  345. m_needToRunOnBuildComplete = false;
  346. Player *owningPlayer = getObject()->getControllingPlayer();
  347. if( owningPlayer == NULL )
  348. return;
  349. TunnelTracker *tunnelTracker = owningPlayer->getTunnelSystem();
  350. if( tunnelTracker == NULL )
  351. return;
  352. tunnelTracker->onTunnelCreated( getObject() );
  353. m_isCurrentlyRegistered = TRUE;
  354. */
  355. }
  356. // ------------------------------------------------------------------------------------------------
  357. // ------------------------------------------------------------------------------------------------
  358. void TunnelContain::onCapture( Player *oldOwner, Player *newOwner )
  359. {
  360. if( m_isCurrentlyRegistered )
  361. {
  362. TunnelTracker *oldTunnelTracker = oldOwner->getTunnelSystem();
  363. if( oldTunnelTracker )
  364. {
  365. DEBUG_ASSERTCRASH( oldTunnelTracker->getContainCount() == 0, ("You shouldn't force a capture of a Tunnel with people in it. Future ExitFromContainer scripts will fail."));
  366. oldTunnelTracker->onTunnelDestroyed(getObject());
  367. }
  368. TunnelTracker *newTunnelTracker = newOwner->getTunnelSystem();
  369. if( newTunnelTracker )
  370. {
  371. newTunnelTracker->onTunnelCreated(getObject());
  372. }
  373. }
  374. // extend base class
  375. OpenContain::onCapture( oldOwner, newOwner );
  376. }
  377. // ------------------------------------------------------------------------------------------------
  378. /** Per frame update */
  379. // ------------------------------------------------------------------------------------------------
  380. UpdateSleepTime TunnelContain::update( void )
  381. {
  382. // extending functionality to heal the units within the tunnel system
  383. OpenContain::update();
  384. const TunnelContainModuleData *modData = getTunnelContainModuleData();
  385. Object *obj = getObject();
  386. Player *controllingPlayer = NULL;
  387. if (obj)
  388. {
  389. controllingPlayer = obj->getControllingPlayer();
  390. }
  391. if (controllingPlayer)
  392. {
  393. TunnelTracker *tunnelSystem = controllingPlayer->getTunnelSystem();
  394. if (tunnelSystem)
  395. {
  396. tunnelSystem->healObjects(modData->m_framesForFullHeal);
  397. }
  398. // check for attacked.
  399. BodyModuleInterface *body = obj->getBodyModule();
  400. if (body) {
  401. const DamageInfo *info = body->getLastDamageInfo();
  402. if (info) {
  403. if (body->getLastDamageTimestamp() + LOGICFRAMES_PER_SECOND > TheGameLogic->getFrame()) {
  404. // winner.
  405. ObjectID attackerID = info->in.m_sourceID;
  406. Object *attacker = TheGameLogic->findObjectByID(attackerID);
  407. if( attacker )
  408. {
  409. if (obj->getRelationship(attacker) == ENEMIES) {
  410. tunnelSystem->updateNemesis(attacker);
  411. }
  412. }
  413. }
  414. }
  415. }
  416. }
  417. return UPDATE_SLEEP_NONE;
  418. }
  419. // ------------------------------------------------------------------------------------------------
  420. /** CRC */
  421. // ------------------------------------------------------------------------------------------------
  422. void TunnelContain::crc( Xfer *xfer )
  423. {
  424. // extend base class
  425. OpenContain::crc( xfer );
  426. } // end crc
  427. // ------------------------------------------------------------------------------------------------
  428. /** Xfer method
  429. * Version Info:
  430. * 1: Initial version */
  431. // ------------------------------------------------------------------------------------------------
  432. void TunnelContain::xfer( Xfer *xfer )
  433. {
  434. // version
  435. XferVersion currentVersion = 1;
  436. XferVersion version = currentVersion;
  437. xfer->xferVersion( &version, currentVersion );
  438. // extend base class
  439. OpenContain::xfer( xfer );
  440. // need to run on build complete
  441. xfer->xferBool( &m_needToRunOnBuildComplete );
  442. // Currently registered with owning player
  443. xfer->xferBool( &m_isCurrentlyRegistered );
  444. } // end xfer
  445. // ------------------------------------------------------------------------------------------------
  446. /** Load post process */
  447. // ------------------------------------------------------------------------------------------------
  448. void TunnelContain::loadPostProcess( void )
  449. {
  450. // extend base class
  451. OpenContain::loadPostProcess();
  452. } // end loadPostProcess