Eva.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  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. // GameClient/Eva.cpp /////////////////////////////////////////////////////////////////////////////
  24. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  25. #include "GameClient/Eva.h"
  26. #include "Common/Player.h"
  27. #include "Common/PlayerList.h"
  28. #include "GameLogic/GameLogic.h"
  29. #ifdef _INTERNAL
  30. // for occasional debugging...
  31. //#pragma optimize("", off)
  32. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  33. #endif
  34. //-------------------------------------------------------------------------------------------------
  35. const char *TheEvaMessageNames[] =
  36. {
  37. "LOWPOWER",
  38. "INSUFFICIENTFUNDS",
  39. "SUPERWEAPONDETECTED_OWN_PARTICLECANNON",
  40. "SUPERWEAPONDETECTED_OWN_NUKE",
  41. "SUPERWEAPONDETECTED_OWN_SCUDSTORM",
  42. "SUPERWEAPONDETECTED_ALLY_PARTICLECANNON",
  43. "SUPERWEAPONDETECTED_ALLY_NUKE",
  44. "SUPERWEAPONDETECTED_ALLY_SCUDSTORM",
  45. "SUPERWEAPONDETECTED_ENEMY_PARTICLECANNON",
  46. "SUPERWEAPONDETECTED_ENEMY_NUKE",
  47. "SUPERWEAPONDETECTED_ENEMY_SCUDSTORM",
  48. "SUPERWEAPONLAUNCHED_OWN_PARTICLECANNON",
  49. "SUPERWEAPONLAUNCHED_OWN_NUKE",
  50. "SUPERWEAPONLAUNCHED_OWN_SCUDSTORM",
  51. "SUPERWEAPONLAUNCHED_ALLY_PARTICLECANNON",
  52. "SUPERWEAPONLAUNCHED_ALLY_NUKE",
  53. "SUPERWEAPONLAUNCHED_ALLY_SCUDSTORM",
  54. "SUPERWEAPONLAUNCHED_ENEMY_PARTICLECANNON",
  55. "SUPERWEAPONLAUNCHED_ENEMY_NUKE",
  56. "SUPERWEAPONLAUNCHED_ENEMY_SCUDSTORM",
  57. "SUPERWEAPONREADY_OWN_PARTICLECANNON",
  58. "SUPERWEAPONREADY_OWN_NUKE",
  59. "SUPERWEAPONREADY_OWN_SCUDSTORM",
  60. "SUPERWEAPONREADY_ALLY_PARTICLECANNON",
  61. "SUPERWEAPONREADY_ALLY_NUKE",
  62. "SUPERWEAPONREADY_ALLY_SCUDSTORM",
  63. "SUPERWEAPONREADY_ENEMY_PARTICLECANNON",
  64. "SUPERWEAPONREADY_ENEMY_NUKE",
  65. "SUPERWEAPONREADY_ENEMY_SCUDSTORM",
  66. "BUILDINGLOST",
  67. "BASEUNDERATTACK",
  68. "ALLYUNDERATTACK",
  69. "BEACONDETECTED",
  70. "ENEMYBLACKLOTUSDETECTED",
  71. "ENEMYJARMENKELLDETECTED",
  72. "ENEMYCOLONELBURTONDETECTED",
  73. "OWNBLACKLOTUSDETECTED",
  74. "OWNJARMENKELLDETECTED",
  75. "OWNCOLONELBURTONDETECTED",
  76. "UNITLOST",
  77. "GENERALLEVELUP",
  78. "VEHICLESTOLEN",
  79. "BUILDINGSTOLEN",
  80. "CASHSTOLEN",
  81. "UPGRADECOMPLETE",
  82. "BUILDINGBEINGSTOLEN",
  83. "BUILDINGSABOTAGED",
  84. "SUPERWEAPONLAUNCHED_OWN_GPS_SCRAMBLER",
  85. "SUPERWEAPONLAUNCHED_ALLY_GPS_SCRAMBLER",
  86. "SUPERWEAPONLAUNCHED_ENEMY_GPS_SCRAMBLER",
  87. "SUPERWEAPONLAUNCHED_OWN_SNEAK_ATTACK",
  88. "SUPERWEAPONLAUNCHED_ALLY_SNEAK_ATTACK",
  89. "SUPERWEAPONLAUNCHED_ENEMY_SNEAK_ATTACK",
  90. //****************************************************************************
  91. //Kris: Don't forget to add another handler below -- it's ghey-ly implemented.
  92. //****************************************************************************
  93. "EVA_INVALID",
  94. };
  95. //-------------------------------------------------------------------------------------------------
  96. const ShouldPlayFunc Eva::s_shouldPlayFuncs[] =
  97. {
  98. Eva::shouldPlayLowPower,
  99. Eva::shouldPlayGenericHandler,
  100. Eva::shouldPlayGenericHandler,
  101. Eva::shouldPlayGenericHandler,
  102. Eva::shouldPlayGenericHandler,
  103. Eva::shouldPlayGenericHandler,
  104. Eva::shouldPlayGenericHandler,
  105. Eva::shouldPlayGenericHandler,
  106. Eva::shouldPlayGenericHandler,
  107. Eva::shouldPlayGenericHandler,
  108. Eva::shouldPlayGenericHandler,
  109. Eva::shouldPlayGenericHandler,
  110. Eva::shouldPlayGenericHandler,
  111. Eva::shouldPlayGenericHandler,
  112. Eva::shouldPlayGenericHandler,
  113. Eva::shouldPlayGenericHandler,
  114. Eva::shouldPlayGenericHandler,
  115. Eva::shouldPlayGenericHandler,
  116. Eva::shouldPlayGenericHandler,
  117. Eva::shouldPlayGenericHandler,
  118. Eva::shouldPlayGenericHandler,
  119. Eva::shouldPlayGenericHandler,
  120. Eva::shouldPlayGenericHandler,
  121. Eva::shouldPlayGenericHandler,
  122. Eva::shouldPlayGenericHandler,
  123. Eva::shouldPlayGenericHandler,
  124. Eva::shouldPlayGenericHandler,
  125. Eva::shouldPlayGenericHandler,
  126. Eva::shouldPlayGenericHandler,
  127. Eva::shouldPlayGenericHandler,
  128. Eva::shouldPlayGenericHandler,
  129. Eva::shouldPlayGenericHandler,
  130. Eva::shouldPlayGenericHandler,
  131. Eva::shouldPlayGenericHandler,
  132. Eva::shouldPlayGenericHandler,
  133. Eva::shouldPlayGenericHandler,
  134. Eva::shouldPlayGenericHandler,
  135. Eva::shouldPlayGenericHandler,
  136. Eva::shouldPlayGenericHandler,
  137. Eva::shouldPlayGenericHandler,
  138. Eva::shouldPlayGenericHandler,
  139. Eva::shouldPlayGenericHandler,
  140. Eva::shouldPlayGenericHandler,
  141. Eva::shouldPlayGenericHandler,
  142. Eva::shouldPlayGenericHandler,
  143. Eva::shouldPlayGenericHandler,
  144. Eva::shouldPlayGenericHandler,
  145. Eva::shouldPlayGenericHandler,
  146. Eva::shouldPlayGenericHandler,
  147. Eva::shouldPlayGenericHandler,
  148. Eva::shouldPlayGenericHandler,
  149. Eva::shouldPlayGenericHandler,
  150. Eva::shouldPlayGenericHandler,
  151. NULL,
  152. };
  153. //------------------------------------------------------------------------------ INI::parseEvaEvent
  154. void INI::parseEvaEvent( INI* ini )
  155. {
  156. AsciiString name;
  157. // read the name
  158. const char* c = ini->getNextToken();
  159. name.set( c );
  160. EvaCheckInfo *check = TheEva->newEvaCheckInfo( name );
  161. if (!check) {
  162. // could be null because it already exists.
  163. return;
  164. }
  165. // parse the ini definition
  166. ini->initFromINI( check, check->getFieldParse() );
  167. }
  168. //----------------------------------------------------------------------------------- EvaSideSounds
  169. static void parseSideSoundsList( INI *ini, void *instance, void *store, const void* userData )
  170. {
  171. std::vector<EvaSideSounds> *sounds = (std::vector<EvaSideSounds>*) store;
  172. EvaSideSounds newSounds;
  173. ini->initFromINI( &newSounds, newSounds.getFieldParse() );
  174. // This could be made more efficient, but to be honest, it shouldn't be that slow.
  175. sounds->push_back(newSounds);
  176. }
  177. //----------------------------------------------------------------------------------- EvaSideSounds
  178. const FieldParse EvaSideSounds::s_evaSideSounds[] =
  179. {
  180. { "Side", INI::parseAsciiString, NULL, offsetof( EvaSideSounds, m_side) },
  181. { "Sounds", INI::parseSoundsList, NULL, offsetof( EvaSideSounds, m_soundNames) },
  182. { 0, 0, 0, 0 },
  183. };
  184. //------------------------------------------------------------------------------------ EvaCheckInfo
  185. EvaCheckInfo::EvaCheckInfo() :
  186. m_message(EVA_COUNT),
  187. m_priority(1), // lowest of all priorities
  188. m_framesBetweenChecks(900), // 30 seconds at 30 fps
  189. m_framesToExpire(150) // 5 seconds at 30 fps
  190. {
  191. }
  192. //-------------------------------------------------------------------------------------------------
  193. const FieldParse EvaCheckInfo::s_evaEventInfo[] =
  194. {
  195. { "Priority", INI::parseUnsignedInt, NULL, offsetof( EvaCheckInfo, m_priority ) },
  196. { "TimeBetweenChecksMS", INI::parseDurationUnsignedInt, NULL, offsetof( EvaCheckInfo, m_framesBetweenChecks ) },
  197. { "ExpirationTimeMS", INI::parseDurationUnsignedInt, NULL, offsetof( EvaCheckInfo, m_framesToExpire) },
  198. { "SideSounds", parseSideSoundsList, NULL, offsetof( EvaCheckInfo, m_evaSideSounds ) },
  199. { 0, 0, 0, 0 },
  200. };
  201. //-------------------------------------------------------------------------------------------------
  202. EvaCheck::EvaCheck() :
  203. m_evaInfo(NULL),
  204. m_triggeredOnFrame(TRIGGEREDON_NOT),
  205. m_timeForNextCheck(NEXT_CHECK_NOW),
  206. m_alreadyPlayed(FALSE)
  207. {
  208. }
  209. //-------------------------------------------------------------------------------------------------
  210. Eva::Eva() :
  211. m_localPlayer(NULL),
  212. m_previousBuildingCount(0),
  213. m_previousUnitCount(0),
  214. m_enabled(TRUE)
  215. {
  216. for (Int i = 0; i < EVA_COUNT; ++i) {
  217. m_shouldPlay[i] = FALSE;
  218. }
  219. }
  220. //-------------------------------------------------------------------------------------------------
  221. Eva::~Eva()
  222. {
  223. EvaCheckInfoPtrVecIt it;
  224. for (it = m_allCheckInfos.begin(); it != m_allCheckInfos.end(); ++it) {
  225. if (*it)
  226. (*it)->deleteInstance();
  227. }
  228. }
  229. //-------------------------------------------------------------------------------------------------
  230. void Eva::init()
  231. {
  232. // parse the INI here, etc.
  233. INI ini;
  234. ini.load( AsciiString( "Data\\INI\\Eva.ini" ), INI_LOAD_OVERWRITE, NULL);
  235. }
  236. //-------------------------------------------------------------------------------------------------
  237. void Eva::reset()
  238. {
  239. m_previousUnitCount = 0;
  240. m_previousBuildingCount = 0;
  241. // remove all pending counters, etc, here.
  242. EvaCheckVecIt it;
  243. for (it = m_checks.begin(); it != m_checks.end(); /* empty */) {
  244. it = m_checks.erase(it);
  245. }
  246. // remove all things flagged as "need to play"
  247. for (Int i = 0; i < EVA_COUNT; ++i) {
  248. m_shouldPlay[i] = FALSE;
  249. }
  250. // If we were previously disabled, re-enable ourselves.
  251. m_enabled = TRUE;
  252. }
  253. //-------------------------------------------------------------------------------------------------
  254. void Eva::update()
  255. {
  256. if (!m_enabled) {
  257. return;
  258. }
  259. m_localPlayer = ThePlayerList->getLocalPlayer();
  260. UnsignedInt frame = TheGameLogic->getFrame();
  261. // Don't update for the first few frames. This way, we don't have to deal with our initial power
  262. // being 0, etc.
  263. if (frame < 2) {
  264. return;
  265. }
  266. for (Int mesg = (Int)EVA_FIRST; mesg < (Int)EVA_COUNT; ++mesg) {
  267. if (isTimeForCheck((EvaMessage)mesg, frame)) {
  268. if (messageShouldPlay((EvaMessage)mesg, frame)) {
  269. playMessage((EvaMessage)mesg, frame);
  270. }
  271. }
  272. }
  273. processPlayingMessages(frame);
  274. m_localPlayer = NULL;
  275. // Reset all of the flags that have been set to true that haven't actually been probed, because
  276. // they will need to trigger again to be valid messages.
  277. for (Int i = EVA_FIRST; i < EVA_COUNT; ++i) {
  278. m_shouldPlay[i] = FALSE;
  279. }
  280. }
  281. //-------------------------------------------------------------------------------------------------
  282. EvaMessage Eva::nameToMessage(const AsciiString& name)
  283. {
  284. DEBUG_ASSERTCRASH( ELEMENTS_OF( TheEvaMessageNames ) == EVA_COUNT + 1, ("TheEvaMessageNames out of sync" ) );
  285. DEBUG_ASSERTCRASH( stricmp( TheEvaMessageNames[ EVA_COUNT ], "EVA_INVALID" ) == 0, ("TheEvaMessageNames out of sync" ) );
  286. DEBUG_ASSERTCRASH( stricmp( TheEvaMessageNames[ EVA_COUNT - 1], "EVA_INVALID" ) != 0, ("TheEvaMessageNames out of sync" ) );
  287. for (Int i = EVA_FIRST; i < EVA_COUNT; ++i) {
  288. if (name.compareNoCase(TheEvaMessageNames[i]) == 0) {
  289. return (EvaMessage) i;
  290. }
  291. }
  292. DEBUG_CRASH(("Invalid requested Eva message translation :%s: jkmcd", name.str()));
  293. return EVA_Invalid;
  294. }
  295. //-------------------------------------------------------------------------------------------------
  296. AsciiString Eva::messageToName(EvaMessage message)
  297. {
  298. DEBUG_ASSERTCRASH( ELEMENTS_OF( TheEvaMessageNames ) == EVA_COUNT + 1, ("TheEvaMessageNames out of sync" ) );
  299. DEBUG_ASSERTCRASH( stricmp( TheEvaMessageNames[ EVA_COUNT ], "EVA_INVALID" ) == 0, ("TheEvaMessageNames out of sync" ) );
  300. DEBUG_ASSERTCRASH( stricmp( TheEvaMessageNames[ EVA_COUNT - 1], "EVA_INVALID" ) != 0, ("TheEvaMessageNames out of sync" ) );
  301. if (message >= EVA_FIRST && message < EVA_COUNT)
  302. return TheEvaMessageNames[message];
  303. DEBUG_CRASH(("Invalid requested Eva message translation. jkmcd"));
  304. return AsciiString::TheEmptyString;
  305. }
  306. //-------------------------------------------------------------------------------------------------
  307. EvaCheckInfo *Eva::newEvaCheckInfo(AsciiString name)
  308. {
  309. EvaMessage mesg = nameToMessage(name);
  310. // Only return a new one if there isn't an existing one.
  311. EvaCheckInfoPtrVecIt it;
  312. for (it = m_allCheckInfos.begin(); it != m_allCheckInfos.end(); ++it) {
  313. if (*it && (*it)->m_message == mesg)
  314. return NULL;
  315. }
  316. EvaCheckInfo *checkInfo = newInstance(EvaCheckInfo);
  317. m_allCheckInfos.push_back(checkInfo);
  318. checkInfo->m_message = mesg;
  319. return checkInfo;
  320. }
  321. //-------------------------------------------------------------------------------------------------
  322. const EvaCheckInfo *Eva::getEvaCheckInfo(AsciiString name)
  323. {
  324. EvaMessage mesg = nameToMessage(name);
  325. // Only return a new one if there isn't an existing one.
  326. EvaCheckInfoPtrVecIt it;
  327. for (it = m_allCheckInfos.begin(); it != m_allCheckInfos.end(); ++it) {
  328. if (*it && (*it)->m_message == mesg)
  329. return *it;
  330. }
  331. return NULL;
  332. }
  333. //-------------------------------------------------------------------------------------------------
  334. void Eva::setShouldPlay(EvaMessage messageToPlay)
  335. {
  336. m_shouldPlay[messageToPlay] = TRUE;
  337. // DEBUG_LOG( ( "Eva message %s play requested\n", messageToName( messageToPlay).str() ) );
  338. }
  339. //-------------------------------------------------------------------------------------------------
  340. void Eva::setEvaEnabled(Bool enabled)
  341. {
  342. // clear out any waiting messages.
  343. for (Int i = EVA_FIRST; i < EVA_COUNT; ++i) {
  344. m_shouldPlay[i] = FALSE;
  345. }
  346. m_enabled = enabled;
  347. }
  348. //-------------------------------------------------------------------------------------------------
  349. Bool Eva::isTimeForCheck(EvaMessage messageToTest, UnsignedInt currentFrame) const
  350. {
  351. EvaCheckVec::const_iterator it;
  352. for (it = m_checks.begin(); it != m_checks.end(); ++it) {
  353. if (it->m_evaInfo->m_message == messageToTest) {
  354. return FALSE;
  355. }
  356. }
  357. return TRUE;
  358. }
  359. //-------------------------------------------------------------------------------------------------
  360. Bool Eva::messageShouldPlay(EvaMessage messageToTest, UnsignedInt currentFrame) const
  361. {
  362. if (m_localPlayer == NULL) {
  363. return FALSE;
  364. }
  365. DEBUG_ASSERTCRASH( ELEMENTS_OF( s_shouldPlayFuncs ) == EVA_COUNT + 1, ("Eva::s_shouldPlayFuncs out of sync" ) );
  366. DEBUG_ASSERTCRASH( s_shouldPlayFuncs[ EVA_COUNT ] == NULL, ("Eva::s_shouldPlayFuncs out of sync" ) );
  367. DEBUG_ASSERTCRASH( s_shouldPlayFuncs[ EVA_COUNT - 1] != NULL, ("Eva::s_shouldPlayFuncs out of sync" ) );
  368. m_messageBeingTested = messageToTest;
  369. return s_shouldPlayFuncs[messageToTest](m_localPlayer);
  370. }
  371. //-------------------------------------------------------------------------------------------------
  372. Bool Eva::shouldPlayLowPower( Player *localPlayer )
  373. {
  374. // @todo make eva sensitive to whether player can do anything about it...
  375. // "Low power, Low power, Low power, yadda yadda yadda..."
  376. //const ThingTemplate *chinaReactorTemplate = findTemplate(;
  377. //const ThingTemplate *americanReactorTemplate;
  378. //if ( chinaReactorTemplate && americanReactorTemplate )
  379. //{
  380. // if ( ! (localPlayer->canBuild(chinaReactorTemplate) || localPlayer->canBuild(americanReactorTemplate)) )
  381. // return FALSE
  382. //}
  383. return !localPlayer->getEnergy()->hasSufficientPower();
  384. }
  385. //-------------------------------------------------------------------------------------------------
  386. Bool Eva::shouldPlayGenericHandler( Player * )
  387. {
  388. if (TheEva->m_shouldPlay[TheEva->m_messageBeingTested]) {
  389. TheEva->m_shouldPlay[TheEva->m_messageBeingTested] = FALSE;
  390. return TRUE;
  391. }
  392. return FALSE;
  393. }
  394. //-------------------------------------------------------------------------------------------------
  395. void Eva::playMessage(EvaMessage messageToTest, UnsignedInt currentFrame)
  396. {
  397. EvaCheck check;
  398. check.m_evaInfo = getEvaCheckInfo(Eva::messageToName(messageToTest));
  399. if (!check.m_evaInfo) {
  400. return;
  401. }
  402. check.m_timeForNextCheck = currentFrame + check.m_evaInfo->m_framesBetweenChecks;
  403. check.m_triggeredOnFrame = currentFrame;
  404. check.m_alreadyPlayed = FALSE;
  405. m_checks.push_back(check);
  406. }
  407. //-------------------------------------------------------------------------------------------------
  408. void Eva::processPlayingMessages(UnsignedInt currentFrame)
  409. {
  410. // First pass, remove all the objects that can check after this frame.
  411. EvaCheckVecIt it;
  412. for (it = m_checks.begin(); it != m_checks.end(); /* empty */) {
  413. // These are requests that will be available next frame because they've played.
  414. if (it->m_timeForNextCheck <= currentFrame + 1 && it->m_alreadyPlayed) {
  415. it = m_checks.erase(it);
  416. continue;
  417. }
  418. // These are requests that never got a chance to play and have since expired.
  419. if (it->m_triggeredOnFrame + it->m_evaInfo->m_framesToExpire <= currentFrame && !it->m_alreadyPlayed) {
  420. it = m_checks.erase(it);
  421. continue;
  422. }
  423. ++it;
  424. }
  425. // It's possible, although unlikely, that we removed everything in the list.
  426. if (m_checks.begin() == m_checks.end()) {
  427. return;
  428. }
  429. // If we're currently playing some audio, we're done.
  430. if (m_evaSpeech.isCurrentlyPlaying()) {
  431. return;
  432. }
  433. // Okay. No one is currently playing anything, so lets find an event and trigger it.
  434. EvaCheckVecIt storedIt = m_checks.end();
  435. UnsignedInt highestPriority = 0;
  436. for (it = m_checks.begin(); it != m_checks.end(); ++it) {
  437. if (it->m_evaInfo->m_priority > highestPriority && !it->m_alreadyPlayed) {
  438. storedIt = it;
  439. highestPriority = it->m_evaInfo->m_priority;
  440. }
  441. }
  442. // There wasn't anything waiting to play.
  443. if (storedIt == m_checks.end()) {
  444. return;
  445. }
  446. // We've got a winner!
  447. AsciiString side = ThePlayerList->getLocalPlayer()->getSide();
  448. Int numSides = storedIt->m_evaInfo->m_evaSideSounds.size();
  449. // clear it. If we can't find the side we want, don't play anything
  450. m_evaSpeech.setEventName(AsciiString::TheEmptyString);
  451. for (Int i = 0; i < numSides; ++i) {
  452. if (side.compareNoCase(storedIt->m_evaInfo->m_evaSideSounds[i].m_side) == 0) {
  453. // Its this one.
  454. if (storedIt->m_evaInfo->m_evaSideSounds[i].m_soundNames.size() > 0) {
  455. Int soundToPlay = GameClientRandomValue(0, storedIt->m_evaInfo->m_evaSideSounds[i].m_soundNames.size() - 1);
  456. m_evaSpeech.setEventName(storedIt->m_evaInfo->m_evaSideSounds[i].m_soundNames[soundToPlay]);
  457. }
  458. break;
  459. }
  460. }
  461. // Update the entry
  462. storedIt->m_alreadyPlayed = true;
  463. storedIt->m_timeForNextCheck = currentFrame + storedIt->m_evaInfo->m_framesBetweenChecks;
  464. // Now that we correctly filter messages, we need to set the player index for who should hear the
  465. // sound to the local player.
  466. m_evaSpeech.setPlayerIndex(m_localPlayer->getPlayerIndex());
  467. m_evaSpeech.setPlayingHandle(TheAudio->addAudioEvent(&m_evaSpeech));
  468. }
  469. //-------------------------------------------------------------------------------------------------
  470. /** Parses the name of an Eva message from an INI file */
  471. //-------------------------------------------------------------------------------------------------
  472. /*static*/void Eva::parseEvaMessageFromIni( INI * ini, void *instance, void *store, const void* userData )
  473. {
  474. const char *token = ini->getNextToken();
  475. EvaMessage message = nameToMessage( token );
  476. if ( message == EVA_Invalid )
  477. {
  478. // debug message already displayed
  479. throw ERROR_BAD_INI;
  480. }
  481. *((EvaMessage *)store) = message;
  482. }
  483. //-------------------------------------------------------------------------------------------------
  484. Eva *TheEva = NULL;