STARTUP.CPP 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  1. //
  2. // Copyright 2020 Electronic Arts Inc.
  3. //
  4. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
  5. // software: you can redistribute it and/or modify it under the terms of
  6. // the GNU General Public License as published by the Free Software Foundation,
  7. // either version 3 of the License, or (at your option) any later version.
  8. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
  9. // in the hope that it will be useful, but with permitted additional restrictions
  10. // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. // distributed with this program. You should have received a copy of the
  12. // GNU General Public License along with permitted additional restrictions
  13. // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
  14. /* $Header: F:\projects\c&c\vcs\code\startup.cpv 2.17 16 Oct 1995 16:48:12 JOE_BOSTIC $ */
  15. /***********************************************************************************************
  16. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  17. ***********************************************************************************************
  18. * *
  19. * Project Name : Command & Conquer *
  20. * *
  21. * File Name : STARTUP.CPP *
  22. * *
  23. * Programmer : Joe L. Bostic *
  24. * *
  25. * Start Date : October 3, 1994 *
  26. * *
  27. * Last Update : August 27, 1995 [JLB] *
  28. * *
  29. *---------------------------------------------------------------------------------------------*
  30. * Functions: *
  31. * Delete_Swap_Files -- Deletes previously existing swap files. *
  32. * Prog_End -- Cleans up library systems in prep for game exit. *
  33. * main -- Initial startup routine (preps library systems). *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "function.h"
  36. #include <conio.h>
  37. #include <io.h>
  38. #include "ccdde.h"
  39. bool Read_Private_Config_Struct(char *profile, NewConfigType *config);
  40. void Delete_Swap_Files(void);
  41. void Print_Error_End_Exit(char *string);
  42. void Print_Error_Exit(char *string);
  43. WinTimerClass *WinTimer;
  44. extern void Create_Main_Window ( HANDLE instance , int command_show , int width , int height);
  45. extern bool ReadyToQuit;
  46. void Read_Setup_Options(RawFileClass *config_file);
  47. bool VideoBackBufferAllowed = true;
  48. void Check_From_WChat(char *wchat_name);
  49. bool SpawnedFromWChat = false;
  50. bool ProgEndCalled = false;
  51. extern "C"{
  52. bool __cdecl Detect_MMX_Availability(void);
  53. void __cdecl Init_MMX(void);
  54. }
  55. #if (0)
  56. char WibbleBuffer[1024*1024];
  57. void CD_Test(void)
  58. {
  59. HANDLE handle;
  60. DWORD size;
  61. handle= CreateFile("e:\\scores.mix", GENERIC_READ, FILE_SHARE_READ,
  62. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  63. if (handle== INVALID_HANDLE_VALUE){
  64. return;
  65. }
  66. unsigned bytes_read;
  67. do{
  68. bytes_read = ReadFile (handle , WibbleBuffer , 1024*1024, &size, NULL);
  69. }while(size == 1024*1024);
  70. CloseHandle (handle);
  71. }
  72. #endif //(0)
  73. /***********************************************************************************************
  74. * main -- Initial startup routine (preps library systems). *
  75. * *
  76. * This is the routine that is first called when the program starts up. It basically *
  77. * handles the command line parsing and setting up library systems. *
  78. * *
  79. * INPUT: argc -- Number of command line arguments. *
  80. * *
  81. * argv -- Pointer to array of comman line argument strings. *
  82. * *
  83. * OUTPUT: Returns with execution failure code (if any). *
  84. * *
  85. * WARNINGS: none *
  86. * *
  87. * HISTORY: *
  88. * 03/20/1995 JLB : Created. *
  89. *=============================================================================================*/
  90. HINSTANCE ProgramInstance;
  91. extern BOOL CC95AlreadyRunning;
  92. void Move_Point(short &x, short &y, register DirType dir, unsigned short distance);
  93. void Check_Use_Compressed_Shapes (void);
  94. extern void DLL_Shutdown(void);
  95. BOOL WINAPI DllMain(HINSTANCE instance, unsigned int fdwReason, void *lpvReserved)
  96. {
  97. lpvReserved;
  98. switch (fdwReason) {
  99. case DLL_PROCESS_ATTACH:
  100. ProgramInstance = instance;
  101. break;
  102. case DLL_PROCESS_DETACH:
  103. if (WindowsTimer) {
  104. delete WindowsTimer;
  105. WindowsTimer = NULL;
  106. }
  107. DLL_Shutdown();
  108. MixFileClass::Free_All();
  109. Uninit_Game();
  110. break;
  111. case DLL_THREAD_ATTACH:
  112. case DLL_THREAD_DETACH:
  113. break;
  114. }
  115. return true;
  116. }
  117. //int PASCAL WinMain ( HINSTANCE instance , HINSTANCE , char * command_line , int command_show )
  118. //{
  119. // Heap_Dump_Check( "first thing in main" );
  120. // malloc(1);
  121. int DLL_Startup(const char * command_line_in)
  122. {
  123. RunningAsDLL = true;
  124. int command_show = SW_HIDE;
  125. HINSTANCE instance = ProgramInstance;
  126. char command_line[1024];
  127. strcpy(command_line, command_line_in);
  128. CCDebugString ("C&C95 - Starting up.\n");
  129. //WindowsTimer = new WinTimerClass(60,FALSE);
  130. //CD_Test();
  131. /*
  132. ** These values return 0x47 if code is working correctly
  133. */
  134. // int temp = Desired_Facing256 (1070, 5419, 1408, 5504);
  135. /*
  136. ** If we are already running then switch to the existing process and exit
  137. */
  138. SpawnedFromWChat = false;
  139. if (CC95AlreadyRunning) { //Set in the DDEServer constructor
  140. //MessageBox (NULL, "Error - attempt to restart C&C95 when already running.", "Command & Conquer", MB_ICONEXCLAMATION|MB_OK);
  141. HWND ccwindow;
  142. ccwindow = FindWindow ("Command & Conquer", "Command & Conquer");
  143. if (ccwindow){
  144. SetForegroundWindow ( ccwindow );
  145. ShowWindow ( ccwindow, SW_RESTORE );
  146. }
  147. return (EXIT_SUCCESS);
  148. }
  149. // ST - 3/6/2019 1:36PM
  150. //DDSCAPS surface_capabilities;
  151. if (Ram_Free(MEM_NORMAL) < 5000000) {
  152. #ifdef GERMAN
  153. printf("Zuwenig Hauptspeicher verf�gbar.\n");
  154. #else
  155. #ifdef FRENCH
  156. printf("M‚moire vive (RAM) insuffisante.\n");
  157. #else
  158. printf("Insufficient RAM available.\n");
  159. #endif
  160. #endif
  161. return(EXIT_FAILURE);
  162. }
  163. //void *test_buffer = Alloc(20,MEM_NORMAL);
  164. //memset ((char*)test_buffer, 0, 21);
  165. //Free(test_buffer);
  166. int argc; //Command line argument count
  167. unsigned command_scan;
  168. char command_char;
  169. char * argv[20]; //Pointers to command line arguments
  170. char path_to_exe[280];
  171. ProgramInstance = instance;
  172. /*
  173. ** Get the full path to the .EXE
  174. */
  175. GetModuleFileName (instance, &path_to_exe[0], 280);
  176. /*
  177. ** First argument is supposed to be a pointer to the .EXE that is running
  178. **
  179. */
  180. argc=1; //Set argument count to 1
  181. argv[0]=&path_to_exe[0]; //Set 1st command line argument to point to full path
  182. /*
  183. ** Get pointers to command line arguments just like if we were in DOS
  184. **
  185. ** The command line we get is cr/zero? terminated.
  186. **
  187. */
  188. command_scan=0;
  189. do {
  190. /*
  191. ** Scan for non-space character on command line
  192. */
  193. do {
  194. command_char = *( command_line+command_scan++ );
  195. } while ( command_char==' ' );
  196. if ( command_char!=0 && command_char != 13 ){
  197. argv[argc++]=command_line+command_scan-1;
  198. /*
  199. ** Scan for space character on command line
  200. */
  201. bool in_quotes = false;
  202. do {
  203. command_char = *( command_line+command_scan++ );
  204. if (command_char == '"') {
  205. in_quotes = !in_quotes;
  206. }
  207. } while ( (in_quotes || command_char!=' ') && command_char != 0 && command_char!=13 );
  208. *( command_line+command_scan-1 ) = 0;
  209. }
  210. } while ( command_char != 0 && command_char != 13 && argc<20 );
  211. /*
  212. ** Remember the current working directory and drive.
  213. */
  214. #if (0) //PG_TO_FIX
  215. unsigned olddrive;
  216. char oldpath[MAX_PATH];
  217. getcwd(oldpath, sizeof(oldpath));
  218. _dos_getdrive(&olddrive);
  219. /*
  220. ** Change directory to the where the executable is located. Handle the
  221. ** case where there is no path attached to argv[0].
  222. */
  223. char drive[_MAX_DRIVE];
  224. char path[_MAX_PATH];
  225. unsigned drivecount;
  226. _splitpath(argv[0], drive, path, NULL, NULL);
  227. if (!drive[0]) {
  228. drive[0] = ('A' + olddrive)-1;
  229. }
  230. if (!path[0]) {
  231. strcpy(path, ".");
  232. }
  233. _dos_setdrive(toupper((drive[0])-'A')+1, &drivecount);
  234. if (path[strlen(path)-1] == '\\') {
  235. path[strlen(path)-1] = '\0';
  236. }
  237. chdir(path);
  238. #endif
  239. #ifdef JAPANESE
  240. ForceEnglish = false;
  241. #endif
  242. if (Parse_Command_Line(argc, argv)) {
  243. WindowsTimer = new WinTimerClass(60,FALSE);
  244. #if (0)
  245. int time_test = WindowsTimer->Get_System_Tick_Count();
  246. Sleep (1000);
  247. if (WindowsTimer->Get_System_Tick_Count() == time_test){
  248. #ifdef FRENCH
  249. MessageBox(0, "Error - L'horloge systŠme n'a pas pu s'initialiser en raison de l'instabilit‚ du sytŠme. Vous devez red‚marrer Windows.", "Command & Conquer" , MB_OK|MB_ICONSTOP);
  250. #else
  251. #ifdef GERMAN
  252. MessageBox(0, "Fehler - das Timer-System konnte aufgrund einer Instabilit„t des Systems nicht initialisiert werden. Bitte starten Sie Windows neu.", "Command & Conquer", MB_OK|MB_ICONSTOP);
  253. #else
  254. MessageBox(0, "Error - Timer system failed to start due to system instability. You need to restart Windows.", "Command & Conquer", MB_OK|MB_ICONSTOP);
  255. #endif //GERMAN
  256. #endif //FRENCH
  257. return(EXIT_FAILURE);
  258. }
  259. #endif
  260. RawFileClass cfile("CONQUER.INI");
  261. #ifdef JAPANESE
  262. //////////////////////////////////////if(!ForceEnglish) KBLanguage = 1;
  263. #endif
  264. /*
  265. ** Check for existance of MMX support on the processor
  266. */
  267. if (Detect_MMX_Availability()){
  268. //MessageBox(NULL, "MMX extensions detected - enabling MMX support.", "Command & Conquer",MB_ICONEXCLAMATION|MB_OK);
  269. MMXAvailable = true;
  270. }
  271. /*
  272. ** If there is loads of memory then use uncompressed shapes
  273. */
  274. Check_Use_Compressed_Shapes();
  275. /*
  276. ** If there is not enough disk space free, dont allow the product to run.
  277. */
  278. if (Disk_Space_Available() < INIT_FREE_DISK_SPACE) {
  279. #ifdef GERMAN
  280. char disk_space_message [512];
  281. sprintf (disk_space_message, "Nicht genug Festplattenplatz f�r Command & Conquer.\nSie brauchen %d MByte freien Platz auf der Festplatte.", (INIT_FREE_DISK_SPACE) / (1024 * 1024));
  282. MessageBox(NULL, disk_space_message, "Command & Conquer", MB_ICONEXCLAMATION|MB_OK);
  283. if ( WindowsTimer )
  284. delete WindowsTimer;
  285. return (EXIT_FAILURE);
  286. #endif
  287. #ifdef FRENCH
  288. char disk_space_message [512];
  289. sprintf (disk_space_message, "Espace disque insuffisant pour lancer Command & Conquer.\nVous devez disposer de %d Mo d'espace disponsible sur disque dur.", (INIT_FREE_DISK_SPACE) / (1024 * 1024));
  290. MessageBox(NULL, disk_space_message, "Command & Conquer", MB_ICONEXCLAMATION|MB_OK);
  291. if ( WindowsTimer )
  292. delete WindowsTimer;
  293. return (EXIT_FAILURE);
  294. #endif
  295. #if !(FRENCH | GERMAN)
  296. int reply = MessageBox(NULL, "Warning - you are critically low on free disk space for virtual memory and save games. Do you want to play C&C anyway?", "Command & Conquer", MB_ICONQUESTION|MB_YESNO);
  297. if (reply == IDNO){
  298. if ( WindowsTimer )
  299. delete WindowsTimer;
  300. return (EXIT_FAILURE);
  301. }
  302. #endif
  303. }
  304. #if (0) // ST - 1/2/2019 5:50PM
  305. CDFileClass::Set_CD_Drive (CDList.Get_First_CD_Drive());
  306. #endif
  307. if (cfile.Is_Available()) {
  308. #ifndef NOMEMCHECK
  309. char * cdata = (char *)Load_Alloc_Data(cfile);
  310. Read_Private_Config_Struct(cdata, &NewConfig);
  311. delete [] cdata;
  312. #else
  313. Read_Private_Config_Struct((char *)Load_Alloc_Data(cfile), &NewConfig);
  314. #endif
  315. Read_Setup_Options( &cfile );
  316. CCDebugString ("C&C95 - Creating main window.\n");
  317. Create_Main_Window( instance , command_show , ScreenWidth , ScreenHeight );
  318. CCDebugString ("C&C95 - Initialising audio.\n");
  319. SoundOn = Audio_Init ( MainWindow , 16 , false , 11025*2 , 0 );
  320. Palette = new(MEM_CLEAR) unsigned char[768];
  321. BOOL video_success = FALSE;
  322. CCDebugString ("C&C95 - Setting video mode.\n");
  323. /*
  324. ** Set 640x400 video mode. If its not available then try for 640x480
  325. */
  326. if (ScreenHeight == 400){
  327. if (Set_Video_Mode (MainWindow, ScreenWidth, ScreenHeight, 8)){
  328. video_success = TRUE;
  329. }else{
  330. if (Set_Video_Mode (MainWindow, ScreenWidth, 480, 8)){
  331. video_success = TRUE;
  332. ScreenHeight = 480;
  333. }
  334. }
  335. }else{
  336. if (Set_Video_Mode (MainWindow, ScreenWidth, ScreenHeight, 8)){
  337. video_success = TRUE;
  338. }
  339. }
  340. if (!video_success){
  341. CCDebugString ("C&C95 - Failed to set video mode.\n");
  342. MessageBox(MainWindow, Text_String(TXT_UNABLE_TO_SET_VIDEO_MODE), "Command & Conquer", MB_ICONEXCLAMATION|MB_OK);
  343. if (WindowsTimer) delete WindowsTimer;
  344. if (Palette) delete [] Palette;
  345. return (EXIT_FAILURE);
  346. }
  347. CCDebugString ("C&C95 - Initialising video surfaces.\n");
  348. if (ScreenWidth==320){
  349. VisiblePage.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0);
  350. ModeXBuff.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)(GBC_VISIBLE | GBC_VIDEOMEM));
  351. } else {
  352. #if (1) //ST - 1/3/2019 2:11PM
  353. VisiblePage.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0);
  354. HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0);
  355. #else
  356. VisiblePage.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)(GBC_VISIBLE | GBC_VIDEOMEM));
  357. /*
  358. ** Check that we really got a video memory page. Failure is fatal.
  359. */
  360. memset (&surface_capabilities, 0, sizeof(surface_capabilities));
  361. VisiblePage.Get_DD_Surface()->GetCaps(&surface_capabilities);
  362. if (surface_capabilities.dwCaps & DDSCAPS_SYSTEMMEMORY){
  363. /*
  364. ** Aaaarrgghh!
  365. */
  366. CCDebugString ("C&C95 - Unable to allocate primary surface.\n");
  367. MessageBox(MainWindow, Text_String(TXT_UNABLE_TO_ALLOCATE_PRIMARY_VIDEO_BUFFER), "Command & Conquer", MB_ICONEXCLAMATION|MB_OK);
  368. if (WindowsTimer) delete WindowsTimer;
  369. if (Palette) delete [] Palette;
  370. return (EXIT_FAILURE);
  371. }
  372. /*
  373. ** If we have enough left then put the hidpage in video memory unless...
  374. **
  375. ** If there is no blitter then we will get better performance with a system
  376. ** memory hidpage
  377. **
  378. ** Use a system memory page if the user has specified it via the ccsetup program.
  379. */
  380. CCDebugString ("C&C95 - Allocating back buffer ");
  381. long video_memory = Get_Free_Video_Memory();
  382. unsigned video_capabilities = Get_Video_Hardware_Capabilities();
  383. if (video_memory < ScreenWidth*ScreenHeight ||
  384. (! (video_capabilities & VIDEO_BLITTER)) ||
  385. (video_capabilities & VIDEO_NO_HARDWARE_ASSIST) ||
  386. !VideoBackBufferAllowed){
  387. CCDebugString ("in system memory.\n");
  388. HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0);
  389. } else {
  390. //HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0);
  391. CCDebugString ("in video memory.\n");
  392. HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)GBC_VIDEOMEM);
  393. /*
  394. ** Make sure we really got a video memory hid page. If we didnt then things
  395. ** will run very slowly.
  396. */
  397. memset (&surface_capabilities, 0, sizeof(surface_capabilities));
  398. HiddenPage.Get_DD_Surface()->GetCaps(&surface_capabilities);
  399. if (surface_capabilities.dwCaps & DDSCAPS_SYSTEMMEMORY){
  400. /*
  401. ** Oh dear, big trub. This must be an IBM Aptiva or something similarly cruddy.
  402. ** We must redo the Hidden Page as system memory.
  403. */
  404. AllSurfaces.Remove_DD_Surface(HiddenPage.Get_DD_Surface()); // Remove the old surface from the AllSurfaces list
  405. HiddenPage.Get_DD_Surface()->Release();
  406. HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0);
  407. }else{
  408. VisiblePage.Attach_DD_Surface(&HiddenPage);
  409. }
  410. }
  411. #endif
  412. }
  413. ScreenHeight = 1536;
  414. if (VisiblePage.Get_Height() == 480){
  415. SeenBuff.Attach(&VisiblePage,0, 40, 1536, 1536);
  416. HidPage.Attach(&HiddenPage, 0, 40, 1536, 1536);
  417. }else{
  418. SeenBuff.Attach(&VisiblePage,0, 0, 1536, 1536);
  419. HidPage.Attach(&HiddenPage, 0, 0, 1536, 1536);
  420. }
  421. CCDebugString ("C&C95 - Adjusting variables for resolution.\n");
  422. Options.Adjust_Variables_For_Resolution();
  423. CCDebugString ("C&C95 - Setting palette.\n");
  424. /////////Set_Palette(Palette);
  425. WindowList[0][WINDOWWIDTH] = SeenBuff.Get_Width() >> 3;
  426. WindowList[0][WINDOWHEIGHT] = SeenBuff.Get_Height();
  427. /*
  428. ** Install the memory error handler
  429. */
  430. Memory_Error = &Memory_Error_Handler;
  431. /*
  432. ** Initialise MMX support if its available
  433. */
  434. CCDebugString ("C&C95 - Entering MMX detection.\n");
  435. if (MMXAvailable){
  436. Init_MMX();
  437. }
  438. CCDebugString ("C&C95 - Creating mouse class.\n");
  439. WWMouse = new WWMouseClass(&SeenBuff, 32, 32);
  440. // MouseInstalled = Install_Mouse(32,24,320,200);
  441. MouseInstalled = TRUE;
  442. /*
  443. ** See if we should run the intro
  444. */
  445. CCDebugString ("C&C95 - Reading CONQUER.INI.\n");
  446. char *buffer = (char*)Alloc(64000 , MEM_NORMAL); //(char *)HidPage.Get_Buffer();
  447. cfile.Read(buffer, cfile.Size());
  448. buffer[cfile.Size()] = '\0';
  449. /*
  450. ** Check for forced intro movie run disabling. If the conquer
  451. ** configuration file says "no", then don't run the intro.
  452. */
  453. char tempbuff[5];
  454. WWGetPrivateProfileString("Intro", "PlayIntro", "Yes", tempbuff, 4, buffer);
  455. if ((stricmp(tempbuff, "No") == 0) || SpawnedFromWChat) {
  456. Special.IsFromInstall = false;
  457. }else{
  458. Special.IsFromInstall = true;
  459. }
  460. SlowPalette = WWGetPrivateProfileInt("Options", "SlowPalette", 1, buffer);
  461. #ifdef DEMO
  462. /*
  463. ** Check for override directory path for CD searches.
  464. */
  465. WWGetPrivateProfileString("CD", "Path", ".", OverridePath, sizeof(OverridePath), buffer);
  466. #endif
  467. /*
  468. ** Regardless of whether we should run it or not, here we're
  469. ** gonna change it to say "no" in the future.
  470. */
  471. WWWritePrivateProfileString("Intro", "PlayIntro", "No", buffer);
  472. cfile.Write(buffer, strlen(buffer));
  473. Free(buffer);
  474. CCDebugString ("C&C95 - Checking availability of C&CSPAWN.INI packet from WChat.\n");
  475. if (DDEServer.Get_MPlayer_Game_Info()){
  476. CCDebugString ("C&C95 - C&CSPAWN.INI packet available.\n");
  477. Check_From_WChat(NULL);
  478. }else{
  479. CCDebugString ("C&C95 - C&CSPAWN.INI packet not arrived yet.\n");
  480. //Check_From_WChat("C&CSPAWN.INI");
  481. //if (Special.IsFromWChat){
  482. // DDEServer.Disable();
  483. //}
  484. }
  485. /*
  486. ** If the intro is being run for the first time, then don't
  487. ** allow breaking out of it with the <ESC> key.
  488. */
  489. if (Special.IsFromInstall) {
  490. BreakoutAllowed = false;
  491. }
  492. Memory_Error_Exit = Print_Error_End_Exit;
  493. CCDebugString ("C&C95 - Entering main game.\n");
  494. Main_Game(argc, argv);
  495. if (RunningAsDLL) {
  496. return (EXIT_SUCCESS);
  497. }
  498. VisiblePage.Clear();
  499. HiddenPage.Clear();
  500. // Set_Video_Mode(RESET_MODE);
  501. Memory_Error_Exit = Print_Error_Exit;
  502. CCDebugString ("C&C95 - About to exit.\n");
  503. ReadyToQuit = 1;
  504. PostMessage(MainWindow, WM_DESTROY, 0, 0);
  505. do
  506. {
  507. Keyboard::Check();
  508. }while (ReadyToQuit == 1);
  509. CCDebugString ("C&C95 - Returned from final message loop.\n");
  510. //Prog_End();
  511. //Invalidate_Cached_Icons();
  512. //VisiblePage.Un_Init();
  513. //HiddenPage.Un_Init();
  514. //AllSurfaces.Release();
  515. //Reset_Video_Mode();
  516. //Stop_Profiler();
  517. return (EXIT_SUCCESS);
  518. } else {
  519. #ifdef GERMAN
  520. puts("Bitte erst das SETUP-Programm starten.\n");
  521. #else
  522. #ifdef FRENCH
  523. puts("Lancez d'abord le programme de configuration SETUP.\n");
  524. #else
  525. puts("Run SETUP program first.");
  526. puts("\n");
  527. #endif
  528. Kbd.Get();
  529. #endif
  530. }
  531. // Remove_Keyboard_Interrupt();
  532. if (WindowsTimer){
  533. delete WindowsTimer;
  534. WindowsTimer = NULL;
  535. }
  536. if (Palette){
  537. delete [] Palette;
  538. Palette = NULL;
  539. }
  540. }
  541. /*
  542. ** Restore the current drive and directory.
  543. */
  544. #ifdef NOT_FOR_WIN95
  545. _dos_setdrive(olddrive, &drivecount);
  546. chdir(oldpath);
  547. #endif //NOT_FOR_WIN95
  548. return(EXIT_SUCCESS);
  549. }
  550. /***********************************************************************************************
  551. * Prog_End -- Cleans up library systems in prep for game exit. *
  552. * *
  553. * This routine should be called before the game terminates. It handles cleaning up *
  554. * library systems so that a graceful return to the host operating system is achieved. *
  555. * *
  556. * INPUT: none *
  557. * *
  558. * OUTPUT: none *
  559. * *
  560. * WARNINGS: none *
  561. * *
  562. * HISTORY: *
  563. * 03/20/1995 JLB : Created. *
  564. *=============================================================================================*/
  565. void __cdecl Prog_End(const char *why, bool fatal) // Added why and fatal parameters. ST - 6/27/2019 10:10PM
  566. {
  567. GlyphX_Debug_Print("Prog_End()");
  568. if (why) {
  569. GlyphX_Debug_Print(why);
  570. }
  571. if (fatal) {
  572. *((int*)0) = 0;
  573. }
  574. #ifndef DEMO
  575. if (GameToPlay == GAME_MODEM || GameToPlay == GAME_NULL_MODEM) {
  576. // NullModem.Change_IRQ_Priority(0);
  577. }
  578. #endif
  579. CCDebugString ("C&C95 - About to call Sound_End.\n");
  580. Sound_End();
  581. CCDebugString ("C&C95 - Returned from Sound_End.\n");
  582. if (WWMouse){
  583. CCDebugString ("C&C95 - Deleting mouse object.\n");
  584. delete WWMouse;
  585. WWMouse = NULL;
  586. }
  587. if (WindowsTimer){
  588. CCDebugString ("C&C95 - Deleting windows timer.\n");
  589. delete WindowsTimer;
  590. WindowsTimer = NULL;
  591. }
  592. if (Palette){
  593. CCDebugString ("C&C95 - Deleting palette object.\n");
  594. delete [] Palette;
  595. Palette = NULL;
  596. }
  597. ProgEndCalled = true;
  598. }
  599. /***********************************************************************************************
  600. * Delete_Swap_Files -- Deletes previously existing swap files. *
  601. * *
  602. * This routine will scan through the current directory and delete any swap files it may *
  603. * find. This is used to clear out any left over swap files from previous runs (crashes) *
  604. * of the game. This routine presumes that it cannot delete the swap file that is created *
  605. * by the current run of the game. *
  606. * *
  607. * INPUT: none *
  608. * *
  609. * OUTPUT: none *
  610. * *
  611. * WARNINGS: none *
  612. * *
  613. * HISTORY: *
  614. * 08/27/1995 JLB : Created. *
  615. *=============================================================================================*/
  616. void Delete_Swap_Files(void)
  617. {
  618. #if (0)
  619. struct find_t ff; // for _dos_findfirst
  620. if (!_dos_findfirst("*.SWP", _A_NORMAL, &ff)) {
  621. do {
  622. unlink(ff.name);
  623. } while(!_dos_findnext(&ff));
  624. }
  625. #endif
  626. }
  627. void Print_Error_End_Exit(char *string)
  628. {
  629. printf( "%s\n", string );
  630. Get_Key();
  631. Prog_End();
  632. printf( "%s\n", string );
  633. if (!RunningAsDLL) {
  634. exit(1);
  635. }
  636. }
  637. void Print_Error_Exit(char *string)
  638. {
  639. printf( "%s\n", string );
  640. if (!RunningAsDLL) {
  641. exit(1);
  642. }
  643. }
  644. /***********************************************************************************************
  645. * Read_Setup_Options -- Read stuff in from the INI file that we need to know sooner *
  646. * *
  647. * *
  648. * *
  649. * INPUT: Nothing *
  650. * *
  651. * OUTPUT: Nothing *
  652. * *
  653. * WARNINGS: None *
  654. * *
  655. * HISTORY: *
  656. * 6/7/96 4:09PM ST : Created *
  657. *=============================================================================================*/
  658. void Read_Setup_Options( RawFileClass *config_file )
  659. {
  660. char *buffer = new char [config_file->Size()];
  661. if (config_file->Is_Available()){
  662. config_file->Read (buffer, config_file->Size());
  663. VideoBackBufferAllowed = WWGetPrivateProfileInt ("Options", "VideoBackBuffer", 1, buffer);
  664. AllowHardwareBlitFills = WWGetPrivateProfileInt ("Options", "HardwareFills", 1, buffer);
  665. ScreenHeight = WWGetPrivateProfileInt ("Options", "Resolution", 0, buffer) ? 1536 : 1536;
  666. IsV107 = WWGetPrivateProfileInt ("Options", "Compatibility", 0, buffer);
  667. /*
  668. ** See if an alternative socket number has been specified
  669. */
  670. int socket = WWGetPrivateProfileInt ("Options", "Socket", 0, buffer);
  671. if (socket >0 ){
  672. socket += 0x4000;
  673. if (socket >= 0x4000 && socket < 0x8000) {
  674. Ipx.Set_Socket (socket);
  675. }
  676. }
  677. /*
  678. ** See if a destination network has been specified
  679. */
  680. char netbuf [512];
  681. memset (netbuf, 0, sizeof (netbuf) );
  682. char *netptr = WWGetPrivateProfileString ("Options", "DestNet", NULL, netbuf, sizeof (netbuf), buffer);
  683. if (netptr && strlen (netbuf)){
  684. NetNumType net;
  685. NetNodeType node;
  686. /*
  687. ** Scan the string, pulling off each address piece
  688. */
  689. int i = 0;
  690. char * p = strtok(netbuf,".");
  691. int x;
  692. while (p) {
  693. sscanf(p,"%x",&x); // convert from hex string to int
  694. if (i < 4) {
  695. net[i] = (char)x; // fill NetNum
  696. } else {
  697. node[i-4] = (char)x; // fill NetNode
  698. }
  699. i++;
  700. p = strtok(NULL,".");
  701. }
  702. /*
  703. ** If all the address components were successfully read, fill in the
  704. ** BridgeNet with a broadcast address to the network across the bridge.
  705. */
  706. if (i >= 4) {
  707. IsBridge = 1;
  708. memset(node, 0xff, 6);
  709. BridgeNet = IPXAddressClass(net, node);
  710. }
  711. }
  712. }
  713. delete [] buffer;
  714. }