RailedTransportAIUpdate.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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: RailedTransportAIUpdate.cpp //////////////////////////////////////////////////////////////
  24. // Author: Colin Day, August 2002
  25. // Desc: Railed Transport AI
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  28. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  29. #include "Common/ThingTemplate.h"
  30. #include "Common/GameState.h"
  31. #include "GameLogic/Locomotor.h"
  32. #include "GameLogic/Module/RailedTransportAIUpdate.h"
  33. #include "GameLogic/Module/RailedTransportDockUpdate.h"
  34. #include "GameLogic/Object.h"
  35. // TYPES //////////////////////////////////////////////////////////////////////////////////////////
  36. static const Int INVALID_PATH = -1;
  37. // ------------------------------------------------------------------------------------------------
  38. // ------------------------------------------------------------------------------------------------
  39. RailedTransportAIUpdateModuleData::RailedTransportAIUpdateModuleData( void )
  40. {
  41. } // end RailedTransportAIUpdateModuleData
  42. // ------------------------------------------------------------------------------------------------
  43. // ------------------------------------------------------------------------------------------------
  44. void RailedTransportAIUpdateModuleData::buildFieldParse( MultiIniFieldParse &p )
  45. {
  46. AIUpdateModuleData::buildFieldParse( p );
  47. static const FieldParse dataFieldParse[] =
  48. {
  49. { "PathPrefixName", INI::parseAsciiString, NULL, offsetof( RailedTransportAIUpdateModuleData, m_pathPrefixName ) },
  50. { 0, 0, 0, 0 }
  51. };
  52. p.add( dataFieldParse );
  53. } // end buildFieldParse
  54. //-------------------------------------------------------------------------------------------------
  55. //-------------------------------------------------------------------------------------------------
  56. RailedTransportAIUpdate::RailedTransportAIUpdate( Thing *thing, const ModuleData *moduleData )
  57. : AIUpdateInterface( thing, moduleData )
  58. {
  59. m_inTransit = FALSE;
  60. for( Int i = 0; i < MAX_WAYPOINT_PATHS; ++i )
  61. {
  62. m_path[ i ].startWaypointID = 0;
  63. m_path[ i ].endWaypointID = 0;
  64. } // end for i
  65. m_numPaths = 0;
  66. m_currentPath = INVALID_PATH;
  67. m_waypointDataLoaded = FALSE;
  68. } // end RailedTransportAIUpdate
  69. //-------------------------------------------------------------------------------------------------
  70. //-------------------------------------------------------------------------------------------------
  71. RailedTransportAIUpdate::~RailedTransportAIUpdate( void )
  72. {
  73. } // end ~RailedTransportAIUpdate
  74. // ------------------------------------------------------------------------------------------------
  75. // ------------------------------------------------------------------------------------------------
  76. void RailedTransportAIUpdate::loadWaypointData( void )
  77. {
  78. const RailedTransportAIUpdateModuleData *modData = getRailedTransportAIUpdateModuleData();
  79. // find all the possible waypoint paths we can use
  80. Waypoint *start, *end;
  81. AsciiString name;
  82. for( Int i = 0; i < MAX_WAYPOINT_PATHS; ++i )
  83. {
  84. // find start waypoint
  85. name.format( "%sStart%02d", modData->m_pathPrefixName.str(), i + 1 );
  86. start = TheTerrainLogic->getWaypointByName( name );
  87. // find end waypoint
  88. name.format( "%sEnd%02d", modData->m_pathPrefixName.str(), i + 1 );
  89. end = TheTerrainLogic->getWaypointByName( name );
  90. // if we have a start and an end, we have a valid path
  91. if( start && end )
  92. {
  93. m_path[ i ].startWaypointID = start->getID();
  94. m_path[ i ].endWaypointID = end->getID();
  95. m_numPaths++;
  96. } // end if
  97. } // end for i
  98. // waypoint data is loaded
  99. m_waypointDataLoaded = TRUE;
  100. } // end loadWaypointData
  101. // ------------------------------------------------------------------------------------------------
  102. // ------------------------------------------------------------------------------------------------
  103. void RailedTransportAIUpdate::pickAndMoveToInitialLocation( void )
  104. {
  105. Object *us = getObject();
  106. const Coord3D *ourPos = us->getPosition();
  107. // select the path with the closest ending waypoint to our location
  108. Waypoint *waypoint, *closestEndWaypoint = NULL;
  109. Int closestPath = INVALID_PATH;
  110. Real closestDist = 99999999.9f;
  111. for( Int i = 0; i < m_numPaths; ++i )
  112. {
  113. // get this waypoint
  114. waypoint = TheTerrainLogic->getWaypointByID( m_path[ i ].endWaypointID );
  115. if( waypoint )
  116. {
  117. Coord3D v;
  118. // vector from us to waypoint
  119. v.x = waypoint->getLocation()->x - ourPos->x;
  120. v.y = waypoint->getLocation()->y - ourPos->y;
  121. v.z = waypoint->getLocation()->z - ourPos->z;
  122. // what is the distance
  123. Real dist = v.length();
  124. // if this distance is smaller, use this one
  125. if( dist < closestDist )
  126. {
  127. closestDist = dist;
  128. closestPath = i;
  129. closestEndWaypoint = waypoint;
  130. } // end if
  131. } // end if
  132. } // end for i
  133. // a path must have been found
  134. DEBUG_ASSERTCRASH( closestPath != INVALID_PATH,
  135. ("No suitable starting waypoint path could be found for '%s'\n",
  136. us->getTemplate()->getName().str()) );
  137. // follow the waypoint path to its destination end point
  138. aiFollowWaypointPath( closestEndWaypoint, CMD_FROM_AI );
  139. // this is now our current path
  140. m_currentPath = closestPath;
  141. // we are now "in transit"
  142. setInTransit( TRUE );
  143. } // end pickAndMoveToInitialLocation
  144. // ------------------------------------------------------------------------------------------------
  145. // ------------------------------------------------------------------------------------------------
  146. UpdateSleepTime RailedTransportAIUpdate::update( void )
  147. {
  148. Object *us = getObject();
  149. // load the waypoint data if not loaded
  150. if( m_waypointDataLoaded == FALSE )
  151. loadWaypointData();
  152. // extend base class
  153. UpdateSleepTime result;
  154. result = AIUpdateInterface::update();
  155. // railed transports move ultra accurate like
  156. Locomotor *currentLocomotor = getCurLocomotor();
  157. if( currentLocomotor )
  158. currentLocomotor->setUltraAccurate( TRUE );
  159. //
  160. // if we have no current path selected pick one and move to the end waypoint of that
  161. // path. this will set us up in an initial position at the end of the closest path
  162. // so that stuff can be loaded into us
  163. //
  164. if( m_currentPath == INVALID_PATH && m_numPaths > 0 )
  165. pickAndMoveToInitialLocation();
  166. //
  167. // if we're in transit, see if we're close enough to the destination waypoint to be
  168. // considered as "there" and open up the dock
  169. //
  170. if( m_inTransit )
  171. {
  172. // sanity
  173. DEBUG_ASSERTCRASH( m_currentPath != INVALID_PATH,
  174. ("RailedTransportAIUpdate: Invalid current path '%s'\n", m_currentPath) );
  175. // get our target waypoint
  176. Waypoint *waypoint = TheTerrainLogic->getWaypointByID( m_path[ m_currentPath ].endWaypointID );
  177. // sanity
  178. DEBUG_ASSERTCRASH( waypoint, ("RailedTransportAIUpdate: Invalid target waypoint\n") );
  179. // how far away are we from the target waypoint
  180. const Coord3D *start = us->getPosition();
  181. const Coord3D *end = waypoint->getLocation();
  182. Coord3D v;
  183. v.x = end->x - start->x;
  184. v.y = end->y - start->y;
  185. v.z = end->z - start->z;
  186. Real dist = v.length();
  187. if( dist <= 5.0f || isIdle() )
  188. {
  189. // we are no longer in transit
  190. setInTransit( FALSE );
  191. } // end if
  192. } // end if
  193. return UPDATE_SLEEP_NONE;
  194. } // end update
  195. // ------------------------------------------------------------------------------------------------
  196. //-------------------------------------------------------------------------------------------------
  197. void RailedTransportAIUpdate::aiDoCommand( const AICommandParms *parms )
  198. {
  199. // if not allowed to respond to any command get out of here
  200. if( isAllowedToRespondToAiCommands(parms) == FALSE )
  201. return;
  202. // we ignore all commands from the player except the one to start a transit and to unload
  203. if( parms->m_cmdSource == CMD_FROM_PLAYER &&
  204. parms->m_cmd != AICMD_EXECUTE_RAILED_TRANSPORT &&
  205. parms->m_cmd != AICMD_EVACUATE )
  206. return;
  207. // call the default do command
  208. AIUpdateInterface::aiDoCommand( parms );
  209. } // end aiDoCommand
  210. ///////////////////////////////////////////////////////////////////////////////////////////////////
  211. // PRIVATE ////////////////////////////////////////////////////////////////////////////////////////
  212. ///////////////////////////////////////////////////////////////////////////////////////////////////
  213. // ------------------------------------------------------------------------------------------------
  214. // ------------------------------------------------------------------------------------------------
  215. void RailedTransportAIUpdate::setInTransit( Bool inTransit )
  216. {
  217. Object *us = getObject();
  218. DockUpdateInterface *dui = us->getDockUpdateInterface();
  219. // open up the dock
  220. if( dui )
  221. dui->setDockOpen( !inTransit );
  222. // no longer in transit
  223. m_inTransit = inTransit;
  224. } // end setInTransit
  225. // ------------------------------------------------------------------------------------------------
  226. // ------------------------------------------------------------------------------------------------
  227. void RailedTransportAIUpdate::privateExecuteRailedTransport( CommandSourceType cmdSource )
  228. {
  229. Object *us = getObject();
  230. //
  231. // find us our railed dock interface, note that we MUST go through the modules here because
  232. // if we just call the method getReailedTransportDockUpdateInterface, it will execute
  233. // the method for *THIS AI UPDATE MODULE* which of course is not our dock update
  234. //
  235. RailedTransportDockUpdateInterface *rtdui = NULL;
  236. for( BehaviorModule **u = us->getBehaviorModules(); *u; ++u )
  237. if( (rtdui = (*u)->getRailedTransportDockUpdateInterface()) != NULL )
  238. break;
  239. // if we've in the process of loading or unloading anything we can't do a transport sequence
  240. if( rtdui == NULL || rtdui->isLoadingOrUnloading() )
  241. return;
  242. // pick the next path
  243. if( ++m_currentPath >= m_numPaths )
  244. m_currentPath = 0;
  245. // find the start waypoint for our current path
  246. Waypoint *startWaypoint = TheTerrainLogic->getWaypointByID( m_path[ m_currentPath ].startWaypointID );
  247. DEBUG_ASSERTCRASH( startWaypoint, ("RailedTransportAIUpdate: Start waypoint not found\n") );
  248. // follow this waypoint path
  249. aiFollowWaypointPath( startWaypoint, CMD_FROM_AI );
  250. // we are now in transit
  251. setInTransit( TRUE );
  252. } // end privateExecuteRailedTransport
  253. // ------------------------------------------------------------------------------------------------
  254. // ------------------------------------------------------------------------------------------------
  255. void RailedTransportAIUpdate::privateEvacuate( Int exposeStealthUnits, CommandSourceType cmdSource )
  256. {
  257. Object *us = getObject();
  258. //
  259. // find us our railed dock interface, note that we MUST go through the modules here because
  260. // if we just call the method getReailedTransportDockUpdateInterface, it will execute
  261. // the method for *THIS AI UPDATE MODULE* which of course is not our dock update
  262. //
  263. RailedTransportDockUpdateInterface *rtdui = NULL;
  264. for( BehaviorModule **u = us->getBehaviorModules(); *u; ++u )
  265. if( (rtdui = (*u)->getRailedTransportDockUpdateInterface()) != NULL )
  266. break;
  267. // sanity
  268. if( rtdui == NULL )
  269. return;
  270. // can't unload when in transit
  271. if( m_inTransit == TRUE )
  272. return;
  273. // cannot evacuate when we're loading or unloading anything
  274. if( rtdui->isLoadingOrUnloading() )
  275. return;
  276. // start the manual undocking process
  277. rtdui->unloadAll();
  278. } // end privateEvacuate
  279. // ------------------------------------------------------------------------------------------------
  280. /** CRC */
  281. // ------------------------------------------------------------------------------------------------
  282. void RailedTransportAIUpdate::crc( Xfer *xfer )
  283. {
  284. // extend base class
  285. AIUpdateInterface::crc(xfer);
  286. } // end crc
  287. // ------------------------------------------------------------------------------------------------
  288. /** Xfer method
  289. * Version Info:
  290. * 1: Initial version */
  291. // ------------------------------------------------------------------------------------------------
  292. void RailedTransportAIUpdate::xfer( Xfer *xfer )
  293. {
  294. XferVersion currentVersion = 1;
  295. XferVersion version = currentVersion;
  296. xfer->xferVersion( &version, currentVersion );
  297. // extend base class
  298. AIUpdateInterface::xfer(xfer);
  299. xfer->xferBool(&m_inTransit);
  300. xfer->xferInt(&m_numPaths);
  301. if (m_numPaths > MAX_WAYPOINT_PATHS) {
  302. DEBUG_CRASH(("m_numPaths %d exceeds limit %d.", m_numPaths, MAX_WAYPOINT_PATHS));
  303. throw SC_INVALID_DATA;
  304. }
  305. Int i;
  306. for (i=0; i<m_numPaths; i++) {
  307. xfer->xferUnsignedInt(&m_path[i].startWaypointID);
  308. xfer->xferUnsignedInt(&m_path[i].endWaypointID);
  309. }
  310. xfer->xferInt(&m_currentPath);
  311. xfer->xferBool(&m_waypointDataLoaded);
  312. } // end xfer
  313. // ------------------------------------------------------------------------------------------------
  314. /** Load post process */
  315. // ------------------------------------------------------------------------------------------------
  316. void RailedTransportAIUpdate::loadPostProcess( void )
  317. {
  318. // extend base class
  319. AIUpdateInterface::loadPostProcess();
  320. } // end loadPostProcess