]> icculus.org git repositories - btb/d2x.git/blob - main/old/descentw.c
get rid of dependencies on predefined display modes
[btb/d2x.git] / main / old / descentw.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14
15 #pragma off (unreferenced)
16 static char rcsid[] = "$Id: descentw.c,v 1.1.1.1 2001-01-19 03:30:14 bradleyb Exp $";
17 #pragma on (unreferenced)
18
19 #include "desw.h"
20
21 #include <mmsystem.h>
22 #include <setjmp.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26
27
28 #include "winapp.h"
29 #include "error.h"
30 #include "gr.h"
31 #include "digi.h"
32 #include "key.h"
33 #include "inferno.h"
34 #include "gamepal.h"
35 #include "game.h"
36 #include "songs.h"
37 #include "mono.h"
38 #include "screens.h"
39 #include "config.h"
40 #include "newdemo.h"
41 #include "text.h"
42 #include "menu.h"
43 #include "vers_id.h"
44 #include "mvelibw.h"
45 #include "modem.h"
46 #include "cntrlcen.h"
47
48 #define D2_ICON 50
49
50 #define MIN_VIRTUAL_MEM_FREE            (16 * (1024*1024))
51 #define MIN_PHYSICAL_MEM_FREE           (16 * (1024*1024))
52 #define SOUND_22K_CUTOFF                        (16 *1024*1024)         // 8.0 MB
53
54
55 //      Globals --------------------------------------------------------------------
56
57 HWND                    _hAppWnd;                                               // Descent Window
58 HINSTANCE       _hAppInstance;
59 int                     _DDraw = 0;                                             // No DirectX
60 char                    *_OffscreenCanvasBits;          // Pointer to Offscreen Canvas Bits.
61 BOOL                    _AppActive = FALSE;                     // Is application active?
62 BOOL                    _AppPaused = FALSE;                     // Shall we run game?
63 BOOL                    _AppInit = FALSE;                               // Is application initialized?
64 BOOL                    _RedrawScreen=FALSE;                    // Shall we force a redraw of the screen?
65 SCREEN_CONTEXT _SCRContext;
66
67 HANDLE          hDescent2Mutex = NULL;          // handle to determine whether D2 is already running
68 HANDLE          hDescent2Mutex2 = NULL;
69
70 BOOL                    AllowActivates = FALSE;
71
72 //      HACK, to keep original CD audio vol.
73 DWORD CD_audio_desktop_vol = 0;
74 int CD_audio_desktop_dev = -1;
75
76 //      EXTERNS
77
78 int Platform_system=0;
79
80
81 extern int Mono_initialized;
82 extern int WinEnableInt3;
83 extern int DD_Emulation;
84 extern int Skip_briefing_screens;               // So we can skip the briefing 
85 extern int digi_system_initialized;
86 extern int framerate_on;
87 extern ubyte gr_palette_faded_out;
88 extern int piggy_low_memory;                            // FROM PIGGY.C!
89 extern RECT ViewportRect;
90 extern int Joystick_calibrating;
91
92 // Game State and other Variables ---------------------------------------------
93
94 static char                     WinErrorMessage[512];
95 static BOOL                     WinErrorTrap = FALSE;
96 static BOOL                     GameShutdown = FALSE;
97 //static BOOL                   GameInitialized = FALSE;
98 static BOOL                     WinEnableMovies = TRUE;
99
100
101 //      External Functions ---------------------------------------------------------
102
103 extern void grwin_gdi_realizepal(HDC hdc);
104 extern void grwin_cleanup_palette();
105
106 extern void GameLoop(int, int);
107 extern void game_setup(void);
108 extern void check_joystick_calibration();
109 extern void DDResizeViewport(void);
110 extern void SetWinMonoInfo(HWND hWnd, HINSTANCE hInstance);
111
112 extern void InitCD(char *arg);
113 extern void     InitVideo(void);
114 extern void     InitIO(void);
115 extern void     InitData(void);
116 extern void     InitSound(void);
117 extern void     InitNetwork(void);
118 extern void InitDescent(void);
119 extern void InitPilot(void);    
120
121
122 //      Function Prototypes --------------------------------------------------------
123
124 int RunGame(int argc, char *argv[]);
125 int RestoreGameSurfaces(void);
126 void ValidateSystem(void);
127 void MakeCodeWritable(void);
128 int ParseArgs(char *argv[], LPSTR lpCmdLine);
129 void WErrorCatch(char *message);
130
131 void DoRegisterCheck(void);
132
133 void AppExit();
134 void AppPaint(HWND hWnd, HDC hdc);
135 void AppSize(HWND hWnd);
136 void AppActivate(HWND hWnd, UINT wParam);
137 void AppQueryPalette(HWND hWnd);
138 void AppPaletteChange(HWND hWnd, UINT wParam);
139 void AppDisplayChange(HWND hWnd, int w, int h, int bpp);
140 BOOL AppHandleSystemKeys(UINT msg, UINT wParam, UINT lParam);
141
142 BOOL GameCheckMultiReactor();
143
144 LRESULT WINAPI _export DescentWndProc(HWND hWnd,UINT msg,UINT wParam,
145                                                                                                          LPARAM lParam);
146
147
148
149 // Initialization and Destruction
150 //      ----------------------------------------------------------------------------
151
152 BOOL AppInit(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
153 {
154 //      Create Application Window and Initialize WinG stuff.
155         WNDCLASS wc;
156
157 #ifdef RELEASE
158         WinEnableInt3=0;
159 #else
160         WinEnableInt3=1;
161 #endif
162
163 #ifndef NDEBUG
164         if (FindArg("-logfile")) loginit("descentw.log");
165 #endif
166
167         ValidateSystem();
168
169         if (!hPrev) {
170                 wc.hCursor                              = LoadCursor(NULL, IDC_ARROW);
171                 wc.hIcon                                        = LoadIcon(hInst, MAKEINTRESOURCE(D2_ICON));
172                 wc.lpszMenuName         = NULL;
173                 wc.lpszClassName                = "DescentWndClass";
174                 wc.hbrBackground                = (HBRUSH)GetStockObject(BLACK_BRUSH);
175                 wc.hInstance                    = hInst;
176                 wc.style                                        = CS_DBLCLKS;
177                 wc.lpfnWndProc                  = (WNDPROC)DescentWndProc;
178                 wc.cbWndExtra                   = 0;
179                 wc.cbClsExtra                   = 0;
180
181                 if (!RegisterClass(&wc)) return FALSE;
182         }
183
184 //      Arrgh, make entire code segment writable for now.
185 //      -codereadonly forces read only code (debug purposes)
186
187         if (!FindArg("-codereadonly")) 
188                 MakeCodeWritable();
189
190 #ifndef RELEASE
191         cinit();
192 #endif
193
194         atexit(AppExit);
195
196         _hAppInstance = hInst;
197         _hAppWnd = CreateWindowEx(WS_EX_APPWINDOW,
198                                         "DescentWndClass", 
199                                         WINAPP_NAME,
200                                         WS_POPUP | WS_SYSMENU | WS_BORDER,
201                                         0, 0,
202                                         GetSystemMetrics(SM_CXSCREEN),
203                                         GetSystemMetrics(SM_CYSCREEN),
204                                         NULL, 
205                                         NULL, 
206                                         hInst, 
207                                         NULL);
208
209         Assert(_hAppWnd != 0);
210
211         ShowWindow(_hAppWnd, SW_SHOWNORMAL);
212         UpdateWindow(_hAppWnd);
213
214 //      Tell Descent Libraries about Windows
215         HideCursorW();
216 //      LoadCursorWin(MOUSE_WAIT_CURSOR);
217 //      ShowCursorW();
218
219 #ifdef RELEASE
220 #ifndef NDEBUG 
221         if (FindArg("-monodebug")) Mono_initialized = 1;
222         else // link to below line!
223 #endif  
224         Mono_initialized = 0;
225 #else
226         Mono_initialized = 1;
227 #endif
228
229         minit();
230
231         SetLibraryWinInfo(_hAppWnd, _hAppInstance);
232
233         #ifndef NDEBUG
234                 mopen( 0, 9, 1, 78, 15, "Debug Spew");
235                 mopen( 1, 2, 1, 78,  5, "Errors & Serious Warnings");
236         #endif
237
238         return TRUE;
239 }
240
241
242 void AppExit()
243 {
244 //      HACK do this when the application is closing! restore the CD audio volume.
245         if (CD_audio_desktop_dev != -1) 
246                 auxSetVolume(CD_audio_desktop_dev, CD_audio_desktop_vol);
247
248         grwin_cleanup_palette();
249
250         LoadCursorWin(MOUSE_DEFAULT_CURSOR);
251         ShowCursorW();
252
253 #ifndef RELEASE
254         if (WinErrorTrap) {
255                 cprintf("\n\n%s", WinErrorMessage);
256                 cgetch();
257         }
258         else {
259                 CloseWindow(_hAppWnd);
260                 cprintf("\n\nDescent II for Win95 done...\n");
261                 cgetch();
262         }
263         cclose();
264 #else 
265         if (WinErrorTrap)
266                 MessageBox(NULL, WinErrorMessage, "Descent II error", MB_OK);
267 #endif
268
269 #ifndef NDEBUG
270         logclose();
271 #endif
272
273         if (hDescent2Mutex2) 
274                 CloseHandle(hDescent2Mutex2);
275
276         if (hDescent2Mutex) 
277                 CloseHandle(hDescent2Mutex);            // Destroy Mutex Object!
278 }
279
280 extern char CDROM_dir[30];
281
282 void DoRegisterCheck()
283 {
284         STARTUPINFO si;
285         PROCESS_INFORMATION pi;
286         BOOL flag;
287         char filename[64];
288
289         strcpy(filename, CDROM_dir);
290         strcat(filename, "regcard.exe");
291
292         memset(&si, 0, sizeof(si));
293         si.cb = sizeof(si);
294         si.dwFlags = STARTF_USESHOWWINDOW;
295         si.wShowWindow = SW_SHOW;
296
297         flag = CreateProcess(
298                         NULL,
299                         filename, NULL, NULL,
300                         FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL,
301                         &si, &pi);                      
302         if (flag) {
303                 DWORD dwval;
304                 dwval = WaitForInputIdle(pi.hProcess, INFINITE);
305
306                 while (WaitForSingleObject(pi.hProcess, 0) != WAIT_OBJECT_0)
307                 {
308                 }
309
310                 mprintf((1, "JOY.CPL process finished?\n"));
311                 ShowWindow(_hAppWnd, SW_MAXIMIZE);
312                 SetForegroundWindow(_hAppWnd);
313         }
314 }
315
316
317 //      Game -----------------------------------------------------------------------
318
319 char commandline_help[] = 
320                         "Command-line options (case is not significant):\n"
321                         "\n"
322                         " General Options:\n"
323                         "\n"
324                         "       -LowMem         Lower animation detail for better performance with low memory\n"
325                         "       -NoLowMem       Force high animation detail even when low memory\n"
326                         "       -Subtitles              Turn on movie subtitles (English-only)\n"
327                         "\n"
328                         " Input devices: -SpecialDevice\n"
329                         "\n"
330                         "       -IForce <n>     Use Immersion tactile feedback joystick on port <n>\n"
331                         "\n"
332                         " Sound & Music:\n"
333                         "\n"
334                         "       -NoSound        Turns off sound & music\n"
335                         "       -NoMusic                Disables music; sound effects remain enabled\n"
336                         "       -Sound22K       Use 22KHz sounds, even if machine has less than 16 MB\n"
337                         "       -Sound11K       Use 11KHz sounds, even if machine has more than 16 MB\n"
338                         "\n"
339                         " Network & Modem:\n"
340                         "\n"
341                         "       -CtsRts         Enables CTS/RTS handshaking during null-modem games\n"
342                         "       -NoNetwork      Disables network drivers\n"
343                         "       -NoSerial               Disables serial drivers\n"
344                         "       -Packets #      Specifies the packets per second where # is the number of packets\n"
345                         "       -Shortpackets   Turn on short packets\n"
346                         "       -Norankings     Disable multiplayer ranking system\n"
347                         "       -Noredunancy    suppresses duplicate messages such as \"You already have ....\"\n"
348                         "\n"
349                         "Diagnostic:\n"
350                         "       -emul           Certain video cards need this option in order to run game.\n"
351                         "       -ddemul         If -emul doesn't work, use this option.\n";
352
353 print_commandline_help()
354 {
355         ShowCursorW();
356         MessageBox(NULL, commandline_help, "Descent II Command-line Options", MB_OK);
357 }
358
359 int RunGame(int argc, char *argv[])
360 {
361         MSG msg;
362         int val;
363
364         setbuf(stdout, NULL);
365         error_init(WErrorCatch, NULL);
366
367 #ifndef RELEASE
368         if (FindArg("-stopwatch"))
369                 timer_init(1); 
370         else
371                 timer_init(0);
372 #else
373         timer_init(0);
374 #endif
375
376 //      InitArgs(argc, argv);
377
378         InitCD(argv[0]);
379         
380 #ifdef RELEASE
381         DoRegisterCheck();
382 #endif
383
384         InitVideo();
385         InitIO();
386         InitData();
387         InitSound();
388
389         if (!FindArg("-nonetwork"))
390                 InitNetwork();
391
392         if (!FindArg("-noserial"))
393                 serial_active = 1;
394
395         AllowActivates = TRUE;  
396
397         InitDescent();
398
399         InitPilot();    
400
401         if (Auto_demo)  {
402                 newdemo_start_playback("DESCENT.DEM");          
403                 if (Newdemo_state == ND_STATE_PLAYBACK )
404                         Function_mode = FMODE_GAME;
405         }
406
407 //      do this here because the demo code can do a longjmp when trying to
408 //              autostart a demo from the main menu, never having gone into the game
409         setjmp(LeaveGame);
410
411         while (Function_mode != FMODE_EXIT)
412         {
413                 val = DoMessageStuff(&msg);
414
415                 DDGRRESTORE;
416
417                 switch (Function_mode) 
418                 {
419                         case FMODE_MENU:
420                         {
421                                 set_screen_mode(SCREEN_MENU);
422                                 if (Auto_demo) {
423                                         DEFINE_SCREEN(NULL);
424                                         newdemo_start_playback(NULL);
425                                         if (Newdemo_state != ND_STATE_PLAYBACK) 
426                                                 Error("No demo files were found for autodemo mode!");
427                                 }
428                                 else {
429                                         DEFINE_SCREEN(Menu_pcx_name);
430                                         mprintf((1, "%s\n", Menu_pcx_name));
431                                         gr_palette_clear();
432                                         DoMenu();
433                                 }
434                                 break;
435                         }
436                         case FMODE_GAME:
437                         {
438                                 HideCursorW();
439                                 DEFINE_SCREEN(NULL);
440                                 game();
441                                 digi_reset();
442                                 digi_reset();
443                                 if ( Function_mode == FMODE_MENU )
444                                         songs_play_song( SONG_TITLE, 1 );
445                                 mprintf((0, "Function mode = %d\n", Function_mode));
446                         }
447                 }
448
449         }       
450
451         dd_gr_set_current_canvas(NULL);
452         dd_gr_clear_canvas(BM_XRGB(0,0,0));
453
454         WriteConfigFile();
455
456         return msg.wParam;
457 }
458
459
460 //      Window Message Functions 
461 //      ----------------------------------------------------------------------------
462
463 void AppPaint(HWND hWnd, HDC hdc)
464 {
465 //      grwin_gdi_realizepal(hdc);
466 }
467
468                                 
469 void AppSize(HWND hWnd)
470 {
471         if (IsIconic(hWnd)) {
472                 _AppPaused = TRUE;
473                 InvalidateRect(hWnd, NULL, TRUE);
474         }
475         else if (GetForegroundWindow() == hWnd) {
476                 _AppPaused = FALSE;
477         }
478           
479         DDResizeViewport();
480         mprintf((0, "Resized window (%d,%d,%d,%d).\n", ViewportRect.left, ViewportRect.top, ViewportRect.right, ViewportRect.bottom));  
481 }
482
483
484 void AppActivate(HWND hWnd, UINT wParam)
485 {
486         _AppActive = (BOOL)(wParam) && GetForegroundWindow()==hWnd && !IsIconic(hWnd);
487                         
488         if (_AppActive) {
489                 mprintf((0, "Descent II is gaining Window focus.\n"));
490                 cprintf("Descent II is gaining Window focus.\n");
491         }
492         else {
493                 mprintf((0, "Descent II is losing Window focus.\n"));
494                 cprintf("Descent II is losing Window focus.\n");
495         }
496
497 // Must now unpause if paused and app is active now.
498         mprintf((0, "AppActivate: Active: %d, Paused: %d\n", _AppActive, _AppPaused));
499
500         if (_AppActive && AllowActivates && !_AppPaused) 
501         {
502                 D2Restore();
503         }
504         else if (AllowActivates) {
505                 D2Shutdown();
506         }
507
508 }
509
510
511 void AppQueryPalette(HWND hWnd)
512 {
513 //      if (!_DDFullScreen && _lpDDPalette && _lpDDSPrimary) {
514 //              gr_palette_load(gr_palette);
515 //      }
516         mprintf((0, "QUERY PALETTE!\n"));
517 }
518
519
520 void AppCreate(HWND hWnd)
521 {
522         HMENU hMenu;
523
524 // Remove system menu components not good
525         hMenu = GetSystemMenu(hWnd, FALSE);
526         
527         RemoveMenu(hMenu, SC_SIZE, MF_BYCOMMAND);
528         RemoveMenu(hMenu, SC_MOVE, MF_BYCOMMAND);
529 }       
530
531
532 void AppPaletteChange(HWND hWnd, UINT wParam)
533 {
534         if ((HWND)wParam != hWnd) {
535                 if (!_DDFullScreen) {
536                         mprintf((0, "Palette changed!\n"));
537                         _AppPaused = TRUE;
538                         mprintf((0, "Descent 2 is paused.\n"));
539                 }       
540         }
541 }
542
543 //static LPDIRECTDRAWSURFACE Page0Buffer = 0;
544
545 void AppDisplayChange(HWND hWnd, int w, int h, int bpp)
546 {         
547 //      mprintf((0, "Windows feels a display change coming...\n"));
548 }
549
550
551 BOOL AppHandleSystemKeys(UINT msg, UINT wParam, UINT lParam)
552 {                
553 //      Intercept ALT keystrokes
554
555         if (msg == WM_SYSKEYUP) {
556                 mprintf((0,"ALT key down!"));
557         }
558
559         send_key_msg(msg, wParam, lParam);
560
561         if (wParam == VK_TAB || wParam == VK_ESCAPE) return FALSE;
562
563         return TRUE;
564 }
565
566
567 int RestoreGameSurfaces()
568 {
569         if (dd_VR_offscreen_buffer) {
570                 if (!dd_VR_offscreen_buffer->lpdds) return 1;
571                 if (IDirectDrawSurface_Restore(dd_VR_offscreen_buffer->lpdds) != DD_OK)  {
572                         mprintf((1, "Warning: Unable to restore dd_VR_offscreen_buffer!\n"));
573                         return 0;
574                 }
575                 mprintf((0, "Restored dd_VR_offscreen_buffer\n"));
576         }
577
578         return 1;
579 }
580
581
582 LRESULT WINAPI _export DescentWndProc(HWND hWnd,
583                                                                 UINT msg, 
584                                                                 UINT wParam,
585                                                                 LPARAM lParam)
586 {
587         //HANDLE h;
588         //static int nTimer = 0;
589
590         switch (msg)
591         {
592                 case WM_CREATE:
593                         AppCreate(hWnd);
594                         return 0;
595
596                 case WM_SYSCOMMAND:
597                         if((wParam&0xFFF0)==SC_SCREENSAVE || (wParam&0xFFF0)==SC_MONITORPOWER)
598             return 0;
599
600                         if ((wParam&0xfff0)== SC_KEYMENU && _AppActive) {
601                                 mprintf((0, "W32: Bypassing system menu.\n"));
602                                 return 0;
603                         }
604                         break;
605
606                 case WM_SIZE:
607                 case WM_MOVE:
608                         AppSize(hWnd);
609                         return 0;
610
611                 case WM_ACTIVATEAPP:                                    // Application is losing focus.
612                         AppActivate(hWnd, wParam);
613                         return 0;
614
615                 case WM_QUERYNEWPALETTE:
616                         AppQueryPalette(hWnd);
617                         break;
618
619                 case WM_PALETTECHANGED:
620                         AppPaletteChange(hWnd, wParam);
621                         break;
622
623                 case WM_DISPLAYCHANGE:                          // Screen Mode is changing.
624                         AppDisplayChange(hWnd, LOWORD(lParam), HIWORD(lParam), wParam);
625                         break;
626
627                 case WM_SYSKEYUP:
628                 case WM_SYSKEYDOWN:
629                         if (AppHandleSystemKeys(msg, wParam,lParam))
630                                 return 0;
631                         break;
632
633                 case WM_KEYDOWN:
634                 case WM_KEYUP:
635                         if (wParam == VK_SNAPSHOT) {
636                                 mprintf((0, "Capture screen begins...\n"));
637                                 save_screen_shot(0);
638                                 if (!clipboard_screenshot()) 
639                                         mprintf((1, "Failed to create clipboard screenshot!\n"));
640                         }
641 //              #ifndef NDEBUG
642 //                      if (msg == WM_KEYDOWN && wParam == 0x49) ipx_debug_hold_packets = 1;
643 //                      if (msg == WM_KEYUP && wParam == 0x49) ipx_debug_hold_packets = 0;
644 //              #endif
645                         send_key_msg(msg, wParam, lParam);
646                         break;
647         
648                 case WM_PAINT:
649 //                      hdc = BeginPaint(hWnd, &ps);                    
650 //                      AppPaint(hWnd, hdc);
651 //                      EndPaint(hWnd, &ps);
652 //                      return 0;
653                         break;
654
655                 case MM_JOY1MOVE:
656                 case MM_JOY1BUTTONDOWN:
657                 case MM_JOY1BUTTONUP:
658                         if (!_AppPaused && (_AppActive || !_DDFullScreen))      {
659                                 joy_handler_win(hWnd, msg, wParam, lParam);
660                         }
661                         break;                  
662
663                 case WM_DESTROY:
664                         mprintf((0, "Killing main window...\n"));
665                         PostQuitMessage(0);
666                         break;
667         }
668
669 //      digi_midi_debug();
670         mouse_win_callback(msg, wParam, lParam);
671         
672         return DefWindowProc(hWnd, msg, wParam, lParam);
673 }
674
675
676 static char *WinArgs[64];
677
678 //      Main Program
679 //      ----------------------------------------------------------------------------
680
681 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, 
682                                                  int nCmdShow)
683 {
684         int retval = 1;
685         int argc;
686
687
688         argc = ParseArgs(WinArgs, szCmdLine);
689         InitArgs(argc, WinArgs);
690
691         if (FindArg( "-?" ) || FindArg( "-help" ) || FindArg( "?" ) ) {
692                 print_commandline_help();
693                 set_exit_message("");
694                 return(0);
695         }
696
697         if (AppInit(hInst, hPrev, szCmdLine, nCmdShow)) {
698                 retval = RunGame(argc, WinArgs);
699         }
700
701         return retval;
702 }
703
704
705
706 //      Low Level Routines
707 //      ----------------------------------------------------------------------------
708
709 static char *NoMovieArg = "-nomovies";
710 static char *PathArg = "descentw.exe";
711
712 int ParseArgs(char *argv[], LPSTR lpCmdLine)
713 {
714         int argc;
715         int i;
716
717         argc = 0;
718         i = 0;
719
720         argv[argc++] = PathArg;
721
722 //      while (lpCmdLine[i] == '-' || lpCmdLine[i] == '/' )
723
724         while (lpCmdLine[i])
725         {
726                 if (lpCmdLine[i] == ' ') i++;
727                 else {
728                         argv[argc++] = &lpCmdLine[i];
729
730                         while (lpCmdLine[i]!=' ' && lpCmdLine[i]!= 0) {
731                                 //mprintf((0, "%c", lpCmdLine[i]));
732                                 i++;
733                         }
734                         lpCmdLine[i++] = 0;
735 //                      mprintf((0, "Argument %s.\n", argv[argc-1]));
736                 }
737         }
738
739         if (!WinEnableMovies) 
740                 argv[argc++] = NoMovieArg;
741
742         return argc;
743 }
744                                         
745
746 extern void rls_stretch_scanline_asm();
747
748
749 void MakeCodeWritable(void)
750 {
751         typedef DWORD __stdcall translator(DWORD);
752
753         HMODULE         modCode;
754         BYTE            *pImageBase = 0;
755         DWORD           version;
756
757         modCode = GetModuleHandle(0);
758         version = GetVersion();
759
760 //      For Win32s we have to use undocumented features
761         if ((version < 0x80000000) || ((BYTE)version >=0x04)) {  
762         //       Win NT, Win95.
763                 pImageBase = (BYTE *)modCode;
764         }
765         else {
766                 MessageBox(NULL, "Descent II cannot run under Windows 3.x", "Descent II", MB_OK);
767                 exit(1);
768
769         }
770
771         if (pImageBase) {
772                 DWORD oldRights;
773                 //char buf[256];
774                 IMAGE_OPTIONAL_HEADER *pHeader = 
775                         (IMAGE_OPTIONAL_HEADER *)(pImageBase + ((IMAGE_DOS_HEADER *)pImageBase)->e_lfanew + 
776                                                                                          sizeof(IMAGE_NT_SIGNATURE) + sizeof(IMAGE_FILE_HEADER));
777
778 //@@            if (!VirtualProtect(pImageBase+pHeader->BaseOfCode, pHeader->SizeOfCode,
779 //@@                                                              PAGE_READWRITE, &oldRights))  {
780 //@@                            exit(1);
781 //@@            }
782
783                 if (!VirtualProtect(rls_stretch_scanline_asm, 4096*2, PAGE_READWRITE, &oldRights))  {
784                         MessageBox(NULL, "Unable to gain write access to requested page.", "Descent II Error", MB_OK);
785                         exit(1);
786                 }
787
788 //              wsprintf(buf, "Start:%x FN1:%x",(DWORD)pImageBase+pHeader->BaseOfCode, (DWORD)rls_stretch_scanline_asm);
789 //              MessageBox(NULL, buf, "Info", MB_OK);
790         }
791 }
792
793
794 void ValidateSystem()
795 {
796         DWORD version;
797
798         version = GetVersion();
799
800         if ((version < 0x80000000) || ((BYTE)version >=0x04)) {
801                 if ((version < 0x80000000)  && ((BYTE)version >= 0x04)) {
802                         Platform_system = WINNT_PLATFORM;
803                         DD_Emulation = 1;
804                 }        
805                 else Platform_system = WIN95_PLATFORM;
806         }
807         else {
808                 MessageBox(NULL, "Descent II will not run under Windows 3.x", "DESCENT II", MB_OK);
809                 exit(1);
810         }
811
812 //      Do the named mutex thingy.
813         {
814                 HANDLE hMutex, hMutex2;
815
816                 hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "BigRedStinksMutex");
817                 if (hMutex) {
818                         hMutex2 = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "BigRedSucksMutex");
819                         if (hMutex2) {
820                                 CloseHandle(hMutex2);
821                                 exit(1);                                // Don't even tell user he's trying to run a third copy
822                         }
823
824                         hDescent2Mutex2 = CreateMutex(NULL, FALSE, "BigRedSucksMutex");
825                         if (!hDescent2Mutex2) {
826                                 MessageBox(NULL, "Unable to create second mutex object.", "Descent II error", MB_OK);
827                                 exit(1);
828                         }
829                         MessageBox(NULL, "You may only run one instance of Descent II at a time.", 
830                                         "Descent II error", MB_OK);
831                         CloseHandle(hMutex);
832                         exit(1);
833                 }
834                 hDescent2Mutex = CreateMutex(NULL, FALSE, "BigRedStinksMutex");
835                 if (!hDescent2Mutex) {
836                         MessageBox(NULL, "Unable to create mutex object.", "Descent II error", MB_OK);
837                         exit(1);
838                 }
839         }
840 //      Do the Version ID thing for Beta testers
841 #if defined(RELEASE) && defined(VERSION_NAME) && !defined(NDEBUG)
842         { 
843                 char buf[256];
844
845                 sprintf(buf, "Descent II %s v%d.%d\n%s\n%s %s", VERSION_TYPE, Version_major, Version_minor,
846                                                                                                                         VERSION_NAME, __DATE__, __TIME__);
847                 MessageBox(NULL, buf, "Descent II beta information", MB_OK);
848         }
849 #endif
850
851 //      Super memory check
852         {
853                 MEMORYSTATUS memstat;
854                 int mem_free;
855
856                 memset(&memstat, 0, sizeof(memstat));
857                 memstat.dwLength = sizeof(memstat);
858                 GlobalMemoryStatus(&memstat);
859
860                 logentry("Memory: \n");
861                 logentry("  MemoryLoad     = %10d\n",memstat.dwMemoryLoad);
862                 logentry("  TotalPhys      = %10d\n",memstat.dwTotalPhys);
863                 logentry("  AvailPhys      = %10d\n",memstat.dwAvailPhys);
864                 logentry("  TotalPageFile  = %10d\n",memstat.dwTotalPageFile);
865                 logentry("  AvailPageFile  = %10d\n",memstat.dwAvailPageFile);
866                 logentry("  TotalVirtual   = %10d\n",memstat.dwTotalVirtual);
867                 logentry("  AvailVirtual   = %10d\n",memstat.dwAvailVirtual);
868
869                 mem_free = memstat.dwTotalPhys;
870 //              mem_free=100;
871 //              logentry("  mem_free       = %10d\n",mem_free);
872                 
873                 if ( mem_free < MIN_PHYSICAL_MEM_FREE) {
874                         logentry("Using low memory option.\n");
875                         piggy_low_memory = 1;
876                 }
877
878                 if ( memstat.dwAvailPageFile < MIN_VIRTUAL_MEM_FREE) {
879                         MessageBox(NULL, "Not enough virtual memory.\n You need at least 16MB of free drive space.\n", 
880                                                         "Descent II Error", MB_OK);
881                         exit(1);
882                 }
883
884                 if ( ((mem_free > SOUND_22K_CUTOFF) || FindArg("-sound22k")) && !FindArg("-sound11k") && !FindArg("-lowmem") ) {
885                         logentry("Using 22KHz sounds\n");
886                         digi_sample_rate = SAMPLE_RATE_22K;
887                 } else {
888                         logentry("Using 11KHz sounds\n");
889                         digi_sample_rate = SAMPLE_RATE_11K;
890                 }
891         }
892 }       
893
894
895 int DoMessageStuff(MSG *msg)
896 {
897
898         while(1)
899         {
900                 if (PeekMessage(msg, NULL, 0, 0, PM_REMOVE)) {
901                         if (msg->message == WM_QUIT) {
902                                 WriteConfigFile();
903                                 exit(0);
904                         }
905
906                         TranslateMessage(msg);
907                         DispatchMessage(msg);
908                 }
909                 else if (!_AppPaused && (_AppActive || !_DDFullScreen)) {
910                         break;
911                 } else {
912
913                         if ((Game_mode & GM_MULTI)) {
914                                 if (Control_center_destroyed) {
915                                         ShowWindow(_hAppWnd, SW_MAXIMIZE);
916                                         WinDelayIdle();
917                                         SetForegroundWindow(_hAppWnd);
918                                         WinDelayIdle();
919                                         _RedrawScreen = TRUE;
920                                 }
921                                 else if (multi_menu_poll() == -1) {
922                                         ShowWindow(_hAppWnd, SW_MAXIMIZE);
923                                         WinDelayIdle();
924
925                                         if (GetForegroundWindow() == _hAppWnd) {
926                                                 if (_AppPaused || !_AppActive) {
927                                                         mprintf((0, "Descent2 Daemon...Pause: %d, Active %d\n",_AppPaused, _AppActive)); 
928                                                         SetActiveWindow(_hAppWnd);
929                                                         _RedrawScreen = FALSE;
930                                                         break;
931                                                 }
932                                         }
933                                         else {
934                                                 SetForegroundWindow(_hAppWnd);
935                                                 WinDelayIdle();
936                                                 _RedrawScreen = FALSE;
937                                         }
938                                 }
939                         }
940                         else {
941                                 mprintf((0, "Waiting...Pause: %d, Active %d\n",_AppPaused, _AppActive)); 
942                                 WaitMessage();
943                         }
944                 }
945         }
946                 
947
948         return MSG_NORMAL;
949 }
950
951
952 void WinDelayIdle()
953 {
954         MSG msg;
955
956         mprintf((0, "Entering Idle message loop...\n"));
957
958         while (1)
959         {
960                 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
961                         if (msg.message == WM_QUIT) {
962                                 WriteConfigFile();
963                                 exit(0);
964                         }
965
966                         mprintf((0, "Retreiving message(0x%x:0x%x,0x%x) in idle loop.\n",msg.message, msg.wParam, msg.lParam));
967
968                         TranslateMessage(&msg);
969                         DispatchMessage(&msg);
970
971                 }
972                 else break;
973         }
974 }
975
976
977 void WinDelay(int msecs)
978 {
979         int timeout;
980         MSG msg;
981
982
983         timeout = timeGetTime() + msecs;
984
985         while (timeout > timeGetTime())
986         {
987                 DoMessageStuff(&msg);
988                 if (msg.message == WM_QUIT) exit(0);
989         }
990 }
991
992
993 void    WErrorCatch(char *message)
994 {
995         mprintf((1, "Bye Bye: %s\n", message));
996
997         strcpy(WinErrorMessage, message);
998
999         WinErrorTrap = 1;
1000
1001         logentry("%s", WinErrorMessage);
1002         CloseWindow(_hAppWnd);
1003 }
1004
1005
1006 //static BOOL CursorVisible = TRUE;
1007 static HANDLE CursorHandle = NULL;
1008
1009
1010 void LoadCursorWin(int cursor)
1011 {
1012         switch (cursor)
1013         {
1014                 case MOUSE_DEFAULT_CURSOR:
1015                         CursorHandle = LoadCursor(NULL, IDC_ARROW);
1016                         break;
1017                 
1018                 case MOUSE_WAIT_CURSOR: 
1019                         CursorHandle = LoadCursor(NULL, IDC_WAIT);
1020                         break;
1021                 
1022                 default:
1023                         CursorHandle = NULL;    
1024         }
1025
1026         SetCursor(CursorHandle);
1027 }
1028  
1029
1030 void HideCursorW()
1031 {                                        
1032         while (ShowCursor(FALSE) >=0);
1033 }
1034  
1035
1036 void ShowCursorW()
1037 {
1038         if (DD_Emulation) return;
1039         
1040         if (CursorHandle == NULL)
1041                 LoadCursorWin(MOUSE_DEFAULT_CURSOR);
1042
1043         while (ShowCursor(TRUE) < 0);
1044 }       
1045
1046
1047
1048 //      Descent 2 Shutdown and Restore functions
1049 //      ----------------------------------------------------------------------------
1050
1051 void SaveVideoState();
1052 void RestoreVideoState();
1053
1054 static int Saved_Game_window_w;
1055 static int Saved_Game_window_h;
1056 static int SavedScreenMode = 0;
1057
1058 extern int Digi_initialized;
1059 extern BOOL WMVEPlaying, RMVEPlaying;
1060 extern int current_song_level;
1061
1062
1063 void RestoreScreenContext()
1064 {
1065         if ( _SCRContext.bkg_filename != NULL ) {
1066                 mprintf((0, "Loading background file...\n"));
1067                 nm_draw_background1( _SCRContext.bkg_filename );
1068         }
1069         gr_palette_load(gr_palette);
1070 }
1071
1072
1073 void D2Shutdown()
1074 {
1075         if (GameShutdown) return;
1076
1077         _AppPaused = TRUE;
1078
1079         if (!Joystick_calibrating) joy_stop_poll();
1080
1081         key_flush();
1082
1083         SaveVideoState();
1084
1085         songs_stop_all();
1086
1087         if (CD_audio_desktop_dev != -1) 
1088                 auxSetVolume(CD_audio_desktop_dev, CD_audio_desktop_vol);
1089
1090         if (Function_mode == FMODE_GAME && !(Game_mode &GM_MULTI)) {
1091                 stop_time();
1092         }
1093
1094         mprintf((0, "WMVE: %d, RMVE: %d\n", WMVEPlaying, RMVEPlaying));
1095
1096         if (WMVEPlaying) MovieShutdown();
1097         if (RMVEPlaying) MVE_rmHoldMovie();
1098
1099         if (!WMVEPlaying) digi_reset();
1100
1101         mprintf((0, "Descent 2 is asleep...\n"));
1102
1103         GameShutdown = TRUE;
1104 }
1105
1106
1107 void D2Restore()
1108 {
1109         if (!GameShutdown) return;
1110         
1111         if (!WMVEPlaying) digi_reset();
1112         if (WMVEPlaying) {
1113                 MovieRestore();
1114                 key_flush();
1115                 if (CD_audio_desktop_dev != -1) 
1116                         auxGetVolume(CD_audio_desktop_dev, &CD_audio_desktop_vol);
1117                 _AppPaused = FALSE;
1118                 goto EndD2Restore;
1119         }
1120         else if (RMVEPlaying) {
1121                 key_flush();
1122         //      if (_lpDD) RestoreVideoState();
1123                 dd_gr_init_screen();
1124                 W95DisplayMode = -1;
1125
1126                 if (SavedScreenMode != -1)  
1127                         set_screen_mode(SavedScreenMode);
1128
1129                 if (CD_audio_desktop_dev != -1) 
1130                         auxGetVolume(CD_audio_desktop_dev, &CD_audio_desktop_vol);
1131                 MVE_rmHoldMovie();
1132                 _RedrawScreen = TRUE;
1133                 _AppPaused = FALSE;
1134                 goto EndD2Restore;
1135         }
1136         else {
1137                 if (_lpDD) RestoreVideoState();
1138
1139                 if (CD_audio_desktop_dev != -1) 
1140                         auxGetVolume(CD_audio_desktop_dev, &CD_audio_desktop_vol);
1141                                                                                                                                                    
1142                 if (Function_mode == FMODE_MENU) songs_play_song(SONG_TITLE, 1);
1143                 if (Function_mode == FMODE_GAME) {
1144                         songs_play_level_song(current_song_level);
1145                 }
1146                 key_flush();
1147                 _AppPaused = FALSE;
1148
1149         }
1150
1151         if (Function_mode == FMODE_GAME && !(Game_mode & GM_MULTI)) start_time();
1152         else if (Function_mode == FMODE_MENU) 
1153                 keyd_time_when_last_pressed = timer_get_fixed_seconds();
1154
1155 EndD2Restore:
1156         if (!Joystick_calibrating) joy_start_poll();
1157         set_redbook_volume(Config_redbook_volume);
1158         mprintf((0, "...Descent 2 is awake!\n"));
1159         
1160         GameShutdown = FALSE;
1161 }
1162
1163
1164 void SaveVideoState()
1165 {
1166 // If in game mode, then restore window size
1167         if (Screen_mode == SCREEN_GAME) {
1168                 Saved_Game_window_w = Game_window_w;
1169                 Saved_Game_window_h = Game_window_h;
1170
1171         }               
1172
1173         SavedScreenMode = Screen_mode;
1174         Screen_mode = -1;
1175 }
1176
1177
1178 void RestoreVideoState()
1179 {
1180 //      Just reinitialize screen state.
1181         dd_gr_init_screen();
1182         W95DisplayMode = -1;
1183
1184
1185 // If in game mode, then restore window size
1186         if (SavedScreenMode != -1)  
1187                 set_screen_mode(SavedScreenMode);
1188                                                                                                                                         
1189         if (SavedScreenMode == SCREEN_GAME) {
1190                 Game_window_w = Saved_Game_window_w;
1191                 Game_window_h = Saved_Game_window_h;
1192                 init_cockpit();
1193         }
1194         if (Function_mode == FMODE_GAME) {
1195                 load_palette(Current_level_palette,1,1);
1196         }                               
1197
1198         _RedrawScreen = TRUE;
1199         RestoreScreenContext();
1200 }
1201
1202