PrisonBehavior.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  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: PrisonBehavior.cpp ///////////////////////////////////////////////////////////////////////
  24. // Author: Colin Day, August 2002
  25. // Desc: Prison Behavior
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  28. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  29. #include "Common/GameState.h"
  30. #include "Common/Player.h"
  31. #include "Common/RandomValue.h"
  32. #include "Common/ThingFactory.h"
  33. #include "Common/Xfer.h"
  34. #include "GameClient/Drawable.h"
  35. #include "GameClient/InGameUI.h"
  36. #include "GameClient/GameClient.h"
  37. #include "GameClient/Line2D.h"
  38. #include "GameLogic/Object.h"
  39. #include "GameLogic/Module/PrisonBehavior.h"
  40. #ifdef ALLOW_SURRENDER
  41. ///////////////////////////////////////////////////////////////////////////////////////////////////
  42. ///////////////////////////////////////////////////////////////////////////////////////////////////
  43. ///////////////////////////////////////////////////////////////////////////////////////////////////
  44. // ------------------------------------------------------------------------------------------------
  45. // ------------------------------------------------------------------------------------------------
  46. class PrisonVisual : public MemoryPoolObject
  47. {
  48. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( PrisonVisual, "PrisonVisual" )
  49. public:
  50. PrisonVisual( void );
  51. // virtual destructor prototype provied by memory pool object
  52. ObjectID m_objectID; ///< object that is contained
  53. DrawableID m_drawableID; ///< associated visual prisoner drawable
  54. PrisonVisual *m_next; ///< next
  55. };
  56. // ------------------------------------------------------------------------------------------------
  57. // ------------------------------------------------------------------------------------------------
  58. PrisonVisual::PrisonVisual( void )
  59. {
  60. m_objectID = INVALID_ID;
  61. m_drawableID = INVALID_DRAWABLE_ID;
  62. m_next = NULL;
  63. } // end PrisonVisual
  64. // ------------------------------------------------------------------------------------------------
  65. // ------------------------------------------------------------------------------------------------
  66. PrisonVisual::~PrisonVisual( void )
  67. {
  68. } // end ~PrisonVisual
  69. ///////////////////////////////////////////////////////////////////////////////////////////////////
  70. ///////////////////////////////////////////////////////////////////////////////////////////////////
  71. ///////////////////////////////////////////////////////////////////////////////////////////////////
  72. // ------------------------------------------------------------------------------------------------
  73. // ------------------------------------------------------------------------------------------------
  74. PrisonBehaviorModuleData::PrisonBehaviorModuleData( void )
  75. {
  76. m_showPrisoners = FALSE;
  77. } // end PrisonBehaviorModuleData
  78. // ------------------------------------------------------------------------------------------------
  79. // ------------------------------------------------------------------------------------------------
  80. /*static*/ void PrisonBehaviorModuleData::buildFieldParse( MultiIniFieldParse &p )
  81. {
  82. OpenContainModuleData::buildFieldParse( p );
  83. static const FieldParse dataFieldParse[] =
  84. {
  85. { "ShowPrisoners", INI::parseBool, NULL, offsetof( PrisonBehaviorModuleData, m_showPrisoners ) },
  86. { "YardBonePrefix", INI::parseAsciiString, NULL, offsetof( PrisonBehaviorModuleData, m_prisonYardBonePrefix ) },
  87. { 0, 0, 0, 0 }
  88. };
  89. p.add( dataFieldParse );
  90. } // end buildFieldParse
  91. ///////////////////////////////////////////////////////////////////////////////////////////////////
  92. ///////////////////////////////////////////////////////////////////////////////////////////////////
  93. ///////////////////////////////////////////////////////////////////////////////////////////////////
  94. // ------------------------------------------------------------------------------------------------
  95. // ------------------------------------------------------------------------------------------------
  96. PrisonBehavior::PrisonBehavior( Thing *thing, const ModuleData *moduleData )
  97. : OpenContain( thing, moduleData )
  98. {
  99. m_visualList = NULL;
  100. } // end PrisonBehavior
  101. // ------------------------------------------------------------------------------------------------
  102. // ------------------------------------------------------------------------------------------------
  103. PrisonBehavior::~PrisonBehavior( void )
  104. {
  105. } // end ~PrisonBehavior
  106. // ------------------------------------------------------------------------------------------------
  107. // ------------------------------------------------------------------------------------------------
  108. void PrisonBehavior::onDelete( void )
  109. {
  110. // extend functionality
  111. OpenContain::onDelete();
  112. // delete our list
  113. Drawable *draw;
  114. PrisonVisual *visual;
  115. while( m_visualList )
  116. {
  117. // delete drawable if found
  118. draw = TheGameClient->findDrawableByID( m_visualList->m_drawableID );
  119. if( draw )
  120. TheGameClient->destroyDrawable( draw );
  121. // delete element and set next to head
  122. visual = m_visualList->m_next;
  123. m_visualList->deleteInstance();
  124. m_visualList = visual;
  125. } // end while
  126. } // end onDelete
  127. // ------------------------------------------------------------------------------------------------
  128. // ------------------------------------------------------------------------------------------------
  129. void PrisonBehavior::onContaining( Object *obj )
  130. {
  131. // extend functionality
  132. OpenContain::onContaining( obj );
  133. // objects inside a prison are held
  134. obj->setDisabled( DISABLED_HELD );
  135. // if we show visuals, make one
  136. const PrisonBehaviorModuleData *modData = getPrisonBehaviorModuleData();
  137. if( modData->m_showPrisoners )
  138. addVisual( obj );
  139. } // end onContaining
  140. // ------------------------------------------------------------------------------------------------
  141. // ------------------------------------------------------------------------------------------------
  142. void PrisonBehavior::onRemoving( Object *obj )
  143. {
  144. // if we show visuals, remove one
  145. const PrisonBehaviorModuleData *modData = getPrisonBehaviorModuleData();
  146. if( modData->m_showPrisoners )
  147. removeVisual( obj );
  148. // object is no longer held inside a garrisoned building
  149. obj->clearDisabled( DISABLED_HELD );
  150. // extend functionality
  151. OpenContain::onRemoving( obj );
  152. } // end onRemoving
  153. ///////////////////////////////////////////////////////////////////////////////////////////////////
  154. // PRIVATE ////////////////////////////////////////////////////////////////////////////////////////
  155. ///////////////////////////////////////////////////////////////////////////////////////////////////
  156. // ------------------------------------------------------------------------------------------------
  157. /** Pick a random location inside the prison yard */
  158. // ------------------------------------------------------------------------------------------------
  159. void PrisonBehavior::pickVisualLocation( Coord3D *pos )
  160. {
  161. Object *us = getObject();
  162. const PrisonBehaviorModuleData *modData = getPrisonBehaviorModuleData();
  163. Int i;
  164. // sanity
  165. if( pos == NULL )
  166. return;
  167. // initialize the picked location to that of the prison center
  168. Coord3D pickedLocation = *us->getPosition();
  169. // get the positions of the bones that make up the prison yard area
  170. const Int MAX_YARD_BONES = 16;
  171. Coord3D yardPositions[ MAX_YARD_BONES ];
  172. Int yardBones = us->getMultiLogicalBonePosition( modData->m_prisonYardBonePrefix.str(),
  173. MAX_YARD_BONES,
  174. yardPositions,
  175. NULL );
  176. //
  177. // we must have at least 3 bone locations to make a yard polygon, otherwise we'll
  178. // default to the object position
  179. //
  180. if( yardBones >= 3 )
  181. {
  182. // find the bounding region of the yard area
  183. Region2D yardRegion;
  184. yardRegion.lo.x = yardPositions[ 0 ].x;
  185. yardRegion.lo.y = yardPositions[ 0 ].y;
  186. yardRegion.hi.x = yardPositions[ 0 ].x;
  187. yardRegion.hi.y = yardPositions[ 0 ].y;
  188. for( i = 1; i < yardBones; i++ )
  189. {
  190. if( yardPositions[ i ].x < yardRegion.lo.x )
  191. yardRegion.lo.x = yardPositions[ i ].x;
  192. if( yardPositions[ i ].y < yardRegion.lo.y )
  193. yardRegion.lo.y = yardPositions[ i ].y;
  194. if( yardPositions[ i ].x > yardRegion.hi.x )
  195. yardRegion.hi.x = yardPositions[ i ].x;
  196. if( yardPositions[ i ].y > yardRegion.hi.y )
  197. yardRegion.hi.y = yardPositions[ i ].y;
  198. } // end for i
  199. //
  200. // now that we have a yard region, the default visual position will be in the middle
  201. // of the yard region instead of the position of our object
  202. //
  203. pickedLocation.x = yardRegion.lo.x + yardRegion.width() / 2.0f;
  204. pickedLocation.y = yardRegion.lo.y + yardRegion.height() / 2.0f;
  205. // NOTE: pickedLocation.z is left alone at the object center Z
  206. // loop till we find a valid location that is inside the yard area
  207. Int maxTries = 32;
  208. Coord3D loc;
  209. for( i = 0; i < maxTries; ++i )
  210. {
  211. // pick a location
  212. loc.x = GameLogicRandomValueReal( yardRegion.lo.x, yardRegion.hi.x );
  213. loc.y = GameLogicRandomValueReal( yardRegion.lo.y, yardRegion.hi.y );
  214. loc.z = pickedLocation.z;
  215. // must be inside the yard polygon
  216. if( PointInsideArea2D( &loc, yardPositions, yardBones ) == TRUE )
  217. {
  218. // use this location, leave Z alone as the center of the prison
  219. pickedLocation = loc;
  220. break; // exit for i
  221. } // end if
  222. } // end for i
  223. } // end if
  224. // return the location picked
  225. *pos = pickedLocation;
  226. } // end pickVisualLocation
  227. // ------------------------------------------------------------------------------------------------
  228. /** Add prisoner visual to the prison yard */
  229. // ------------------------------------------------------------------------------------------------
  230. void PrisonBehavior::addVisual( Object *obj )
  231. {
  232. // sanity
  233. if( obj == NULL )
  234. return;
  235. // create a drawable
  236. Drawable *draw = TheThingFactory->newDrawable( obj->getTemplate() );
  237. // set the color of the drawable to that of the object
  238. if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT)
  239. draw->setIndicatorColor( obj->getNightIndicatorColor() );
  240. else
  241. draw->setIndicatorColor( obj->getIndicatorColor() );
  242. // pick a location insid the prison yard
  243. Coord3D pos;
  244. pickVisualLocation( &pos );
  245. // place drawable withing the prison yard area
  246. draw->setPosition( &pos );
  247. draw->setOrientation( GameLogicRandomValueReal( 0, TWO_PI ) );
  248. DrawableInfo *drawInfo=draw->getDrawableInfo();
  249. drawInfo->m_shroudStatusObjectID=getObject()->getID();
  250. // record this object/drawable pair
  251. PrisonVisual *visual = newInstance(PrisonVisual);
  252. visual->m_objectID = obj->getID();
  253. visual->m_drawableID = draw->getID();
  254. visual->m_next = m_visualList;
  255. m_visualList = visual;
  256. } // end addVisual
  257. // ------------------------------------------------------------------------------------------------
  258. /** Remove prisoner visual from the prison yard */
  259. // ------------------------------------------------------------------------------------------------
  260. void PrisonBehavior::removeVisual( Object *obj )
  261. {
  262. // sanity
  263. if( obj == NULL )
  264. return;
  265. // initialize a drawable ID to invalid
  266. DrawableID drawableID = INVALID_DRAWABLE_ID;
  267. // find visual info in our list, once found, take this opportunity to remove it from that list
  268. PrisonVisual *visual, *prevVisual = NULL;
  269. for( visual = m_visualList; visual; visual = visual->m_next )
  270. {
  271. // is this the one we're looking for
  272. if( visual->m_objectID == obj->getID() )
  273. {
  274. // record the information we need here
  275. drawableID = visual->m_drawableID;
  276. // remove from list
  277. if( prevVisual )
  278. prevVisual->m_next = visual->m_next;
  279. else
  280. m_visualList = visual->m_next;
  281. // delete the element
  282. visual->deleteInstance();
  283. break; // exit for
  284. } // end if
  285. // keep a pointer to the previous element
  286. prevVisual = visual;
  287. } // end for
  288. // find the drawable visual and destroy it
  289. Drawable *draw = TheGameClient->findDrawableByID( drawableID );
  290. if( draw )
  291. TheGameClient->destroyDrawable( draw );
  292. } // end removeVisual
  293. // ------------------------------------------------------------------------------------------------
  294. /** CRC */
  295. // ------------------------------------------------------------------------------------------------
  296. void PrisonBehavior::crc( Xfer *xfer )
  297. {
  298. // extend base class
  299. OpenContain::crc( xfer );
  300. } // end crc
  301. // ------------------------------------------------------------------------------------------------
  302. /** Xfer method
  303. * Version Info:
  304. * 1: Initial version */
  305. // ------------------------------------------------------------------------------------------------
  306. void PrisonBehavior::xfer( Xfer *xfer )
  307. {
  308. // version
  309. XferVersion currentVersion = 1;
  310. XferVersion version = currentVersion;
  311. xfer->xferVersion( &version, currentVersion );
  312. // extend base class
  313. OpenContain::xfer( xfer );
  314. // count and data for the prison visuals
  315. UnsignedShort visualCount = 0;
  316. PrisonVisual *visual;
  317. for( visual = m_visualList; visual; visual = visual->m_next )
  318. visualCount++;
  319. xfer->xferUnsignedShort( &visualCount );
  320. if( xfer->getXferMode() == XFER_SAVE )
  321. {
  322. // write all data
  323. for( visual = m_visualList; visual; visual = visual->m_next )
  324. {
  325. // object id
  326. xfer->xferObjectID( &visual->m_objectID );
  327. // drawable id
  328. xfer->xferDrawableID( &visual->m_drawableID );
  329. } // end for, visual
  330. } // end if, save
  331. else
  332. {
  333. // the visual list should be empty
  334. if( m_visualList != NULL )
  335. {
  336. DEBUG_CRASH(( "PrisonBehavior::xfer - the visual list should be empty but is not\n" ));
  337. throw SC_INVALID_DATA;
  338. } // end if
  339. // read each item
  340. for( UnsignedShort i = 0; i < visualCount; ++i )
  341. {
  342. // allocate a new visual and tie to list
  343. visual = newInstance(PrisonVisual);
  344. visual->m_next = m_visualList;
  345. m_visualList = visual;
  346. // read object id
  347. xfer->xferObjectID( &visual->m_objectID );
  348. // read drawable id
  349. xfer->xferDrawableID( &visual->m_drawableID );
  350. } // end for, i
  351. } // end else, load
  352. } // end xfer
  353. // ------------------------------------------------------------------------------------------------
  354. /** Load post process */
  355. // ------------------------------------------------------------------------------------------------
  356. void PrisonBehavior::loadPostProcess( void )
  357. {
  358. // extend base class
  359. OpenContain::loadPostProcess();
  360. } // end loadPostProcess
  361. #endif