GameEngine.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  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. // GameEngine.cpp /////////////////////////////////////////////////////////////////////////////////
  24. // Implementation of the Game Engine singleton
  25. // Author: Michael S. Booth, April 2001
  26. #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine
  27. #include "Common/ActionManager.h"
  28. #include "Common/AudioAffect.h"
  29. #include "Common/BuildAssistant.h"
  30. #include "Common/CRCDebug.h"
  31. #include "Common/Radar.h"
  32. #include "Common/PlayerTemplate.h"
  33. #include "Common/Team.h"
  34. #include "Common/PlayerList.h"
  35. #include "Common/GameAudio.h"
  36. #include "Common/GameEngine.h"
  37. #include "Common/INI.h"
  38. #include "Common/INIException.h"
  39. #include "Common/MessageStream.h"
  40. #include "Common/ThingFactory.h"
  41. #include "Common/File.h"
  42. #include "Common/FileSystem.h"
  43. #include "Common/ArchiveFileSystem.h"
  44. #include "Common/LocalFileSystem.h"
  45. #include "Common/CDManager.h"
  46. #include "Common/GlobalData.h"
  47. #include "Common/PerfTimer.h"
  48. #include "Common/RandomValue.h"
  49. #include "Common/NameKeyGenerator.h"
  50. #include "Common/ModuleFactory.h"
  51. #include "Common/Debug.h"
  52. #include "Common/GameState.h"
  53. #include "Common/GameStateMap.h"
  54. #include "Common/Science.h"
  55. #include "Common/FunctionLexicon.h"
  56. #include "Common/CommandLine.h"
  57. #include "Common/DamageFX.h"
  58. #include "Common/MultiplayerSettings.h"
  59. #include "Common/Recorder.h"
  60. #include "Common/SpecialPower.h"
  61. #include "Common/TerrainTypes.h"
  62. #include "Common/Upgrade.h"
  63. #include "Common/UserPreferences.h"
  64. #include "Common/Xfer.h"
  65. #include "Common/XferCRC.h"
  66. #include "Common/GameLOD.h"
  67. #include "Common/Registry.h"
  68. #include "Common/GameCommon.h" // FOR THE ALLOW_DEBUG_CHEATS_IN_RELEASE #define
  69. #include "GameLogic/Armor.h"
  70. #include "GameLogic/AI.h"
  71. #include "GameLogic/CaveSystem.h"
  72. #include "GameLogic/CrateSystem.h"
  73. #include "GameLogic/Damage.h"
  74. #include "GameLogic/VictoryConditions.h"
  75. #include "GameLogic/ObjectCreationList.h"
  76. #include "GameLogic/Weapon.h"
  77. #include "GameLogic/GameLogic.h"
  78. #include "GameLogic/Locomotor.h"
  79. #include "GameLogic/RankInfo.h"
  80. #include "GameLogic/ScriptEngine.h"
  81. #include "GameLogic/SidesList.h"
  82. #include "GameClient/Display.h"
  83. #include "GameClient/FXList.h"
  84. #include "GameClient/GameClient.h"
  85. #include "GameClient/Keyboard.h"
  86. #include "GameClient/Shell.h"
  87. #include "GameClient/GameText.h"
  88. #include "GameClient/ParticleSys.h"
  89. #include "GameClient/Water.h"
  90. #include "GameClient/TerrainRoads.h"
  91. #include "GameClient/MetaEvent.h"
  92. #include "GameClient/MapUtil.h"
  93. #include "GameClient/GameWindowManager.h"
  94. #include "GameClient/GlobalLanguage.h"
  95. #include "GameClient/Drawable.h"
  96. #include "GameClient/GUICallbacks.h"
  97. #include "GameNetwork/NetworkInterface.h"
  98. #include "GameNetwork/WOLBrowser/WebBrowser.h"
  99. #include "GameNetwork/LANAPI.h"
  100. #include "GameNetwork/GameSpy/GameResultsThread.h"
  101. #include "Common/Version.h"
  102. #ifdef _INTERNAL
  103. // for occasional debugging...
  104. //#pragma optimize("", off)
  105. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  106. #endif
  107. //-------------------------------------------------------------------------------------------------
  108. #ifdef DEBUG_CRC
  109. class DeepCRCSanityCheck : public SubsystemInterface
  110. {
  111. public:
  112. DeepCRCSanityCheck() {}
  113. virtual ~DeepCRCSanityCheck() {}
  114. virtual void init(void) {}
  115. virtual void reset(void);
  116. virtual void update(void) {}
  117. protected:
  118. };
  119. DeepCRCSanityCheck *TheDeepCRCSanityCheck = NULL;
  120. void DeepCRCSanityCheck::reset(void)
  121. {
  122. static Int timesThrough = 0;
  123. static UnsignedInt lastCRC = 0;
  124. AsciiString fname;
  125. fname.format("%sCRCAfter%dMaps.dat", TheGlobalData->getPath_UserData().str(), timesThrough);
  126. UnsignedInt thisCRC = TheGameLogic->getCRC( CRC_RECALC, fname );
  127. DEBUG_LOG(("DeepCRCSanityCheck: CRC is %X\n", thisCRC));
  128. DEBUG_ASSERTCRASH(timesThrough == 0 || thisCRC == lastCRC,
  129. ("CRC after reset did not match beginning CRC!\nNetwork games won't work after this.\nOld: 0x%8.8X, New: 0x%8.8X",
  130. lastCRC, thisCRC));
  131. lastCRC = thisCRC;
  132. timesThrough++;
  133. }
  134. #endif // DEBUG_CRC
  135. //-------------------------------------------------------------------------------------------------
  136. /// The GameEngine singleton instance
  137. GameEngine *TheGameEngine = NULL;
  138. //-------------------------------------------------------------------------------------------------
  139. SubsystemInterfaceList* TheSubsystemList = NULL;
  140. //-------------------------------------------------------------------------------------------------
  141. template<class SUBSYSTEM>
  142. void initSubsystem(SUBSYSTEM*& sysref, AsciiString name, SUBSYSTEM* sys, Xfer *pXfer, const char* path1 = NULL,
  143. const char* path2 = NULL, const char* dirpath = NULL)
  144. {
  145. sysref = sys;
  146. TheSubsystemList->initSubsystem(sys, path1, path2, dirpath, pXfer, name);
  147. }
  148. //-------------------------------------------------------------------------------------------------
  149. extern HINSTANCE ApplicationHInstance; ///< our application instance
  150. extern CComModule _Module;
  151. //-------------------------------------------------------------------------------------------------
  152. static void updateTGAtoDDS();
  153. Int GameEngine::getFramesPerSecondLimit( void )
  154. {
  155. return m_maxFPS;
  156. }
  157. //-------------------------------------------------------------------------------------------------
  158. GameEngine::GameEngine( void )
  159. {
  160. // Set the time slice size to 1 ms.
  161. timeBeginPeriod(1);
  162. // initialize to non garbage values
  163. m_maxFPS = 0;
  164. m_quitting = FALSE;
  165. m_isActive = FALSE;
  166. _Module.Init(NULL, ApplicationHInstance);
  167. }
  168. //-------------------------------------------------------------------------------------------------
  169. GameEngine::~GameEngine()
  170. {
  171. //extern std::vector<std::string> preloadTextureNamesGlobalHack;
  172. //preloadTextureNamesGlobalHack.clear();
  173. delete TheMapCache;
  174. TheMapCache = NULL;
  175. // delete TheShell;
  176. // TheShell = NULL;
  177. TheGameResultsQueue->endThreads();
  178. TheSubsystemList->shutdownAll();
  179. delete TheSubsystemList;
  180. TheSubsystemList = NULL;
  181. delete TheNetwork;
  182. TheNetwork = NULL;
  183. delete TheCommandList;
  184. TheCommandList = NULL;
  185. delete TheNameKeyGenerator;
  186. TheNameKeyGenerator = NULL;
  187. delete TheFileSystem;
  188. TheFileSystem = NULL;
  189. if (TheGameLODManager)
  190. delete TheGameLODManager;
  191. Drawable::killStaticImages();
  192. _Module.Term();
  193. #ifdef PERF_TIMERS
  194. PerfGather::termPerfDump();
  195. #endif
  196. // Restore the previous time slice for Windows.
  197. timeEndPeriod(1);
  198. }
  199. void GameEngine::setFramesPerSecondLimit( Int fps )
  200. {
  201. DEBUG_LOG(("GameEngine::setFramesPerSecondLimit() - setting max fps to %d (TheGlobalData->m_useFpsLimit == %d)\n", fps, TheGlobalData->m_useFpsLimit));
  202. m_maxFPS = fps;
  203. }
  204. /** -----------------------------------------------------------------------------------------------
  205. * Initialize the game engine by initializing the GameLogic and GameClient.
  206. */
  207. void GameEngine::init( void ) {} /// @todo: I changed this to take argc & argv so we can parse those after the GDF is loaded. We need to rethink this immediately as it is a nasty hack
  208. void GameEngine::init( int argc, char *argv[] )
  209. {
  210. try {
  211. //create an INI object to use for loading stuff
  212. INI ini;
  213. #ifdef DEBUG_LOGGING
  214. if (TheVersion)
  215. {
  216. DEBUG_LOG(("================================================================================\n"));
  217. #if defined _DEBUG
  218. const char *buildType = "Debug";
  219. #elif defined _INTERNAL
  220. const char *buildType = "Internal";
  221. #else
  222. const char *buildType = "Release";
  223. #endif
  224. DEBUG_LOG(("Generals version %s (%s)\n", TheVersion->getAsciiVersion().str(), buildType));
  225. DEBUG_LOG(("Build date: %s\n", TheVersion->getAsciiBuildTime().str()));
  226. DEBUG_LOG(("Build location: %s\n", TheVersion->getAsciiBuildLocation().str()));
  227. DEBUG_LOG(("Built by: %s\n", TheVersion->getAsciiBuildUser().str()));
  228. DEBUG_LOG(("================================================================================\n"));
  229. }
  230. #endif
  231. #if defined(PERF_TIMERS) || defined(DUMP_PERF_STATS)
  232. DEBUG_LOG(("Calculating CPU frequency for performance timers.\n"));
  233. InitPrecisionTimer();
  234. #endif
  235. #ifdef PERF_TIMERS
  236. PerfGather::initPerfDump("AAAPerfStats", PerfGather::PERF_NETTIME);
  237. #endif
  238. #ifdef DUMP_PERF_STATS////////////////////////////////////////////////////////////
  239. __int64 startTime64;//////////////////////////////////////////////////////////////
  240. __int64 endTime64,freq64;///////////////////////////////////////////////////////////
  241. GetPrecisionTimerTicksPerSec(&freq64);///////////////////////////////////////////////
  242. GetPrecisionTimer(&startTime64);////////////////////////////////////////////////////
  243. char Buf[256];//////////////////////////////////////////////////////////////////////
  244. #endif//////////////////////////////////////////////////////////////////////////////
  245. m_maxFPS = DEFAULT_MAX_FPS;
  246. TheSubsystemList = MSGNEW("GameEngineSubsystem") SubsystemInterfaceList;
  247. TheSubsystemList->addSubsystem(this);
  248. // initialize the random number system
  249. InitRandom();
  250. // Create the low-level file system interface
  251. TheFileSystem = createFileSystem();
  252. //Kris: Patch 1.01 - November 17, 2003
  253. //I was unable to resolve the RTPatch method of deleting a shipped file. English, Chinese, and Korean
  254. //SKU's shipped with two INIZH.big files. One properly in the Run directory and the other in Run\INI\Data.
  255. //We need to toast the latter in order for the game to patch properly.
  256. DeleteFile( "Data\\INI\\INIZH.big" );
  257. // not part of the subsystem list, because it should normally never be reset!
  258. TheNameKeyGenerator = MSGNEW("GameEngineSubsystem") NameKeyGenerator;
  259. TheNameKeyGenerator->init();
  260. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  261. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  262. sprintf(Buf,"----------------------------------------------------------------------------After TheNameKeyGenerator = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  263. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  264. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  265. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  266. // not part of the subsystem list, because it should normally never be reset!
  267. TheCommandList = MSGNEW("GameEngineSubsystem") CommandList;
  268. TheCommandList->init();
  269. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  270. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  271. sprintf(Buf,"----------------------------------------------------------------------------After TheCommandList = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  272. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  273. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  274. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  275. XferCRC xferCRC;
  276. xferCRC.open("lightCRC");
  277. initSubsystem(TheLocalFileSystem, "TheLocalFileSystem", createLocalFileSystem(), NULL);
  278. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  279. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  280. sprintf(Buf,"----------------------------------------------------------------------------After TheLocalFileSystem = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  281. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  282. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  283. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  284. initSubsystem(TheArchiveFileSystem, "TheArchiveFileSystem", createArchiveFileSystem(), NULL); // this MUST come after TheLocalFileSystem creation
  285. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  286. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  287. sprintf(Buf,"----------------------------------------------------------------------------After TheArchiveFileSystem = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  288. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  289. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  290. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  291. initSubsystem(TheWritableGlobalData, "TheWritableGlobalData", MSGNEW("GameEngineSubsystem") GlobalData(), &xferCRC, "Data\\INI\\Default\\GameData.ini", "Data\\INI\\GameData.ini");
  292. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  293. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  294. sprintf(Buf,"----------------------------------------------------------------------------After TheWritableGlobalData = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  295. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  296. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  297. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  298. #if defined(_DEBUG) || defined(_INTERNAL)
  299. // If we're in Debug or Internal, load the Debug info as well.
  300. ini.load( AsciiString( "Data\\INI\\GameDataDebug.ini" ), INI_LOAD_OVERWRITE, NULL );
  301. #endif
  302. // special-case: parse command-line parameters after loading global data
  303. parseCommandLine(argc, argv);
  304. // doesn't require resets so just create a single instance here.
  305. TheGameLODManager = MSGNEW("GameEngineSubsystem") GameLODManager;
  306. TheGameLODManager->init();
  307. // after parsing the command line, we may want to perform dds stuff. Do that here.
  308. if (TheGlobalData->m_shouldUpdateTGAToDDS) {
  309. // update any out of date targas here.
  310. updateTGAtoDDS();
  311. }
  312. // read the water settings from INI (must do prior to initing GameClient, apparently)
  313. ini.load( AsciiString( "Data\\INI\\Default\\Water.ini" ), INI_LOAD_OVERWRITE, &xferCRC );
  314. ini.load( AsciiString( "Data\\INI\\Water.ini" ), INI_LOAD_OVERWRITE, &xferCRC );
  315. ini.load( AsciiString( "Data\\INI\\Default\\Weather.ini" ), INI_LOAD_OVERWRITE, &xferCRC );
  316. ini.load( AsciiString( "Data\\INI\\Weather.ini" ), INI_LOAD_OVERWRITE, &xferCRC );
  317. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  318. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  319. sprintf(Buf,"----------------------------------------------------------------------------After water INI's = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  320. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  321. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  322. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  323. #ifdef DEBUG_CRC
  324. initSubsystem(TheDeepCRCSanityCheck, "TheDeepCRCSanityCheck", MSGNEW("GameEngineSubystem") DeepCRCSanityCheck, NULL, NULL, NULL, NULL);
  325. #endif // DEBUG_CRC
  326. initSubsystem(TheGameText, "TheGameText", CreateGameTextInterface(), NULL);
  327. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  328. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  329. sprintf(Buf,"----------------------------------------------------------------------------After TheGameText = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  330. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  331. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  332. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  333. initSubsystem(TheScienceStore,"TheScienceStore", MSGNEW("GameEngineSubsystem") ScienceStore(), &xferCRC, "Data\\INI\\Default\\Science.ini", "Data\\INI\\Science.ini");
  334. initSubsystem(TheMultiplayerSettings,"TheMultiplayerSettings", MSGNEW("GameEngineSubsystem") MultiplayerSettings(), &xferCRC, "Data\\INI\\Default\\Multiplayer.ini", "Data\\INI\\Multiplayer.ini");
  335. initSubsystem(TheTerrainTypes,"TheTerrainTypes", MSGNEW("GameEngineSubsystem") TerrainTypeCollection(), &xferCRC, "Data\\INI\\Default\\Terrain.ini", "Data\\INI\\Terrain.ini");
  336. initSubsystem(TheTerrainRoads,"TheTerrainRoads", MSGNEW("GameEngineSubsystem") TerrainRoadCollection(), &xferCRC, "Data\\INI\\Default\\Roads.ini", "Data\\INI\\Roads.ini");
  337. initSubsystem(TheGlobalLanguageData,"TheGlobalLanguageData",MSGNEW("GameEngineSubsystem") GlobalLanguage, NULL); // must be before the game text
  338. initSubsystem(TheCDManager,"TheCDManager", CreateCDManager(), NULL);
  339. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  340. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  341. sprintf(Buf,"----------------------------------------------------------------------------After TheCDManager = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  342. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  343. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  344. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  345. initSubsystem(TheAudio,"TheAudio", createAudioManager(), NULL);
  346. if (!TheAudio->isMusicAlreadyLoaded())
  347. setQuitting(TRUE);
  348. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  349. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  350. sprintf(Buf,"----------------------------------------------------------------------------After TheAudio = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  351. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  352. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  353. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  354. initSubsystem(TheFunctionLexicon,"TheFunctionLexicon", createFunctionLexicon(), NULL);
  355. initSubsystem(TheModuleFactory,"TheModuleFactory", createModuleFactory(), NULL);
  356. initSubsystem(TheMessageStream,"TheMessageStream", createMessageStream(), NULL);
  357. initSubsystem(TheSidesList,"TheSidesList", MSGNEW("GameEngineSubsystem") SidesList(), NULL);
  358. initSubsystem(TheCaveSystem,"TheCaveSystem", MSGNEW("GameEngineSubsystem") CaveSystem(), NULL);
  359. initSubsystem(TheRankInfoStore,"TheRankInfoStore", MSGNEW("GameEngineSubsystem") RankInfoStore(), &xferCRC, NULL, "Data\\INI\\Rank.ini");
  360. initSubsystem(ThePlayerTemplateStore,"ThePlayerTemplateStore", MSGNEW("GameEngineSubsystem") PlayerTemplateStore(), &xferCRC, "Data\\INI\\Default\\PlayerTemplate.ini", "Data\\INI\\PlayerTemplate.ini");
  361. initSubsystem(TheParticleSystemManager,"TheParticleSystemManager", createParticleSystemManager(), NULL);
  362. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  363. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  364. sprintf(Buf,"----------------------------------------------------------------------------After TheParticleSystemManager = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  365. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  366. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  367. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  368. initSubsystem(TheFXListStore,"TheFXListStore", MSGNEW("GameEngineSubsystem") FXListStore(), &xferCRC, "Data\\INI\\Default\\FXList.ini", "Data\\INI\\FXList.ini");
  369. initSubsystem(TheWeaponStore,"TheWeaponStore", MSGNEW("GameEngineSubsystem") WeaponStore(), &xferCRC, NULL, "Data\\INI\\Weapon.ini");
  370. initSubsystem(TheObjectCreationListStore,"TheObjectCreationListStore", MSGNEW("GameEngineSubsystem") ObjectCreationListStore(), &xferCRC, "Data\\INI\\Default\\ObjectCreationList.ini", "Data\\INI\\ObjectCreationList.ini");
  371. initSubsystem(TheLocomotorStore,"TheLocomotorStore", MSGNEW("GameEngineSubsystem") LocomotorStore(), &xferCRC, NULL, "Data\\INI\\Locomotor.ini");
  372. initSubsystem(TheSpecialPowerStore,"TheSpecialPowerStore", MSGNEW("GameEngineSubsystem") SpecialPowerStore(), &xferCRC, "Data\\INI\\Default\\SpecialPower.ini", "Data\\INI\\SpecialPower.ini");
  373. initSubsystem(TheDamageFXStore,"TheDamageFXStore", MSGNEW("GameEngineSubsystem") DamageFXStore(), &xferCRC, NULL, "Data\\INI\\DamageFX.ini");
  374. initSubsystem(TheArmorStore,"TheArmorStore", MSGNEW("GameEngineSubsystem") ArmorStore(), &xferCRC, NULL, "Data\\INI\\Armor.ini");
  375. initSubsystem(TheBuildAssistant,"TheBuildAssistant", MSGNEW("GameEngineSubsystem") BuildAssistant, NULL);
  376. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  377. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  378. sprintf(Buf,"----------------------------------------------------------------------------After TheBuildAssistant = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  379. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  380. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  381. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  382. initSubsystem(TheThingFactory,"TheThingFactory", createThingFactory(), &xferCRC, "Data\\INI\\Default\\Object.ini", NULL, "Data\\INI\\Object");
  383. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  384. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  385. sprintf(Buf,"----------------------------------------------------------------------------After TheThingFactory = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  386. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  387. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  388. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  389. initSubsystem(TheUpgradeCenter,"TheUpgradeCenter", MSGNEW("GameEngineSubsystem") UpgradeCenter, &xferCRC, "Data\\INI\\Default\\Upgrade.ini", "Data\\INI\\Upgrade.ini");
  390. initSubsystem(TheGameClient,"TheGameClient", createGameClient(), NULL);
  391. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  392. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  393. sprintf(Buf,"----------------------------------------------------------------------------After TheGameClient = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  394. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  395. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  396. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  397. initSubsystem(TheAI,"TheAI", MSGNEW("GameEngineSubsystem") AI(), &xferCRC, "Data\\INI\\Default\\AIData.ini", "Data\\INI\\AIData.ini");
  398. initSubsystem(TheGameLogic,"TheGameLogic", createGameLogic(), NULL);
  399. initSubsystem(TheTeamFactory,"TheTeamFactory", MSGNEW("GameEngineSubsystem") TeamFactory(), NULL);
  400. initSubsystem(TheCrateSystem,"TheCrateSystem", MSGNEW("GameEngineSubsystem") CrateSystem(), &xferCRC, "Data\\INI\\Default\\Crate.ini", "Data\\INI\\Crate.ini");
  401. initSubsystem(ThePlayerList,"ThePlayerList", MSGNEW("GameEngineSubsystem") PlayerList(), NULL);
  402. initSubsystem(TheRecorder,"TheRecorder", createRecorder(), NULL);
  403. initSubsystem(TheRadar,"TheRadar", createRadar(), NULL);
  404. initSubsystem(TheVictoryConditions,"TheVictoryConditions", createVictoryConditions(), NULL);
  405. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  406. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  407. sprintf(Buf,"----------------------------------------------------------------------------After TheVictoryConditions = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  408. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  409. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  410. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  411. AsciiString fname;
  412. fname.format("Data\\%s\\CommandMap.ini", GetRegistryLanguage().str());
  413. initSubsystem(TheMetaMap,"TheMetaMap", MSGNEW("GameEngineSubsystem") MetaMap(), NULL, fname.str(), "Data\\INI\\CommandMap.ini");
  414. #if defined(_DEBUG) || defined(_INTERNAL)
  415. ini.load("Data\\INI\\CommandMapDebug.ini", INI_LOAD_MULTIFILE, NULL);
  416. #endif
  417. #if defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE)
  418. ini.load("Data\\INI\\CommandMapDemo.ini", INI_LOAD_MULTIFILE, NULL);
  419. #endif
  420. initSubsystem(TheActionManager,"TheActionManager", MSGNEW("GameEngineSubsystem") ActionManager(), NULL);
  421. //initSubsystem((CComObject<WebBrowser> *)TheWebBrowser,"(CComObject<WebBrowser> *)TheWebBrowser", (CComObject<WebBrowser> *)createWebBrowser(), NULL);
  422. initSubsystem(TheGameStateMap,"TheGameStateMap", MSGNEW("GameEngineSubsystem") GameStateMap, NULL, NULL, NULL );
  423. initSubsystem(TheGameState,"TheGameState", MSGNEW("GameEngineSubsystem") GameState, NULL, NULL, NULL );
  424. // Create the interface for sending game results
  425. initSubsystem(TheGameResultsQueue,"TheGameResultsQueue", GameResultsInterface::createNewGameResultsInterface(), NULL, NULL, NULL, NULL);
  426. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  427. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  428. sprintf(Buf,"----------------------------------------------------------------------------After TheGameResultsQueue = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  429. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  430. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  431. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  432. xferCRC.close();
  433. TheWritableGlobalData->m_iniCRC = xferCRC.getCRC();
  434. DEBUG_LOG(("INI CRC is 0x%8.8X\n", TheGlobalData->m_iniCRC));
  435. TheSubsystemList->postProcessLoadAll();
  436. setFramesPerSecondLimit(TheGlobalData->m_framesPerSecondLimit);
  437. TheAudio->setOn(TheGlobalData->m_audioOn && TheGlobalData->m_musicOn, AudioAffect_Music);
  438. TheAudio->setOn(TheGlobalData->m_audioOn && TheGlobalData->m_soundsOn, AudioAffect_Sound);
  439. TheAudio->setOn(TheGlobalData->m_audioOn && TheGlobalData->m_sounds3DOn, AudioAffect_Sound3D);
  440. TheAudio->setOn(TheGlobalData->m_audioOn && TheGlobalData->m_speechOn, AudioAffect_Speech);
  441. // We're not in a network game yet, so set the network singleton to NULL.
  442. TheNetwork = NULL;
  443. //Create a default ini file for options if it doesn't already exist.
  444. //OptionPreferences prefs( TRUE );
  445. // If we turn m_quitting to FALSE here, then we throw away any requests to quit that
  446. // took place during loading. :-\ - jkmcd
  447. // If this really needs to take place, please make sure that pressing cancel on the audio
  448. // load music dialog will still cause the game to quit.
  449. // m_quitting = FALSE;
  450. // for fingerprinting, we need to ensure the presence of these files
  451. #if !defined(_INTERNAL) && !defined(_DEBUG)
  452. AsciiString dirName;
  453. dirName = TheArchiveFileSystem->getArchiveFilenameForFile("generalsbzh.sec");
  454. if (dirName.compareNoCase("genseczh.big") != 0)
  455. {
  456. DEBUG_LOG(("generalsbzh.sec was not found in genseczh.big - it was in '%s'\n", dirName.str()));
  457. m_quitting = TRUE;
  458. }
  459. dirName = TheArchiveFileSystem->getArchiveFilenameForFile("generalsazh.sec");
  460. const char *noPath = dirName.reverseFind('\\');
  461. if (noPath) {
  462. dirName = noPath + 1;
  463. }
  464. if (dirName.compareNoCase("musiczh.big") != 0)
  465. {
  466. DEBUG_LOG(("generalsazh.sec was not found in musiczh.big - it was in '%s'\n", dirName.str()));
  467. m_quitting = TRUE;
  468. }
  469. #endif
  470. // initialize the MapCache
  471. TheMapCache = MSGNEW("GameEngineSubsystem") MapCache;
  472. TheMapCache->updateCache();
  473. #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
  474. GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
  475. sprintf(Buf,"----------------------------------------------------------------------------After TheMapCache->updateCache = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
  476. startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
  477. DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
  478. #endif/////////////////////////////////////////////////////////////////////////////////////////////
  479. if (TheGlobalData->m_buildMapCache)
  480. {
  481. // just quit, since the map cache has already updated
  482. //populateMapListbox(NULL, true, true);
  483. m_quitting = TRUE;
  484. }
  485. // load the initial shell screen
  486. //TheShell->push( AsciiString("Menus/MainMenu.wnd") );
  487. // This allows us to run a map/reply from the command line
  488. if (TheGlobalData->m_initialFile.isEmpty() == FALSE)
  489. {
  490. AsciiString fname = TheGlobalData->m_initialFile;
  491. fname.toLower();
  492. if (fname.endsWithNoCase(".map"))
  493. {
  494. TheWritableGlobalData->m_shellMapOn = FALSE;
  495. TheWritableGlobalData->m_playIntro = FALSE;
  496. TheWritableGlobalData->m_pendingFile = TheGlobalData->m_initialFile;
  497. // shutdown the top, but do not pop it off the stack
  498. // TheShell->hideShell();
  499. // send a message to the logic for a new game
  500. GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_NEW_GAME );
  501. msg->appendIntegerArgument(GAME_SINGLE_PLAYER);
  502. msg->appendIntegerArgument(DIFFICULTY_NORMAL);
  503. msg->appendIntegerArgument(0);
  504. InitRandom(0);
  505. }
  506. else if (fname.endsWithNoCase(".rep"))
  507. {
  508. TheRecorder->playbackFile(fname);
  509. }
  510. }
  511. //
  512. if (TheMapCache && TheGlobalData->m_shellMapOn)
  513. {
  514. AsciiString lowerName = TheGlobalData->m_shellMapName;
  515. lowerName.toLower();
  516. MapCache::const_iterator it = TheMapCache->find(lowerName);
  517. if (it == TheMapCache->end())
  518. {
  519. TheWritableGlobalData->m_shellMapOn = FALSE;
  520. }
  521. }
  522. if(!TheGlobalData->m_playIntro)
  523. TheWritableGlobalData->m_afterIntro = TRUE;
  524. //initDisabledMasks();
  525. }
  526. catch (ErrorCode ec)
  527. {
  528. if (ec == ERROR_INVALID_D3D)
  529. {
  530. RELEASE_CRASHLOCALIZED("ERROR:D3DFailurePrompt", "ERROR:D3DFailureMessage");
  531. }
  532. }
  533. catch (INIException e)
  534. {
  535. if (e.mFailureMessage)
  536. RELEASE_CRASH((e.mFailureMessage));
  537. else
  538. RELEASE_CRASH(("Uncaught Exception during initialization."));
  539. }
  540. catch (...)
  541. {
  542. RELEASE_CRASH(("Uncaught Exception during initialization."));
  543. }
  544. if(!TheGlobalData->m_playIntro)
  545. TheWritableGlobalData->m_afterIntro = TRUE;
  546. initKindOfMasks();
  547. initDisabledMasks();
  548. initDamageTypeFlags();
  549. TheSubsystemList->resetAll();
  550. HideControlBar();
  551. } // end init
  552. /** -----------------------------------------------------------------------------------------------
  553. * Reset all necessary parts of the game engine to be ready to accept new game data
  554. */
  555. void GameEngine::reset( void )
  556. {
  557. WindowLayout *background = TheWindowManager->winCreateLayout("Menus/BlankWindow.wnd");
  558. DEBUG_ASSERTCRASH(background,("We Couldn't Load Menus/BlankWindow.wnd"));
  559. background->hide(FALSE);
  560. background->bringForward();
  561. background->getFirstWindow()->winClearStatus(WIN_STATUS_IMAGE);
  562. Bool deleteNetwork = false;
  563. if (TheGameLogic->isInMultiplayerGame())
  564. deleteNetwork = true;
  565. TheSubsystemList->resetAll();
  566. if (deleteNetwork)
  567. {
  568. DEBUG_ASSERTCRASH(TheNetwork, ("Deleting NULL TheNetwork!"));
  569. if (TheNetwork)
  570. delete TheNetwork;
  571. TheNetwork = NULL;
  572. }
  573. if(background)
  574. {
  575. background->destroyWindows();
  576. background->deleteInstance();
  577. background = NULL;
  578. }
  579. }
  580. /// -----------------------------------------------------------------------------------------------
  581. DECLARE_PERF_TIMER(GameEngine_update)
  582. /** -----------------------------------------------------------------------------------------------
  583. * Update the game engine by updating the GameClient and GameLogic singletons.
  584. * @todo Allow the client to run as fast as possible, but limit the execution
  585. * of TheNetwork and TheGameLogic to a fixed framerate.
  586. */
  587. void GameEngine::update( void )
  588. {
  589. USE_PERF_TIMER(GameEngine_update)
  590. {
  591. {
  592. // VERIFY CRC needs to be in this code block. Please to not pull TheGameLogic->update() inside this block.
  593. VERIFY_CRC
  594. TheRadar->UPDATE();
  595. /// @todo Move audio init, update, etc, into GameClient update
  596. TheAudio->UPDATE();
  597. TheGameClient->UPDATE();
  598. TheMessageStream->propagateMessages();
  599. if (TheNetwork != NULL)
  600. {
  601. TheNetwork->UPDATE();
  602. }
  603. TheCDManager->UPDATE();
  604. }
  605. if ((TheNetwork == NULL && !TheGameLogic->isGamePaused()) || (TheNetwork && TheNetwork->isFrameDataReady()))
  606. {
  607. TheGameLogic->UPDATE();
  608. }
  609. } // end perfGather
  610. }
  611. // Horrible reference, but we really, really need to know if we are windowed.
  612. extern bool DX8Wrapper_IsWindowed;
  613. extern HWND ApplicationHWnd;
  614. /** -----------------------------------------------------------------------------------------------
  615. * The "main loop" of the game engine. It will not return until the game exits.
  616. */
  617. void GameEngine::execute( void )
  618. {
  619. DWORD prevTime = timeGetTime();
  620. #if defined(_DEBUG) || defined(_INTERNAL)
  621. DWORD startTime = timeGetTime() / 1000;
  622. #endif
  623. // pretty basic for now
  624. while( !m_quitting )
  625. {
  626. //if (TheGlobalData->m_vTune)
  627. {
  628. #ifdef PERF_TIMERS
  629. PerfGather::resetAll();
  630. #endif
  631. }
  632. {
  633. #if defined(_DEBUG) || defined(_INTERNAL)
  634. {
  635. // enter only if in benchmark mode
  636. if (TheGlobalData->m_benchmarkTimer > 0)
  637. {
  638. DWORD currentTime = timeGetTime() / 1000;
  639. if (TheGlobalData->m_benchmarkTimer < currentTime - startTime)
  640. {
  641. if (TheGameLogic->isInGame())
  642. {
  643. if (TheRecorder->getMode() == RECORDERMODETYPE_RECORD)
  644. {
  645. TheRecorder->stopRecording();
  646. }
  647. TheGameLogic->clearGameData();
  648. }
  649. TheGameEngine->setQuitting(TRUE);
  650. }
  651. }
  652. }
  653. #endif
  654. {
  655. try
  656. {
  657. // compute a frame
  658. update();
  659. }
  660. catch (INIException e)
  661. {
  662. // Release CRASH doesn't return, so don't worry about executing additional code.
  663. if (e.mFailureMessage)
  664. RELEASE_CRASH((e.mFailureMessage));
  665. else
  666. RELEASE_CRASH(("Uncaught Exception in GameEngine::update"));
  667. }
  668. catch (...)
  669. {
  670. // try to save info off
  671. try
  672. {
  673. if (TheRecorder && TheRecorder->getMode() == RECORDERMODETYPE_RECORD && TheRecorder->isMultiplayer())
  674. TheRecorder->cleanUpReplayFile();
  675. }
  676. catch (...)
  677. {
  678. }
  679. RELEASE_CRASH(("Uncaught Exception in GameEngine::update"));
  680. } // catch
  681. } // perf
  682. {
  683. if (TheTacticalView->getTimeMultiplier()<=1 && !TheScriptEngine->isTimeFast())
  684. {
  685. // I'm disabling this in internal because many people need alt-tab capability. If you happen to be
  686. // doing performance tuning, please just change this on your local system. -MDC
  687. #if defined(_DEBUG) || defined(_INTERNAL)
  688. ::Sleep(1); // give everyone else a tiny time slice.
  689. #endif
  690. #if defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE)
  691. if ( ! TheGlobalData->m_TiVOFastMode )
  692. #else //always allow this cheatkey if we're in a replaygame.
  693. if ( ! (TheGlobalData->m_TiVOFastMode && TheGameLogic->isInReplayGame()))
  694. #endif
  695. {
  696. // limit the framerate
  697. DWORD now = timeGetTime();
  698. DWORD limit = (1000.0f/m_maxFPS)-1;
  699. while (TheGlobalData->m_useFpsLimit && (now - prevTime) < limit)
  700. {
  701. ::Sleep(0);
  702. now = timeGetTime();
  703. }
  704. //Int slept = now - prevTime;
  705. //DEBUG_LOG(("delayed %d\n",slept));
  706. prevTime = now;
  707. }
  708. }
  709. }
  710. } // perfgather for execute_loop
  711. #ifdef PERF_TIMERS
  712. if (!m_quitting && TheGameLogic->isInGame() && !TheGameLogic->isInShellGame() && !TheGameLogic->isGamePaused())
  713. {
  714. PerfGather::dumpAll(TheGameLogic->getFrame());
  715. PerfGather::displayGraph(TheGameLogic->getFrame());
  716. PerfGather::resetAll();
  717. }
  718. #endif
  719. }
  720. }
  721. /** -----------------------------------------------------------------------------------------------
  722. * Factory for the message stream
  723. */
  724. MessageStream *GameEngine::createMessageStream( void )
  725. {
  726. // if you change this update the tools that use the engine systems
  727. // like GUIEdit, it creates a message stream to run in "test" mode
  728. return MSGNEW("GameEngineSubsystem") MessageStream;
  729. }
  730. //-------------------------------------------------------------------------------------------------
  731. FileSystem *GameEngine::createFileSystem( void )
  732. {
  733. return MSGNEW("GameEngineSubsystem") FileSystem;
  734. }
  735. //-------------------------------------------------------------------------------------------------
  736. Bool GameEngine::isMultiplayerSession( void )
  737. {
  738. return TheRecorder->isMultiplayer();
  739. }
  740. //-------------------------------------------------------------------------------------------------
  741. //-------------------------------------------------------------------------------------------------
  742. //-------------------------------------------------------------------------------------------------
  743. #define CONVERT_EXEC1 "..\\Build\\nvdxt -list buildDDS.txt -dxt5 -full -outdir Art\\Textures > buildDDS.out"
  744. void updateTGAtoDDS()
  745. {
  746. // Here's the scoop. We're going to traverse through all of the files in the Art\Textures folder
  747. // and determine if there are any .tga files that are newer than associated .dds files. If there
  748. // are, then we will re-run the compression tool on them.
  749. File *fp = TheLocalFileSystem->openFile("buildDDS.txt", File::WRITE | File::CREATE | File::TRUNCATE | File::TEXT);
  750. if (!fp) {
  751. return;
  752. }
  753. FilenameList files;
  754. TheLocalFileSystem->getFileListInDirectory("Art\\Textures\\", "", "*.tga", files, TRUE);
  755. FilenameList::iterator it;
  756. for (it = files.begin(); it != files.end(); ++it) {
  757. AsciiString filenameTGA = *it;
  758. AsciiString filenameDDS = *it;
  759. FileInfo infoTGA;
  760. TheLocalFileSystem->getFileInfo(filenameTGA, &infoTGA);
  761. // skip the water textures, since they need to be NOT compressed
  762. filenameTGA.toLower();
  763. if (strstr(filenameTGA.str(), "caust"))
  764. {
  765. continue;
  766. }
  767. // and the recolored stuff.
  768. if (strstr(filenameTGA.str(), "zhca"))
  769. {
  770. continue;
  771. }
  772. // replace tga with dds
  773. filenameDDS.removeLastChar(); // a
  774. filenameDDS.removeLastChar(); // g
  775. filenameDDS.removeLastChar(); // t
  776. filenameDDS.concat("dds");
  777. Bool needsToBeUpdated = FALSE;
  778. FileInfo infoDDS;
  779. if (TheFileSystem->doesFileExist(filenameDDS.str())) {
  780. TheFileSystem->getFileInfo(filenameDDS, &infoDDS);
  781. if (infoTGA.timestampHigh > infoDDS.timestampHigh ||
  782. (infoTGA.timestampHigh == infoDDS.timestampHigh &&
  783. infoTGA.timestampLow > infoDDS.timestampLow)) {
  784. needsToBeUpdated = TRUE;
  785. }
  786. } else {
  787. needsToBeUpdated = TRUE;
  788. }
  789. if (!needsToBeUpdated) {
  790. continue;
  791. }
  792. filenameTGA.concat("\n");
  793. fp->write(filenameTGA.str(), filenameTGA.getLength());
  794. }
  795. fp->close();
  796. system(CONVERT_EXEC1);
  797. }
  798. //-------------------------------------------------------------------------------------------------
  799. // System things
  800. // If we're using the Wide character version of MessageBox, then there's no additional
  801. // processing necessary. Please note that this is a sleazy way to get this information,
  802. // but pending a better one, this'll have to do.
  803. extern const Bool TheSystemIsUnicode = (((void*) (::MessageBox)) == ((void*) (::MessageBoxW)));