CaveContain.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  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: CaveContain.cpp ////////////////////////////////////////////////////////////////////////////
  24. // Author: Graham Smallwood, July 2002
  25. // Desc: A version of OpenContain that overrides where the passengers are stored: one of CaveSystem's
  26. // entries. Changing entry is a script or ini command. All queries about capacity and
  27. // contents are also redirected. They change sides like Garrison too.
  28. ///////////////////////////////////////////////////////////////////////////////////////////////////
  29. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  30. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  31. #include "Common/GameState.h"
  32. #include "Common/Player.h"
  33. #include "Common/PlayerList.h"
  34. #include "Common/Team.h"
  35. #include "Common/ThingTemplate.h"
  36. #include "Common/TunnelTracker.h"
  37. #include "Common/Xfer.h"
  38. #include "GameClient/Drawable.h"
  39. #include "GameLogic/Module/AIUpdate.h"
  40. #include "GameLogic/Module/CaveContain.h"
  41. #include "GameLogic/CaveSystem.h"
  42. #include "GameLogic/Object.h"
  43. #include "GameLogic/PartitionManager.h"
  44. ///////////////////////////////////////////////////////////////////////////////////////////////////
  45. // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
  46. ///////////////////////////////////////////////////////////////////////////////////////////////////
  47. //-------------------------------------------------------------------------------------------------
  48. //-------------------------------------------------------------------------------------------------
  49. CaveContain::CaveContain( Thing *thing, const ModuleData* moduleData ) : OpenContain( thing, moduleData )
  50. {
  51. m_needToRunOnBuildComplete = true;
  52. m_caveIndex = 0;
  53. m_originalTeam = NULL;
  54. }
  55. //-------------------------------------------------------------------------------------------------
  56. //-------------------------------------------------------------------------------------------------
  57. CaveContain::~CaveContain()
  58. {
  59. }
  60. void CaveContain::addToContainList( Object *obj )
  61. {
  62. TunnelTracker *myTracker = TheCaveSystem->getTunnelTrackerForCaveIndex( m_caveIndex );
  63. myTracker->addToContainList( obj );
  64. }
  65. //-------------------------------------------------------------------------------------------------
  66. /** Remove 'obj' from the m_containList of objects in this module.
  67. * This will trigger an onRemoving event for the object that this module
  68. * is a part of and an onRemovedFrom event for the object being removed */
  69. //-------------------------------------------------------------------------------------------------
  70. void CaveContain::removeFromContain( Object *obj, Bool exposeStealthUnits )
  71. {
  72. // sanity
  73. if( obj == NULL )
  74. return;
  75. //
  76. // we can only remove this object from the contains list of this module if
  77. // it is actually contained by this module
  78. //
  79. TunnelTracker *myTracker = TheCaveSystem->getTunnelTrackerForCaveIndex( m_caveIndex );
  80. if( ! myTracker->isInContainer( obj ) )
  81. {
  82. return;
  83. }
  84. // This must come before the onRemov*, because CaveContain's version has a edge-0 triggered event.
  85. // If that were to go first, the number would still be 1 at that time. Noone else cares about
  86. // order.
  87. myTracker->removeFromContain( obj, exposeStealthUnits );
  88. // trigger an onRemoving event for 'm_object' no longer containing 'itemToRemove->m_object'
  89. if (getObject()->getContain())
  90. getObject()->getContain()->onRemoving( obj );
  91. // trigger an onRemovedFrom event for 'remove'
  92. obj->onRemovedFrom( getObject() );
  93. }
  94. //-------------------------------------------------------------------------------------------------
  95. /** Remove all contained objects from the contained list */
  96. //-------------------------------------------------------------------------------------------------
  97. void CaveContain::removeAllContained( Bool exposeStealthUnits )
  98. {
  99. TunnelTracker *myTracker = TheCaveSystem->getTunnelTrackerForCaveIndex( m_caveIndex );
  100. const ContainedItemsList *fullList = myTracker->getContainedItemsList();
  101. Object *obj;
  102. ContainedItemsList::const_iterator it;
  103. it = (*fullList).begin();
  104. while( it != (*fullList).end() )
  105. {
  106. obj = *it;
  107. it++;
  108. removeFromContain( obj, exposeStealthUnits );
  109. }
  110. }
  111. //-------------------------------------------------------------------------------------------------
  112. /** Iterate the contained list and call the callback on each of the objects */
  113. //-------------------------------------------------------------------------------------------------
  114. void CaveContain::iterateContained( ContainIterateFunc func, void *userData, Bool reverse )
  115. {
  116. TunnelTracker *myTracker = TheCaveSystem->getTunnelTrackerForCaveIndex( m_caveIndex );
  117. myTracker->iterateContained( func, userData, reverse );
  118. }
  119. //-------------------------------------------------------------------------------------------------
  120. void CaveContain::onContaining( Object *obj )
  121. {
  122. OpenContain::onContaining(obj);
  123. // objects inside a building are held
  124. obj->setDisabled( DISABLED_HELD );
  125. //
  126. // the team of the building is now the same as those that have garrisoned it, be sure
  127. // to save our original team tho so that we can revert back to it when all the
  128. // occupants are gone
  129. //
  130. recalcApparentControllingPlayer();
  131. }
  132. //-------------------------------------------------------------------------------------------------
  133. void CaveContain::onRemoving( Object *obj )
  134. {
  135. OpenContain::onRemoving(obj);
  136. // object is no longer held inside a garrisoned building
  137. obj->clearDisabled( DISABLED_HELD );
  138. /// place the object in the world at position of the container m_object
  139. ThePartitionManager->registerObject( obj );
  140. obj->setPosition( getObject()->getPosition() );
  141. if( obj->getDrawable() )
  142. {
  143. obj->getDrawable()->setDrawableHidden( false );
  144. }
  145. doUnloadSound();
  146. if( getContainCount() == 0 )
  147. {
  148. // put us back on our original team
  149. // (hokey exception: if our team is null, don't bother -- this
  150. // usually means we are being called during game-teardown and
  151. // the teams are no longer valid...)
  152. if (getObject()->getTeam() != NULL)
  153. {
  154. changeTeamOnAllConnectedCaves( m_originalTeam, FALSE );
  155. m_originalTeam = NULL;
  156. }
  157. // change the state back from garrisoned
  158. Drawable *draw = getObject()->getDrawable();
  159. if( draw )
  160. {
  161. draw->clearModelConditionState( MODELCONDITION_GARRISONED );
  162. }
  163. } // end if
  164. }
  165. Bool CaveContain::isValidContainerFor(const Object* obj, Bool checkCapacity) const
  166. {
  167. TunnelTracker *myTracker = TheCaveSystem->getTunnelTrackerForCaveIndex( m_caveIndex );
  168. return myTracker->isValidContainerFor( obj, checkCapacity );
  169. }
  170. UnsignedInt CaveContain::getContainCount() const
  171. {
  172. TunnelTracker *myTracker = TheCaveSystem->getTunnelTrackerForCaveIndex( m_caveIndex );
  173. return myTracker->getContainCount();
  174. }
  175. Int CaveContain::getContainMax( void ) const
  176. {
  177. TunnelTracker *myTracker = TheCaveSystem->getTunnelTrackerForCaveIndex( m_caveIndex );
  178. return myTracker->getContainMax();
  179. }
  180. const ContainedItemsList* CaveContain::getContainedItemsList() const
  181. {
  182. TunnelTracker *myTracker = TheCaveSystem->getTunnelTrackerForCaveIndex( m_caveIndex );
  183. return myTracker->getContainedItemsList();
  184. }
  185. //-------------------------------------------------------------------------------------------------
  186. /** The die callback. */
  187. //-------------------------------------------------------------------------------------------------
  188. void CaveContain::onDie( const DamageInfo * damageInfo )
  189. {
  190. // override the onDie we inherit from OpenContain. no super call.
  191. if (!getCaveContainModuleData()->m_dieMuxData.isDieApplicable(getObject(), damageInfo))
  192. return;
  193. if( BitTest( getObject()->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION ) )
  194. return;//it never registered itself as a tunnel
  195. TunnelTracker *myTracker = TheCaveSystem->getTunnelTrackerForCaveIndex( m_caveIndex );
  196. TheCaveSystem->unregisterCave( m_caveIndex );
  197. myTracker->onTunnelDestroyed( getObject() );
  198. }
  199. //-------------------------------------------------------------------------------------------------
  200. void CaveContain::onCreate( void )
  201. {
  202. m_caveIndex = getCaveContainModuleData()->m_caveIndexData;
  203. }
  204. //-------------------------------------------------------------------------------------------------
  205. void CaveContain::onBuildComplete( void )
  206. {
  207. if( ! shouldDoOnBuildComplete() )
  208. return;
  209. m_needToRunOnBuildComplete = false;
  210. TheCaveSystem->registerNewCave( m_caveIndex );
  211. TunnelTracker *myTracker = TheCaveSystem->getTunnelTrackerForCaveIndex( m_caveIndex );
  212. myTracker->onTunnelCreated( getObject() );
  213. }
  214. //-------------------------------------------------------------------------------------------------
  215. void CaveContain::tryToSetCaveIndex( Int newIndex )
  216. {
  217. if( TheCaveSystem->canSwitchIndexToIndex( m_caveIndex, newIndex ) )
  218. {
  219. TunnelTracker *myOldTracker = TheCaveSystem->getTunnelTrackerForCaveIndex( m_caveIndex );
  220. TheCaveSystem->unregisterCave( m_caveIndex );
  221. myOldTracker->onTunnelDestroyed( getObject() );
  222. m_caveIndex = newIndex;
  223. TheCaveSystem->registerNewCave( m_caveIndex );
  224. TunnelTracker *myNewTracker = TheCaveSystem->getTunnelTrackerForCaveIndex( m_caveIndex );
  225. myNewTracker->onTunnelCreated( getObject() );
  226. }
  227. }
  228. //-------------------------------------------------------------------------------------------------
  229. //-------------------------------------------------------------------------------------------------
  230. void CaveContain::recalcApparentControllingPlayer( void )
  231. {
  232. //Record original team first time through.
  233. if( m_originalTeam == NULL )
  234. {
  235. m_originalTeam = getObject()->getTeam();
  236. }
  237. // (hokey trick: if our team is null, nuke originalTeam -- this
  238. // usually means we are being called during game-teardown and
  239. // the teams are no longer valid...)
  240. if (getObject()->getTeam() == NULL)
  241. m_originalTeam = NULL;
  242. // This is called from onContaining, so a one is the edge trigger to do capture stuff
  243. if( getContainCount() == 1 )
  244. {
  245. ContainedItemsList::const_iterator it = getContainedItemsList()->begin();
  246. Object *rider = *it;
  247. // This also gets called during reset from the PlayerList, so we might not actually have players.
  248. // Check like the hokey trick mentioned above
  249. if( rider->getControllingPlayer() )
  250. changeTeamOnAllConnectedCaves( rider->getControllingPlayer()->getDefaultTeam(), TRUE );
  251. }
  252. else if( getContainCount() == 0 )
  253. {
  254. // And a 0 is the edge trigger to do uncapture stuff
  255. changeTeamOnAllConnectedCaves( m_originalTeam, FALSE );
  256. }
  257. // Handle the team color that is rendered
  258. const Player* controller = getApparentControllingPlayer(ThePlayerList->getLocalPlayer());
  259. if (controller)
  260. {
  261. if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT)
  262. getObject()->getDrawable()->setIndicatorColor( controller->getPlayerNightColor() );
  263. else
  264. getObject()->getDrawable()->setIndicatorColor( controller->getPlayerColor() );
  265. }
  266. }
  267. /////////////////////////////////////////////////////////////////////////////////////
  268. static CaveInterface* findCave(Object* obj)
  269. {
  270. for (BehaviorModule** i = obj->getBehaviorModules(); *i; ++i)
  271. {
  272. CaveInterface* c = (*i)->getCaveInterface();
  273. if (c != NULL)
  274. return c;
  275. }
  276. return NULL;
  277. }
  278. /////////////////////////////////////////////////////////////////////////////////////
  279. void CaveContain::changeTeamOnAllConnectedCaves( Team *newTeam, Bool setOriginalTeams )
  280. {
  281. TunnelTracker *myTracker = TheCaveSystem->getTunnelTrackerForCaveIndex( m_caveIndex );
  282. const std::list<ObjectID> *allCaves = myTracker->getContainerList();
  283. for( std::list<ObjectID>::const_iterator iter = allCaves->begin(); iter != allCaves->end(); iter++ )
  284. {
  285. // For each ID, look it up and change its team. We all get captured together.
  286. Object *currentCave = TheGameLogic->findObjectByID( *iter );
  287. if( currentCave )
  288. {
  289. // This is a distributed Garrison in terms of capturing, so when one node
  290. // triggers the change, he needs to tell everyone, so anyone can do the un-change.
  291. CaveInterface *caveModule = findCave(currentCave);
  292. if( caveModule == NULL )
  293. continue;
  294. if( setOriginalTeams )
  295. caveModule->setOriginalTeam( currentCave->getTeam() );
  296. else
  297. caveModule->setOriginalTeam( NULL );
  298. // Now do the actual switch for this one.
  299. currentCave->defect( newTeam, 0 );
  300. // currentCave->setTeam( newTeam );
  301. }
  302. }
  303. }
  304. /////////////////////////////////////////////////////////////////////////////////////
  305. void CaveContain::setOriginalTeam( Team *oldTeam )
  306. {
  307. m_originalTeam = oldTeam;
  308. }
  309. // ------------------------------------------------------------------------------------------------
  310. /** CRC */
  311. // ------------------------------------------------------------------------------------------------
  312. void CaveContain::crc( Xfer *xfer )
  313. {
  314. // extend base class
  315. OpenContain::crc( xfer );
  316. } // end crc
  317. // ------------------------------------------------------------------------------------------------
  318. /** Xfer method
  319. * Version Info:
  320. * 1: Initial version */
  321. // ------------------------------------------------------------------------------------------------
  322. void CaveContain::xfer( Xfer *xfer )
  323. {
  324. // version
  325. XferVersion currentVersion = 1;
  326. XferVersion version = currentVersion;
  327. xfer->xferVersion( &version, currentVersion );
  328. // extend base class
  329. OpenContain::xfer( xfer );
  330. // need to run on build complete
  331. xfer->xferBool( &m_needToRunOnBuildComplete );
  332. // cave index
  333. xfer->xferInt( &m_caveIndex );
  334. // original team
  335. TeamID teamID = m_originalTeam ? m_originalTeam->getID() : TEAM_ID_INVALID;
  336. xfer->xferUser( &teamID, sizeof( TeamID ) );
  337. if( xfer->getXferMode() == XFER_LOAD )
  338. {
  339. if( teamID != TEAM_ID_INVALID )
  340. {
  341. m_originalTeam = TheTeamFactory->findTeamByID( teamID );
  342. if( m_originalTeam == NULL )
  343. {
  344. DEBUG_CRASH(( "CaveContain::xfer - Unable to find original team by id\n" ));
  345. throw SC_INVALID_DATA;
  346. } // end if
  347. } // end if
  348. else
  349. m_originalTeam = NULL;
  350. } // end if
  351. } // end xfer
  352. // ------------------------------------------------------------------------------------------------
  353. /** Load post process */
  354. // ------------------------------------------------------------------------------------------------
  355. void CaveContain::loadPostProcess( void )
  356. {
  357. // extend base class
  358. OpenContain::loadPostProcess();
  359. } // end loadPostProcess