HackInternetAIUpdate.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  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. // HackInternetAIUpdate.cpp ////////////
  24. // Author: Kris Morness, June 2002
  25. // Desc: State machine that handles internet hacking (free cash)
  26. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  27. #include "Common/Player.h"
  28. #include "Common/ThingFactory.h"
  29. #include "Common/ThingTemplate.h"
  30. #include "GameClient/Drawable.h"
  31. #include "GameClient/InGameUI.h"
  32. #include "GameClient/GameText.h"
  33. #include "GameLogic/ExperienceTracker.h"
  34. #include "GameLogic/Module/BodyModule.h"
  35. #include "GameLogic/Module/ContainModule.h"
  36. #include "GameLogic/Module/HackInternetAIUpdate.h"
  37. #include "GameLogic/Module/PhysicsUpdate.h"
  38. #include "GameLogic/Object.h"
  39. //#include "GameLogic/PartitionManager.h"
  40. #ifdef _INTERNAL
  41. // for occasional debugging...
  42. //#pragma optimize("", off)
  43. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  44. #endif
  45. //-------------------------------------------------------------------------------------------------
  46. //-------------------------------------------------------------------------------------------------
  47. //-------------------------------------------------------------------------------------------------
  48. //-------------------------------------------------------------------------------------------------
  49. AIStateMachine* HackInternetAIUpdate::makeStateMachine()
  50. {
  51. return newInstance(HackInternetStateMachine)( getObject(), "HackInternetBasicAI");
  52. }
  53. //-------------------------------------------------------------------------------------------------
  54. HackInternetAIUpdate::HackInternetAIUpdate( Thing *thing, const ModuleData* moduleData ) : AIUpdateInterface( thing, moduleData )
  55. {
  56. m_hasPendingCommand = false;
  57. }
  58. //-------------------------------------------------------------------------------------------------
  59. HackInternetAIUpdate::~HackInternetAIUpdate( void )
  60. {
  61. }
  62. //-------------------------------------------------------------------------------------------------
  63. Bool HackInternetAIUpdate::isIdle() const
  64. {
  65. // we need to do this because we enter an idle state briefly between takeoff/landing in these cases,
  66. // but scripting relies on us never claiming to be "idle"...
  67. if (m_hasPendingCommand)
  68. return false;
  69. return AIUpdateInterface::isIdle();
  70. }
  71. //-------------------------------------------------------------------------------------------------
  72. Bool HackInternetAIUpdate::isHacking() const
  73. {
  74. if( getStateMachine()->getCurrentStateID() == HACK_INTERNET )
  75. {
  76. return true;
  77. }
  78. return false;
  79. }
  80. //-------------------------------------------------------------------------------------------------
  81. Bool HackInternetAIUpdate::isHackingPackingOrUnpacking() const
  82. {
  83. if( getStateMachine()->getCurrentStateID() == HACK_INTERNET ||
  84. getStateMachine()->getCurrentStateID() == PACKING ||
  85. getStateMachine()->getCurrentStateID() == UNPACKING )
  86. {
  87. return true;
  88. }
  89. return false;
  90. }
  91. //-------------------------------------------------------------------------------------------------
  92. UpdateSleepTime HackInternetAIUpdate::update( void )
  93. {
  94. // have to call our parent's isIdle, because we override it to never return true
  95. // when we have a pending command...
  96. if( AIUpdateInterface::isIdle() )
  97. {
  98. if( m_hasPendingCommand )
  99. {
  100. AICommandParms parms( AICMD_MOVE_TO_POSITION, CMD_FROM_AI ); // values don't matter, will be wiped by next line
  101. m_pendingCommand.reconstitute( parms );
  102. m_hasPendingCommand = false;
  103. aiDoCommand(&parms);
  104. }
  105. }
  106. /*UpdateSleepTime ret =*/ AIUpdateInterface::update();
  107. //return (mine < ret) ? mine : ret;
  108. /// @todo srj -- someday, make sleepy. for now, must not sleep.
  109. return UPDATE_SLEEP_NONE;
  110. }
  111. //-------------------------------------------------------------------------------------------------
  112. void HackInternetAIUpdate::aiDoCommand(const AICommandParms* parms)
  113. {
  114. if (!isAllowedToRespondToAiCommands(parms))
  115. return;
  116. //If our hacker is currently packing up his gear, we need to prevent him
  117. //from moving until completed. In order to accomplish this, we'll detect,
  118. //then
  119. if( getStateMachine()->getCurrentStateID() == HACK_INTERNET || getStateMachine()->getCurrentStateID() == PACKING )
  120. {
  121. // nuke any existing pending cmd
  122. m_pendingCommand.store(*parms);
  123. m_hasPendingCommand = true;
  124. if( getStateMachine()->getCurrentStateID() == HACK_INTERNET )
  125. {
  126. getStateMachine()->clear();
  127. setLastCommandSource( CMD_FROM_AI );
  128. getStateMachine()->setState( PACKING );
  129. }
  130. return;
  131. }
  132. m_hasPendingCommand = false;
  133. AIUpdateInterface::aiDoCommand(parms);
  134. }
  135. //-------------------------------------------------------------------------------------------------
  136. void HackInternetAIUpdate::hackInternet()
  137. {
  138. //if (m_hackInternetStateMachine)
  139. // m_hackInternetStateMachine->deleteInstance();
  140. //m_hackInternetStateMachine = NULL;
  141. // must make the state machine AFTER initing the other stuff, since it may inquire of its values...
  142. //m_hackInternetStateMachine = newInstance(HackInternetStateMachine)( getObject() );
  143. //m_hackInternetStateMachine->initDefaultState();
  144. #ifdef _DEBUG
  145. //m_hackInternetStateMachine->setName("HackInternetSpecificAI");
  146. #endif
  147. getStateMachine()->setState(UNPACKING);
  148. }
  149. // ------------------------------------------------------------------------------------------------
  150. /** CRC */
  151. // ------------------------------------------------------------------------------------------------
  152. void HackInternetAIUpdate::crc( Xfer *xfer )
  153. {
  154. // extend base class
  155. AIUpdateInterface::crc(xfer);
  156. } // end crc
  157. // ------------------------------------------------------------------------------------------------
  158. /** Xfer method
  159. * Version Info:
  160. * 1: Initial version */
  161. // ------------------------------------------------------------------------------------------------
  162. void HackInternetAIUpdate::xfer( Xfer *xfer )
  163. {
  164. // version
  165. XferVersion currentVersion = 1;
  166. XferVersion version = currentVersion;
  167. xfer->xferVersion( &version, currentVersion );
  168. // extend base class
  169. AIUpdateInterface::xfer(xfer);
  170. xfer->xferBool(&m_hasPendingCommand);
  171. if (m_hasPendingCommand) {
  172. m_pendingCommand.doXfer(xfer);
  173. }
  174. } // end xfer
  175. // ------------------------------------------------------------------------------------------------
  176. /** Load post process */
  177. // ------------------------------------------------------------------------------------------------
  178. void HackInternetAIUpdate::loadPostProcess( void )
  179. {
  180. // extend base class
  181. AIUpdateInterface::loadPostProcess();
  182. } // end loadPostProcess
  183. //-------------------------------------------------------------------------------------------------
  184. //-------------------------------------------------------------------------------------------------
  185. //-------------------------------------------------------------------------------------------------
  186. //-------------------------------------------------------------------------------------------------
  187. HackInternetStateMachine::HackInternetStateMachine( Object *owner, AsciiString name ) : AIStateMachine( owner, "HackInternetStateMachine" )
  188. {
  189. //HackInternetAIUpdate *ai = (HackInternetAIUpdate*)owner->getAIUpdateInterface();
  190. // order matters: first state is the default state.
  191. defineState( UNPACKING, newInstance(UnpackingState)( this ), HACK_INTERNET, HACK_INTERNET );
  192. defineState( HACK_INTERNET, newInstance(HackInternetState)( this ), PACKING, PACKING );
  193. defineState( PACKING, newInstance(PackingState)( this ), AI_IDLE, AI_IDLE );
  194. }
  195. //-------------------------------------------------------------------------------------------------
  196. HackInternetStateMachine::~HackInternetStateMachine()
  197. {
  198. }
  199. // ------------------------------------------------------------------------------------------------
  200. /** CRC */
  201. // ------------------------------------------------------------------------------------------------
  202. void UnpackingState::crc( Xfer *xfer )
  203. {
  204. } // end crc
  205. // ------------------------------------------------------------------------------------------------
  206. /** Xfer Method */
  207. // ------------------------------------------------------------------------------------------------
  208. void UnpackingState::xfer( Xfer *xfer )
  209. {
  210. // version
  211. XferVersion currentVersion = 1;
  212. XferVersion version = currentVersion;
  213. xfer->xferVersion( &version, currentVersion );
  214. xfer->xferUnsignedInt(&m_framesRemaining);
  215. } // end xfer
  216. // ------------------------------------------------------------------------------------------------
  217. /** Load post process */
  218. // ------------------------------------------------------------------------------------------------
  219. void UnpackingState::loadPostProcess( void )
  220. {
  221. } // end loadPostProcess
  222. //-------------------------------------------------------------------------------------------------
  223. StateReturnType UnpackingState::onEnter()
  224. {
  225. Object *owner = getMachineOwner();
  226. HackInternetAIUpdate *ai = (HackInternetAIUpdate*)owner->getAIUpdateInterface();
  227. if( !ai )
  228. {
  229. return STATE_FAILURE;
  230. }
  231. owner->clearModelConditionFlags( MAKE_MODELCONDITION_MASK3( MODELCONDITION_PACKING, MODELCONDITION_FIRING_A, MODELCONDITION_UNPACKING ) );
  232. owner->setModelConditionState( MODELCONDITION_UNPACKING );
  233. AudioEventRTS sound = *owner->getTemplate()->getPerUnitSound( "UnitUnpack" );
  234. sound.setObjectID( owner->getID() );
  235. TheAudio->addAudioEvent( &sound );
  236. Real variationFactor = ai->getPackUnpackVariationFactor();
  237. Real variation = GameLogicRandomValueReal( 1.0f - variationFactor, 1.0f + variationFactor );
  238. m_framesRemaining = ai->getUnpackTime() * variation; //In frames
  239. owner->getDrawable()->setAnimationLoopDuration( m_framesRemaining );
  240. return STATE_CONTINUE;
  241. }
  242. //-------------------------------------------------------------------------------------------------
  243. StateReturnType UnpackingState::update()
  244. {
  245. Object *owner = getMachineOwner();
  246. // HackInternetAIUpdate *ai = (HackInternetAIUpdate*)owner->getAIUpdateInterface();
  247. // This is a bit hacky, no pun intended, but if this Update is engeged specialability (disablebuilding)
  248. // The unpacking modelconditionflag gets cleared by specialability::cleanup() after my onEnter() sets it!
  249. // Why HackInterent wasn't included within specialability I can't figure out, but... too late to change now.
  250. owner->setModelConditionState( MODELCONDITION_UNPACKING );
  251. if( m_framesRemaining > 0 )
  252. {
  253. m_framesRemaining--;
  254. }
  255. else
  256. {
  257. return STATE_SUCCESS;
  258. }
  259. return STATE_CONTINUE;
  260. }
  261. //-------------------------------------------------------------------------------------------------
  262. void UnpackingState::onExit( StateExitType status )
  263. {
  264. Object *owner = getMachineOwner();
  265. owner->clearModelConditionState( MODELCONDITION_UNPACKING );
  266. }
  267. //-------------------------------------------------------------------------------------------------
  268. //-------------------------------------------------------------------------------------------------
  269. //-------------------------------------------------------------------------------------------------
  270. // ------------------------------------------------------------------------------------------------
  271. /** CRC */
  272. // ------------------------------------------------------------------------------------------------
  273. void PackingState::crc( Xfer *xfer )
  274. {
  275. } // end crc
  276. // ------------------------------------------------------------------------------------------------
  277. /** Xfer Method */
  278. // ------------------------------------------------------------------------------------------------
  279. void PackingState::xfer( Xfer *xfer )
  280. {
  281. // version
  282. XferVersion currentVersion = 1;
  283. XferVersion version = currentVersion;
  284. xfer->xferVersion( &version, currentVersion );
  285. xfer->xferUnsignedInt(&m_framesRemaining);
  286. } // end xfer
  287. // ------------------------------------------------------------------------------------------------
  288. /** Load post process */
  289. // ------------------------------------------------------------------------------------------------
  290. void PackingState::loadPostProcess( void )
  291. {
  292. } // end loadPostProcess
  293. //-------------------------------------------------------------------------------------------------
  294. StateReturnType PackingState::onEnter()
  295. {
  296. Object *owner = getMachineOwner();
  297. HackInternetAIUpdate *ai = (HackInternetAIUpdate*)owner->getAIUpdateInterface();
  298. if( !ai )
  299. {
  300. return STATE_FAILURE;
  301. }
  302. owner->clearAndSetModelConditionFlags( MAKE_MODELCONDITION_MASK( MODELCONDITION_FIRING_A ),
  303. MAKE_MODELCONDITION_MASK( MODELCONDITION_PACKING ) );
  304. AudioEventRTS sound = *owner->getTemplate()->getPerUnitSound( "UnitPack" );
  305. sound.setObjectID( owner->getID() );
  306. TheAudio->addAudioEvent( &sound );
  307. Real variationFactor = ai->getPackUnpackVariationFactor();
  308. Real variation = GameLogicRandomValueReal( 1.0f - variationFactor, 1.0f + variationFactor );
  309. m_framesRemaining = ai->getPackTime() * variation; //In frames
  310. owner->getDrawable()->setAnimationLoopDuration( m_framesRemaining );
  311. return STATE_CONTINUE;
  312. }
  313. //-------------------------------------------------------------------------------------------------
  314. StateReturnType PackingState::update()
  315. {
  316. // Object *owner = getMachineOwner();
  317. // HackInternetAIUpdate *ai = (HackInternetAIUpdate*)owner->getAIUpdateInterface();
  318. if( m_framesRemaining > 0 )
  319. {
  320. m_framesRemaining--;
  321. }
  322. else
  323. {
  324. return STATE_SUCCESS;
  325. }
  326. return STATE_CONTINUE;
  327. }
  328. //-------------------------------------------------------------------------------------------------
  329. void PackingState::onExit( StateExitType status )
  330. {
  331. Object *owner = getMachineOwner();
  332. owner->clearModelConditionState( MODELCONDITION_PACKING );
  333. }
  334. // ------------------------------------------------------------------------------------------------
  335. /** CRC */
  336. // ------------------------------------------------------------------------------------------------
  337. void HackInternetState::crc( Xfer *xfer )
  338. {
  339. } // end crc
  340. // ------------------------------------------------------------------------------------------------
  341. /** Xfer Method */
  342. // ------------------------------------------------------------------------------------------------
  343. void HackInternetState::xfer( Xfer *xfer )
  344. {
  345. // version
  346. XferVersion currentVersion = 1;
  347. XferVersion version = currentVersion;
  348. xfer->xferVersion( &version, currentVersion );
  349. xfer->xferUnsignedInt(&m_framesRemaining);
  350. } // end xfer
  351. // ------------------------------------------------------------------------------------------------
  352. /** Load post process */
  353. // ------------------------------------------------------------------------------------------------
  354. void HackInternetState::loadPostProcess( void )
  355. {
  356. } // end loadPostProcess
  357. //-------------------------------------------------------------------------------------------------
  358. StateReturnType HackInternetState::onEnter()
  359. {
  360. //Go into the hack internet stance.
  361. Object *owner = getMachineOwner();
  362. HackInternetAIUpdate *ai = (HackInternetAIUpdate*)owner->getAIUpdateInterface();
  363. if( !ai )
  364. {
  365. return STATE_FAILURE;
  366. }
  367. owner->clearAndSetModelConditionFlags( MAKE_MODELCONDITION_MASK( MODELCONDITION_UNPACKING ),
  368. MAKE_MODELCONDITION_MASK( MODELCONDITION_FIRING_A ) );
  369. m_framesRemaining = ai->getCashUpdateDelay();
  370. return STATE_CONTINUE;
  371. }
  372. //-------------------------------------------------------------------------------------------------
  373. StateReturnType HackInternetState::update()
  374. {
  375. Object *owner = getMachineOwner();
  376. HackInternetAIUpdate *ai = (HackInternetAIUpdate*)owner->getAIUpdateInterface();
  377. if( !ai )
  378. {
  379. return STATE_FAILURE;
  380. }
  381. if( m_framesRemaining > 0 )
  382. {
  383. //Decrement frame counter.
  384. m_framesRemaining--;
  385. }
  386. else
  387. {
  388. //We have waited the full amount of the delay, so hack some cash from the heavens!
  389. //Add cash
  390. Money *money = owner->getControllingPlayer()->getMoney();
  391. if( money )
  392. {
  393. ExperienceTracker *xp = owner->getExperienceTracker();
  394. if( xp )
  395. {
  396. UnsignedInt amount = 0;
  397. switch( xp->getVeterancyLevel() )
  398. {
  399. case LEVEL_HEROIC:
  400. amount = ai->getHeroicCashAmount();
  401. if( amount )
  402. {
  403. break;
  404. }
  405. //If entry missing, fall through!
  406. case LEVEL_ELITE:
  407. amount = ai->getEliteCashAmount();
  408. if( amount )
  409. {
  410. break;
  411. }
  412. //If entry missing, fall through!
  413. case LEVEL_VETERAN:
  414. amount = ai->getVeteranCashAmount();
  415. if( amount )
  416. {
  417. break;
  418. }
  419. //If entry missing, fall through!
  420. case LEVEL_REGULAR:
  421. amount = ai->getRegularCashAmount();
  422. if( amount )
  423. {
  424. break;
  425. }
  426. //If entry missing, fall through!
  427. default:
  428. amount = 1;
  429. break;
  430. }
  431. money->deposit( amount );
  432. owner->getControllingPlayer()->getScoreKeeper()->addMoneyEarned( amount );
  433. //Grant the unit some experience for a successful hack.
  434. xp->addExperiencePoints( ai->getXpPerCashUpdate() );
  435. //Display cash income floating over the hacker.
  436. UnicodeString moneyString;
  437. moneyString.format( TheGameText->fetch( "GUI:AddCash" ), amount );
  438. Coord3D pos;
  439. pos.zero();
  440. pos.add( owner->getPosition() );
  441. pos.z += 20.0f; //add a little z to make it show up above the unit.
  442. TheInGameUI->addFloatingText( moneyString, &pos, GameMakeColor( 0, 255, 0, 255 ) );
  443. AudioEventRTS sound = *(owner->getTemplate()->getPerUnitSound( "UnitCashPing" ));
  444. sound.setObjectID( owner->getID() );
  445. TheAudio->addAudioEvent( &sound );
  446. }
  447. }
  448. //Reset timer and start a new cycle.
  449. m_framesRemaining = ai->getCashUpdateDelay();
  450. }
  451. //This is a persistent state until told otherwise.
  452. return STATE_CONTINUE;
  453. }
  454. //-------------------------------------------------------------------------------------------------
  455. void HackInternetState::onExit( StateExitType status )
  456. {
  457. Object *owner = getMachineOwner();
  458. owner->clearModelConditionState( MODELCONDITION_FIRING_A );
  459. }