GameClient.cpp 47 KB

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