SupplyTruckAIUpdate.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  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. // SupplyTruckAIUpdate.cpp ////////////
  24. // Author: Graham Smallwood, February 2002
  25. // Desc: State machine that controls when and with who a Truck docks
  26. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  27. #include "Common/Player.h"
  28. #include "Common/ResourceGatheringManager.h"
  29. #include "Common/ThingTemplate.h"
  30. #include "GameLogic/Object.h"
  31. #include "GameLogic/PartitionManager.h"
  32. #include "GameLogic/Module/SupplyTruckAIUpdate.h"
  33. #include "GameLogic/Module/SupplyCenterDockUpdate.h"
  34. #include "GameLogic/Module/SupplyWarehouseDockUpdate.h"
  35. #include "GameLogic/Module/WorkerAIUpdate.h"
  36. #include "GameClient/Drawable.h"
  37. #include "GameClient/InGameUI.h"
  38. #ifdef _INTERNAL
  39. // for occasional debugging...
  40. //#pragma optimize("", off)
  41. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  42. #endif
  43. #define NO_DEBUG_SUPPLY_STATE
  44. #ifdef DEBUG_SUPPLY_STATE
  45. static const char* statenames[] =
  46. {
  47. "ST_IDLE", ///< Not doing anything. Should I autopilot?
  48. "ST_BUSY", ///< Direct player involvement (move) has taken me off autopilot
  49. "ST_WANTING", ///< Search for warehouse or center and dock with it
  50. "ST_REGROUPING", ///< Wanting failed, so hang out at base until something changes. Still on autopilot, but resting.
  51. "ST_DOCKING" ///< Docking substates are running, wait for them to finish
  52. };
  53. #endif
  54. //-------------------------------------------------------------------------------------------------
  55. //-------------------------------------------------------------------------------------------------
  56. //-------------------------------------------------------------------------------------------------
  57. //-------------------------------------------------------------------------------------------------
  58. AIStateMachine* SupplyTruckAIUpdate::makeStateMachine()
  59. {
  60. return newInstance(AIStateMachine)( getObject(), "SupplyTruckAIUpdateMachine");
  61. }
  62. //-------------------------------------------------------------------------------------------------
  63. SupplyTruckAIUpdate::SupplyTruckAIUpdate( Thing *thing, const ModuleData* moduleData ) : AIUpdateInterface( thing, moduleData )
  64. {
  65. m_supplyTruckStateMachine = NULL;
  66. m_preferredDock = INVALID_ID;
  67. m_numberBoxes = 0;
  68. m_forcePending = FALSE;
  69. m_forcedBusyPending = FALSE;
  70. m_supplyTruckStateMachine = newInstance(SupplyTruckStateMachine)( getObject() );
  71. m_supplyTruckStateMachine->initDefaultState();
  72. m_suppliesDepletedVoice = getSupplyTruckAIUpdateModuleData()->m_suppliesDepletedVoice;
  73. }
  74. //-------------------------------------------------------------------------------------------------
  75. SupplyTruckAIUpdate::~SupplyTruckAIUpdate( void )
  76. {
  77. m_supplyTruckStateMachine->deleteInstance();
  78. }
  79. //-------------------------------------------------------------------------------------------------
  80. UpdateSleepTime SupplyTruckAIUpdate::update( void )
  81. {
  82. StateReturnType stRet = m_supplyTruckStateMachine->updateStateMachine();
  83. UpdateSleepTime mine = IS_STATE_SLEEP(stRet) ? UPDATE_SLEEP(GET_STATE_SLEEP_FRAMES(stRet)) : UPDATE_SLEEP_NONE;
  84. // extend
  85. UpdateSleepTime ret = AIUpdateInterface::update();
  86. return (mine < ret) ? mine : ret;
  87. }
  88. //-------------------------------------------------------------------------------------------------
  89. Bool SupplyTruckAIUpdate::isCurrentlyFerryingSupplies() const
  90. {
  91. if (m_supplyTruckStateMachine)
  92. {
  93. switch (m_supplyTruckStateMachine->getCurrentStateID())
  94. {
  95. case ST_IDLE:
  96. case ST_BUSY:
  97. case ST_REGROUPING:
  98. return false;
  99. case ST_WANTING:
  100. case ST_DOCKING:
  101. return true;
  102. }
  103. }
  104. return false;
  105. }
  106. //-------------------------------------------------------------------------------------------------
  107. Bool SupplyTruckAIUpdate::isAvailableForSupplying() const
  108. {
  109. return true;
  110. }
  111. //-------------------------------------------------------------------------------------------------
  112. Bool SupplyTruckAIUpdate::loseOneBox()
  113. {
  114. if( m_numberBoxes == 0 )
  115. return FALSE;
  116. --m_numberBoxes;
  117. Drawable *draw = getObject()->getDrawable();
  118. if( draw )
  119. {
  120. draw->updateDrawableSupplyStatus( getSupplyTruckAIUpdateModuleData()->m_maxBoxesData, m_numberBoxes );
  121. }
  122. return TRUE;
  123. }
  124. //-------------------------------------------------------------------------------------------------
  125. Bool SupplyTruckAIUpdate::gainOneBox( Int remainingStock )
  126. {
  127. if( getSupplyTruckAIUpdateModuleData() && m_numberBoxes >= getSupplyTruckAIUpdateModuleData()->m_maxBoxesData )
  128. return FALSE;
  129. ++m_numberBoxes;
  130. //if I just took the last box,
  131. //i will announce that this supply source is now empty
  132. if (remainingStock == 0)
  133. {
  134. Object* bestWarehouse = getObject()->getControllingPlayer()->getResourceGatheringManager()->findBestSupplyWarehouse( getObject() );
  135. Bool playDepleted = FALSE;
  136. if ( bestWarehouse )
  137. {
  138. //figure out whether the best one is considerably far from the previous one (current position)
  139. Coord3D delta = *getObject()->getPosition();
  140. delta.sub( bestWarehouse->getPosition() );
  141. if ( delta.length() > getWarehouseScanDistance()/4)
  142. playDepleted = TRUE;
  143. }
  144. else
  145. playDepleted = TRUE;
  146. if (playDepleted && m_suppliesDepletedVoice.getEventName().isEmpty() == false)
  147. {
  148. m_suppliesDepletedVoice.setObjectID(getObject()->getID());
  149. m_suppliesDepletedVoice.setPlayingHandle(TheAudio->addAudioEvent(&m_suppliesDepletedVoice));
  150. }
  151. }
  152. Drawable *draw = getObject()->getDrawable();
  153. if( draw )
  154. {
  155. draw->updateDrawableSupplyStatus( getSupplyTruckAIUpdateModuleData()->m_maxBoxesData, m_numberBoxes );
  156. }
  157. return TRUE;
  158. }
  159. //----------------------------------------------------------------------------------------
  160. void SupplyTruckAIUpdate::privateIdle(CommandSourceType cmdSource)
  161. {
  162. // If the user gives a stop command, I have to turn off autopilot
  163. if( cmdSource == CMD_FROM_PLAYER )
  164. setForceBusyState(TRUE);
  165. AIUpdateInterface::privateIdle(cmdSource);
  166. }
  167. //----------------------------------------------------------------------------------------
  168. void SupplyTruckAIUpdate::privateDock( Object *dock, CommandSourceType cmdSource )
  169. {
  170. AIUpdateInterface::privateDock( dock, cmdSource );
  171. // If this is a command from a player, I will remember this as my favorite dock to override
  172. // ResourceManager searches.
  173. if ((cmdSource == CMD_FROM_PLAYER) && dock)
  174. {
  175. // Please note, there is not a separate Warehouse and Center memory by Design. Because
  176. // we lack a UI way to click Warehouse and drag to center to set up a specific path, the
  177. // practical realization has been made that you do not want separate memory.
  178. m_preferredDock = dock->getID();
  179. }
  180. }
  181. //----------------------------------------------------------------------------------------
  182. UnsignedInt SupplyTruckAIUpdate::getActionDelayForDock( Object *dock )
  183. {
  184. // Decide whether to use my Center or Warehouse delay time
  185. static const NameKeyType key_warehouseUpdate = NAMEKEY("SupplyWarehouseDockUpdate");
  186. SupplyWarehouseDockUpdate *warehouseModule = (SupplyWarehouseDockUpdate*) dock->findUpdateModule( key_warehouseUpdate );
  187. if (warehouseModule) {
  188. return getSupplyTruckAIUpdateModuleData()->m_warehouseDelay;
  189. }
  190. static const NameKeyType key_centerUpdate = NAMEKEY("SupplyCenterDockUpdate");
  191. SupplyCenterDockUpdate *centerModule = (SupplyCenterDockUpdate*) dock->findUpdateModule( key_centerUpdate );
  192. if (centerModule) {
  193. return getSupplyTruckAIUpdateModuleData()->m_centerDelay;
  194. }
  195. return 0;
  196. }
  197. //-------------------------------------------------------------------------------------------------
  198. //-------------------------------------------------------------------------------------------------
  199. Real SupplyTruckAIUpdate::getWarehouseScanDistance() const
  200. {
  201. // Ai players get larger scan range. jba.
  202. if (getObject()->getControllingPlayer()->getPlayerType() == PLAYER_COMPUTER) {
  203. return 2 * getSupplyTruckAIUpdateModuleData()->m_warehouseScanDistance;
  204. }
  205. return getSupplyTruckAIUpdateModuleData()->m_warehouseScanDistance;
  206. }
  207. // ------------------------------------------------------------------------------------------------
  208. /** CRC */
  209. // ------------------------------------------------------------------------------------------------
  210. void SupplyTruckAIUpdate::crc( Xfer *xfer )
  211. {
  212. // extend base class
  213. AIUpdateInterface::crc(xfer);
  214. } // end crc
  215. // ------------------------------------------------------------------------------------------------
  216. /** Xfer method
  217. * Version Info:
  218. * 1: Initial version */
  219. // ------------------------------------------------------------------------------------------------
  220. void SupplyTruckAIUpdate::xfer( Xfer *xfer )
  221. {
  222. XferVersion currentVersion = 1;
  223. XferVersion version = currentVersion;
  224. xfer->xferVersion( &version, currentVersion );
  225. // extend base class
  226. AIUpdateInterface::xfer(xfer);
  227. xfer->xferSnapshot(m_supplyTruckStateMachine);
  228. xfer->xferObjectID(&m_preferredDock);
  229. xfer->xferInt(&m_numberBoxes);
  230. xfer->xferBool(&m_forcePending);
  231. } // end xfer
  232. // ------------------------------------------------------------------------------------------------
  233. /** Load post process */
  234. // ------------------------------------------------------------------------------------------------
  235. void SupplyTruckAIUpdate::loadPostProcess( void )
  236. {
  237. // extend base class
  238. AIUpdateInterface::loadPostProcess();
  239. } // end loadPostProcess
  240. //----------------------------------------------------------------------------------------
  241. //----------------------------------------------------------------------------------------
  242. //----------------------------------------------------------------------------------------
  243. //----------------------------------------------------------------------------------------
  244. class SupplyTruckBusyState : public State
  245. {
  246. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(SupplyTruckBusyState, "SupplyTruckBusyState")
  247. protected:
  248. // snapshot interface STUBBED.
  249. virtual void crc( Xfer *xfer ){};
  250. virtual void xfer( Xfer *xfer ){};
  251. virtual void loadPostProcess(){};
  252. public:
  253. SupplyTruckBusyState( StateMachine *machine ) : State( machine, "SupplyTruckBusyState" ) { }
  254. virtual StateReturnType onEnter()
  255. {
  256. if( getMachineOwner() && getMachineOwner()->getAI() )
  257. {
  258. // Have to check, since constructor sets a state. Phhbbt. Constructor = set up, init = do first thing.
  259. SupplyTruckAIInterface *update = getMachineOwner()->getAI()->getSupplyTruckAIInterface();
  260. if( update )
  261. {
  262. // Turn off the Busy latch when we make it to Busy
  263. update->setForceBusyState( FALSE );
  264. }
  265. }
  266. #ifdef DEBUG_SUPPLY_STATE
  267. TheInGameUI->DEBUG_addFloatingText("entering busy state", getMachineOwner()->getPosition(), GameMakeColor(255, 0, 0, 255));
  268. #endif
  269. return STATE_CONTINUE;
  270. }
  271. virtual StateReturnType update()
  272. {
  273. return STATE_CONTINUE;
  274. }
  275. virtual void onExit(StateExitType status)
  276. {
  277. #ifdef DEBUG_SUPPLY_STATE
  278. TheInGameUI->DEBUG_addFloatingText("exiting busy state", getMachineOwner()->getPosition(), GameMakeColor(255, 0, 0, 255));
  279. #endif
  280. }
  281. };
  282. EMPTY_DTOR(SupplyTruckBusyState)
  283. //-----------------------------------------------------------------------------------------------------------
  284. class SupplyTruckIdleState : public State
  285. {
  286. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(SupplyTruckIdleState, "SupplyTruckIdleState")
  287. protected:
  288. // snapshot interface STUBBED.
  289. virtual void crc( Xfer *xfer ){};
  290. virtual void xfer( Xfer *xfer ){};
  291. virtual void loadPostProcess(){};
  292. public:
  293. SupplyTruckIdleState( StateMachine *machine ) : State( machine, "SupplyTruckIdleState" ) { }
  294. virtual StateReturnType onEnter();
  295. virtual StateReturnType update()
  296. {
  297. return STATE_CONTINUE;
  298. }
  299. virtual void onExit(StateExitType status)
  300. {
  301. #ifdef DEBUG_SUPPLY_STATE
  302. TheInGameUI->DEBUG_addFloatingText("exiting idle state", getMachineOwner()->getPosition(), GameMakeColor(255, 0, 0, 255));
  303. #endif
  304. }
  305. };
  306. EMPTY_DTOR(SupplyTruckIdleState)
  307. StateReturnType SupplyTruckIdleState::onEnter()
  308. {
  309. #ifdef DEBUG_SUPPLY_STATE
  310. TheInGameUI->DEBUG_addFloatingText("entering idle state", getMachineOwner()->getPosition(), GameMakeColor(255, 0, 0, 255));
  311. #endif
  312. Object *owner = getMachineOwner();
  313. if (owner != NULL) {
  314. AIUpdateInterface * ownerAI = owner->getAIUpdateInterface();
  315. if (ownerAI != NULL) {
  316. // This is to get idle workers to always show up on the
  317. // "idle worker button."
  318. // Basically if you have a worker interface, and we are entering
  319. // the idle state for the supply truck, we let the worker interface
  320. // know so it can decide which idle state it wants us to actually
  321. // be in from its perspective.
  322. WorkerAIInterface *workerAI = ownerAI->getWorkerAIInterface();
  323. if (workerAI != NULL) {
  324. workerAI->exitingSupplyTruckState();
  325. }
  326. }
  327. }
  328. return STATE_CONTINUE;
  329. }
  330. //-------------------------------------------------------------------------------------------------
  331. //-------------------------------------------------------------------------------------------------
  332. //-------------------------------------------------------------------------------------------------
  333. //-------------------------------------------------------------------------------------------------
  334. SupplyTruckStateMachine::SupplyTruckStateMachine( Object *owner ) : StateMachine( owner, "SupplyTruckStateMachine" )
  335. {
  336. static const StateConditionInfo busyConditions[] =
  337. {
  338. StateConditionInfo(ownerIdle, ST_IDLE, NULL),
  339. StateConditionInfo(ownerDocking, ST_DOCKING, NULL),
  340. StateConditionInfo(NULL, NULL, NULL) // keep last
  341. };
  342. static const StateConditionInfo idleConditions[] =
  343. {
  344. StateConditionInfo(isForcedIntoBusyState, ST_BUSY, NULL),
  345. StateConditionInfo(isForcedIntoWantingState, ST_WANTING, NULL),
  346. StateConditionInfo(ownerDocking, ST_DOCKING, NULL),
  347. StateConditionInfo(ownerNotDockingOrIdle, ST_BUSY, NULL),
  348. StateConditionInfo(NULL, NULL, NULL) // keep last
  349. };
  350. static const StateConditionInfo wantingConditions[] =
  351. {
  352. StateConditionInfo(ownerDocking, ST_DOCKING, NULL),
  353. StateConditionInfo(ownerNotDockingOrIdle, ST_BUSY, NULL),
  354. StateConditionInfo(NULL, NULL, NULL) // keep last
  355. };
  356. static const StateConditionInfo regroupingConditions[] =
  357. {
  358. StateConditionInfo(ownerIdle, ST_IDLE, NULL),
  359. StateConditionInfo(ownerDocking, ST_DOCKING, NULL),
  360. StateConditionInfo(NULL, NULL, NULL) // keep last
  361. };
  362. static const StateConditionInfo dockingConditions[] =
  363. {
  364. StateConditionInfo(isForcedIntoBusyState, ST_BUSY, NULL),
  365. StateConditionInfo(ownerAvailableForSupplying, ST_WANTING, NULL),
  366. StateConditionInfo(ownerNotDockingOrIdle, ST_BUSY, NULL),
  367. StateConditionInfo(NULL, NULL, NULL) // keep last
  368. };
  369. // order matters: first state is the default state.
  370. defineState( ST_BUSY, newInstance(SupplyTruckBusyState)( this ), ST_BUSY, ST_BUSY, busyConditions );
  371. defineState( ST_IDLE, newInstance(SupplyTruckIdleState)( this ), ST_BUSY, ST_BUSY, idleConditions );
  372. defineState( ST_WANTING, newInstance(SupplyTruckWantsToPickUpOrDeliverBoxesState)( this ), ST_BUSY, ST_REGROUPING, wantingConditions );
  373. defineState( ST_REGROUPING, newInstance(RegroupingState)( this ), ST_WANTING, ST_BUSY, regroupingConditions );
  374. defineState( ST_DOCKING, newInstance(DockingState)( this ), ST_BUSY, ST_BUSY, dockingConditions );
  375. }
  376. //-------------------------------------------------------------------------------------------------
  377. SupplyTruckStateMachine::~SupplyTruckStateMachine()
  378. {
  379. }
  380. // ------------------------------------------------------------------------------------------------
  381. /** CRC */
  382. // ------------------------------------------------------------------------------------------------
  383. void SupplyTruckStateMachine::crc( Xfer *xfer )
  384. {
  385. StateMachine::crc(xfer);
  386. } // end crc
  387. // ------------------------------------------------------------------------------------------------
  388. /** Xfer Method */
  389. // ------------------------------------------------------------------------------------------------
  390. void SupplyTruckStateMachine::xfer( Xfer *xfer )
  391. {
  392. XferVersion cv = 1;
  393. XferVersion v = cv;
  394. xfer->xferVersion( &v, cv );
  395. StateMachine::xfer(xfer);
  396. } // end xfer
  397. // ------------------------------------------------------------------------------------------------
  398. /** Load post process */
  399. // ------------------------------------------------------------------------------------------------
  400. void SupplyTruckStateMachine::loadPostProcess( void )
  401. {
  402. StateMachine::loadPostProcess();
  403. } // end loadPostProcess
  404. //-------------------------------------------------------------------------------------------------
  405. //-------------------------------------------------------------------------------------------------
  406. //-------------------------------------------------------------------------------------------------
  407. //-------------------------------------------------------------------------------------------------
  408. StateReturnType SupplyTruckWantsToPickUpOrDeliverBoxesState::onEnter()
  409. {
  410. #ifdef DEBUG_SUPPLY_STATE
  411. TheInGameUI->DEBUG_addFloatingText("entering wanting state", getMachineOwner()->getPosition(), GameMakeColor(255, 0, 0, 255));
  412. #endif
  413. return STATE_CONTINUE;
  414. }
  415. //-------------------------------------------------------------------------------------------------
  416. void SupplyTruckWantsToPickUpOrDeliverBoxesState::onExit(StateExitType status)
  417. {
  418. #ifdef DEBUG_SUPPLY_STATE
  419. TheInGameUI->DEBUG_addFloatingText("exiting wanting state", getMachineOwner()->getPosition(), GameMakeColor(255, 0, 0, 255));
  420. #endif
  421. }
  422. //-------------------------------------------------------------------------------------------------
  423. StateReturnType SupplyTruckWantsToPickUpOrDeliverBoxesState::update()
  424. {
  425. Object* owner = getMachineOwner();
  426. AIUpdateInterface* ownerAI = owner->getAIUpdateInterface();
  427. if (!ownerAI)
  428. return STATE_FAILURE;
  429. Player* ownerPlayer = owner->getControllingPlayer();
  430. ResourceGatheringManager *manager = ownerPlayer->getResourceGatheringManager();
  431. SupplyTruckAIInterface* update = ownerAI->getSupplyTruckAIInterface();
  432. if (!update)
  433. return STATE_FAILURE;
  434. if (!update->isAvailableForSupplying())
  435. {
  436. DEBUG_CRASH(("SupplyTruckWantsToPickUpOrDeliverBoxesState: isAvailableForSupplying==false; should not get here"));
  437. return STATE_FAILURE;
  438. }
  439. Int numBoxes = update->getNumberBoxes();
  440. if (numBoxes > 0)
  441. {
  442. // want a center.
  443. Object *bestCenter = manager->findBestSupplyCenter( owner );
  444. if( bestCenter )
  445. {
  446. ownerAI->aiDock( bestCenter, CMD_FROM_AI );
  447. return STATE_SUCCESS;
  448. }
  449. }
  450. else
  451. {
  452. // want a warehouse.
  453. Object* bestWarehouse = manager->findBestSupplyWarehouse( owner );
  454. if( bestWarehouse )
  455. {
  456. ownerAI->aiDock( bestWarehouse, CMD_FROM_AI );
  457. return STATE_SUCCESS;
  458. }
  459. }
  460. return STATE_FAILURE;// we aren't going to wait right here, we will go back to base and wait for
  461. // wanting to succeed some place safe.
  462. }
  463. //-------------------------------------------------------------------------------------------------
  464. StateReturnType RegroupingState::onEnter()
  465. {
  466. #ifdef DEBUG_SUPPLY_STATE
  467. TheInGameUI->DEBUG_addFloatingText("entering regrouping state", getMachineOwner()->getPosition(), GameMakeColor(255, 0, 0, 255));
  468. #endif
  469. // I have failed to find a dock, so my first choice is to go hang out at a Supply Center (I may have
  470. // failed to find a Warehouse). My second choices is to go to a ConYard. My last choice is just to
  471. // go to a friendly building.
  472. Object* owner = getMachineOwner();
  473. AIUpdateInterface* ownerAI = owner->getAIUpdateInterface();
  474. Player* ownerPlayer = owner->getControllingPlayer();
  475. if( !ownerPlayer || !ownerAI )
  476. return STATE_FAILURE;
  477. ownerAI->ignoreObstacle( NULL );
  478. SupplyTruckAIInterface *update = owner->getAIUpdateInterface()->getSupplyTruckAIInterface();
  479. if( !update )
  480. {
  481. return STATE_FAILURE;
  482. }
  483. Int numBoxes = update->getNumberBoxes();
  484. // If we are forced to regroup, and we have boxes, we want to wait for the player to
  485. // rebuild a supply center & go to it.
  486. Bool wanting = numBoxes > 0;
  487. update->setForceWantingState( wanting );
  488. Object *destinationObject = NULL;
  489. KindOfMaskType kindof;
  490. KindOfMaskType kindofnot;
  491. kindof.set(KINDOF_CASH_GENERATOR);
  492. kindofnot.clear();
  493. // can't do best supply center of the player's resource brain, because that adds canTransfer checks.
  494. destinationObject = ownerPlayer->findClosestByKindOf( owner, kindof, kindofnot );
  495. if( !destinationObject )
  496. {
  497. kindof.clear();
  498. kindof.set(KINDOF_COMMANDCENTER);
  499. kindofnot.clear();
  500. destinationObject = ownerPlayer->findClosestByKindOf( owner, kindof, kindofnot );
  501. }
  502. if( !destinationObject )
  503. {
  504. kindof.clear();
  505. kindof.set( KINDOF_STRUCTURE );
  506. kindofnot.clear();
  507. destinationObject = ownerPlayer->findClosestByKindOf( owner, kindof, kindofnot );
  508. }
  509. if( !destinationObject )
  510. {
  511. return STATE_FAILURE;
  512. }
  513. Coord3D destination;
  514. FindPositionOptions fpOptions;
  515. fpOptions.minRadius = 0.0f;
  516. fpOptions.maxRadius = 100.0f;
  517. if( ! ThePartitionManager->findPositionAround( destinationObject->getPosition(), &fpOptions, &destination ) )
  518. return STATE_FAILURE;
  519. ownerAI->aiMoveToPosition( &destination, CMD_FROM_AI );
  520. return STATE_CONTINUE;// Remember to say continue when you change ai command inside a state
  521. }
  522. //-------------------------------------------------------------------------------------------------
  523. void RegroupingState::onExit(StateExitType status)
  524. {
  525. #ifdef DEBUG_SUPPLY_STATE
  526. TheInGameUI->DEBUG_addFloatingText("exiting regroup state", getMachineOwner()->getPosition(), GameMakeColor(255, 0, 0, 255));
  527. #endif
  528. }
  529. //-------------------------------------------------------------------------------------------------
  530. StateReturnType DockingState::onEnter()
  531. {
  532. #ifdef DEBUG_SUPPLY_STATE
  533. TheInGameUI->DEBUG_addFloatingText("entering docking state", getMachineOwner()->getPosition(), GameMakeColor(255, 0, 0, 255));
  534. #endif
  535. Object *owner = getMachineOwner();
  536. SupplyTruckAIInterface *update = owner->getAIUpdateInterface()->getSupplyTruckAIInterface();
  537. if( !update )
  538. {
  539. return STATE_FAILURE;
  540. }
  541. // after we dock the first time, we clear this, and then follow our normal state machine path
  542. update->setForceWantingState(false);
  543. return STATE_CONTINUE;
  544. }
  545. //-------------------------------------------------------------------------------------------------
  546. StateReturnType DockingState::update()
  547. {
  548. return STATE_CONTINUE;
  549. }
  550. //-------------------------------------------------------------------------------------------------
  551. void DockingState::onExit(StateExitType status)
  552. {
  553. #ifdef DEBUG_SUPPLY_STATE
  554. TheInGameUI->DEBUG_addFloatingText("exiting docking state", getMachineOwner()->getPosition(), GameMakeColor(255, 0, 0, 255));
  555. #endif
  556. }
  557. //-------------------------------------------------------------------------------------------------
  558. //-------------------------------------------------------------------------------------------------
  559. //-------------------------------------------------------------------------------------------------
  560. //-------------------------------------------------------------------------------------------------
  561. //-------------------------------------------------------------------------------------------------
  562. //-------------------------------------------------------------------------------------------------
  563. //-------------------------------------------------------------------------------------------------
  564. /* static */ Bool SupplyTruckStateMachine::isForcedIntoWantingState( State *thisState, void* userData )
  565. {
  566. Object *owner = thisState->getMachineOwner();
  567. AIUpdateInterface *ai = owner->getAIUpdateInterface();
  568. if( !ai )
  569. return false;
  570. SupplyTruckAIInterface *update = ai->getSupplyTruckAIInterface();
  571. if( !update )
  572. return false;
  573. if (update->isForcedIntoWantingState())
  574. {
  575. #ifdef DEBUG_SUPPLY_STATE
  576. AsciiString tmp;
  577. tmp.format("isForcedIntoWantingState returns true (%s)",statenames[thisState->getID()]);
  578. TheInGameUI->DEBUG_addFloatingText(tmp, owner->getPosition(), GameMakeColor(255, 0, 0, 255));
  579. #endif
  580. return true;
  581. }
  582. return false;
  583. }
  584. //-------------------------------------------------------------------------------------------------
  585. /* static */ Bool SupplyTruckStateMachine::isForcedIntoBusyState( State *thisState, void* userData )
  586. {
  587. Object *owner = thisState->getMachineOwner();
  588. AIUpdateInterface *ai = owner->getAIUpdateInterface();
  589. if( !ai )
  590. return false;
  591. SupplyTruckAIInterface *update = ai->getSupplyTruckAIInterface();
  592. if( !update )
  593. return false;
  594. if (update->isForcedIntoBusyState())
  595. {
  596. #ifdef DEBUG_SUPPLY_STATE
  597. AsciiString tmp;
  598. tmp.format("isForcedIntoBusytate returns true (%s)",statenames[thisState->getID()]);
  599. TheInGameUI->DEBUG_addFloatingText(tmp, owner->getPosition(), GameMakeColor(255, 0, 0, 255));
  600. #endif
  601. return true;
  602. }
  603. return false;
  604. }
  605. //-------------------------------------------------------------------------------------------------
  606. /* static */ Bool SupplyTruckStateMachine::ownerDocking( State *thisState, void* userData )
  607. {
  608. Object *owner = thisState->getMachineOwner();
  609. AIUpdateInterface *ai = owner->getAIUpdateInterface();
  610. if( !ai )
  611. return false;
  612. AIStateType masterState = ai->getAIStateType();
  613. if (masterState == AI_DOCK)
  614. {
  615. #ifdef DEBUG_SUPPLY_STATE
  616. AsciiString tmp;
  617. tmp.format("ownerDocking returns true (%s)",statenames[thisState->getID()]);
  618. TheInGameUI->DEBUG_addFloatingText(tmp, owner->getPosition(), GameMakeColor(255, 0, 0, 255));
  619. #endif
  620. return true;
  621. }
  622. return false;
  623. }
  624. //-------------------------------------------------------------------------------------------------
  625. /* static */ Bool SupplyTruckStateMachine::ownerIdle( State *thisState, void* userData )
  626. {
  627. Object *owner = thisState->getMachineOwner();
  628. AIUpdateInterface *ai = owner->getAIUpdateInterface();
  629. if( !ai )
  630. return false;
  631. if (ai->isIdle())
  632. {
  633. #ifdef DEBUG_SUPPLY_STATE
  634. AsciiString tmp;
  635. tmp.format("ownerIdle returns true (%s)",statenames[thisState->getID()]);
  636. TheInGameUI->DEBUG_addFloatingText(tmp, owner->getPosition(), GameMakeColor(255, 0, 0, 255));
  637. #endif
  638. return true;
  639. }
  640. return false;
  641. }
  642. //-------------------------------------------------------------------------------------------------
  643. /* static */ Bool SupplyTruckStateMachine::ownerAvailableForSupplying( State *thisState, void* userData )
  644. {
  645. Object *owner = thisState->getMachineOwner();
  646. AIUpdateInterface *ai = owner->getAIUpdateInterface();
  647. if( !ai )
  648. return false;
  649. SupplyTruckAIInterface *update = ai->getSupplyTruckAIInterface();
  650. if( !update )
  651. return false;
  652. if (update->isAvailableForSupplying() && ai->isIdle())
  653. {
  654. #ifdef DEBUG_SUPPLY_STATE
  655. AsciiString tmp;
  656. tmp.format("ownerAvailableForSupplying returns true (%s)",statenames[thisState->getID()]);
  657. TheInGameUI->DEBUG_addFloatingText(tmp, owner->getPosition(), GameMakeColor(255, 0, 0, 255));
  658. #endif
  659. return true;
  660. }
  661. return false;
  662. }
  663. //-------------------------------------------------------------------------------------------------
  664. /* static */ Bool SupplyTruckStateMachine::ownerNotDockingOrIdle( State *thisState, void* userData )
  665. {
  666. Object *owner = thisState->getMachineOwner();
  667. AIUpdateInterface *ai = owner->getAIUpdateInterface();
  668. if( !ai )
  669. return false;
  670. if (!ai->isIdle() && ai->getAIStateType() != AI_DOCK)
  671. {
  672. #ifdef DEBUG_SUPPLY_STATE
  673. AsciiString tmp;
  674. tmp.format("ownerNotDockingOrIdle returns true (%s)",statenames[thisState->getID()]);
  675. TheInGameUI->DEBUG_addFloatingText(tmp, owner->getPosition(), GameMakeColor(255, 0, 0, 255));
  676. #endif
  677. return true;
  678. }
  679. return false;
  680. }