SupplyTruckAIUpdate.cpp 29 KB

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