GameClient.cpp 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613
  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. // FILE: GameClient.cpp ////////////////////////////////////////////////////
  24. // Implementation of GameClient singleton
  25. // Author: Michael S. Booth, March 2001
  26. ///////////////////////////////////////////////////////////////////////////////
  27. // SYSTEM INCLUDES ////////////////////////////////////////////////////////////
  28. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  29. #include "GameClient/GameClient.h"
  30. // USER INCLUDES //////////////////////////////////////////////////////////////
  31. #include "Common/ActionManager.h"
  32. #include "Common/GameEngine.h"
  33. #include "Common/GameState.h"
  34. #include "Common/GlobalData.h"
  35. #include "Common/PerfTimer.h"
  36. #include "Common/Player.h"
  37. #include "Common/PlayerList.h"
  38. #include "Common/ThingFactory.h"
  39. #include "Common/ThingTemplate.h"
  40. #include "Common/Xfer.h"
  41. #include "Common/GameLOD.h"
  42. #include "GameClient/Anim2D.h"
  43. #include "GameClient/CampaignManager.h"
  44. #include "GameClient/ChallengeGenerals.h"
  45. #include "GameClient/CommandXlat.h"
  46. #include "GameClient/ControlBar.h"
  47. #include "GameClient/Diplomacy.h"
  48. #include "GameClient/Display.h"
  49. #include "GameClient/DisplayStringManager.h"
  50. #include "GameClient/Drawable.h"
  51. #include "GameClient/DrawGroupInfo.h"
  52. #include "GameClient/Eva.h"
  53. #include "GameClient/GameWindowManager.h"
  54. #include "GameClient/GlobalLanguage.h"
  55. #include "GameClient/GraphDraw.h"
  56. #include "GameClient/GUICommandTranslator.h"
  57. #include "GameClient/HeaderTemplate.h"
  58. #include "GameClient/HintSpy.h"
  59. #include "GameClient/HotKey.h"
  60. #include "GameClient/IMEManager.h"
  61. #include "GameClient/InGameUI.h"
  62. #include "GameClient/Keyboard.h"
  63. #include "GameClient/LanguageFilter.h"
  64. #include "GameClient/LookAtXlat.h"
  65. #include "GameClient/MetaEvent.h"
  66. #include "GameClient/Mouse.h"
  67. #include "GameClient/ParticleSys.h"
  68. #include "GameClient/PlaceEventTranslator.h"
  69. #include "GameClient/RayEffect.h"
  70. #include "GameClient/SelectionXlat.h"
  71. #include "GameClient/Shell.h"
  72. #include "GameClient/Snow.h"
  73. #include "GameClient/TerrainVisual.h"
  74. #include "GameClient/View.h"
  75. #include "GameClient/VideoPlayer.h"
  76. #include "GameClient/WindowXlat.h"
  77. #include "GameLogic/FPUControl.h"
  78. #include "GameLogic/GameLogic.h"
  79. #include "GameLogic/GhostObject.h"
  80. #include "GameLogic/Object.h"
  81. #include "GameLogic/ScriptEngine.h" // For TheScriptEngine - jkmcd
  82. #ifdef _INTERNAL
  83. // for occasional debugging...
  84. //#pragma optimize("", off)
  85. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  86. #endif
  87. #define DRAWABLE_HASH_SIZE 8192
  88. /// The GameClient singleton instance
  89. GameClient *TheGameClient = NULL;
  90. //-------------------------------------------------------------------------------------------------
  91. GameClient::GameClient()
  92. {
  93. // zero our translator list
  94. for( Int i = 0; i < MAX_CLIENT_TRANSLATORS; i++ )
  95. m_translators[ i ] = TRANSLATOR_ID_INVALID;
  96. m_numTranslators = 0;
  97. m_commandTranslator = NULL;
  98. // Added By Sadullah Nader
  99. // Initializations missing and needed
  100. m_drawableTOC.clear();
  101. //
  102. m_textBearingDrawableList.clear();
  103. m_frame = 0;
  104. m_drawableList = NULL;
  105. m_nextDrawableID = (DrawableID)1;
  106. TheDrawGroupInfo = new DrawGroupInfo;
  107. }
  108. //std::vector<std::string> preloadTextureNamesGlobalHack;
  109. //std::vector<std::string> preloadTextureNamesGlobalHack2;
  110. //-------------------------------------------------------------------------------------------------
  111. GameClient::~GameClient()
  112. {
  113. #ifdef PERF_TIMERS
  114. delete TheGraphDraw;
  115. TheGraphDraw = NULL;
  116. #endif
  117. if (TheDrawGroupInfo)
  118. {
  119. delete TheDrawGroupInfo;
  120. TheDrawGroupInfo = NULL;
  121. }
  122. // clear any drawable TOC we might have
  123. m_drawableTOC.clear();
  124. //DEBUG_LOG(("Preloaded texture files ------------------------------------------\n"));
  125. //for (Int oog=0; oog<preloadTextureNamesGlobalHack2.size(); ++oog)
  126. //{
  127. // DEBUG_LOG(("%s\n", preloadTextureNamesGlobalHack2[oog]));
  128. //}
  129. //DEBUG_LOG(("------------------------------------------------------------------\n"));
  130. //for (oog=0; oog<preloadTextureNamesGlobalHack.size(); ++oog)
  131. //{
  132. // DEBUG_LOG(("%s\n", preloadTextureNamesGlobalHack[oog]));
  133. //}
  134. //DEBUG_LOG(("End Texture files ------------------------------------------------\n"));
  135. if(TheCampaignManager)
  136. delete TheCampaignManager;
  137. TheCampaignManager = NULL;
  138. // destroy all Drawables
  139. Drawable *draw, *nextDraw;
  140. for( draw = m_drawableList; draw; draw = nextDraw )
  141. {
  142. nextDraw = draw->getNextDrawable();
  143. destroyDrawable( draw );
  144. }
  145. m_drawableList = NULL;
  146. // delete the ray effects
  147. delete TheRayEffects;
  148. TheRayEffects = NULL;
  149. // delete the hot key manager
  150. delete TheHotKeyManager;
  151. TheHotKeyManager = NULL;
  152. // destroy the in-game user interface
  153. delete TheInGameUI;
  154. TheInGameUI = NULL;
  155. delete TheChallengeGenerals;
  156. TheChallengeGenerals = NULL;
  157. // delete the shell
  158. delete TheShell;
  159. TheShell = NULL;
  160. delete TheIMEManager;
  161. TheIMEManager = NULL;
  162. // delete window manager
  163. delete TheWindowManager;
  164. TheWindowManager = NULL;
  165. // delete the font library
  166. TheFontLibrary->reset();
  167. delete TheFontLibrary;
  168. TheFontLibrary = NULL;
  169. delete TheMouse;
  170. TheMouse = NULL;
  171. ///@todo : TheTerrainVisual used to be the first thing destroyed.
  172. //I had to put in here so that drawables free their track marks before
  173. //the terrain visual deletes the track laying system. MW
  174. // destroy the terrain visual representation
  175. delete TheTerrainVisual;
  176. TheTerrainVisual = NULL;
  177. // destroy the display
  178. delete TheDisplay;
  179. TheDisplay = NULL;
  180. delete TheHeaderTemplateManager;
  181. TheHeaderTemplateManager = NULL;
  182. delete TheLanguageFilter;
  183. TheLanguageFilter = NULL;
  184. delete TheVideoPlayer;
  185. TheVideoPlayer = NULL;
  186. // destroy all translators
  187. for( Int i = 0; i < m_numTranslators; i++ )
  188. TheMessageStream->removeTranslator( m_translators[ i ] );
  189. m_numTranslators = 0;
  190. m_commandTranslator = NULL;
  191. delete TheAnim2DCollection;
  192. TheAnim2DCollection = NULL;
  193. delete TheMappedImageCollection;
  194. TheMappedImageCollection = NULL;
  195. delete TheKeyboard;
  196. TheKeyboard = NULL;
  197. delete TheDisplayStringManager;
  198. TheDisplayStringManager = NULL;
  199. delete TheEva;
  200. TheEva = NULL;
  201. delete TheSnowManager;
  202. TheSnowManager = NULL;
  203. } // end ~GameClient
  204. //-------------------------------------------------------------------------------------------------
  205. /** Initialize resources for the game client */
  206. //-------------------------------------------------------------------------------------------------
  207. void GameClient::init( void )
  208. {
  209. setFrameRate(MSEC_PER_LOGICFRAME_REAL); // from GameCommon.h... tell W3D what our expected framerate is
  210. INI ini;
  211. // Load the DrawGroupInfo here, before the Display Manager is loaded.
  212. ini.load("Data\\INI\\DrawGroupInfo.ini", INI_LOAD_OVERWRITE, NULL);
  213. // Override the ini values with localized versions:
  214. if (TheGlobalLanguageData && TheGlobalLanguageData->m_drawGroupInfoFont.name.isNotEmpty())
  215. {
  216. TheDrawGroupInfo->m_fontName = TheGlobalLanguageData->m_drawGroupInfoFont.name;
  217. TheDrawGroupInfo->m_fontSize = TheGlobalLanguageData->m_drawGroupInfoFont.size;
  218. TheDrawGroupInfo->m_fontIsBold = TheGlobalLanguageData->m_drawGroupInfoFont.bold;
  219. }
  220. // create the display string factory
  221. TheDisplayStringManager = createDisplayStringManager();
  222. if( TheDisplayStringManager ) {
  223. TheDisplayStringManager->init();
  224. TheDisplayStringManager->setName("TheDisplayStringManager");
  225. }
  226. // create the keyboard
  227. TheKeyboard = createKeyboard();
  228. TheKeyboard->init();
  229. TheKeyboard->setName("TheKeyboard");
  230. // allocate and load image collection for the GUI and just load the 256x256 ones for now
  231. TheMappedImageCollection = MSGNEW("GameClientSubsystem") ImageCollection;
  232. TheMappedImageCollection->load( 512 );
  233. // now that we have all the images loaded ... load any animation definitions from those images
  234. TheAnim2DCollection = MSGNEW("GameClientSubsystem") Anim2DCollection;
  235. TheAnim2DCollection->init();
  236. TheAnim2DCollection->setName("TheAnim2DCollection");
  237. // register message translators
  238. if( TheMessageStream )
  239. {
  240. //
  241. // NOTE: Make sure m_translators[] is large enough to accomodate all the translators you
  242. // are loading here. See MAX_CLIENT_TRANSLATORS
  243. //
  244. // since we only allocate one of each, don't bother pooling 'em
  245. m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") WindowTranslator, 10 );
  246. m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") MetaEventTranslator, 20 );
  247. m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") HotKeyTranslator, 25 );
  248. m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") PlaceEventTranslator, 30 );
  249. m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") GUICommandTranslator, 40 );
  250. m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") SelectionTranslator, 50 );
  251. m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") LookAtTranslator, 60 );
  252. m_translators[ m_numTranslators ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") CommandTranslator, 70 );
  253. // we keep a pointer to the command translator because it's useful
  254. m_commandTranslator = (CommandTranslator *)TheMessageStream->findTranslator( m_translators[ m_numTranslators++ ] );
  255. m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") HintSpyTranslator, 100 );
  256. //
  257. // the client message translator should probably remain as the last reaction of the
  258. // client before the messages are given to the network for processing. This
  259. // lets all systems in the client give events that can be processed by the
  260. // client message translator
  261. //
  262. m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") GameClientMessageDispatcher, 999999999 );
  263. }
  264. // create the font library
  265. TheFontLibrary = createFontLibrary();
  266. if( TheFontLibrary )
  267. TheFontLibrary->init();
  268. // create the mouse
  269. TheMouse = createMouse();
  270. TheMouse->parseIni();
  271. TheMouse->initCursorResources();
  272. TheMouse->setName("TheMouse");
  273. // instantiate the display
  274. TheDisplay = createGameDisplay();
  275. if( TheDisplay ) {
  276. TheDisplay->init();
  277. TheDisplay->setName("TheDisplay");
  278. }
  279. TheHeaderTemplateManager = MSGNEW("GameClientSubsystem") HeaderTemplateManager;
  280. if(TheHeaderTemplateManager){
  281. TheHeaderTemplateManager->init();
  282. }
  283. // create the window manager
  284. TheWindowManager = createWindowManager();
  285. if( TheWindowManager )
  286. {
  287. TheWindowManager->init();
  288. TheWindowManager->setName("TheWindowManager");
  289. // TheWindowManager->initTestGUI();
  290. } // end if
  291. // create the IME manager
  292. TheIMEManager = CreateIMEManagerInterface();
  293. if ( TheIMEManager )
  294. {
  295. TheIMEManager->init();
  296. TheIMEManager->setName("TheIMEManager");
  297. }
  298. // create the shell
  299. TheShell = MSGNEW("GameClientSubsystem") Shell;
  300. if( TheShell ) {
  301. TheShell->init();
  302. TheShell->setName("TheShell");
  303. }
  304. // instantiate the in-game user interface
  305. TheInGameUI = createInGameUI();
  306. if( TheInGameUI ) {
  307. TheInGameUI->init();
  308. TheInGameUI->setName("TheInGameUI");
  309. }
  310. TheChallengeGenerals = createChallengeGenerals();
  311. if( TheChallengeGenerals ) {
  312. TheChallengeGenerals->init();
  313. }
  314. TheHotKeyManager = MSGNEW("GameClientSubsystem") HotKeyManager;
  315. if( TheHotKeyManager ) {
  316. TheHotKeyManager->init();
  317. TheHotKeyManager->setName("TheHotKeyManager");
  318. }
  319. // instantiate the terrain visual display
  320. TheTerrainVisual = createTerrainVisual();
  321. if( TheTerrainVisual ) {
  322. TheTerrainVisual->init();
  323. TheTerrainVisual->setName("TheTerrainVisual");
  324. }
  325. // allocate the ray effects manager
  326. TheRayEffects = MSGNEW("GameClientSubsystem") RayEffectSystem;
  327. if( TheRayEffects ) {
  328. TheRayEffects->init();
  329. TheRayEffects->setName("TheRayEffects");
  330. }
  331. TheMouse->init(); //finish initializing the mouse.
  332. // set the limits of the mouse now that we've created the display and such
  333. if( TheMouse )
  334. {
  335. TheMouse->setPosition( 0, 0 );
  336. TheMouse->setMouseLimits();
  337. TheMouse->setName("TheMouse");
  338. } // end if
  339. // create the video player
  340. TheVideoPlayer = createVideoPlayer();
  341. if ( TheVideoPlayer )
  342. {
  343. TheVideoPlayer->init();
  344. TheVideoPlayer->setName("TheVideoPlayer");
  345. }
  346. // create the language filter.
  347. TheLanguageFilter = createLanguageFilter();
  348. if (TheLanguageFilter)
  349. {
  350. TheLanguageFilter->init();
  351. TheLanguageFilter->setName("TheLanguageFilter");
  352. }
  353. TheCampaignManager = MSGNEW("GameClientSubsystem") CampaignManager;
  354. TheCampaignManager->init();
  355. TheEva = MSGNEW("GameClientSubsystem") Eva;
  356. TheEva->init();
  357. TheEva->setName("TheEva");
  358. TheDisplayStringManager->postProcessLoad();
  359. TheSnowManager = createSnowManager();
  360. if (TheSnowManager)
  361. {
  362. TheSnowManager->init();
  363. TheSnowManager->setName("TheSnowManager");
  364. }
  365. #ifdef PERF_TIMERS
  366. TheGraphDraw = new GraphDraw;
  367. #endif
  368. } // end init
  369. //-------------------------------------------------------------------------------------------------
  370. /** Reset the game client for a new game */
  371. void GameClient::reset( void )
  372. {
  373. Drawable *draw, *nextDraw;
  374. // m_drawableHash.clear();
  375. // m_drawableHash.resize(DRAWABLE_HASH_SIZE);
  376. m_drawableVector.clear();
  377. m_drawableVector.resize(DRAWABLE_HASH_SIZE, NULL);
  378. // need to reset the in game UI to clear drawables before they are destroyed
  379. TheInGameUI->reset();
  380. // destroy all Drawables
  381. for( draw = m_drawableList; draw; draw = nextDraw )
  382. {
  383. nextDraw = draw->getNextDrawable();
  384. destroyDrawable( draw );
  385. }
  386. m_drawableList = NULL;
  387. TheDisplay->reset();
  388. TheTerrainVisual->reset();
  389. TheRayEffects->reset();
  390. TheVideoPlayer->reset();
  391. TheEva->reset();
  392. if (TheSnowManager)
  393. TheSnowManager->reset();
  394. // clear any drawable TOC we might have
  395. m_drawableTOC.clear();
  396. } // end reset
  397. /** -----------------------------------------------------------------------------------------------
  398. * Return a new unique object id.
  399. */
  400. DrawableID GameClient::allocDrawableID( void )
  401. {
  402. /// @todo Find unused value in current set
  403. DrawableID ret = m_nextDrawableID;
  404. m_nextDrawableID = (DrawableID)((UnsignedInt)m_nextDrawableID + 1);
  405. return ret;
  406. }
  407. /** -----------------------------------------------------------------------------------------------
  408. * Given a drawable, register it with the GameClient and give it a unique ID.
  409. */
  410. void GameClient::registerDrawable( Drawable *draw )
  411. {
  412. // assign this drawable a unique ID, this will add it to the fast lookup table too
  413. draw->setID( allocDrawableID() );
  414. // add the drawable to the master list
  415. draw->prependToList( &m_drawableList );
  416. } // end registerDrawable
  417. /** -----------------------------------------------------------------------------------------------
  418. * Redraw all views, update the GUI, play sound effects, etc.
  419. */
  420. DECLARE_PERF_TIMER(GameClient_update)
  421. DECLARE_PERF_TIMER(GameClient_draw)
  422. void GameClient::update( void )
  423. {
  424. USE_PERF_TIMER(GameClient_update)
  425. // create the FRAME_TICK message
  426. GameMessage *frameMsg = TheMessageStream->appendMessage( GameMessage::MSG_FRAME_TICK );
  427. frameMsg->appendTimestampArgument( getFrame() );
  428. static Bool playSizzle = FALSE;
  429. // We need to show the movie first.
  430. if(TheGlobalData->m_playIntro && !TheDisplay->isMoviePlaying())
  431. {
  432. if(TheGameLODManager && TheGameLODManager->didMemPass())
  433. TheDisplay->playLogoMovie("EALogoMovie", 5000, 3000);
  434. else
  435. TheDisplay->playLogoMovie("EALogoMovie640", 5000, 3000);
  436. TheWritableGlobalData->m_playIntro = FALSE;
  437. TheWritableGlobalData->m_afterIntro = TRUE;
  438. playSizzle = TRUE;
  439. }
  440. //Initial Game Codition. We must show the movie first and then we can display the shell
  441. if(TheGlobalData->m_afterIntro && !TheDisplay->isMoviePlaying())
  442. {
  443. if( playSizzle && TheGlobalData->m_playSizzle )
  444. {
  445. TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
  446. if(TheGameLODManager && TheGameLODManager->didMemPass())
  447. TheDisplay->playMovie("Sizzle");
  448. else
  449. TheDisplay->playMovie("Sizzle640");
  450. playSizzle = FALSE;
  451. }
  452. else
  453. {
  454. TheWritableGlobalData->m_breakTheMovie = TRUE;
  455. TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
  456. if(TheGameLODManager && !TheGameLODManager->didMemPass())
  457. {
  458. TheWritableGlobalData->m_breakTheMovie = FALSE;
  459. WindowLayout *legal = TheWindowManager->winCreateLayout("Menus/LegalPage.wnd");
  460. if(legal)
  461. {
  462. legal->hide(FALSE);
  463. legal->bringForward();
  464. Int beginTime = timeGetTime();
  465. while(beginTime + 4000 > timeGetTime() )
  466. {
  467. TheWindowManager->update();
  468. // redraw all views, update the GUI
  469. TheDisplay->draw();
  470. Sleep(100);
  471. }
  472. setFPMode();
  473. legal->destroyWindows();
  474. legal->deleteInstance();
  475. }
  476. TheWritableGlobalData->m_breakTheMovie = TRUE;
  477. }
  478. TheShell->showShellMap(TRUE);
  479. TheShell->showShell();
  480. TheWritableGlobalData->m_afterIntro = FALSE;
  481. }
  482. }
  483. //Update snow particles.
  484. if (TheSnowManager)
  485. TheSnowManager->UPDATE();
  486. // update animation 2d collection
  487. TheAnim2DCollection->UPDATE();
  488. // update the keyboard
  489. if( TheKeyboard )
  490. {
  491. TheKeyboard->UPDATE();
  492. TheKeyboard->createStreamMessages();
  493. } // end if
  494. // Update the Eva stuff
  495. TheEva->UPDATE();
  496. // update the mouse
  497. if( TheMouse )
  498. {
  499. TheMouse->UPDATE();
  500. TheMouse->createStreamMessages();
  501. } // end if
  502. if (TheInGameUI->isCameraTrackingDrawable())
  503. {
  504. Drawable *draw = TheInGameUI->getFirstSelectedDrawable();
  505. if ( draw )
  506. {
  507. const Coord3D *pos = draw->getPosition();
  508. TheTacticalView->lookAt( pos );
  509. }
  510. else
  511. TheInGameUI->setCameraTrackingDrawable( FALSE );
  512. }
  513. if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro)
  514. {
  515. // redraw all views, update the GUI
  516. {
  517. TheDisplay->DRAW();
  518. }
  519. {
  520. TheDisplay->UPDATE();
  521. }
  522. return;
  523. }
  524. // update the window system itself
  525. {
  526. TheWindowManager->UPDATE();
  527. }
  528. // update the video player
  529. {
  530. TheVideoPlayer->UPDATE();
  531. }
  532. Bool freezeTime = TheTacticalView->isTimeFrozen() && !TheTacticalView->isCameraMovementFinished();
  533. freezeTime = freezeTime || TheScriptEngine->isTimeFrozenDebug();
  534. freezeTime = freezeTime || TheScriptEngine->isTimeFrozenScript();
  535. freezeTime = freezeTime || TheGameLogic->isGamePaused();
  536. Int localPlayerIndex = ThePlayerList ? ThePlayerList->getLocalPlayer()->getPlayerIndex() : 0;
  537. // hack to let client spin fast in network games but still do effects at the same pace. -MDC
  538. static UnsignedInt lastFrame = ~0;
  539. freezeTime = freezeTime || (lastFrame == m_frame);
  540. lastFrame = m_frame;
  541. if (!freezeTime)
  542. {
  543. #if defined(_DEBUG) || defined(_INTERNAL)
  544. if (TheGlobalData->m_shroudOn)
  545. #else
  546. if (true)
  547. #endif
  548. {
  549. //localPlayerIndex=TheGhostObjectManager->getLocalPlayerIndex(); //always use the first local player set since normally can't change. Doesn't work with debug "CTRL_SHIFT_SPACE"
  550. #ifdef DEBUG_FOG_MEMORY
  551. //Find indices of all active players
  552. Int numPlayers=ThePlayerList->getPlayerCount();
  553. Int numNonLocalPlayers=0;
  554. Int nonLocalPlayerIndices[MAX_PLAYER_COUNT];
  555. for (Int i=0; i<numPlayers; i++)
  556. { Player *player=ThePlayerList->getNthPlayer(i);
  557. //if (player->getPlayerType == PLAYER_HUMAN)
  558. if (player->getPlayerIndex() != localPlayerIndex)
  559. nonLocalPlayerIndices[numNonLocalPlayers++]=player->getPlayerIndex();
  560. }
  561. //update ghostObjects which don't have drawables or objects.
  562. TheGhostObjectManager->updateOrphanedObjects(nonLocalPlayerIndices,numNonLocalPlayers);
  563. #else
  564. TheGhostObjectManager->updateOrphanedObjects(NULL,0);
  565. #endif
  566. }
  567. // call the update for all client drawables
  568. Drawable* draw = firstDrawable();
  569. while (draw)
  570. { // update() could free the Drawable, so go ahead and grab 'next'
  571. Drawable* next = draw->getNextDrawable();
  572. #if defined(_DEBUG) || defined(_INTERNAL)
  573. if (TheGlobalData->m_shroudOn)
  574. #else
  575. if (true)
  576. #endif
  577. { //immobile objects need to take snapshots whenever they become fogged
  578. //so need to refresh their status. We can't rely on external calls
  579. //to getShroudStatus() because they are only made for visible on-screen
  580. //objects.
  581. Object *object=draw->getObject();
  582. if (object)
  583. {
  584. #ifdef DEBUG_FOG_MEMORY
  585. Int *playerIndex=nonLocalPlayerIndices;
  586. for (i=0; i<numNonLocalPlayers; i++, playerIndex++)
  587. object->getShroudedStatus(*playerIndex);
  588. #endif
  589. ObjectShroudStatus ss=object->getShroudedStatus(localPlayerIndex);
  590. if (ss >= OBJECTSHROUD_FOGGED && draw->getShroudClearFrame()!=0) {
  591. UnsignedInt limit = 2*LOGICFRAMES_PER_SECOND;
  592. if (object->isEffectivelyDead()) {
  593. // extend the time, so we can see the dead plane blow up & crash.
  594. limit += 3*LOGICFRAMES_PER_SECOND;
  595. }
  596. if (TheGameLogic->getFrame() < limit + draw->getShroudClearFrame()) {
  597. // It's been less than 2 seconds since we could see them clear, so keep showing them.
  598. ss = OBJECTSHROUD_CLEAR;
  599. }
  600. }
  601. draw->setFullyObscuredByShroud(ss >= OBJECTSHROUD_FOGGED);
  602. }
  603. }
  604. draw->updateDrawable();
  605. draw = next;
  606. }
  607. }
  608. #if defined(_INTERNAL) || defined(_DEBUG)
  609. // need to draw the first frame, then don't draw again until TheGlobalData->m_noDraw
  610. if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0)
  611. {
  612. return;
  613. }
  614. #endif
  615. // update all particle systems
  616. if( !freezeTime )
  617. {
  618. // update particle systems
  619. TheParticleSystemManager->setLocalPlayerIndex(localPlayerIndex);
  620. // TheParticleSystemManager->update();
  621. } // end if
  622. // update the terrain visuals
  623. {
  624. TheTerrainVisual->UPDATE();
  625. }
  626. // update display
  627. {
  628. TheDisplay->UPDATE();
  629. }
  630. {
  631. USE_PERF_TIMER(GameClient_draw)
  632. // redraw all views, update the GUI
  633. //if(TheGameLogic->getFrame() >= 2)
  634. TheDisplay->DRAW();
  635. }
  636. {
  637. // let display string factory handle its update
  638. TheDisplayStringManager->update();
  639. }
  640. {
  641. // update the shell
  642. TheShell->UPDATE();
  643. }
  644. {
  645. // update the in game UI
  646. TheInGameUI->UPDATE();
  647. }
  648. } // end update
  649. /** -----------------------------------------------------------------------------------------------
  650. * Call the given callback function for each object contained within the given region.
  651. */
  652. void GameClient::iterateDrawablesInRegion( Region3D *region, GameClientFuncPtr userFunc, void *userData )
  653. {
  654. Drawable *draw, *nextDrawable;
  655. for( draw = m_drawableList; draw; draw=nextDrawable )
  656. {
  657. nextDrawable = draw->getNextDrawable();
  658. Coord3D pos = *draw->getPosition();
  659. if( region == NULL ||
  660. (pos.x >= region->lo.x && pos.x <= region->hi.x &&
  661. pos.y >= region->lo.y && pos.y <= region->hi.y &&
  662. pos.z >= region->lo.z && pos.z <= region->hi.z) )
  663. {
  664. (*userFunc)( draw, userData );
  665. }
  666. }
  667. }
  668. /**Helper function to update fake GLA structures to become visible to certain players.
  669. We should only call this during critical moments, such as changing teams, changing to
  670. observer, etc.*/
  671. void GameClient::updateFakeDrawables(void)
  672. {
  673. for( Drawable *draw = getDrawableList(); draw; draw = draw->getNextDrawable() )
  674. {
  675. const Object *object=draw->getObject();
  676. if( object && object->isKindOf( KINDOF_FS_FAKE ) )
  677. {
  678. Relationship rel=ThePlayerList->getLocalPlayer()->getRelationship(object->getTeam());
  679. if (rel == ALLIES || rel == NEUTRAL)
  680. draw->setTerrainDecal(TERRAIN_DECAL_SHADOW_TEXTURE);
  681. else
  682. draw->setTerrainDecal(TERRAIN_DECAL_NONE);
  683. }
  684. }
  685. }
  686. /** -----------------------------------------------------------------------------------------------
  687. * Destroy the drawable immediately.
  688. */
  689. void GameClient::destroyDrawable( Drawable *draw )
  690. {
  691. // remove any notion of the Drawable in the in-game user interface
  692. TheInGameUI->disregardDrawable( draw );
  693. // remove from the master list
  694. draw->removeFromList(&m_drawableList);
  695. //
  696. // because drawables and objects are tightly coupled, not only MUST we maintain
  697. // our links in all instances, but it is NECESSARY for the client to actually
  698. // modify data in the logic, that is the pointer in an object to *this* drawable
  699. //
  700. Object *obj = draw->getObject();
  701. if( obj )
  702. {
  703. DEBUG_ASSERTCRASH( obj->getDrawable() == draw, ("Object/Drawable pointer mismatch!\n") );
  704. obj->friend_bindToDrawable( NULL );
  705. } // end if
  706. // remove the drawable from our hash of drawables
  707. removeDrawableFromLookupTable( draw );
  708. // free storage
  709. draw->deleteInstance();
  710. }
  711. // ------------------------------------------------------------------------------------------------
  712. /** Add drawable to lookup table for fast id searching */
  713. // ------------------------------------------------------------------------------------------------
  714. void GameClient::addDrawableToLookupTable(Drawable *draw )
  715. {
  716. // sanity
  717. if( draw == NULL )
  718. return;
  719. // add to lookup
  720. // m_drawableHash[ draw->getID() ] = draw;
  721. DrawableID newID = draw->getID();
  722. while( newID >= m_drawableVector.size() ) // Fail case is hella rare, so faster to double up on size() call
  723. m_drawableVector.resize(m_drawableVector.size() * 2, NULL);
  724. m_drawableVector[ newID ] = draw;
  725. } // end addDrawableToLookupTable
  726. // ------------------------------------------------------------------------------------------------
  727. /** Remove drawable from lookup table of fast id searching */
  728. // ------------------------------------------------------------------------------------------------
  729. void GameClient::removeDrawableFromLookupTable( Drawable *draw )
  730. {
  731. // sanity
  732. if( draw == NULL )
  733. return;
  734. // remove from table
  735. // m_drawableHash.erase( draw->getID() );
  736. m_drawableVector[ draw->getID() ] = NULL;
  737. } // end removeDrawableFromLookupTable
  738. //-------------------------------------------------------------------------------------------------
  739. /** Load a map into the game interface */
  740. Bool GameClient::loadMap( AsciiString mapName )
  741. {
  742. // sanity
  743. if( mapName.isEmpty() )
  744. return false;
  745. assert( 0 ); // who calls this?
  746. return TRUE;
  747. } // end loadMap
  748. //-------------------------------------------------------------------------------------------------
  749. /** Unload a map from the game interface */
  750. void GameClient::unloadMap( AsciiString mapName )
  751. {
  752. assert( 0 ); // who calls this?
  753. } // end unloadMap
  754. //-------------------------------------------------------------------------------------------------
  755. void GameClient::setTimeOfDay( TimeOfDay tod )
  756. {
  757. Drawable *draw = firstDrawable();
  758. while( draw )
  759. {
  760. draw->setTimeOfDay( tod );
  761. draw = draw->getNextDrawable();
  762. }
  763. }
  764. //-------------------------------------------------------------------------------------------------
  765. void GameClient::assignSelectedDrawablesToGroup( Int group )
  766. {
  767. /*
  768. Drawable *draw = firstDrawable();
  769. while( draw )
  770. {
  771. if( draw->isSelected() && draw->getObject()->isLocallyControlled())
  772. {
  773. draw->setDrawableGroup( group );
  774. }
  775. else if( draw->getDrawableGroup() == group )
  776. {
  777. draw->setDrawableGroup( 0 );
  778. }
  779. draw = draw->getNextDrawable();
  780. }
  781. */
  782. }
  783. //-------------------------------------------------------------------------------------------------
  784. void GameClient::selectDrawablesInGroup( Int group )
  785. {
  786. /*
  787. Drawable *draw = firstDrawable();
  788. // create a message that will assign a group ID to all the selected drawables, this
  789. // way when we do things with this current selected group of units, we only have
  790. // to refer to the group ID and not each individual object ID
  791. GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP );
  792. //We are creating a new group from scratch.
  793. teamMsg->appendBooleanArgument( true );
  794. while( draw )
  795. {
  796. int counter = 0;
  797. const Object *object = draw->getObject();
  798. if( object && draw->getDrawableGroup() == group && object->isLocallyControlled() && !object->isContained() )
  799. {
  800. //Only select the object if it is locally controlled and not contained by anything.
  801. TheInGameUI->selectDrawable(draw);
  802. teamMsg->appendObjectIDArgument( draw->getObject()->getID() );
  803. }
  804. else
  805. {
  806. TheInGameUI->deselectDrawable(draw);
  807. }
  808. draw = draw->getNextDrawable();
  809. counter++;
  810. }
  811. */
  812. }
  813. // ------------------------------------------------------------------------------------------------
  814. void GameClient::addTextBearingDrawable( Drawable *tbd )
  815. {
  816. if ( tbd != NULL )
  817. m_textBearingDrawableList.push_back( tbd );
  818. }
  819. // ------------------------------------------------------------------------------------------------
  820. void GameClient::flushTextBearingDrawables( void )
  821. {
  822. /////////////////////////////
  823. // WALK THIS LIST AND CALL EACH DRAWABLES TEXTY STUFF
  824. /////////////////////////////
  825. for( TextBearingDrawableListIterator it = m_textBearingDrawableList.begin(); it != m_textBearingDrawableList.end(); ++it )
  826. (*it)->drawUIText();
  827. m_textBearingDrawableList.clear();
  828. }
  829. // ------------------------------------------------------------------------------------------------
  830. GameMessage::Type GameClient::evaluateContextCommand( Drawable *draw,
  831. const Coord3D *pos,
  832. CommandTranslator::CommandEvaluateType cmdType )
  833. {
  834. if( m_commandTranslator )
  835. return m_commandTranslator->evaluateContextCommand( draw, pos, cmdType );
  836. else
  837. return GameMessage::MSG_INVALID;
  838. } // end evaluateContextCommand
  839. //-------------------------------------------------------------------------------------------------
  840. /** Get the ray effect data for a drawable */
  841. void GameClient::getRayEffectData( Drawable *draw, RayEffectData *effectData )
  842. {
  843. TheRayEffects->getRayEffectData( draw, effectData );
  844. } // end getRayEffectData
  845. //-------------------------------------------------------------------------------------------------
  846. /** remove the drawble from the ray effects sytem if present */
  847. void GameClient::removeFromRayEffects( Drawable *draw )
  848. {
  849. TheRayEffects->deleteRayEffect( draw );
  850. } // end removeFromRayEffects
  851. /** frees all shadow resources used by this module - used by Options screen.*/
  852. void GameClient::releaseShadows(void)
  853. {
  854. Drawable *draw;
  855. for( draw = firstDrawable(); draw; draw = draw->getNextDrawable() )
  856. draw->releaseShadows();
  857. }
  858. /** create shadow resources if not already present. Used by Options screen.*/
  859. void GameClient::allocateShadows(void)
  860. {
  861. Drawable *draw;
  862. for( draw = firstDrawable(); draw; draw = draw->getNextDrawable() )
  863. draw->allocateShadows();
  864. }
  865. //-------------------------------------------------------------------------------------------------
  866. /** Preload assets for the currently loaded map. Those assets include all the damage states
  867. * for every building loaded, as well as any faction units/structures we can build and
  868. * all their damage states */
  869. //-------------------------------------------------------------------------------------------------
  870. void GameClient::preloadAssets( TimeOfDay timeOfDay )
  871. {
  872. MEMORYSTATUS before, after;
  873. GlobalMemoryStatus(&before);
  874. // first, for every drawable in the map load the assets for all states we care about
  875. Drawable *draw;
  876. for( draw = firstDrawable(); draw; draw = draw->getNextDrawable() )
  877. draw->preloadAssets( timeOfDay );
  878. //
  879. // now create a temporary drawble for each of the faction things we can create, preload
  880. // their assets, and dump the drawable
  881. //
  882. AsciiString side;
  883. const ThingTemplate *tTemplate;
  884. for( tTemplate = TheThingFactory->firstTemplate();
  885. tTemplate;
  886. tTemplate = tTemplate->friend_getNextTemplate() )
  887. {
  888. // if this isn't one of the objects that can be preloaded ignore it
  889. if( tTemplate->isKindOf( KINDOF_PRELOAD ) == FALSE && !TheGlobalData->m_preloadEverything )
  890. continue;
  891. // create the drawable and do the preloading
  892. draw = TheThingFactory->newDrawable( tTemplate );
  893. if( draw )
  894. {
  895. // preload the assets
  896. draw->preloadAssets( timeOfDay );
  897. // destroy the drawable
  898. TheGameClient->destroyDrawable( draw );
  899. } // end if
  900. } // end for
  901. GlobalMemoryStatus(&after);
  902. DEBUG_LOG(("Preloading memory dwAvailPageFile %d --> %d : %d\n",
  903. before.dwAvailPageFile, after.dwAvailPageFile, before.dwAvailPageFile - after.dwAvailPageFile));
  904. DEBUG_LOG(("Preloading memory dwAvailPhys %d --> %d : %d\n",
  905. before.dwAvailPhys, after.dwAvailPhys, before.dwAvailPhys - after.dwAvailPhys));
  906. DEBUG_LOG(("Preloading memory dwAvailVirtual %d --> %d : %d\n",
  907. before.dwAvailVirtual, after.dwAvailVirtual, before.dwAvailVirtual - after.dwAvailVirtual));
  908. /*
  909. DEBUG_LOG(("Preloading memory dwLength %d --> %d : %d\n",
  910. before.dwLength, after.dwLength, before.dwLength - after.dwLength));
  911. DEBUG_LOG(("Preloading memory dwMemoryLoad %d --> %d : %d\n",
  912. before.dwMemoryLoad, after.dwMemoryLoad, before.dwMemoryLoad - after.dwMemoryLoad));
  913. DEBUG_LOG(("Preloading memory dwTotalPageFile %d --> %d : %d\n",
  914. before.dwTotalPageFile, after.dwTotalPageFile, before.dwTotalPageFile - after.dwTotalPageFile));
  915. DEBUG_LOG(("Preloading memory dwTotalPhys %d --> %d : %d\n",
  916. before.dwTotalPhys , after.dwTotalPhys, before.dwTotalPhys - after.dwTotalPhys));
  917. DEBUG_LOG(("Preloading memory dwTotalVirtual %d --> %d : %d\n",
  918. before.dwTotalVirtual , after.dwTotalVirtual, before.dwTotalVirtual - after.dwTotalVirtual));
  919. */
  920. GlobalMemoryStatus(&before);
  921. extern std::vector<AsciiString> debrisModelNamesGlobalHack;
  922. for (Int i=0; i<debrisModelNamesGlobalHack.size(); ++i)
  923. {
  924. TheDisplay->preloadModelAssets(debrisModelNamesGlobalHack[i]);
  925. }
  926. GlobalMemoryStatus(&after);
  927. debrisModelNamesGlobalHack.clear();
  928. DEBUG_LOG(("Preloading memory dwAvailPageFile %d --> %d : %d\n",
  929. before.dwAvailPageFile, after.dwAvailPageFile, before.dwAvailPageFile - after.dwAvailPageFile));
  930. DEBUG_LOG(("Preloading memory dwAvailPhys %d --> %d : %d\n",
  931. before.dwAvailPhys, after.dwAvailPhys, before.dwAvailPhys - after.dwAvailPhys));
  932. DEBUG_LOG(("Preloading memory dwAvailVirtual %d --> %d : %d\n",
  933. before.dwAvailVirtual, after.dwAvailVirtual, before.dwAvailVirtual - after.dwAvailVirtual));
  934. TheControlBar->preloadAssets( timeOfDay );
  935. GlobalMemoryStatus(&before);
  936. TheParticleSystemManager->preloadAssets( timeOfDay );
  937. GlobalMemoryStatus(&after);
  938. DEBUG_LOG(("Preloading memory dwAvailPageFile %d --> %d : %d\n",
  939. before.dwAvailPageFile, after.dwAvailPageFile, before.dwAvailPageFile - after.dwAvailPageFile));
  940. DEBUG_LOG(("Preloading memory dwAvailPhys %d --> %d : %d\n",
  941. before.dwAvailPhys, after.dwAvailPhys, before.dwAvailPhys - after.dwAvailPhys));
  942. DEBUG_LOG(("Preloading memory dwAvailVirtual %d --> %d : %d\n",
  943. before.dwAvailVirtual, after.dwAvailVirtual, before.dwAvailVirtual - after.dwAvailVirtual));
  944. char *textureNames[] = {
  945. "ptspruce01.tga",
  946. "exrktflame.tga",
  947. "cvlimo3_d2.tga",
  948. "exfthrowerstream.tga",
  949. "uvrockbug_d1.tga",
  950. "arcbackgroundc.tga",
  951. "grade3.tga",
  952. "framebasec.tga",
  953. "gradec.tga",
  954. "frametopc.tga",
  955. "arcbackgrounda.tga",
  956. "arcglow2.tga",
  957. "framebasea.tga",
  958. "gradea.tga",
  959. "frametopa.tga",
  960. "sauserinterface256_002.tga",
  961. "sauserinterface256_001.tga",
  962. "unitbackgrounda.tga",
  963. "sauserinterface256_004.tga",
  964. "sagentank.tga",
  965. "sauserinterface256_005.tga",
  966. "sagenair.tga",
  967. "sauserinterface256_003.tga",
  968. "sagenspec.tga",
  969. "snuserinterface256_003.tga",
  970. "snuserinterface256_002.tga",
  971. "unitbackgroundc.tga",
  972. "snuserinterface256_004.tga",
  973. "sngenredarm.tga",
  974. "snuserinterface256_001.tga",
  975. "sngenspewea.tga",
  976. "sngensecpol.tga",
  977. "ciburn.tga",
  978. "ptmaple02.tga",
  979. "scuserinterface256_005.tga",
  980. "scuserinterface256_002.tga",
  981. "sauserinterface256_006.tga",
  982. "pmcrates.tga",
  983. ""
  984. };
  985. GlobalMemoryStatus(&before);
  986. for (i=0; *textureNames[i]; ++i)
  987. TheDisplay->preloadTextureAssets(textureNames[i]);
  988. GlobalMemoryStatus(&after);
  989. DEBUG_LOG(("Preloading memory dwAvailPageFile %d --> %d : %d\n",
  990. before.dwAvailPageFile, after.dwAvailPageFile, before.dwAvailPageFile - after.dwAvailPageFile));
  991. DEBUG_LOG(("Preloading memory dwAvailPhys %d --> %d : %d\n",
  992. before.dwAvailPhys, after.dwAvailPhys, before.dwAvailPhys - after.dwAvailPhys));
  993. DEBUG_LOG(("Preloading memory dwAvailVirtual %d --> %d : %d\n",
  994. before.dwAvailVirtual, after.dwAvailVirtual, before.dwAvailVirtual - after.dwAvailVirtual));
  995. // preloadTextureNamesGlobalHack2 = preloadTextureNamesGlobalHack;
  996. // preloadTextureNamesGlobalHack.clear();
  997. } // end preloadAssets
  998. // ------------------------------------------------------------------------------------------------
  999. /** Given a string name, find the drawable TOC entry (if any) associated with it */
  1000. // ------------------------------------------------------------------------------------------------
  1001. GameClient::DrawableTOCEntry *GameClient::findTOCEntryByName( AsciiString name )
  1002. {
  1003. for( DrawableTOCListIterator it = m_drawableTOC.begin(); it != m_drawableTOC.end(); ++it )
  1004. if( (*it).name == name )
  1005. return &(*it);
  1006. return NULL;
  1007. } // end findTOCEntryByname
  1008. // ------------------------------------------------------------------------------------------------
  1009. /** Given a drawable TOC identifier, find the drawable TOC if any */
  1010. // ------------------------------------------------------------------------------------------------
  1011. GameClient::DrawableTOCEntry *GameClient::findTOCEntryById( UnsignedShort id )
  1012. {
  1013. for( DrawableTOCListIterator it = m_drawableTOC.begin(); it != m_drawableTOC.end(); ++it )
  1014. if( (*it).id == id )
  1015. return &(*it);
  1016. return NULL;
  1017. } // end findTOCEntryById
  1018. // ------------------------------------------------------------------------------------------------
  1019. /** Add an drawable TOC entry */
  1020. // ------------------------------------------------------------------------------------------------
  1021. void GameClient::addTOCEntry( AsciiString name, UnsignedShort id )
  1022. {
  1023. DrawableTOCEntry tocEntry;
  1024. tocEntry.name = name;
  1025. tocEntry.id = id;
  1026. m_drawableTOC.push_back( tocEntry );
  1027. } // end addTOCEntry
  1028. // ------------------------------------------------------------------------------------------------
  1029. static Bool shouldSaveDrawable(const Drawable* draw)
  1030. {
  1031. if (draw->testDrawableStatus(DRAWABLE_STATUS_NO_SAVE))
  1032. {
  1033. if (draw->getObject() == NULL)
  1034. {
  1035. return false;
  1036. }
  1037. else
  1038. {
  1039. DEBUG_CRASH(("You should not ever set DRAWABLE_STATUS_NO_SAVE for a Drawable with an object. (%s)\n",draw->getTemplate()->getName().str()));
  1040. }
  1041. }
  1042. return true;
  1043. }
  1044. // ------------------------------------------------------------------------------------------------
  1045. /** Xfer drawable table of contents */
  1046. // ------------------------------------------------------------------------------------------------
  1047. void GameClient::xferDrawableTOC( Xfer *xfer )
  1048. {
  1049. // version
  1050. XferVersion currentVersion = 1;
  1051. XferVersion version = currentVersion;
  1052. xfer->xferVersion( &version, currentVersion );
  1053. // clear our current table of contents
  1054. m_drawableTOC.clear();
  1055. // xfer the table
  1056. UnsignedInt tocCount = 0;
  1057. if( xfer->getXferMode() == XFER_SAVE )
  1058. {
  1059. AsciiString templateName;
  1060. // generate a new TOC based on the drawables that are in the map
  1061. for( Drawable *draw = getDrawableList(); draw; draw = draw->getNextDrawable() )
  1062. {
  1063. if (!shouldSaveDrawable(draw))
  1064. continue;
  1065. // get the name we're working with
  1066. templateName = draw->getTemplate()->getName();
  1067. // if is this drawable name already in the TOC, skip it
  1068. if( findTOCEntryByName( templateName ) != NULL )
  1069. continue;
  1070. // add this entry to the TOC
  1071. addTOCEntry( draw->getTemplate()->getName(), ++tocCount );
  1072. } // end for obj
  1073. // xfer entries in the TOC
  1074. xfer->xferUnsignedInt( &tocCount );
  1075. // xfer each TOC entry
  1076. DrawableTOCListIterator it;
  1077. DrawableTOCEntry *tocEntry;
  1078. for( it = m_drawableTOC.begin(); it != m_drawableTOC.end(); ++it )
  1079. {
  1080. // get this toc entry
  1081. tocEntry = &(*it);
  1082. // xfer the name
  1083. xfer->xferAsciiString( &tocEntry->name );
  1084. // xfer the paired id
  1085. xfer->xferUnsignedShort( &tocEntry->id );
  1086. } // end for
  1087. } // end if
  1088. else
  1089. {
  1090. AsciiString templateName;
  1091. UnsignedShort id;
  1092. // how many entries are we going to read
  1093. xfer->xferUnsignedInt( &tocCount );
  1094. // read all the entries
  1095. for( UnsignedInt i = 0; i < tocCount; ++i )
  1096. {
  1097. // read the name
  1098. xfer->xferAsciiString( &templateName );
  1099. // read the id
  1100. xfer->xferUnsignedShort( &id );
  1101. // add this to the TOC
  1102. addTOCEntry( templateName, id );
  1103. } // end for i
  1104. } // end else
  1105. } // end xferDrawableTOC
  1106. // ------------------------------------------------------------------------------------------------
  1107. /** Xfer method for Game Client
  1108. * Version History:
  1109. * 1: Initial
  1110. * 2: Adding mission briefing history
  1111. * 3: Added block markers around drawable data, no version checking is done and therefore
  1112. * this version breaks compatibility with previous versions. (CBD)
  1113. */
  1114. // ------------------------------------------------------------------------------------------------
  1115. void GameClient::xfer( Xfer *xfer )
  1116. {
  1117. // version
  1118. XferVersion currentVersion = 3;
  1119. XferVersion version = currentVersion;
  1120. xfer->xferVersion( &version, currentVersion );
  1121. // client frame number
  1122. xfer->xferUnsignedInt( &m_frame );
  1123. //
  1124. // note that we do not do the id counter here, we did it in the game state block because
  1125. // it's important to do that part very early in the load process
  1126. //
  1127. // !!!DON'T DO THIS!!! ----> xfer->xferDrawableID( &m_nextDrawableID ); <---- !!!DON'T DO THIS!!!
  1128. //
  1129. // xfer a table of contents that contain thing template and indentifier pairs. this
  1130. // table of contents is good for this save file only as unique numbers are only
  1131. // generated and stored for the actual things that are on this map
  1132. //
  1133. xferDrawableTOC( xfer );
  1134. // drawable count
  1135. Drawable *draw;
  1136. UnsignedShort drawableCount = 0;
  1137. for( draw = getDrawableList(); draw; draw = draw->getNextDrawable() )
  1138. {
  1139. if (xfer->getXferMode() == XFER_SAVE && !shouldSaveDrawable(draw))
  1140. continue;
  1141. drawableCount++;
  1142. }
  1143. xfer->xferUnsignedShort( &drawableCount );
  1144. // drawable data
  1145. DrawableTOCEntry *tocEntry;
  1146. ObjectID objectID;
  1147. if( xfer->getXferMode() == XFER_SAVE )
  1148. {
  1149. // iterate all drawables
  1150. for( draw = getDrawableList(); draw; draw = draw->getNextDrawable() )
  1151. {
  1152. if (!shouldSaveDrawable(draw))
  1153. continue;
  1154. // get TOC entry for this drawable
  1155. tocEntry = findTOCEntryByName( draw->getTemplate()->getName() );
  1156. if( tocEntry == NULL )
  1157. {
  1158. DEBUG_CRASH(( "GameClient::xfer - Drawable TOC entry not found for '%s'\n", draw->getTemplate()->getName().str() ));
  1159. throw SC_INVALID_DATA;
  1160. } // end if
  1161. // xfer toc id entry
  1162. xfer->xferUnsignedShort( &tocEntry->id );
  1163. // begin data block
  1164. xfer->beginBlock();
  1165. // write the object ID this drawable is attached to
  1166. objectID = draw->getObject() ? draw->getObject()->getID() : INVALID_ID;
  1167. xfer->xferObjectID( &objectID );
  1168. // write snapshot data
  1169. xfer->xferSnapshot( draw );
  1170. // end data block
  1171. xfer->endBlock();
  1172. } // end for, draw
  1173. } // end if, save
  1174. else
  1175. {
  1176. UnsignedShort tocID;
  1177. const ThingTemplate *thingTemplate;
  1178. Int dataSize;
  1179. // read all entries
  1180. for( UnsignedShort i = 0; i < drawableCount; ++i )
  1181. {
  1182. // read toc id entry
  1183. xfer->xferUnsignedShort( &tocID );
  1184. // find TOC entry with this identifier
  1185. tocEntry = findTOCEntryById( tocID );
  1186. if( tocEntry == NULL )
  1187. {
  1188. DEBUG_CRASH(( "GameClient::xfer - No TOC entry match for id '%d'\n", tocID ));
  1189. throw SC_INVALID_DATA;
  1190. } // end if
  1191. // read data block size
  1192. dataSize = xfer->beginBlock();
  1193. // find matching thing template
  1194. thingTemplate = TheThingFactory->findTemplate( tocEntry->name );
  1195. if( thingTemplate == NULL )
  1196. {
  1197. DEBUG_CRASH(( "GameClient::xfer - Unrecognized thing template '%s', skipping. ENGINEERS - Are you *sure* it's OK to be ignoring this object from the save file??? Think hard about it!\n",
  1198. tocEntry->name.str() ));
  1199. xfer->skip( dataSize );
  1200. continue;
  1201. } // end if
  1202. // read the object ID this drawable is attached to (if any)
  1203. xfer->xferObjectID( &objectID );
  1204. //
  1205. // if we have an attached object ID, we won't create a new drawable, we'll use the
  1206. // one that has been created and attached to the object already
  1207. //
  1208. if( objectID != INVALID_ID )
  1209. {
  1210. Object *object = TheGameLogic->findObjectByID( objectID );
  1211. // sanity
  1212. if( object == NULL )
  1213. {
  1214. DEBUG_CRASH(( "GameClient::xfer - Cannot find object '%d' that is supposed to be attached to this drawable '%s'\n",
  1215. objectID, thingTemplate->getName().str() ));
  1216. throw SC_INVALID_DATA;
  1217. } // end if
  1218. // get the drawable from the object
  1219. draw = object->getDrawable();
  1220. if( draw == NULL )
  1221. {
  1222. DEBUG_CRASH(( "GameClient::xfer - There is no drawable attached to the object '%s' (%d) and there should be\n",
  1223. object->getTemplate()->getName().str(), object->getID() ));
  1224. throw SC_INVALID_DATA;
  1225. } // end if
  1226. // srj sez: some objects (eg, diguised bombtrucks) may have an "abnormal" drawable. so check.
  1227. //
  1228. // note carefully: we do NOT want to use isEquivalentTo() here, because different object reskins
  1229. // SHOULD count as different templates for our purposes here (which are purely visual). however, we
  1230. // do need to compare getFinalOverride, because draw->getTemplate() is always gonna return the final
  1231. // override, while TheThingFactory->findTemplate does not.
  1232. //
  1233. const ThingTemplate* drawTemplate = draw->getTemplate();
  1234. if (drawTemplate->getFinalOverride() != thingTemplate->getFinalOverride())
  1235. {
  1236. TheGameClient->destroyDrawable( draw );
  1237. draw = TheThingFactory->newDrawable( thingTemplate );
  1238. TheGameLogic->bindObjectAndDrawable(object, draw);
  1239. }
  1240. } // end if
  1241. else
  1242. {
  1243. //
  1244. // there was no object attached to this drawable when we saved, we need to create a
  1245. // whole brand new drawable now
  1246. //
  1247. draw = TheThingFactory->newDrawable( thingTemplate );
  1248. // sanity
  1249. if( draw == NULL )
  1250. {
  1251. DEBUG_CRASH(( "GameClient::xfer - Unable to create drawable for '%s'\n",
  1252. thingTemplate->getName().str() ));
  1253. throw SC_INVALID_DATA;
  1254. } // end if
  1255. } // end else
  1256. // xfer the drawable data
  1257. xfer->xferSnapshot( draw );
  1258. // end block (not necessary since this is a no-op but symettrically nice)
  1259. xfer->endBlock();
  1260. } // end for, i
  1261. } // end else, load
  1262. // xfer the in-game mission briefing history list
  1263. if (version >= 2)
  1264. {
  1265. if( xfer->getXferMode() == XFER_SAVE )
  1266. {
  1267. BriefingList *bList = GetBriefingTextList();
  1268. Int numEntries = bList->size();
  1269. xfer->xferInt(&numEntries);
  1270. DEBUG_LOG(("Saving %d briefing lines\n", numEntries));
  1271. for (BriefingList::const_iterator bIt = bList->begin(); bIt != bList->end(); ++bIt)
  1272. {
  1273. AsciiString tempStr = *bIt;
  1274. DEBUG_LOG(("'%s'\n", tempStr.str()));
  1275. xfer->xferAsciiString(&tempStr);
  1276. }
  1277. }
  1278. else // XFER_LOAD
  1279. {
  1280. Int numEntries = 0;
  1281. xfer->xferInt(&numEntries);
  1282. DEBUG_LOG(("Loading %d briefing lines\n", numEntries));
  1283. UpdateDiplomacyBriefingText(AsciiString::TheEmptyString, TRUE); // clear out briefing list first
  1284. while (numEntries-- > 0)
  1285. {
  1286. AsciiString tempStr;
  1287. xfer->xferAsciiString(&tempStr);
  1288. DEBUG_LOG(("'%s'\n", tempStr.str()));
  1289. UpdateDiplomacyBriefingText(tempStr, FALSE);
  1290. }
  1291. }
  1292. }
  1293. } // end xfer
  1294. // ------------------------------------------------------------------------------------------------
  1295. /** Load post process */
  1296. // ------------------------------------------------------------------------------------------------
  1297. void GameClient::loadPostProcess( void )
  1298. {
  1299. //
  1300. // due to the fact that during the load process we have called newDrawable for drawables
  1301. // without objects, and then overwrote their ids with data from the save file, our allocater
  1302. // id may be far higher than it needs to be. We'll pull it back down as low as we can
  1303. //
  1304. Drawable *draw;
  1305. for( draw = getDrawableList(); draw; draw = draw->getNextDrawable() )
  1306. if( draw->getID() >= m_nextDrawableID )
  1307. m_nextDrawableID = (DrawableID)((UnsignedInt)draw->getID() + 1);
  1308. } // end loadPostProcess
  1309. // ------------------------------------------------------------------------------------------------
  1310. /** CRC */
  1311. // ------------------------------------------------------------------------------------------------
  1312. void GameClient::crc( Xfer *xfer )
  1313. {
  1314. } // end crc