AIDock.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  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. // AIDock.cpp
  24. // Implementation of docking behavior
  25. // Author: Michael S. Booth, February 2002
  26. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  27. #include "Common/Module.h"
  28. #include "Common/Player.h"
  29. #include "GameLogic/Object.h"
  30. #include "GameLogic/AIDock.h"
  31. #include "GameLogic/Module/AIUpdate.h"
  32. #include "GameLogic/Module/SupplyTruckAIUpdate.h"
  33. #include "GameLogic/Module/UpdateModule.h"
  34. //----------------------------------------------------------------------------------------------------------
  35. /**
  36. * Create an AI state machine. Define all of the states the machine
  37. * can possibly be in, and set the initial (default) state.
  38. */
  39. AIDockMachine::AIDockMachine( Object *obj ) : StateMachine( obj, "AIDockMachine" )
  40. {
  41. static const StateConditionInfo waitForClearanceConditions[] =
  42. {
  43. StateConditionInfo(ableToAdvance, AI_DOCK_ADVANCE_POSITION, NULL),
  44. StateConditionInfo(NULL, NULL, NULL) // keep last
  45. };
  46. // order matters: first state is the default state.
  47. defineState( AI_DOCK_APPROACH, newInstance(AIDockApproachState)( this ), AI_DOCK_WAIT_FOR_CLEARANCE, EXIT_MACHINE_WITH_FAILURE );
  48. defineState( AI_DOCK_WAIT_FOR_CLEARANCE, newInstance(AIDockWaitForClearanceState)( this ), AI_DOCK_MOVE_TO_ENTRY, EXIT_MACHINE_WITH_FAILURE, waitForClearanceConditions );
  49. defineState( AI_DOCK_ADVANCE_POSITION, newInstance(AIDockAdvancePositionState)( this ), AI_DOCK_WAIT_FOR_CLEARANCE, EXIT_MACHINE_WITH_FAILURE );
  50. defineState( AI_DOCK_MOVE_TO_ENTRY, newInstance(AIDockMoveToEntryState)( this ), AI_DOCK_MOVE_TO_DOCK, AI_DOCK_MOVE_TO_EXIT );
  51. defineState( AI_DOCK_MOVE_TO_DOCK, newInstance(AIDockMoveToDockState)( this ), AI_DOCK_PROCESS_DOCK, AI_DOCK_MOVE_TO_EXIT );
  52. defineState( AI_DOCK_PROCESS_DOCK, newInstance(AIDockProcessDockState)( this ), AI_DOCK_MOVE_TO_EXIT, AI_DOCK_MOVE_TO_EXIT );
  53. defineState( AI_DOCK_MOVE_TO_EXIT, newInstance(AIDockMoveToExitState)( this ), AI_DOCK_MOVE_TO_RALLY, EXIT_MACHINE_WITH_FAILURE );
  54. defineState( AI_DOCK_MOVE_TO_RALLY, newInstance(AIDockMoveToRallyState)( this ), EXIT_MACHINE_WITH_SUCCESS, EXIT_MACHINE_WITH_FAILURE );
  55. m_approachPosition = -1;
  56. }
  57. AIDockMachine::~AIDockMachine()
  58. {
  59. }
  60. //-----------------------------------------------------------------------------
  61. void AIDockMachine::halt()
  62. {
  63. Object *goalObject = getGoalObject();
  64. // sanity
  65. if( goalObject != NULL )
  66. {
  67. // get dock update interface
  68. DockUpdateInterface *dock = goalObject->getDockUpdateInterface();
  69. // We need to say goodbye, or we will leave our spot taken forever.
  70. if( dock != NULL )
  71. dock->cancelDock( getOwner() );
  72. }
  73. StateMachine::halt();
  74. }
  75. // ------------------------------------------------------------------------------------------------
  76. /** CRC */
  77. // ------------------------------------------------------------------------------------------------
  78. void AIDockMachine::crc( Xfer *xfer )
  79. {
  80. StateMachine::crc(xfer);
  81. } // end crc
  82. // ------------------------------------------------------------------------------------------------
  83. /** Xfer Method */
  84. // ------------------------------------------------------------------------------------------------
  85. void AIDockMachine::xfer( Xfer *xfer )
  86. {
  87. XferVersion cv = 1;
  88. XferVersion v = cv;
  89. xfer->xferVersion( &v, cv );
  90. StateMachine::xfer(xfer);
  91. xfer->xferInt(&m_approachPosition);
  92. } // end xfer
  93. // ------------------------------------------------------------------------------------------------
  94. /** Load post process */
  95. // ------------------------------------------------------------------------------------------------
  96. void AIDockMachine::loadPostProcess( void )
  97. {
  98. StateMachine::loadPostProcess();
  99. } // end loadPostProcess
  100. // State transition conditions ----------------------------------------------------------------------------
  101. //-------------------------------------------------------------------------------------------------
  102. /* static */ Bool AIDockMachine::ableToAdvance( State *thisState, void* userData )
  103. {
  104. Object *goalObject = thisState->getMachineGoalObject();
  105. AIDockMachine *myMachine = (AIDockMachine *)thisState->getMachine();
  106. if( goalObject == NULL )
  107. return FALSE;
  108. DockUpdateInterface *dock = goalObject->getDockUpdateInterface();
  109. // if we have nothing to dock with, fail
  110. if( dock == NULL )
  111. return FALSE;
  112. // if the dock says we can advance, then sidetrack to the scoot forward state
  113. if( dock->isClearToAdvance( thisState->getMachineOwner(), myMachine->m_approachPosition ) )
  114. return TRUE;
  115. // continue to wait
  116. return FALSE;
  117. }
  118. //----------------------------------------------------------------------------------------------
  119. //----------------------------------------------------------------------------------------------
  120. //----------------------------------------------------------------------------------------------
  121. // ------------------------------------------------------------------------------------------------
  122. /** Xfer Method */
  123. // ------------------------------------------------------------------------------------------------
  124. void AIDockApproachState::xfer( Xfer *xfer )
  125. {
  126. // version
  127. XferVersion currentVersion = 2;
  128. XferVersion version = currentVersion;
  129. xfer->xferVersion( &version, currentVersion );
  130. if (version>=2) {
  131. AIInternalMoveToState::xfer(xfer);
  132. }
  133. } // end xfer
  134. //----------------------------------------------------------------------------------------------
  135. /**
  136. * Approach our waiting spot next to the dock.
  137. */
  138. StateReturnType AIDockApproachState::onEnter( void )
  139. {
  140. Object *goalObject = getMachineGoalObject();
  141. // sanity
  142. if( goalObject == NULL )
  143. return STATE_FAILURE;
  144. // get dock update interface
  145. DockUpdateInterface *dock = goalObject->getDockUpdateInterface();
  146. // if we have nothing to dock with, fail
  147. if (dock == NULL)
  148. return STATE_FAILURE;
  149. // fail if the dock is closed
  150. if( dock->isDockOpen() == FALSE )
  151. {
  152. dock->cancelDock( getMachineOwner() );
  153. return STATE_FAILURE;
  154. }
  155. // get a good place to wait from the dock
  156. Bool reserved = dock->reserveApproachPosition( getMachineOwner(), &m_goalPosition, &(( (AIDockMachine*)getMachine() )->m_approachPosition) );
  157. if( reserved == FALSE )
  158. {
  159. // dock is full
  160. return STATE_FAILURE;
  161. }
  162. AIUpdateInterface *ai = getMachineOwner()->getAIUpdateInterface();
  163. if (ai) {
  164. ai->ignoreObstacle( NULL );
  165. }
  166. // this behavior is an extention of basic MoveTo
  167. return AIInternalMoveToState::onEnter();
  168. }
  169. //----------------------------------------------------------------------------------------------
  170. StateReturnType AIDockApproachState::update( void )
  171. {
  172. Object *goalObject = getMachineGoalObject();
  173. // if we have nothing to dock with, fail
  174. if (goalObject == NULL)
  175. return STATE_FAILURE;
  176. // this behavior is an extention of basic MoveTo
  177. return AIInternalMoveToState::update();
  178. }
  179. //----------------------------------------------------------------------------------------------
  180. void AIDockApproachState::onExit( StateExitType status )
  181. {
  182. Object *goalObject = getMachineGoalObject();
  183. DockUpdateInterface *dock = NULL;
  184. if( goalObject )
  185. dock = goalObject->getDockUpdateInterface();
  186. // tell the dock we have approached
  187. if (dock)
  188. {
  189. // if we were interrupted, let the dock know we're not coming
  190. if (status == EXIT_RESET || dock->isDockOpen() == FALSE)
  191. dock->cancelDock( getMachineOwner() );
  192. else
  193. dock->onApproachReached( getMachineOwner() );
  194. }
  195. // this behavior is an extention of basic MoveTo
  196. AIInternalMoveToState::onExit( status );
  197. }
  198. //----------------------------------------------------------------------------------------------
  199. //----------------------------------------------------------------------------------------------
  200. //----------------------------------------------------------------------------------------------
  201. //----------------------------------------------------------------------------------------------
  202. /**
  203. * We have approached, now wait at our queue position until the dock says we can enter.
  204. */
  205. StateReturnType AIDockWaitForClearanceState::onEnter( void )
  206. {
  207. m_enterFrame = TheGameLogic->getFrame();
  208. return STATE_CONTINUE;
  209. }
  210. /**
  211. * We have approached, now wait at our queue position until the dock says we can enter.
  212. * @todo What if we are pushed off of our queue spot? We need to move back on... (MSB)
  213. */
  214. StateReturnType AIDockWaitForClearanceState::update( void )
  215. {
  216. Object *goalObject = getMachineGoalObject();
  217. if( goalObject == NULL )
  218. return STATE_FAILURE;
  219. DockUpdateInterface *dock = goalObject->getDockUpdateInterface();
  220. // if we have nothing to dock with, fail
  221. if (dock == NULL)
  222. return STATE_FAILURE;
  223. // fail if the dock is closed
  224. if( dock->isDockOpen() == FALSE )
  225. {
  226. dock->cancelDock( getMachineOwner() );
  227. return STATE_FAILURE;
  228. }
  229. // if the dock says we can enter, our wait is over
  230. if (dock->isClearToEnter( getMachineOwner() ))
  231. return STATE_SUCCESS;
  232. if (m_enterFrame + 30*LOGICFRAMES_PER_SECOND < TheGameLogic->getFrame()) {
  233. return STATE_FAILURE;
  234. }
  235. // continue to wait
  236. return STATE_CONTINUE;
  237. }
  238. //----------------------------------------------------------------------------------------------
  239. void AIDockWaitForClearanceState::onExit( StateExitType status )
  240. {
  241. Object *goalObject = getMachineGoalObject();
  242. DockUpdateInterface *dock = NULL;
  243. if( goalObject )
  244. dock = goalObject->getDockUpdateInterface();
  245. // if we were interrupted, let the dock know we're not coming
  246. if (dock && (dock->isDockOpen() == FALSE || status == EXIT_RESET))
  247. dock->cancelDock( getMachineOwner() );
  248. }
  249. //----------------------------------------------------------------------------------------------
  250. void AIDockWaitForClearanceState::xfer(Xfer *xfer )
  251. {
  252. XferVersion cv = 2;
  253. XferVersion v = cv;
  254. xfer->xferVersion( &v, cv );
  255. if (v >= 2) {
  256. xfer->xferUnsignedInt(&m_enterFrame);
  257. } else {
  258. m_enterFrame = TheGameLogic->getFrame();
  259. }
  260. }
  261. //----------------------------------------------------------------------------------------------
  262. //----------------------------------------------------------------------------------------------
  263. //----------------------------------------------------------------------------------------------
  264. //----------------------------------------------------------------------------------------------
  265. /**
  266. * Advance to our next waiting spot next to the dock.
  267. */
  268. StateReturnType AIDockAdvancePositionState::onEnter( void )
  269. {
  270. Object *goalObject = getMachineGoalObject();
  271. // sanity
  272. if( goalObject == NULL )
  273. return STATE_FAILURE;
  274. // get dock update interface
  275. DockUpdateInterface *dock = goalObject->getDockUpdateInterface();
  276. // if we have nothing to dock with, fail
  277. if (dock == NULL)
  278. return STATE_FAILURE;
  279. // fail if the dock is closed
  280. if( dock->isDockOpen() == FALSE )
  281. {
  282. dock->cancelDock( getMachineOwner() );
  283. return STATE_FAILURE;
  284. }
  285. // get a good place to wait from the dock
  286. Bool reserved = dock->advanceApproachPosition( getMachineOwner(), &m_goalPosition, &(( (AIDockMachine*)getMachine() )->m_approachPosition) );
  287. if( reserved == FALSE )
  288. {
  289. // dock is full
  290. return STATE_FAILURE;
  291. }
  292. AIUpdateInterface *ai = getMachineOwner()->getAIUpdateInterface();
  293. if (ai) {
  294. ai->ignoreObstacle( NULL );
  295. }
  296. // this behavior is an extention of basic MoveTo
  297. return AIInternalMoveToState::onEnter();
  298. }
  299. //----------------------------------------------------------------------------------------------
  300. StateReturnType AIDockAdvancePositionState::update( void )
  301. {
  302. Object *goalObject = getMachineGoalObject();
  303. // if we have nothing to dock with, fail
  304. if (goalObject == NULL)
  305. return STATE_FAILURE;
  306. // this behavior is an extention of basic MoveTo
  307. return AIInternalMoveToState::update();
  308. }
  309. //----------------------------------------------------------------------------------------------
  310. void AIDockAdvancePositionState::onExit( StateExitType status )
  311. {
  312. Object *goalObject = getMachineGoalObject();
  313. DockUpdateInterface *dock = NULL;
  314. if( goalObject )
  315. dock = goalObject->getDockUpdateInterface();
  316. // tell the dock we have approached
  317. if (dock)
  318. {
  319. // if we were interrupted, let the dock know we're not coming
  320. if (status == EXIT_RESET || dock->isDockOpen() == FALSE)
  321. dock->cancelDock( getMachineOwner() );
  322. else
  323. dock->onApproachReached( getMachineOwner() );
  324. }
  325. // this behavior is an extention of basic MoveTo
  326. AIInternalMoveToState::onExit( status );
  327. }
  328. //----------------------------------------------------------------------------------------------
  329. //----------------------------------------------------------------------------------------------
  330. //----------------------------------------------------------------------------------------------
  331. //----------------------------------------------------------------------------------------------
  332. /**
  333. * Move to the dock's entry position.
  334. */
  335. StateReturnType AIDockMoveToEntryState::onEnter( void )
  336. {
  337. Object *goalObject = getMachineGoalObject();
  338. DockUpdateInterface *dock = NULL;
  339. if( goalObject )
  340. dock = goalObject->getDockUpdateInterface();
  341. // if we have nothing to dock with, fail
  342. if (dock == NULL)
  343. return STATE_FAILURE;
  344. // fail if the dock is closed
  345. if( dock->isDockOpen() == FALSE )
  346. {
  347. dock->cancelDock( getMachineOwner() );
  348. return STATE_FAILURE;
  349. }
  350. AIUpdateInterface *ai = getMachineOwner()->getAIUpdateInterface();
  351. if( ai && dock->isAllowPassthroughType() )
  352. {
  353. ai->ignoreObstacle( getMachineGoalObject() );
  354. }
  355. // get the enter position and set as our goal position
  356. dock->getEnterPosition( getMachineOwner(), &m_goalPosition );
  357. ( (AIDockMachine*)getMachine() )->m_approachPosition = -1;
  358. // this behavior is an extention of basic MoveTo
  359. return AIInternalMoveToState::onEnter();
  360. }
  361. //----------------------------------------------------------------------------------------------
  362. StateReturnType AIDockMoveToEntryState::update( void )
  363. {
  364. // if we have nothing to dock with, fail
  365. if (getMachineGoalObject() == NULL)
  366. return STATE_FAILURE;
  367. // this behavior is an extention of basic MoveTo
  368. return AIInternalMoveToState::update();
  369. }
  370. //----------------------------------------------------------------------------------------------
  371. void AIDockMoveToEntryState::onExit( StateExitType status )
  372. {
  373. Object *goalObject = getMachineGoalObject();
  374. DockUpdateInterface *dock = NULL;
  375. if( goalObject )
  376. dock = goalObject->getDockUpdateInterface();
  377. if (dock)
  378. {
  379. if (dock->isDockOpen() == FALSE || status == EXIT_RESET)
  380. {
  381. // if we were interrupted, let the dock know we're not coming
  382. dock->cancelDock( getMachineOwner() );
  383. }
  384. else
  385. {
  386. // tell the dock we are at the entrance
  387. dock->onEnterReached( getMachineOwner() );
  388. }
  389. }
  390. // this behavior is an extention of basic MoveTo
  391. AIInternalMoveToState::onExit( status );
  392. }
  393. //----------------------------------------------------------------------------------------------
  394. //----------------------------------------------------------------------------------------------
  395. //----------------------------------------------------------------------------------------------
  396. //----------------------------------------------------------------------------------------------
  397. /**
  398. * Move to the dock's docking position.
  399. */
  400. StateReturnType AIDockMoveToDockState::onEnter( void )
  401. {
  402. Object *goalObject = getMachineGoalObject();
  403. DockUpdateInterface *dock = NULL;
  404. if( goalObject )
  405. dock = goalObject->getDockUpdateInterface();
  406. // if we have nothing to dock with, fail
  407. if (dock == NULL)
  408. return STATE_FAILURE;
  409. // fail if the dock is closed
  410. if( dock->isDockOpen() == FALSE )
  411. {
  412. dock->cancelDock( getMachineOwner() );
  413. return STATE_FAILURE;
  414. }
  415. // get the docking position
  416. dock->getDockPosition( getMachineOwner(), &m_goalPosition );
  417. AIUpdateInterface *ai = getMachineOwner()->getAIUpdateInterface();
  418. if( ai && dock->isAllowPassthroughType() )
  419. {
  420. ai->ignoreObstacle( getMachineGoalObject() );
  421. setAdjustsDestination(false);
  422. }
  423. // since we are moving inside the dock, disallow interruptions
  424. getMachine()->lock("AIDockMoveToDockState::onEnter");
  425. // this behavior is an extention of basic MoveTo
  426. return AIInternalMoveToState::onEnter();
  427. }
  428. //----------------------------------------------------------------------------------------------
  429. StateReturnType AIDockMoveToDockState::update( void )
  430. {
  431. Object *goalObject = getMachineGoalObject();
  432. // if we have nothing to dock with, fail
  433. if (goalObject == NULL)
  434. return STATE_FAILURE;
  435. DockUpdateInterface *dock = goalObject->getDockUpdateInterface();
  436. if( dock->isDockOpen() == FALSE )
  437. return STATE_FAILURE;
  438. // this behavior is an extention of basic MoveTo
  439. return AIInternalMoveToState::update();
  440. }
  441. //----------------------------------------------------------------------------------------------
  442. void AIDockMoveToDockState::onExit( StateExitType status )
  443. {
  444. Object *goalObject = getMachineGoalObject();
  445. DockUpdateInterface *dock = NULL;
  446. if( goalObject )
  447. dock = goalObject->getDockUpdateInterface();
  448. // tell the dock we are at the docking point
  449. if (dock)
  450. {
  451. // if we were interrupted, let the dock know we're not coming
  452. if (status == EXIT_RESET || dock->isDockOpen() == FALSE )
  453. dock->cancelDock( getMachineOwner() );
  454. else
  455. dock->onDockReached( getMachineOwner() );
  456. }
  457. // unlock the machine
  458. getMachine()->unlock();
  459. // this behavior is an extention of basic MoveTo
  460. AIInternalMoveToState::onExit( status );
  461. }
  462. //----------------------------------------------------------------------------------------------
  463. //----------------------------------------------------------------------------------------------
  464. AIDockProcessDockState::AIDockProcessDockState( StateMachine *machine ) : State( machine, "AIDockProcessDockState" )
  465. {
  466. m_nextDockActionFrame = 0;
  467. }
  468. //----------------------------------------------------------------------------------------------
  469. //----------------------------------------------------------------------------------------------
  470. void AIDockProcessDockState::setNextDockActionFrame()
  471. {
  472. // If we have a SupplyTruck Interface, then we will ask for our specific delay time
  473. SupplyTruckAIInterface *supplyTruck = getMachineOwner()->getAI()->getSupplyTruckAIInterface();
  474. if( supplyTruck )
  475. {
  476. m_nextDockActionFrame = TheGameLogic->getFrame() + supplyTruck->getActionDelayForDock( getMachineGoalObject() );
  477. return;
  478. }
  479. // The default is that it is simply okay to Action right away
  480. m_nextDockActionFrame = TheGameLogic->getFrame();
  481. }
  482. //----------------------------------------------------------------------------------------------
  483. //----------------------------------------------------------------------------------------------
  484. StateReturnType AIDockProcessDockState::onEnter( void )
  485. {
  486. Object *goalObject = getMachineGoalObject();
  487. DockUpdateInterface *dock = NULL;
  488. if( goalObject )
  489. dock = goalObject->getDockUpdateInterface();
  490. // if we have nothing to dock with, fail
  491. if (dock == NULL)
  492. return STATE_FAILURE;
  493. setNextDockActionFrame();
  494. return STATE_CONTINUE;
  495. }
  496. //----------------------------------------------------------------------------------------------
  497. //----------------------------------------------------------------------------------------------
  498. /**
  499. * We are now docked. Invoke the dock's action() method until it returns false.
  500. */
  501. StateReturnType AIDockProcessDockState::update( void )
  502. {
  503. Object *goalObject = getMachineGoalObject();
  504. DockUpdateInterface *dock = NULL;
  505. if( goalObject )
  506. dock = goalObject->getDockUpdateInterface();
  507. // if we have nothing to dock with, fail
  508. if (dock == NULL)
  509. return STATE_FAILURE;
  510. // Some dockers can have a delay built in
  511. if( TheGameLogic->getFrame() < m_nextDockActionFrame )
  512. return STATE_CONTINUE;
  513. setNextDockActionFrame();
  514. Object *drone = findMyDrone();
  515. // invoke the dock's action until it tells us it is done or the dock becomes closed
  516. if( dock->isDockOpen() == false || dock->action( getMachineOwner(), drone ) == false )
  517. return STATE_SUCCESS;
  518. return STATE_CONTINUE;
  519. }
  520. //----------------------------------------------------------------------------------------------
  521. struct DroneInfo
  522. {
  523. Object *owner;
  524. Object *drone;
  525. Bool found;
  526. };
  527. void findDrone( Object *obj, void *droneInfo )
  528. {
  529. DroneInfo *dInfo = (DroneInfo*)droneInfo;
  530. if( !dInfo->found && obj )
  531. {
  532. if( obj->isKindOf( KINDOF_DRONE ) && obj->getProducerID() == dInfo->owner->getID() )
  533. {
  534. dInfo->found = TRUE;
  535. dInfo->drone = obj;
  536. }
  537. }
  538. }
  539. //----------------------------------------------------------------------------------------------
  540. Object* AIDockProcessDockState::findMyDrone()
  541. {
  542. //First do the fast cached check.
  543. Object *drone = TheGameLogic->findObjectByID( m_droneID );
  544. if( drone )
  545. {
  546. return drone;
  547. }
  548. //Nope... look for a drone (perhaps we just finished building one after docking?)
  549. Object *self = getMachineOwner();
  550. Player *player = self->getControllingPlayer();
  551. DroneInfo dInfo;
  552. dInfo.found = FALSE;
  553. dInfo.drone = NULL;
  554. dInfo.owner = self;
  555. //Iterate the objects in search for a drone with a producer ID of me.
  556. if( player )
  557. {
  558. player->iterateObjects( findDrone, &dInfo );
  559. }
  560. //If we found a drone, store it's ID as cached.
  561. if( dInfo.drone )
  562. {
  563. m_droneID = dInfo.drone->getID();
  564. }
  565. return dInfo.drone;
  566. }
  567. //----------------------------------------------------------------------------------------------
  568. void AIDockProcessDockState::onExit( StateExitType status )
  569. {
  570. // unlock the machine
  571. getMachine()->unlock();
  572. }
  573. //----------------------------------------------------------------------------------------------
  574. //----------------------------------------------------------------------------------------------
  575. //----------------------------------------------------------------------------------------------
  576. //----------------------------------------------------------------------------------------------
  577. /**
  578. * Move to the dock's exit position.
  579. */
  580. StateReturnType AIDockMoveToExitState::onEnter( void )
  581. {
  582. Object *goalObject = getMachineGoalObject();
  583. DockUpdateInterface *dock = NULL;
  584. if( goalObject )
  585. dock = goalObject->getDockUpdateInterface();
  586. // if we have nothing to dock with, fail
  587. if (dock == NULL)
  588. return STATE_FAILURE;
  589. // get the exit position
  590. dock->getExitPosition( getMachineOwner(), &m_goalPosition );
  591. AIUpdateInterface *ai = getMachineOwner()->getAIUpdateInterface();
  592. if( ai && dock->isAllowPassthroughType() )
  593. {
  594. ai->ignoreObstacle( getMachineGoalObject() );
  595. setAdjustsDestination(false);
  596. }
  597. // this behavior is an extention of basic MoveTo
  598. return AIInternalMoveToState::onEnter();
  599. }
  600. //----------------------------------------------------------------------------------------------
  601. StateReturnType AIDockMoveToExitState::update( void )
  602. {
  603. // if we have nothing to dock with, fail
  604. if (getMachineGoalObject() == NULL)
  605. return STATE_FAILURE;
  606. // this behavior is an extention of basic MoveTo
  607. return AIInternalMoveToState::update();
  608. }
  609. //----------------------------------------------------------------------------------------------
  610. void AIDockMoveToExitState::onExit( StateExitType status )
  611. {
  612. Object *goalObject = getMachineGoalObject();
  613. DockUpdateInterface *dock = NULL;
  614. if( goalObject )
  615. dock = goalObject->getDockUpdateInterface();
  616. // tell the dock we have exited
  617. if (dock)
  618. dock->onExitReached( getMachineOwner() );
  619. // unlock the machine
  620. getMachine()->unlock();
  621. // this behavior is an extention of basic MoveTo
  622. AIInternalMoveToState::onExit( status );
  623. }
  624. //----------------------------------------------------------------------------------------------
  625. //----------------------------------------------------------------------------------------------
  626. //----------------------------------------------------------------------------------------------
  627. //----------------------------------------------------------------------------------------------
  628. /**
  629. * Move to the dock's rally position, if he wants me to.
  630. */
  631. StateReturnType AIDockMoveToRallyState::onEnter( void )
  632. {
  633. Object *goalObject = getMachineGoalObject();
  634. DockUpdateInterface *dock = NULL;
  635. if( goalObject )
  636. dock = goalObject->getDockUpdateInterface();
  637. // if we have nothing to dock with, fail
  638. if (dock == NULL)
  639. return STATE_FAILURE;
  640. // if they don't have anywhere to send us, then we are good
  641. if( ! dock->isRallyPointAfterDockType() //Chooses not to
  642. || goalObject->getObjectExitInterface() == NULL //or can't
  643. || goalObject->getObjectExitInterface()->getRallyPoint() == NULL //or can't right now.
  644. )
  645. {
  646. return STATE_SUCCESS; // Success in an Enter is like success in an update. We're all fine here
  647. }
  648. // get the rally point and set as our goal position
  649. m_goalPosition = *goalObject->getObjectExitInterface()->getRallyPoint();
  650. // this behavior is an extention of basic MoveTo
  651. return AIInternalMoveToState::onEnter();
  652. }
  653. //----------------------------------------------------------------------------------------------
  654. StateReturnType AIDockMoveToRallyState::update( void )
  655. {
  656. // This state is fine with the loss of the goal object after the move starts
  657. // this behavior is an extention of basic MoveTo
  658. return AIInternalMoveToState::update();
  659. }
  660. //----------------------------------------------------------------------------------------------
  661. void AIDockMoveToRallyState::onExit( StateExitType status )
  662. {
  663. // This state is fine with the loss of the goal object after the move starts
  664. // this behavior is an extention of basic MoveTo
  665. AIInternalMoveToState::onExit( status );
  666. }