HelixContain.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  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. ///////////////////////////////////////////////////////////////////////////////////////////////////
  24. //
  25. // FILE: HelixContain.cpp ////////////////////////////////////////////////////////////////////////
  26. // Author: Mark Lorenzen, April, 2003
  27. //
  28. // Desc:
  29. //
  30. ///////////////////////////////////////////////////////////////////////////////////////////////////
  31. // USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
  32. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  33. #include "Common/Player.h"
  34. #include "Common/Xfer.h"
  35. #include "Common/ThingTemplate.h"
  36. #include "Common/ThingFactory.h"
  37. #include "GameClient/ControlBar.h"
  38. #include "GameClient/Drawable.h"
  39. #include "GameLogic/Module/BodyModule.h"
  40. #include "GameLogic/Module/HelixContain.h"
  41. #include "GameLogic/Object.h"
  42. #include "GameLogic/PartitionManager.h"
  43. #include "GameLogic/GameLogic.h"
  44. #include "GameLogic/Weapon.h"
  45. #ifdef _INTERNAL
  46. // for occasional debugging...
  47. //#pragma optimize("", off)
  48. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  49. #endif
  50. // ------------------------------------------------------------------------------------------------
  51. // ------------------------------------------------------------------------------------------------
  52. HelixContainModuleData::HelixContainModuleData()
  53. {
  54. // m_initialPayload.count = 0;
  55. m_drawPips = TRUE;
  56. }
  57. // ------------------------------------------------------------------------------------------------
  58. // ------------------------------------------------------------------------------------------------
  59. void HelixContainModuleData::buildFieldParse(MultiIniFieldParse& p)
  60. {
  61. TransportContainModuleData::buildFieldParse(p);
  62. static const FieldParse dataFieldParse[] =
  63. {
  64. { "PayloadTemplateName", INI::parseAsciiStringVectorAppend, NULL, offsetof(HelixContainModuleData, m_payloadTemplateNameData) },
  65. {"ShouldDrawPips", INI::parseBool, NULL, offsetof(HelixContainModuleData, m_drawPips) },
  66. { 0, 0, 0, 0 }
  67. };
  68. p.add(dataFieldParse);
  69. }
  70. // ------------------------------------------------------------------------------------------------
  71. // ------------------------------------------------------------------------------------------------
  72. //void HelixContainModuleData::parseInitialPayload( INI* ini, void *instance, void *store, const void* /*userData*/ )
  73. //{
  74. // HelixContainModuleData* self = (HelixContainModuleData*)instance;
  75. // const char* name = ini->getNextToken();
  76. // const char* countStr = ini->getNextTokenOrNull();
  77. // Int count = countStr ? INI::scanInt(countStr) : 1;
  78. // self->m_initialPayload.name.set(name);
  79. // self->m_initialPayload.count = count;
  80. //}
  81. // ------------------------------------------------------------------------------------------------
  82. // ------------------------------------------------------------------------------------------------
  83. HelixContain::HelixContain( Thing *thing, const ModuleData *moduleData ) :
  84. TransportContain( thing, moduleData )
  85. {
  86. m_payloadCreated = FALSE;
  87. m_portableStructureID = INVALID_ID;
  88. }
  89. //-------------------------------------------------------------------------------------------------
  90. //-------------------------------------------------------------------------------------------------
  91. HelixContain::~HelixContain( void )
  92. {
  93. }
  94. void HelixContain::onObjectCreated( void )
  95. {
  96. HelixContain::createPayload();
  97. }
  98. // ------------------------------------------------------------------------------------------------
  99. // ------------------------------------------------------------------------------------------------
  100. UpdateSleepTime HelixContain::update()
  101. {
  102. Object *portable = getPortableStructure();
  103. if ( portable )
  104. {
  105. portable->setPosition( getObject()->getPosition());
  106. portable->setOrientation( getObject()->getOrientation());
  107. }
  108. return TransportContain::update(); // extend base
  109. }
  110. void HelixContain::redeployOccupants( void )
  111. {
  112. Coord3D firePos = *getObject()->getPosition();
  113. firePos.z += 8;
  114. for (ContainedItemsList::iterator it = m_containList.begin(); it != m_containList.end(); ++it)
  115. {
  116. Object* rider = *it;
  117. if (rider)
  118. rider->setPosition( &firePos );
  119. }
  120. }
  121. //-------------------------------------------------------------------------------------------------
  122. // ------------------------------------------------------------------------------------------------
  123. void HelixContain::createPayload()
  124. {
  125. HelixContainModuleData* self = (HelixContainModuleData*)getHelixContainModuleData();
  126. // Any number of different passengers can be loaded here at init time
  127. Object* object = getObject();
  128. ContainModuleInterface *contain = object->getContain();
  129. if( contain )
  130. {
  131. contain->enableLoadSounds( FALSE );
  132. TemplateNameList list = self->m_payloadTemplateNameData;
  133. TemplateNameIterator iter = list.begin();
  134. while ( iter != list.end() )
  135. {
  136. const ThingTemplate* temp = TheThingFactory->findTemplate( *iter );
  137. if (temp)
  138. {
  139. Object* payload = TheThingFactory->newObject( temp, object->getTeam() );
  140. if( contain->isValidContainerFor( payload, true ) )
  141. {
  142. contain->addToContain( payload );
  143. }
  144. else
  145. {
  146. DEBUG_CRASH( ( "HelixContain::createPayload: %s is full, or not valid for the payload %s!", object->getName().str(), self->m_initialPayload.name.str() ) );
  147. }
  148. }
  149. ++iter;
  150. }
  151. contain->enableLoadSounds( TRUE );
  152. } // endif contain
  153. m_payloadCreated = TRUE;
  154. }
  155. // ------------------------------------------------------------------------------------------------
  156. //-------------------------------------------------------------------------------------------------
  157. void HelixContain::onBodyDamageStateChange( const DamageInfo* damageInfo,
  158. BodyDamageType oldState,
  159. BodyDamageType newState) ///< state change callback
  160. {
  161. // Need to apply state change to the portable structure
  162. Object *portable = getPortableStructure();
  163. if ( newState != BODY_RUBBLE && portable )
  164. {
  165. portable->getBodyModule()->setDamageState( newState );
  166. }
  167. }
  168. //-------------------------------------------------------------------------------------------------
  169. //-------------------------------------------------------------------------------------------------
  170. Object* HelixContain::getPortableStructure( void )
  171. {
  172. return TheGameLogic->findObjectByID( m_portableStructureID );
  173. }
  174. //-------------------------------------------------------------------------------------------------
  175. void HelixContain::onDie( const DamageInfo *damageInfo )
  176. {
  177. Object *portable = getPortableStructure();
  178. if ( portable )
  179. portable->kill();
  180. TransportContain::onDie( damageInfo );//extend base class
  181. }
  182. //-------------------------------------------------------------------------------------------------
  183. void HelixContain::onDelete( void )
  184. {
  185. Object *portable = getPortableStructure();
  186. if ( portable )
  187. TheGameLogic->destroyObject( portable );
  188. TransportContain::onDelete( );
  189. }
  190. // ------------------------------------------------------------------------------------------------
  191. void HelixContain::onCapture( Player *oldOwner, Player *newOwner )
  192. {
  193. // Need to setteam() the portable structure, that's all;
  194. Object *portable = getPortableStructure();
  195. if ( portable )
  196. portable->setTeam( newOwner->getDefaultTeam() );
  197. }
  198. //-------------------------------------------------------------------------------------------------
  199. void HelixContain::addToContainList( Object *obj )
  200. {
  201. if ( obj->isKindOf( KINDOF_PORTABLE_STRUCTURE ) && m_portableStructureID == INVALID_ID)
  202. {
  203. Object *portable = getPortableStructure();
  204. if ( portable )
  205. TheGameLogic->destroyObject( portable );
  206. m_portableStructureID = obj->getID();
  207. obj->friend_setContainedBy( getObject() );//fool portable into thinking my object is his container
  208. }
  209. else
  210. TransportContain::addToContainList( obj );
  211. }
  212. //-------------------------------------------------------------------------------------------------
  213. void HelixContain::addToContain( Object *obj )
  214. {
  215. if ( obj->isKindOf( KINDOF_PORTABLE_STRUCTURE ) && m_portableStructureID == INVALID_ID)
  216. {
  217. Object *portable = getPortableStructure();
  218. if ( portable )
  219. TheGameLogic->destroyObject( portable );
  220. m_portableStructureID = obj->getID();
  221. obj->friend_setContainedBy( getObject() );//fool portable into thinking my object is his container
  222. }
  223. else
  224. TransportContain::addToContain( obj );
  225. }
  226. //-------------------------------------------------------------------------------------------------
  227. void HelixContain::removeFromContain( Object *obj, Bool exposeStealthUnits )
  228. {
  229. if ( obj->isKindOf( KINDOF_PORTABLE_STRUCTURE ) && obj->getID() == m_portableStructureID )
  230. {
  231. Object *portable = getPortableStructure();
  232. if ( portable )
  233. m_portableStructureID = INVALID_ID;
  234. //portable->kill();
  235. }
  236. else
  237. {
  238. TransportContain::removeFromContain( obj, exposeStealthUnits );
  239. }
  240. }
  241. //-------------------------------------------------------------------------------------------------
  242. Bool HelixContain::isValidContainerFor(const Object* obj, Bool checkCapacity) const
  243. {
  244. if ( obj->isKindOf( KINDOF_PORTABLE_STRUCTURE ) && INVALID_ID == m_portableStructureID )
  245. return TRUE;
  246. return TransportContain::isValidContainerFor( obj, checkCapacity );
  247. }
  248. //-------------------------------------------------------------------------------------------------
  249. const Object *HelixContain::friend_getRider() const
  250. {
  251. // The draw order dependency bug for riders means that our draw module needs to cheat to get around it.
  252. if ( m_portableStructureID != INVALID_ID )
  253. {
  254. const Object *portableAsRider = TheGameLogic->findObjectByID( m_portableStructureID );
  255. return portableAsRider;
  256. }
  257. return NULL;
  258. }
  259. //-------------------------------------------------------------------------------------------------
  260. Bool HelixContain::isEnclosingContainerFor( const Object *obj ) const
  261. {
  262. if ( m_portableStructureID == obj->getID() )
  263. {
  264. const Object *portableAsRider = TheGameLogic->findObjectByID( m_portableStructureID );
  265. if ( portableAsRider == obj )
  266. return FALSE;
  267. }
  268. return TransportContain::isEnclosingContainerFor( obj );
  269. }
  270. //-------------------------------------------------------------------------------------------------
  271. //-------------------------------------------------------------------------------------------------
  272. // if my object gets selected, then my visible passengers should, too
  273. // this gets called from
  274. void HelixContain::clientVisibleContainedFlashAsSelected()
  275. {
  276. if ( m_portableStructureID != INVALID_ID)
  277. {
  278. Object *portable = getPortableStructure();
  279. if ( portable && portable->isKindOf(KINDOF_PORTABLE_STRUCTURE) )
  280. {
  281. Drawable *draw = portable->getDrawable();
  282. if ( draw )
  283. {
  284. draw->flashAsSelected(); //WOW!
  285. }
  286. }
  287. }
  288. }
  289. Bool HelixContain::isPassengerAllowedToFire( ObjectID id ) const
  290. {
  291. // WHETHER WE ARE ALLOWED TO FIRE DEPENDS ON WHO WE ARE
  292. // PASSENGERS (PROPER) MAY ONLY IF THE FLAG IS TRUE
  293. // RIDERS ARE ALWAYS ALLOWED TO FIRE (GATTLING CANNONS)
  294. if ( getObject() && getObject()->getContainedBy() ) // nested containment voids firing, always
  295. return FALSE;
  296. if ( m_portableStructureID != INVALID_ID && m_portableStructureID == id )
  297. return TRUE;
  298. else
  299. {
  300. const Object *rider = TheGameLogic->findObjectByID( id );
  301. if ( rider && rider->isKindOf( KINDOF_INFANTRY ))
  302. return TransportContain::isPassengerAllowedToFire( id );//extend
  303. }
  304. return FALSE;
  305. }
  306. //-------------------------------------------------------------------------------------------------
  307. void HelixContain::onContaining( Object *obj, Bool wasSelected )
  308. {
  309. // extend base class
  310. TransportContain::onContaining( obj, wasSelected );
  311. // give the object a garrisoned version of its weapon
  312. obj->setWeaponBonusCondition( WEAPONBONUSCONDITION_GARRISONED );
  313. obj->setDisabled( DISABLED_HELD );
  314. if ( obj->isKindOf( KINDOF_PORTABLE_STRUCTURE ) && getObject()->testStatus( OBJECT_STATUS_STEALTHED ) )
  315. {
  316. StealthUpdate *myStealth = obj->getStealth();
  317. if ( myStealth )
  318. {
  319. myStealth->receiveGrant( true );
  320. // note to anyone... once stealth is granted to this gattlingcannon ( or such )
  321. // let its own stealthupdate govern the allowedtostealth cases
  322. // a portable structure never gets removed, so...
  323. }
  324. }
  325. } // end onContaining
  326. void HelixContain::onRemoving( Object *obj )
  327. {
  328. // extend base class
  329. TransportContain::onRemoving(obj);
  330. // give the object back a regular weapon
  331. obj->clearWeaponBonusCondition( WEAPONBONUSCONDITION_GARRISONED );
  332. obj->clearDisabled( DISABLED_HELD );
  333. } // end onRemoving
  334. // ------------------------------------------------------------------------------------------------
  335. /** CRC */
  336. // ------------------------------------------------------------------------------------------------
  337. void HelixContain::crc( Xfer *xfer )
  338. {
  339. // extend base class
  340. TransportContain::crc( xfer );
  341. } // end crc
  342. // ------------------------------------------------------------------------------------------------
  343. /** Xfer method
  344. * Version Info:
  345. * 1: Initial version */
  346. // ------------------------------------------------------------------------------------------------
  347. void HelixContain::xfer( Xfer *xfer )
  348. {
  349. // version
  350. XferVersion currentVersion = 2;
  351. XferVersion version = currentVersion;
  352. xfer->xferVersion( &version, currentVersion );
  353. if (version >= 2)
  354. xfer->xferObjectID( &m_portableStructureID );
  355. // extend base class
  356. TransportContain::xfer( xfer );
  357. } // end xfer
  358. // ------------------------------------------------------------------------------------------------
  359. /** Load post process */
  360. // ------------------------------------------------------------------------------------------------
  361. void HelixContain::loadPostProcess( void )
  362. {
  363. // extend base class
  364. TransportContain::loadPostProcess();
  365. } // end loadPostProcess