TunnelContain.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. /*
  2. ** Command & Conquer Generals(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. /** Remove all contained objects from the contained list */
  98. //-------------------------------------------------------------------------------------------------
  99. void TunnelContain::removeAllContained( Bool exposeStealthUnits )
  100. {
  101. Player *owningPlayer = getObject()->getControllingPlayer();
  102. const ContainedItemsList *fullList = owningPlayer->getTunnelSystem()->getContainedItemsList();
  103. Object *obj;
  104. ContainedItemsList::const_iterator it;
  105. it = (*fullList).begin();
  106. while( it != (*fullList).end() )
  107. {
  108. obj = *it;
  109. it++;
  110. removeFromContain( obj, exposeStealthUnits );
  111. }
  112. }
  113. //-------------------------------------------------------------------------------------------------
  114. /** Iterate the contained list and call the callback on each of the objects */
  115. //-------------------------------------------------------------------------------------------------
  116. void TunnelContain::iterateContained( ContainIterateFunc func, void *userData, Bool reverse )
  117. {
  118. Player *owningPlayer = getObject()->getControllingPlayer();
  119. owningPlayer->getTunnelSystem()->iterateContained( func, userData, reverse );
  120. }
  121. //-------------------------------------------------------------------------------------------------
  122. void TunnelContain::onContaining( Object *obj )
  123. {
  124. OpenContain::onContaining(obj);
  125. // objects inside a building are held
  126. obj->setDisabled( DISABLED_HELD );
  127. }
  128. //-------------------------------------------------------------------------------------------------
  129. void TunnelContain::onRemoving( Object *obj )
  130. {
  131. OpenContain::onRemoving(obj);
  132. // object is no longer held inside a garrisoned building
  133. obj->clearDisabled( DISABLED_HELD );
  134. /// place the object in the world at position of the container m_object
  135. ThePartitionManager->registerObject( obj );
  136. obj->setPosition( getObject()->getPosition() );
  137. if( obj->getDrawable() )
  138. {
  139. obj->setSafeOcclusionFrame(TheGameLogic->getFrame()+obj->getTemplate()->getOcclusionDelay());
  140. obj->getDrawable()->setDrawableHidden( false );
  141. }
  142. doUnloadSound();
  143. }
  144. //-------------------------------------------------------------------------------------------------
  145. void TunnelContain::onSelling()
  146. {
  147. // A TunnelContain tells everyone to leave if this is the last tunnel
  148. Player *owningPlayer = getObject()->getControllingPlayer();
  149. if( owningPlayer == NULL )
  150. return;
  151. TunnelTracker *tunnelTracker = owningPlayer->getTunnelSystem();
  152. if( tunnelTracker == NULL )
  153. return;
  154. // We are the last tunnel, so kick everyone out. This makes tunnels act like Palace and Bunker
  155. // rather than killing the occupants as if the last tunnel died.
  156. if( tunnelTracker->friend_getTunnelCount() == 1 )
  157. removeAllContained(FALSE);// Can't be order to exit, as I have no time to organize their exits.
  158. // If they don't go right now, I will delete them in a moment
  159. // Unregister after the kick out, or else the unregistering will activate a cavein-kill.
  160. // We need to do this in case someone sells their last two tunnels at the same time.
  161. if( m_isCurrentlyRegistered )
  162. {
  163. tunnelTracker->onTunnelDestroyed( getObject() );
  164. m_isCurrentlyRegistered = FALSE;
  165. }
  166. }
  167. //-------------------------------------------------------------------------------------------------
  168. Bool TunnelContain::isValidContainerFor(const Object* obj, Bool checkCapacity) const
  169. {
  170. Player *owningPlayer = getObject()->getControllingPlayer();
  171. return owningPlayer->getTunnelSystem()->isValidContainerFor( obj, checkCapacity );
  172. }
  173. UnsignedInt TunnelContain::getContainCount() const
  174. {
  175. Player *owningPlayer = getObject()->getControllingPlayer();
  176. if( owningPlayer && owningPlayer->getTunnelSystem() )
  177. {
  178. return owningPlayer->getTunnelSystem()->getContainCount();
  179. }
  180. return 0;
  181. }
  182. Int TunnelContain::getContainMax( void ) const
  183. {
  184. Player *owningPlayer = getObject()->getControllingPlayer();
  185. return owningPlayer->getTunnelSystem()->getContainMax();
  186. }
  187. const ContainedItemsList* TunnelContain::getContainedItemsList() const
  188. {
  189. Player *owningPlayer = getObject()->getControllingPlayer();
  190. return owningPlayer->getTunnelSystem()->getContainedItemsList();
  191. }
  192. ///////////////////////////////////////////////////////////////////////////////////////////////////
  193. // PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////////////////////
  194. ///////////////////////////////////////////////////////////////////////////////////////////////////
  195. //-------------------------------------------------------------------------------------------------
  196. void TunnelContain::scatterToNearbyPosition(Object* obj)
  197. {
  198. Object *theContainer = getObject();
  199. //
  200. // for now we will just set the position of the object that is being removed from us
  201. // at a random angle away from our center out some distance
  202. //
  203. //
  204. // pick an angle that is in the view of the current camera position so that
  205. // the thing will come out "toward" the player and they can see it
  206. // NOPE, can't do that ... all players screen angles will be different, unless
  207. // we maintain the angle of each players screen in the player structure or something
  208. //
  209. Real angle = GameLogicRandomValueReal( 0.0f, 2.0f * PI );
  210. // angle = TheTacticalView->getAngle();
  211. // angle -= GameLogicRandomValueReal( PI / 3.0f, 2.0f * (PI / 3.0F) );
  212. Real minRadius = theContainer->getGeometryInfo().getBoundingCircleRadius();
  213. Real maxRadius = minRadius + minRadius / 2.0f;
  214. const Coord3D *containerPos = theContainer->getPosition();
  215. Real dist = GameLogicRandomValueReal( minRadius, maxRadius );
  216. Coord3D pos;
  217. pos.x = dist * Cos( angle ) + containerPos->x;
  218. pos.y = dist * Sin( angle ) + containerPos->y;
  219. pos.z = TheTerrainLogic->getGroundHeight( pos.x, pos.y );
  220. // set orientation
  221. obj->setOrientation( angle );
  222. AIUpdateInterface *ai = obj->getAIUpdateInterface();
  223. if( ai )
  224. {
  225. // set position of the object at center of building and move them toward pos
  226. obj->setPosition( theContainer->getPosition() );
  227. ai->ignoreObstacle(theContainer);
  228. ai->aiMoveToPosition( &pos, CMD_FROM_AI );
  229. } // end if
  230. else
  231. {
  232. // no ai, just set position at the target pos
  233. obj->setPosition( &pos );
  234. } // end else
  235. }
  236. //-------------------------------------------------------------------------------------------------
  237. /** The die callback. */
  238. //-------------------------------------------------------------------------------------------------
  239. void TunnelContain::onDie( const DamageInfo * damageInfo )
  240. {
  241. // override the onDie we inherit from OpenContain. no super call.
  242. if (!getTunnelContainModuleData()->m_dieMuxData.isDieApplicable(getObject(), damageInfo))
  243. return;
  244. if( !m_isCurrentlyRegistered )
  245. return;//it isn't registered as a tunnel
  246. Player *owningPlayer = getObject()->getControllingPlayer();
  247. if( owningPlayer == NULL )
  248. return;
  249. TunnelTracker *tunnelTracker = owningPlayer->getTunnelSystem();
  250. if( tunnelTracker == NULL )
  251. return;
  252. tunnelTracker->onTunnelDestroyed( getObject() );
  253. m_isCurrentlyRegistered = FALSE;
  254. }
  255. //-------------------------------------------------------------------------------------------------
  256. void TunnelContain::onDelete( void )
  257. {
  258. // Being sold is a straight up delete. no death
  259. if( !m_isCurrentlyRegistered )
  260. return;//it isn't registered as a tunnel
  261. Player *owningPlayer = getObject()->getControllingPlayer();
  262. if( owningPlayer == NULL )
  263. return;
  264. TunnelTracker *tunnelTracker = owningPlayer->getTunnelSystem();
  265. if( tunnelTracker == NULL )
  266. return;
  267. tunnelTracker->onTunnelDestroyed( getObject() );
  268. m_isCurrentlyRegistered = FALSE;
  269. }
  270. //-------------------------------------------------------------------------------------------------
  271. void TunnelContain::onCreate( void )
  272. {
  273. }
  274. //-------------------------------------------------------------------------------------------------
  275. void TunnelContain::onBuildComplete( void )
  276. {
  277. if( ! shouldDoOnBuildComplete() )
  278. return;
  279. m_needToRunOnBuildComplete = false;
  280. Player *owningPlayer = getObject()->getControllingPlayer();
  281. if( owningPlayer == NULL )
  282. return;
  283. TunnelTracker *tunnelTracker = owningPlayer->getTunnelSystem();
  284. if( tunnelTracker == NULL )
  285. return;
  286. tunnelTracker->onTunnelCreated( getObject() );
  287. m_isCurrentlyRegistered = TRUE;
  288. }
  289. // ------------------------------------------------------------------------------------------------
  290. /** Per frame update */
  291. // ------------------------------------------------------------------------------------------------
  292. UpdateSleepTime TunnelContain::update( void )
  293. {
  294. // extending functionality to heal the units within the tunnel system
  295. OpenContain::update();
  296. const TunnelContainModuleData *modData = getTunnelContainModuleData();
  297. Object *obj = getObject();
  298. Player *controllingPlayer = NULL;
  299. if (obj)
  300. {
  301. controllingPlayer = obj->getControllingPlayer();
  302. }
  303. if (controllingPlayer)
  304. {
  305. TunnelTracker *tunnelSystem = controllingPlayer->getTunnelSystem();
  306. if (tunnelSystem)
  307. {
  308. tunnelSystem->healObjects(modData->m_framesForFullHeal);
  309. }
  310. // check for attacked.
  311. BodyModuleInterface *body = obj->getBodyModule();
  312. if (body) {
  313. const DamageInfo *info = body->getLastDamageInfo();
  314. if (info) {
  315. if (body->getLastDamageTimestamp() + LOGICFRAMES_PER_SECOND > TheGameLogic->getFrame()) {
  316. // winner.
  317. ObjectID attackerID = info->in.m_sourceID;
  318. Object *attacker = TheGameLogic->findObjectByID(attackerID);
  319. if( attacker )
  320. {
  321. if (obj->getRelationship(attacker) == ENEMIES) {
  322. tunnelSystem->updateNemesis(attacker);
  323. }
  324. }
  325. }
  326. }
  327. }
  328. }
  329. return UPDATE_SLEEP_NONE;
  330. }
  331. // ------------------------------------------------------------------------------------------------
  332. /** CRC */
  333. // ------------------------------------------------------------------------------------------------
  334. void TunnelContain::crc( Xfer *xfer )
  335. {
  336. // extend base class
  337. OpenContain::crc( xfer );
  338. } // end crc
  339. // ------------------------------------------------------------------------------------------------
  340. /** Xfer method
  341. * Version Info:
  342. * 1: Initial version */
  343. // ------------------------------------------------------------------------------------------------
  344. void TunnelContain::xfer( Xfer *xfer )
  345. {
  346. // version
  347. XferVersion currentVersion = 1;
  348. XferVersion version = currentVersion;
  349. xfer->xferVersion( &version, currentVersion );
  350. // extend base class
  351. OpenContain::xfer( xfer );
  352. // need to run on build complete
  353. xfer->xferBool( &m_needToRunOnBuildComplete );
  354. // Currently registered with owning player
  355. xfer->xferBool( &m_isCurrentlyRegistered );
  356. } // end xfer
  357. // ------------------------------------------------------------------------------------------------
  358. /** Load post process */
  359. // ------------------------------------------------------------------------------------------------
  360. void TunnelContain::loadPostProcess( void )
  361. {
  362. // extend base class
  363. OpenContain::loadPostProcess();
  364. } // end loadPostProcess