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