AITNGuard.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: AITNGuard.cpp
  24. /*---------------------------------------------------------------------------*/
  25. /* EA Pacific */
  26. /* Confidential Information */
  27. /* Copyright (C) 2001 - All Rights Reserved */
  28. /* DO NOT DISTRIBUTE */
  29. /*---------------------------------------------------------------------------*/
  30. /* Project: RTS3 */
  31. /* File name: AITNGuard.cpp */
  32. /* Created: John Ahlquist., 12/20/2002 */
  33. /* Desc: // Set up guard tunnel network states for AI */
  34. /* Revision History: */
  35. /* 12/20/2002 : Initial creation - modified from AIGuard.cpp */
  36. /*---------------------------------------------------------------------------*/
  37. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  38. #include "Common/PerfTimer.h"
  39. #include "Common/Team.h"
  40. #include "Common/Player.h"
  41. #include "Common/Xfer.h"
  42. #include "GameLogic/AI.h"
  43. #include "GameLogic/AIPathfind.h"
  44. #include "GameLogic/AITNGuard.h"
  45. #include "GameLogic/Module/AIUpdate.h"
  46. #include "GameLogic/Module/BodyModule.h"
  47. #include "GameLogic/Module/CollideModule.h"
  48. #include "Common/TunnelTracker.h"
  49. #include "GameLogic/Object.h"
  50. #include "GameLogic/PartitionManager.h"
  51. #include "GameLogic/PolygonTrigger.h"
  52. const Real CLOSE_ENOUGH = (25.0f);
  53. #ifdef _INTERNAL
  54. // for occasional debugging...
  55. //#pragma optimize("", off)
  56. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  57. #endif
  58. static Bool hasAttackedMeAndICanReturnFire( State *thisState, void* /*userData*/ )
  59. {
  60. Object *obj = thisState->getMachineOwner();
  61. BodyModuleInterface *bmi = obj ? obj->getBodyModule() : NULL;
  62. if (!(obj && bmi)) {
  63. return FALSE;
  64. }
  65. if (bmi->getClearableLastAttacker() == INVALID_ID) {
  66. return FALSE;
  67. }
  68. // K. It appears we have a valid aggressor. Find it, and determine if we can attack it, etc.
  69. Object *target = TheGameLogic->findObjectByID(bmi->getClearableLastAttacker());
  70. bmi->clearLastAttacker();
  71. // We use the clearable last attacker because we should continue attacking the guy. But if he
  72. // stops attacking us, then we want our timer to kick us off of him and make us go attack
  73. // other units instead.
  74. if (!target) {
  75. return FALSE;
  76. }
  77. if (obj->getRelationship(target) != ENEMIES) {
  78. return FALSE;
  79. }
  80. // This is a quick test on the target. It will be duplicated in getAbleToAttackSpecificObject,
  81. // but the payoff is worth the duplication.
  82. if (target->isEffectivelyDead()) {
  83. return FALSE;
  84. }
  85. CanAttackResult result = obj->getAbleToAttackSpecificObject(ATTACK_NEW_TARGET, target, CMD_FROM_AI);
  86. if( result == ATTACKRESULT_POSSIBLE || result == ATTACKRESULT_POSSIBLE_AFTER_MOVING )
  87. {
  88. return TRUE;
  89. }
  90. return FALSE;
  91. }
  92. static Object *findBestTunnel(Player *ownerPlayer, const Coord3D *pos)
  93. {
  94. if (!ownerPlayer) return NULL; // should never happen, but hey. jba.
  95. TunnelTracker *tunnels = ownerPlayer->getTunnelSystem();
  96. Object *bestTunnel = NULL;
  97. Real bestDistSqr = 0;
  98. const std::list<ObjectID> *allTunnels = tunnels->getContainerList();
  99. for( std::list<ObjectID>::const_iterator iter = allTunnels->begin(); iter != allTunnels->end(); iter++ ) {
  100. // For each ID, look it up and change its team. We all get captured together.
  101. Object *currentTunnel = TheGameLogic->findObjectByID( *iter );
  102. if( currentTunnel ) {
  103. Real dx = currentTunnel->getPosition()->x-pos->x;
  104. Real dy = currentTunnel->getPosition()->y-pos->y;
  105. Real distSqr = dx*dx+dy*dy;
  106. if (bestTunnel==NULL || distSqr<bestDistSqr) {
  107. bestDistSqr = distSqr;
  108. bestTunnel = currentTunnel;
  109. }
  110. }
  111. }
  112. return bestTunnel;
  113. }
  114. //-- ExitConditions -------------------------------------------------------------------------------
  115. /**
  116. * This returns true if the conditions specified have been met, false otherwise.
  117. */
  118. Bool TunnelNetworkExitConditions::shouldExit(const StateMachine* machine) const
  119. {
  120. if (TheGameLogic->getFrame() >= m_attackGiveUpFrame)
  121. {
  122. return true;
  123. }
  124. return false;
  125. }
  126. //-- AITNGuardMachine -------------------------------------------------------------------------------
  127. //--------------------------------------------------------------------------------------
  128. AITNGuardMachine::AITNGuardMachine( Object *owner ) :
  129. StateMachine(owner, "AITNGuardMachine"),
  130. m_nemesisToAttack(INVALID_ID),
  131. m_guardMode(GUARDMODE_NORMAL)
  132. {
  133. m_positionToGuard.zero();
  134. static const StateConditionInfo attackAggressors[] =
  135. {
  136. StateConditionInfo(hasAttackedMeAndICanReturnFire, AI_TN_GUARD_ATTACK_AGGRESSOR, NULL),
  137. StateConditionInfo(NULL, NULL, NULL) // keep last
  138. };
  139. // order matters: first state is the default state.
  140. // srj sez: I made "return" the start state, so that if ordered to guard a position
  141. // that isn't the unit's current position, it moves to that position first.
  142. defineState( AI_TN_GUARD_RETURN, newInstance(AITNGuardReturnState)( this ), AI_TN_GUARD_IDLE, AI_TN_GUARD_INNER, attackAggressors );
  143. defineState( AI_TN_GUARD_IDLE, newInstance(AITNGuardIdleState)( this ), AI_TN_GUARD_INNER, AI_TN_GUARD_RETURN );
  144. defineState( AI_TN_GUARD_INNER, newInstance(AITNGuardInnerState)( this ), AI_TN_GUARD_OUTER, AI_TN_GUARD_OUTER , attackAggressors);
  145. defineState( AI_TN_GUARD_OUTER, newInstance(AITNGuardOuterState)( this ), AI_TN_GUARD_GET_CRATE, AI_TN_GUARD_GET_CRATE );
  146. defineState( AI_TN_GUARD_GET_CRATE, newInstance(AITNGuardPickUpCrateState)( this ), AI_TN_GUARD_RETURN, AI_TN_GUARD_RETURN );
  147. defineState( AI_TN_GUARD_ATTACK_AGGRESSOR, newInstance(AITNGuardAttackAggressorState)( this ), AI_TN_GUARD_RETURN, AI_TN_GUARD_RETURN );
  148. #ifdef STATE_MACHINE_DEBUG
  149. setDebugOutput(true);
  150. #endif
  151. }
  152. //--------------------------------------------------------------------------------------
  153. AITNGuardMachine::~AITNGuardMachine()
  154. {
  155. }
  156. //--------------------------------------------------------------------------------------
  157. /*static*/ Real AITNGuardMachine::getStdGuardRange(const Object* obj)
  158. {
  159. Real visionRange = TheAI->getAdjustedVisionRangeForObject(obj,
  160. AI_VISIONFACTOR_OWNERTYPE | AI_VISIONFACTOR_MOOD | AI_VISIONFACTOR_GUARDINNER);
  161. return visionRange;
  162. }
  163. //--------------------------------------------------------------------------------------
  164. Bool AITNGuardMachine::lookForInnerTarget(void)
  165. {
  166. Object* owner = getOwner();
  167. // Check if team auto targets same victim.
  168. Object *teamVictim = NULL;
  169. if (owner->getTeam()->getPrototype()->getTemplateInfo()->m_attackCommonTarget)
  170. {
  171. teamVictim = owner->getTeam()->getTeamTargetObject();
  172. if (teamVictim)
  173. {
  174. setNemesisID(teamVictim->getID());
  175. return true; // Transitions to AITNGuardInnerState.
  176. }
  177. }
  178. // Find tunnel network to defend.
  179. // Scan my tunnels.
  180. Player *ownerPlayer = getOwner()->getControllingPlayer();
  181. if (!ownerPlayer) return false; // should never happen, but hey. jba.
  182. TunnelTracker *tunnels = ownerPlayer->getTunnelSystem();
  183. if (tunnels==NULL) return false;
  184. if (tunnels->getCurNemesis()) {
  185. setNemesisID(tunnels->getCurNemesis()->getID());
  186. return true; // Transitions to AITNGuardInnerState.
  187. }
  188. const std::list<ObjectID> *allTunnels = tunnels->getContainerList();
  189. for( std::list<ObjectID>::const_iterator iter = allTunnels->begin(); iter != allTunnels->end(); iter++ ) {
  190. Object *currentTunnel = TheGameLogic->findObjectByID( *iter );
  191. if( currentTunnel ) {
  192. // Check for attacking.
  193. if (currentTunnel->getAI()) {
  194. Object *victim = currentTunnel->getAI()->getGoalObject();
  195. if (owner->getRelationship(victim) == ENEMIES) {
  196. setNemesisID(victim->getID());
  197. return true;
  198. }
  199. }
  200. // check for attacked.
  201. BodyModuleInterface *body = currentTunnel->getBodyModule();
  202. if (body) {
  203. const DamageInfo *info = body->getLastDamageInfo();
  204. if (info) {
  205. if (info->out.m_noEffect) {
  206. continue;
  207. }
  208. if (body->getLastDamageTimestamp() + TheAI->getAiData()->m_guardEnemyScanRate > TheGameLogic->getFrame()) {
  209. // winner.
  210. ObjectID attackerID = info->in.m_sourceID;
  211. Object *attacker = TheGameLogic->findObjectByID(attackerID);
  212. if( attacker )
  213. {
  214. if (owner->getRelationship(attacker) != ENEMIES) {
  215. continue;
  216. }
  217. CanAttackResult result = getOwner()->getAbleToAttackSpecificObject(ATTACK_TUNNEL_NETWORK_GUARD, attacker, CMD_FROM_AI);
  218. if( result == ATTACKRESULT_POSSIBLE || result == ATTACKRESULT_POSSIBLE_AFTER_MOVING )
  219. {
  220. setNemesisID(attackerID);
  221. owner->getTeam()->setTeamTargetObject(attacker);
  222. tunnels->updateNemesis(attacker);
  223. return true; // Transitions to AITNGuardInnerState.
  224. }
  225. }
  226. }
  227. }
  228. }
  229. }
  230. }
  231. return false;
  232. }
  233. // ------------------------------------------------------------------------------------------------
  234. /** CRC */
  235. // ------------------------------------------------------------------------------------------------
  236. void AITNGuardMachine::crc( Xfer *xfer )
  237. {
  238. } // end crc
  239. // ------------------------------------------------------------------------------------------------
  240. /** Xfer Method */
  241. // ------------------------------------------------------------------------------------------------
  242. void AITNGuardMachine::xfer( Xfer *xfer )
  243. {
  244. // version
  245. XferVersion currentVersion = 2;
  246. XferVersion version = currentVersion;
  247. xfer->xferVersion( &version, currentVersion );
  248. if (version>=2) {
  249. StateMachine::xfer(xfer); // Forgot this in initial implementation. jba.
  250. }
  251. xfer->xferObjectID(&m_nemesisToAttack);
  252. xfer->xferCoord3D(&m_positionToGuard);
  253. } // end xfer
  254. // ------------------------------------------------------------------------------------------------
  255. /** Load post process */
  256. // ------------------------------------------------------------------------------------------------
  257. void AITNGuardMachine::loadPostProcess( void )
  258. {
  259. } // end loadPostProcess
  260. //-- AITNGuardInnerState ----------------------------------------------------------------------------
  261. // ------------------------------------------------------------------------------------------------
  262. /** CRC */
  263. // ------------------------------------------------------------------------------------------------
  264. void AITNGuardInnerState::crc( Xfer *xfer )
  265. {
  266. } // end crc
  267. // ------------------------------------------------------------------------------------------------
  268. /** Xfer Method */
  269. // ------------------------------------------------------------------------------------------------
  270. void AITNGuardInnerState::xfer( Xfer *xfer )
  271. {
  272. // version
  273. XferVersion currentVersion = 1;
  274. XferVersion version = currentVersion;
  275. xfer->xferVersion( &version, currentVersion );
  276. } // end xfer
  277. // ------------------------------------------------------------------------------------------------
  278. /** Load post process */
  279. // ------------------------------------------------------------------------------------------------
  280. void AITNGuardInnerState::loadPostProcess( void )
  281. {
  282. onEnter();
  283. } // end loadPostProcess
  284. //--------------------------------------------------------------------------------------
  285. StateReturnType AITNGuardInnerState::onEnter( void )
  286. {
  287. Object* nemesis = TheGameLogic->findObjectByID(getGuardMachine()->getNemesisID()) ;
  288. if (nemesis == NULL)
  289. {
  290. DEBUG_LOG(("Unexpected NULL nemesis in AITNGuardInnerState.\n"));
  291. return STATE_SUCCESS;
  292. }
  293. m_exitConditions.m_attackGiveUpFrame = TheGameLogic->getFrame() + TheAI->getAiData()->m_guardChaseUnitFrames;
  294. m_attackState = newInstance(AIAttackState)(getMachine(), false, true, false, &m_exitConditions);
  295. m_attackState->getMachine()->setGoalObject(nemesis);
  296. StateReturnType returnVal = m_attackState->onEnter();
  297. if (returnVal == STATE_CONTINUE) {
  298. return STATE_CONTINUE;
  299. }
  300. // if we had no one to attack, we were successful, so go to the next state.
  301. return STATE_SUCCESS;
  302. }
  303. static Object *TunnelNetworkScan(Object *owner)
  304. {
  305. PartitionFilterRelationship f1(owner, PartitionFilterRelationship::ALLOW_ENEMIES);
  306. PartitionFilterPossibleToAttack f2(ATTACK_NEW_TARGET, owner, CMD_FROM_AI);
  307. PartitionFilterSameMapStatus filterMapStatus(owner);
  308. PartitionFilter *filters[16];
  309. Int count = 0;
  310. filters[count++] = &f1;
  311. filters[count++] = &f2;
  312. filters[count++] = &filterMapStatus;
  313. Real visionRange = AITNGuardMachine::getStdGuardRange(owner);
  314. filters[count++] = NULL;
  315. Object* target = ThePartitionManager->getClosestObject(owner->getPosition(), visionRange, FROM_CENTER_2D, filters);
  316. return target;
  317. }
  318. //--------------------------------------------------------------------------------------
  319. StateReturnType AITNGuardInnerState::update( void )
  320. {
  321. Object* nemesis = TheGameLogic->findObjectByID(getGuardMachine()->getNemesisID()) ;
  322. Player *ownerPlayer = getMachineOwner()->getControllingPlayer();
  323. TunnelTracker *tunnels = NULL;
  324. if (ownerPlayer) {
  325. tunnels = ownerPlayer->getTunnelSystem();
  326. }
  327. Object* owner = getMachineOwner();
  328. // killed him.
  329. Object *teamVictim = owner->getTeam()->getTeamTargetObject();
  330. if (nemesis == NULL)
  331. {
  332. if (teamVictim)
  333. {
  334. getGuardMachine()->setNemesisID(teamVictim->getID());
  335. m_exitConditions.m_attackGiveUpFrame = TheGameLogic->getFrame() + TheAI->getAiData()->m_guardChaseUnitFrames;
  336. return STATE_CONTINUE;
  337. }
  338. // Check tunnel.
  339. if (tunnels) {
  340. nemesis = tunnels->getCurNemesis();
  341. if (nemesis) {
  342. getGuardMachine()->setNemesisID(nemesis->getID());
  343. m_exitConditions.m_attackGiveUpFrame = TheGameLogic->getFrame() + TheAI->getAiData()->m_guardChaseUnitFrames;
  344. return STATE_CONTINUE;
  345. }
  346. }
  347. if (m_scanForEnemy) {
  348. m_scanForEnemy = false; // we just do 1 scan.
  349. nemesis = TunnelNetworkScan(owner);
  350. if (nemesis) {
  351. m_attackState->onExit(EXIT_RESET);
  352. m_attackState->getMachine()->setGoalObject(nemesis);
  353. if (tunnels) {
  354. tunnels->updateNemesis(nemesis);
  355. }
  356. StateReturnType returnVal = m_attackState->onEnter();
  357. return returnVal;
  358. }
  359. }
  360. } else {
  361. if (nemesis != teamVictim && teamVictim != NULL) {
  362. tunnels->updateNemesis(nemesis);
  363. getGuardMachine()->setNemesisID(teamVictim->getID());
  364. }
  365. }
  366. return m_attackState->update();
  367. }
  368. //--------------------------------------------------------------------------------------
  369. void AITNGuardInnerState::onExit( StateExitType status )
  370. {
  371. if (m_attackState)
  372. {
  373. m_attackState->onExit(status);
  374. m_attackState->deleteInstance();
  375. m_attackState = NULL;
  376. }
  377. }
  378. //-- AITNGuardOuterState ----------------------------------------------------------------------------
  379. // ------------------------------------------------------------------------------------------------
  380. /** CRC */
  381. // ------------------------------------------------------------------------------------------------
  382. void AITNGuardOuterState::crc( Xfer *xfer )
  383. {
  384. } // end crc
  385. // ------------------------------------------------------------------------------------------------
  386. /** Xfer Method */
  387. // ------------------------------------------------------------------------------------------------
  388. void AITNGuardOuterState::xfer( Xfer *xfer )
  389. {
  390. // version
  391. XferVersion currentVersion = 1;
  392. XferVersion version = currentVersion;
  393. xfer->xferVersion( &version, currentVersion );
  394. } // end xfer
  395. // ------------------------------------------------------------------------------------------------
  396. /** Load post process */
  397. // ------------------------------------------------------------------------------------------------
  398. void AITNGuardOuterState::loadPostProcess( void )
  399. { AITNGuardOuterState
  400. onEnter();
  401. } // end loadPostProcess
  402. //--------------------------------------------------------------------------------------
  403. StateReturnType AITNGuardOuterState::onEnter( void )
  404. {
  405. if (getGuardMachine()->getGuardMode() == GUARDMODE_GUARD_WITHOUT_PURSUIT)
  406. {
  407. // "patrol" mode does not follow targets outside the guard area.
  408. return STATE_SUCCESS;
  409. }
  410. Object* nemesis = TheGameLogic->findObjectByID(getGuardMachine()->getNemesisID()) ;
  411. if (nemesis == NULL)
  412. {
  413. DEBUG_LOG(("Unexpected NULL nemesis in AITNGuardOuterState.\n"));
  414. return STATE_SUCCESS;
  415. }
  416. m_exitConditions.m_attackGiveUpFrame = TheGameLogic->getFrame() + TheAI->getAiData()->m_guardChaseUnitFrames;
  417. m_attackState = newInstance(AIAttackState)(getMachine(), false, true, false, &m_exitConditions);
  418. m_attackState->getMachine()->setGoalObject(nemesis);
  419. StateReturnType returnVal = m_attackState->onEnter();
  420. if (returnVal == STATE_CONTINUE) {
  421. return STATE_CONTINUE;
  422. }
  423. // if we had no one to attack, we were successful, so go to the next state.
  424. return STATE_SUCCESS;
  425. }
  426. //--------------------------------------------------------------------------------------
  427. StateReturnType AITNGuardOuterState::update( void )
  428. {
  429. Object *owner = getMachineOwner();
  430. Object* goalObj = m_attackState->getMachineGoalObject();
  431. if (goalObj)
  432. {
  433. } else {
  434. Object* nemesis = TheGameLogic->findObjectByID(getGuardMachine()->getNemesisID()) ;
  435. if (nemesis) {
  436. goalObj = nemesis;
  437. }
  438. // Check if team auto targets same victim.
  439. Object *teamVictim = NULL;
  440. if (goalObj == NULL && owner->getTeam()->getPrototype()->getTemplateInfo()->m_attackCommonTarget)
  441. {
  442. teamVictim = owner->getTeam()->getTeamTargetObject();
  443. if (teamVictim)
  444. {
  445. goalObj = teamVictim;
  446. }
  447. m_attackState->getMachine()->setGoalObject(goalObj);
  448. return m_attackState->onEnter();
  449. }
  450. }
  451. return m_attackState->update();
  452. }
  453. //--------------------------------------------------------------------------------------
  454. void AITNGuardOuterState::onExit( StateExitType status )
  455. {
  456. if (m_attackState)
  457. {
  458. m_attackState->onExit(status);
  459. m_attackState->deleteInstance();
  460. m_attackState = NULL;
  461. }
  462. }
  463. //-- AITNGuardReturnState ----------------------------------------------------------------------------
  464. // ------------------------------------------------------------------------------------------------
  465. /** CRC */
  466. // ------------------------------------------------------------------------------------------------
  467. void AITNGuardReturnState::crc( Xfer *xfer )
  468. {
  469. AIEnterState::crc(xfer);
  470. } // end crc
  471. // ------------------------------------------------------------------------------------------------
  472. /** Xfer Method */
  473. // ------------------------------------------------------------------------------------------------
  474. void AITNGuardReturnState::xfer( Xfer *xfer )
  475. {
  476. // version
  477. XferVersion currentVersion = 1;
  478. XferVersion version = currentVersion;
  479. xfer->xferVersion( &version, currentVersion );
  480. AIEnterState::xfer(xfer);
  481. xfer->xferUnsignedInt(&m_nextReturnScanTime);
  482. } // end xfer
  483. // ------------------------------------------------------------------------------------------------
  484. /** Load post process */
  485. // ------------------------------------------------------------------------------------------------
  486. void AITNGuardReturnState::loadPostProcess( void )
  487. {
  488. AIEnterState::loadPostProcess();
  489. } // end loadPostProcess
  490. //--------------------------------------------------------------------------------------
  491. StateReturnType AITNGuardReturnState::onEnter( void )
  492. {
  493. UnsignedInt now = TheGameLogic->getFrame();
  494. m_nextReturnScanTime = now + GameLogicRandomValue(0, TheAI->getAiData()->m_guardEnemyReturnScanRate);
  495. // no, no, no, don't do this in onEnter, unless you like really slow maps. (srj)
  496. // if (getGuardMachine()->lookForInnerTarget())
  497. // return STATE_FAILURE; // early termination because we found a target.
  498. // Find tunnel network to enter.
  499. // Scan my tunnels.
  500. Object *bestTunnel = findBestTunnel(getMachineOwner()->getControllingPlayer(), getMachineOwner()->getPosition());
  501. if (bestTunnel==NULL) return STATE_FAILURE;
  502. getMachine()->setGoalObject(bestTunnel);
  503. getMachineOwner()->getAI()->friend_setGoalObject(bestTunnel);
  504. return AIEnterState::onEnter();
  505. }
  506. //--------------------------------------------------------------------------------------
  507. StateReturnType AITNGuardReturnState::update( void )
  508. {
  509. Player *ownerPlayer = getMachineOwner()->getControllingPlayer();
  510. if (getMachineOwner()->getTeam()) {
  511. Object *teamVictim = getMachineOwner()->getTeam()->getTeamTargetObject();
  512. if (teamVictim) {
  513. getGuardMachine()->setNemesisID(teamVictim->getID());
  514. return STATE_FAILURE; // Fail to return goes to inner attack state.
  515. }
  516. }
  517. // Check tunnel for target.
  518. TunnelTracker *tunnels = NULL;
  519. if (ownerPlayer) {
  520. tunnels = ownerPlayer->getTunnelSystem();
  521. }
  522. if (tunnels) {
  523. Object *nemesis = tunnels->getCurNemesis();
  524. if (nemesis) {
  525. // Check distance.
  526. //Coord3D dist;
  527. //Coord3D curPos;
  528. //dist.set()
  529. getGuardMachine()->setNemesisID(nemesis->getID());
  530. return STATE_FAILURE; // Fail to return goes to inner attack state.
  531. }
  532. }
  533. // Just let the return movement finish.
  534. StateReturnType ret = AIEnterState::update();
  535. if (ret==STATE_CONTINUE) return STATE_CONTINUE;
  536. return STATE_SUCCESS;
  537. }
  538. //--------------------------------------------------------------------------------------
  539. void AITNGuardReturnState::onExit( StateExitType status )
  540. {
  541. AIEnterState::onExit( status );
  542. }
  543. //-- AITNGuardIdleState ----------------------------------------------------------------------------
  544. // ------------------------------------------------------------------------------------------------
  545. /** CRC */
  546. // ------------------------------------------------------------------------------------------------
  547. void AITNGuardIdleState::crc( Xfer *xfer )
  548. {
  549. } // end crc
  550. // ------------------------------------------------------------------------------------------------
  551. /** Xfer Method */
  552. // ------------------------------------------------------------------------------------------------
  553. void AITNGuardIdleState::xfer( Xfer *xfer )
  554. {
  555. // version
  556. XferVersion currentVersion = 1;
  557. XferVersion version = currentVersion;
  558. xfer->xferVersion( &version, currentVersion );
  559. xfer->xferUnsignedInt(&m_nextEnemyScanTime);
  560. } // end xfer
  561. // ------------------------------------------------------------------------------------------------
  562. /** Load post process */
  563. // ------------------------------------------------------------------------------------------------
  564. void AITNGuardIdleState::loadPostProcess( void )
  565. {
  566. } // end loadPostProcess
  567. //--------------------------------------------------------------------------------------
  568. StateReturnType AITNGuardIdleState::onEnter( void )
  569. {
  570. // first time thru, use a random amount so that everyone doesn't scan on the same frame,
  571. // to avoid "spikes".
  572. UnsignedInt now = TheGameLogic->getFrame();
  573. m_nextEnemyScanTime = now + GameLogicRandomValue(0, TheAI->getAiData()->m_guardEnemyScanRate);
  574. getMachineOwner()->getAI()->friend_setGoalObject(NULL);
  575. return STATE_CONTINUE;
  576. }
  577. //--------------------------------------------------------------------------------------
  578. StateReturnType AITNGuardIdleState::update( void )
  579. {
  580. //DEBUG_LOG(("AITNGuardIdleState frame %d: %08lx\n",TheGameLogic->getFrame(),getMachineOwner()));
  581. UnsignedInt now = TheGameLogic->getFrame();
  582. if (now < m_nextEnemyScanTime)
  583. return STATE_SLEEP(m_nextEnemyScanTime - now);
  584. m_nextEnemyScanTime = now + TheAI->getAiData()->m_guardEnemyScanRate;
  585. getMachineOwner()->getAI()->friend_setGoalObject(NULL);
  586. #ifdef STATE_MACHINE_DEBUG
  587. //getMachine()->setDebugOutput(true);
  588. #endif
  589. Object *owner = getMachineOwner();
  590. AIUpdateInterface *ai = owner->getAIUpdateInterface();
  591. // Check to see if we have created a crate we need to pick up.
  592. if (ai->getCrateID() != INVALID_ID)
  593. {
  594. getMachine()->setState(AI_TN_GUARD_GET_CRATE);
  595. return STATE_SLEEP(m_nextEnemyScanTime - now);
  596. }
  597. // if anyone is in the inner area, return success.
  598. if (getGuardMachine()->lookForInnerTarget())
  599. {
  600. Object *nemesis = TheGameLogic->findObjectByID(getGuardMachine()->getNemesisID());
  601. if (nemesis == NULL)
  602. {
  603. DEBUG_LOG(("Unexpected NULL nemesis in AITNGuardAttackAggressorState.\n"));
  604. return STATE_SLEEP(0);
  605. }
  606. if (getMachineOwner()->getContainedBy()) {
  607. Object *bestTunnel = findBestTunnel(owner->getControllingPlayer(), nemesis->getPosition());
  608. ExitInterface* goalExitInterface = bestTunnel->getContain() ? bestTunnel->getContain()->getContainExitInterface() : NULL;
  609. if( goalExitInterface == NULL )
  610. return STATE_FAILURE;
  611. if( goalExitInterface->isExitBusy() )
  612. return STATE_SLEEP(0);// Just wait a sec.
  613. goalExitInterface->exitObjectInAHurry(getMachineOwner());
  614. return STATE_SLEEP(0);
  615. }
  616. return STATE_SUCCESS; // Transitions to AITNGuardInnerState.
  617. }
  618. if (!owner->getContainedBy() && findBestTunnel(owner->getControllingPlayer(), owner->getPosition())) {
  619. return STATE_FAILURE; // go to AITNGuardReturnState, & enter a tunnel.
  620. }
  621. return STATE_SLEEP(m_nextEnemyScanTime - now);
  622. }
  623. //--------------------------------------------------------------------------------------
  624. void AITNGuardIdleState::onExit( StateExitType status )
  625. {
  626. }
  627. //-- AITNGuardPickUpCrateState ----------------------------------------------------------------------
  628. //-------------------------------------------------------------------------------------------------
  629. AITNGuardPickUpCrateState::AITNGuardPickUpCrateState( StateMachine *machine ) : AIPickUpCrateState(machine)
  630. {
  631. #ifdef STATE_MACHINE_DEBUG
  632. setName("AITNGuardPickUpCrateState");
  633. #endif
  634. }
  635. //--------------------------------------------------------------------------------------
  636. StateReturnType AITNGuardPickUpCrateState::onEnter( void )
  637. {
  638. Object *owner = getMachineOwner();
  639. AIUpdateInterface *ai = owner->getAIUpdateInterface();
  640. // Check to see if we have created a crate we need to pick up.
  641. Object* crate = ai->checkForCrateToPickup();
  642. if (crate)
  643. {
  644. getMachine()->setGoalObject(crate);
  645. return AIPickUpCrateState::onEnter();
  646. }
  647. return STATE_SUCCESS; // no crate, so we're done.
  648. }
  649. //--------------------------------------------------------------------------------------
  650. StateReturnType AITNGuardPickUpCrateState::update( void )
  651. {
  652. return AIPickUpCrateState::update();
  653. }
  654. //--------------------------------------------------------------------------------------
  655. void AITNGuardPickUpCrateState::onExit( StateExitType status )
  656. {
  657. }
  658. //-- AITNGuardAttackAggressorState ------------------------------------------------------------------
  659. //-------------------------------------------------------------------------------------------------
  660. AITNGuardAttackAggressorState::AITNGuardAttackAggressorState( StateMachine *machine ) :
  661. State( machine, "AITNGuardAttackAggressorState" )
  662. {
  663. m_attackState = NULL;
  664. }
  665. //-------------------------------------------------------------------------------------------------
  666. StateReturnType AITNGuardAttackAggressorState::onEnter( void )
  667. {
  668. Object *obj = getMachineOwner();
  669. ObjectID nemID = INVALID_ID;
  670. if (obj->getBodyModule() && obj->getBodyModule()->getLastDamageInfo()->in.m_sourceID) {
  671. nemID = obj->getBodyModule()->getLastDamageInfo()->in.m_sourceID;
  672. getGuardMachine()->setNemesisID(nemID);
  673. }
  674. Object *nemesis = TheGameLogic->findObjectByID(getGuardMachine()->getNemesisID());
  675. if (nemesis == NULL)
  676. {
  677. DEBUG_LOG(("Unexpected NULL nemesis in AITNGuardAttackAggressorState.\n"));
  678. return STATE_SUCCESS;
  679. }
  680. Player *ownerPlayer = getMachineOwner()->getControllingPlayer();
  681. TunnelTracker *tunnels = NULL;
  682. if (ownerPlayer) {
  683. tunnels = ownerPlayer->getTunnelSystem();
  684. }
  685. if (tunnels) tunnels->updateNemesis(nemesis);
  686. m_exitConditions.m_attackGiveUpFrame = TheGameLogic->getFrame() + TheAI->getAiData()->m_guardChaseUnitFrames;
  687. m_attackState = newInstance(AIAttackState)(getMachine(), true, true, false, &m_exitConditions);
  688. m_attackState->getMachine()->setGoalObject(nemesis);
  689. StateReturnType returnVal = m_attackState->onEnter();
  690. if (returnVal == STATE_CONTINUE) {
  691. return STATE_CONTINUE;
  692. }
  693. // if we had no one to attack, we were successful, so go to the next state.
  694. return STATE_SUCCESS;
  695. }
  696. //-------------------------------------------------------------------------------------------------
  697. StateReturnType AITNGuardAttackAggressorState::update( void )
  698. {
  699. if (m_attackState->getMachine()->getCurrentStateID() == AttackStateMachine::FIRE_WEAPON) {
  700. Object *nemesis = TheGameLogic->findObjectByID(getGuardMachine()->getNemesisID());
  701. Player *ownerPlayer = getMachineOwner()->getControllingPlayer();
  702. TunnelTracker *tunnels = NULL;
  703. if (ownerPlayer) {
  704. tunnels = ownerPlayer->getTunnelSystem();
  705. }
  706. if (tunnels) tunnels->updateNemesis(nemesis);
  707. }
  708. return m_attackState->update();
  709. }
  710. //-------------------------------------------------------------------------------------------------
  711. void AITNGuardAttackAggressorState::onExit( StateExitType status )
  712. {
  713. Object *obj = getMachineOwner();
  714. if (m_attackState)
  715. {
  716. m_attackState->onExit(status);
  717. m_attackState->deleteInstance();
  718. m_attackState = NULL;
  719. }
  720. if (obj->getTeam())
  721. {
  722. obj->getTeam()->setTeamTargetObject(NULL); // clear the target.
  723. }
  724. }
  725. //-------------------------------------------------------------------------------------------------
  726. void AITNGuardAttackAggressorState::crc( Xfer *xfer )
  727. {
  728. }
  729. //-------------------------------------------------------------------------------------------------
  730. void AITNGuardAttackAggressorState::xfer( Xfer *xfer )
  731. {
  732. // version
  733. XferVersion currentVersion = 1;
  734. XferVersion version = currentVersion;
  735. xfer->xferVersion( &version, currentVersion );
  736. }
  737. //-------------------------------------------------------------------------------------------------
  738. void AITNGuardAttackAggressorState::loadPostProcess()
  739. {
  740. onEnter();
  741. }