1 
2 //**************************************************************************
3 //**
4 //** m_misc.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile: m_misc.c,v $
7 //** $Revision: 1.18 $
8 //** $Date: 96/01/07 16:51:18 $
9 //** $Author: bgokey $
10 //**
11 //**************************************************************************
12 
13 // HEADER FILES ------------------------------------------------------------
14 
15 #ifdef __NeXT__
16 #include <libc.h>
17 #else
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <fcntl.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #endif
24 #include <ctype.h>
25 #include "h2def.h"
26 #include "p_local.h"
27 #include "soundst.h"
28 
29 // MACROS ------------------------------------------------------------------
30 
31 #define MALLOC_CLIB 1
32 #define MALLOC_ZONE 2
33 
34 // TYPES -------------------------------------------------------------------
35 
36 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
37 
38 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
39 
40 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
41 
42 static int ReadFile(char const *name, byte **buffer, int mallocType);
43 
44 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
45 extern char *SavePath;
46 
47 // PUBLIC DATA DEFINITIONS -------------------------------------------------
48 
49 int myargc;
50 char **myargv;
51 
52 // PRIVATE DATA DEFINITIONS ------------------------------------------------
53 
54 // CODE --------------------------------------------------------------------
55 
56 //==========================================================================
57 //
58 // M_CheckParm
59 //
60 // Checks for the given parameter in the program's command line arguments.
61 // Returns the argument number (1 to argc-1) or 0 if not present.
62 //
63 //==========================================================================
64 
M_CheckParm(char * check)65 int M_CheckParm(char *check)
66 {
67 	int i;
68 
69 	for(i = 1; i < myargc; i++)
70 	{
71 		if(!strcasecmp(check, myargv[i]))
72 		{
73 			return i;
74 		}
75 	}
76 	return 0;
77 }
78 
79 //==========================================================================
80 //
81 // M_ParmExists
82 //
83 // Returns true if the given parameter exists in the program's command
84 // line arguments, false if not.
85 //
86 //==========================================================================
87 
M_ParmExists(char * check)88 boolean M_ParmExists(char *check)
89 {
90 	return M_CheckParm(check) != 0 ? true : false;
91 }
92 
93 //==========================================================================
94 //
95 // M_ExtractFileBase
96 //
97 //==========================================================================
98 
M_ExtractFileBase(char * path,char * dest)99 void M_ExtractFileBase(char *path, char *dest)
100 {
101 	char *src;
102 	int length;
103 
104 	src = path+strlen(path)-1;
105 
106 	// Back up until a \ or the start
107 	while(src != path && *(src-1) != '\\' && *(src-1) != '/')
108 	{
109 		src--;
110 	}
111 
112 	// Copy up to eight characters
113 	memset(dest, 0, 8);
114 	length = 0;
115 	while(*src && *src != '.')
116 	{
117 		if(++length == 9)
118 		{
119 			I_Error("Filename base of %s > 8 chars", path);
120 		}
121 		*dest++ = toupper((int)*src++);
122 	}
123 }
124 
125 /*
126 ===============
127 =
128 = M_Random
129 =
130 = Returns a 0-255 number
131 =
132 ===============
133 */
134 
135 
136 // This is the new flat distribution table
137 unsigned char rndtable[256] = {
138 	201,  1,243, 19, 18, 42,183,203,101,123,154,137, 34,118, 10,216,
139 	135,246,  0,107,133,229, 35,113,177,211,110, 17,139, 84,251,235,
140 	182,166,161,230,143, 91, 24, 81, 22, 94,  7, 51,232,104,122,248,
141 	175,138,127,171,222,213, 44, 16,  9, 33, 88,102,170,150,136,114,
142 	 62,  3,142,237,  6,252,249, 56, 74, 30, 13, 21,180,199, 32,132,
143 	187,234, 78,210, 46,131,197,  8,206,244, 73,  4,236,178,195, 70,
144 	121, 97,167,217,103, 40,247,186,105, 39, 95,163, 99,149,253, 29,
145 	119, 83,254, 26,202, 65,130,155, 60, 64,184,106,221, 93,164,196,
146 	112,108,179,141, 54,109, 11,126, 75,165,191,227, 87,225,156, 15,
147 	 98,162,116, 79,169,140,190,205,168,194, 41,250, 27, 20, 14,241,
148 	 50,214, 72,192,220,233, 67,148, 96,185,176,181,215,207,172, 85,
149 	 89, 90,209,128,124,  2, 55,173, 66,152, 47,129, 59, 43,159,240,
150 	239, 12,189,212,144, 28,200, 77,219,198,134,228, 45, 92,125,151,
151 	  5, 53,255, 52, 68,245,160,158, 61, 86, 58, 82,117, 37,242,145,
152 	 69,188,115, 76, 63,100, 49,111,153, 80, 38, 57,174,224, 71,231,
153 	 23, 25, 48,218,120,147,208, 36,226,223,193,238,157,204,146, 31
154 };
155 
156 
157 int rndindex = 0;
158 int prndindex = 0;
159 
M_Random(void)160 int M_Random (void)
161 {
162 	rndindex = (rndindex+1)&0xff;
163 	return rndtable[rndindex];
164 }
165 
M_ClearRandom(void)166 void M_ClearRandom (void)
167 {
168 	rndindex = prndindex = 0;
169 }
170 
171 
M_ClearBox(fixed_t * box)172 void M_ClearBox (fixed_t *box)
173 {
174 	box[BOXTOP] = box[BOXRIGHT] = MININT;
175 	box[BOXBOTTOM] = box[BOXLEFT] = MAXINT;
176 }
177 
M_AddToBox(fixed_t * box,fixed_t x,fixed_t y)178 void M_AddToBox (fixed_t *box, fixed_t x, fixed_t y)
179 {
180 	if (x<box[BOXLEFT])
181 		box[BOXLEFT] = x;
182 	else if (x>box[BOXRIGHT])
183 		box[BOXRIGHT] = x;
184 	if (y<box[BOXBOTTOM])
185 		box[BOXBOTTOM] = y;
186 	else if (y>box[BOXTOP])
187 		box[BOXTOP] = y;
188 }
189 
190 /*
191 ==================
192 =
193 = M_WriteFile
194 =
195 ==================
196 */
197 
198 #ifndef O_BINARY
199 #define O_BINARY 0
200 #endif
201 
M_WriteFile(char const * name,void * source,int length)202 boolean M_WriteFile (char const *name, void *source, int length)
203 {
204 	int handle, count;
205 
206 	handle = open (name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
207 	if (handle == -1)
208 		return false;
209 	count = write (handle, source, length);
210 	close (handle);
211 
212 	if (count < length)
213 		return false;
214 
215 	return true;
216 }
217 
218 //==========================================================================
219 //
220 // M_ReadFile
221 //
222 // Read a file into a buffer allocated using Z_Malloc().
223 //
224 //==========================================================================
225 
M_ReadFile(char const * name,byte ** buffer)226 int M_ReadFile(char const *name, byte **buffer)
227 {
228 	return ReadFile(name, buffer, MALLOC_ZONE);
229 }
230 
231 //==========================================================================
232 //
233 // M_ReadFileCLib
234 //
235 // Read a file into a buffer allocated using malloc().
236 //
237 //==========================================================================
238 
M_ReadFileCLib(char const * name,byte ** buffer)239 int M_ReadFileCLib(char const *name, byte **buffer)
240 {
241 	return ReadFile(name, buffer, MALLOC_CLIB);
242 }
243 
244 //==========================================================================
245 //
246 // ReadFile
247 //
248 //==========================================================================
249 
ReadFile(char const * name,byte ** buffer,int mallocType)250 static int ReadFile(char const *name, byte **buffer, int mallocType)
251 {
252 	int handle, count, length;
253 	struct stat fileinfo;
254 	byte *buf;
255 
256 	handle = open(name, O_RDONLY|O_BINARY, 0666);
257 	if(handle == -1)
258 	{
259 		I_Error("Couldn't read file %s", name);
260 	}
261 	if(fstat(handle, &fileinfo) == -1)
262 	{
263 		I_Error("Couldn't read file %s", name);
264 	}
265 	length = fileinfo.st_size;
266 	if(mallocType == MALLOC_ZONE)
267 	{ // Use zone memory allocation
268 		buf = Z_Malloc(length, PU_STATIC, NULL);
269 	}
270 	else
271 	{ // Use c library memory allocation
272 		buf = malloc(length);
273 		if(buf == NULL)
274 		{
275 			I_Error("Couldn't malloc buffer %d for file %s.",
276 				length, name);
277 		}
278 	}
279 	count = read(handle, buf, length);
280 	close(handle);
281 	if(count < length)
282 	{
283 		I_Error("Couldn't read file %s", name);
284 	}
285 	*buffer = buf;
286 	return length;
287 }
288 
289 //---------------------------------------------------------------------------
290 //
291 // PROC M_FindResponseFile
292 //
293 //---------------------------------------------------------------------------
294 
295 #define MAXARGVS 100
296 
M_FindResponseFile(void)297 void M_FindResponseFile(void)
298 {
299 	int i;
300 
301 	for(i = 1; i < myargc; i++)
302 	{
303 		if(myargv[i][0] == '@')
304 		{
305 			FILE *handle;
306 			int size;
307 			int k;
308 			int index;
309 			int indexinfile;
310 			char *infile;
311 			char *file;
312 			char *moreargs[20];
313 			char *firstargv;
314 
315 			// READ THE RESPONSE FILE INTO MEMORY
316 			handle = fopen(&myargv[i][1], "rb");
317 			if(!handle)
318 			{
319 				printf("\nNo such response file!");
320 				exit(1);
321 			}
322 			ST_Message("Found response file %s!\n",&myargv[i][1]);
323 			fseek (handle,0,SEEK_END);
324 			size = ftell(handle);
325 			fseek (handle,0,SEEK_SET);
326 			file = malloc (size);
327 			fread (file,size,1,handle);
328 			fclose (handle);
329 
330 			// KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
331 			for (index = 0,k = i+1; k < myargc; k++)
332 				moreargs[index++] = myargv[k];
333 
334 			firstargv = myargv[0];
335 			myargv = malloc(sizeof(char *)*MAXARGVS);
336 			memset(myargv,0,sizeof(char *)*MAXARGVS);
337 			myargv[0] = firstargv;
338 
339 			infile = file;
340 			indexinfile = k = 0;
341 			indexinfile++;  // SKIP PAST ARGV[0] (KEEP IT)
342 			do
343 			{
344 				myargv[indexinfile++] = infile+k;
345 				while(k < size &&
346 
347 					((*(infile+k)>= ' '+1) && (*(infile+k)<='z')))
348 					k++;
349 				*(infile+k) = 0;
350 				while(k < size &&
351 					((*(infile+k)<= ' ') || (*(infile+k)>'z')))
352 					k++;
353 			} while(k < size);
354 
355 			for (k = 0;k < index;k++)
356 				myargv[indexinfile++] = moreargs[k];
357 			myargc = indexinfile;
358 			// DISPLAY ARGS
359 			if(M_CheckParm("-debug"))
360 			{
361 				ST_Message("%d command-line args:\n", myargc);
362 				for(k = 1; k < myargc; k++)
363 				{
364 					ST_Message("%s\n", myargv[k]);
365 				}
366 			}
367 			break;
368 		}
369 	}
370 }
371 
372 //---------------------------------------------------------------------------
373 //
374 // PROC M_ForceUppercase
375 //
376 // Change string to uppercase.
377 //
378 //---------------------------------------------------------------------------
379 
M_ForceUppercase(char * text)380 void M_ForceUppercase(char *text)
381 {
382 	char c;
383 
384 	while((c = *text) != 0)
385 	{
386 		if(c >= 'a' && c <= 'z')
387 		{
388 			*text++ = c-('a'-'A');
389 		}
390 		else
391 		{
392 			text++;
393 		}
394 	}
395 }
396 
397 /*
398 ==============================================================================
399 
400 							DEFAULTS
401 
402 ==============================================================================
403 */
404 
405 int     usemouse;
406 int     usejoystick;
407 
408 extern int key_right, key_left, key_up, key_down;
409 extern int key_strafeleft, key_straferight, key_jump;
410 extern int key_fire, key_use, key_strafe, key_speed;
411 extern int key_flyup, key_flydown, key_flycenter;
412 extern int key_lookup, key_lookdown, key_lookcenter;
413 extern int key_invleft, key_invright, key_useartifact;
414 
415 extern int speed_lock;
416 extern int mouse_scale_factor;
417 
418 extern int mousebfire;
419 extern int mousebstrafe;
420 extern int mousebforward;
421 extern int mousebjump;
422 
423 extern int joybfire;
424 extern int joybstrafe;
425 extern int joybuse;
426 extern int joybspeed;
427 extern int joybjump;
428 
429 extern boolean messageson;
430 
431 extern  int     viewwidth, viewheight;
432 
433 int mouseSensitivity;
434 
435 extern  int screenblocks;
436 
437 extern char *chat_macros[10];
438 
439 typedef struct
440 {
441 	char    *name;
442 	int     *location;
443 	intptr_t defaultvalue;
444 	int     scantranslate;      // PC scan code hack
445 	int     untranslated;       // lousy hack
446 } default_t;
447 
448 extern int snd_Channels;
449 
450 default_t defaults[] =
451 {
452 	{ "mouse_sensitivity", &mouseSensitivity, 5 },
453 
454 #ifndef __NeXT__
455 	{ "sfx_volume", &snd_MaxVolume, 10},
456 	{ "music_volume", &snd_MusicVolume, 10},
457 #endif
458 
459 	{ "key_right", &key_right, KEY_RIGHTARROW },
460 	{ "key_left", &key_left, KEY_LEFTARROW },
461 	{ "key_up", &key_up, KEY_UPARROW },
462 	{ "key_down", &key_down, KEY_DOWNARROW },
463 	{ "key_strafeleft", &key_strafeleft, KEY_HOME },
464 	{ "key_straferight", &key_straferight, KEY_PGUP },
465 	{ "key_jump", &key_jump, 'x'},
466 	{ "key_flyup", &key_flyup, 'w' },
467 	{ "key_flydown", &key_flydown, 's' },
468 	{ "key_flycenter", &key_flycenter, 'c' },
469 	{ "key_lookup", &key_lookup, 'q' },
470 	{ "key_lookdown", &key_lookdown, 'z' },
471 	{ "key_lookcenter", &key_lookcenter, 'a' },
472 	{ "key_invleft", &key_invleft, '[' },
473 	{ "key_invright", &key_invright, ']' },
474 	{ "key_useartifact", &key_useartifact, 13 },
475 
476 	{ "key_fire", &key_fire, ' ', 1 },
477 	{ "key_use", &key_use, KEY_RCTRL, 1 },
478 	{ "key_strafe", &key_strafe, KEY_RALT, 1 },
479 	{ "key_speed", &key_speed, KEY_RSHIFT, 1 },
480 
481 	{ "use_mouse", &usemouse, 1 },
482 	{ "mouseb_fire", &mousebfire, 0 },
483 	{ "mouseb_strafe", &mousebstrafe, 1 },
484 	{ "mouseb_forward", &mousebforward, 2 },
485 	{ "mouseb_jump", &mousebjump, -1 },
486 
487 	{ "use_joystick", &usejoystick, 0 },
488 	{ "joyb_fire", &joybfire, 0 },
489 	{ "joyb_strafe", &joybstrafe, 1 },
490 	{ "joyb_use", &joybuse, 3 },
491 	{ "joyb_speed", &joybspeed, 2 },
492 	{ "joyb_jump", &joybjump, -1 },
493 
494 	{ "screenblocks", &screenblocks, 10 },
495 
496 #ifndef __NeXT__
497 	{ "snd_channels", &snd_Channels, 3 },
498 #endif
499 
500 	{ "mouse_scale_factor", &mouse_scale_factor, 10 },
501 
502 	{ "usegamma", &usegamma, 0 },
503 
504 #define DEFAULT_SAVEPATH		"hexndata/"
505 
506 	{ "savedir", (int *) &SavePath, (intptr_t) DEFAULT_SAVEPATH },
507 
508 	{ "messageson", (int *) &messageson, 1 },
509         { "speed_lock", (int *) &speed_lock, 1 },
510 	{ "chatmacro0", (int *) &chat_macros[0], (intptr_t) HUSTR_CHATMACRO0 },
511 	{ "chatmacro1", (int *) &chat_macros[1], (intptr_t) HUSTR_CHATMACRO1 },
512 	{ "chatmacro2", (int *) &chat_macros[2], (intptr_t) HUSTR_CHATMACRO2 },
513 	{ "chatmacro3", (int *) &chat_macros[3], (intptr_t) HUSTR_CHATMACRO3 },
514 	{ "chatmacro4", (int *) &chat_macros[4], (intptr_t) HUSTR_CHATMACRO4 },
515 	{ "chatmacro5", (int *) &chat_macros[5], (intptr_t) HUSTR_CHATMACRO5 },
516 	{ "chatmacro6", (int *) &chat_macros[6], (intptr_t) HUSTR_CHATMACRO6 },
517 	{ "chatmacro7", (int *) &chat_macros[7], (intptr_t) HUSTR_CHATMACRO7 },
518 	{ "chatmacro8", (int *) &chat_macros[8], (intptr_t) HUSTR_CHATMACRO8 },
519 	{ "chatmacro9", (int *) &chat_macros[9], (intptr_t) HUSTR_CHATMACRO9 }
520 };
521 
522 int numdefaults;
523 char defaultfile[256];
524 
525 /*
526 ==============
527 =
528 = M_SaveDefaults
529 =
530 ==============
531 */
532 
M_SaveDefaults(void)533 void M_SaveDefaults (void)
534 {
535 	int     i,v;
536 	FILE    *f;
537 
538 	f = fopen (defaultfile, "w");
539 	if (!f)
540 		return;         // can't write the file, but don't complain
541 
542 	for (i=0 ; i<numdefaults ; i++)
543 	{
544 #ifdef __WATCOMC__
545 		if (defaults[i].scantranslate)
546 			defaults[i].location = &defaults[i].untranslated;
547 #endif
548 		if (defaults[i].defaultvalue > -0xfff
549 		  && defaults[i].defaultvalue < 0xfff)
550 		{
551 			v = *defaults[i].location;
552 			fprintf (f,"%s\t\t%i\n",defaults[i].name,v);
553 		} else {
554 			fprintf (f,"%s\t\t\"%s\"\n",defaults[i].name,
555 			  * (char **) (defaults[i].location));
556 		}
557 	}
558 
559 	fclose (f);
560 }
561 
562 //==========================================================================
563 //
564 // M_LoadDefaults
565 //
566 //==========================================================================
567 
568 extern byte scantokey[128];
569 
M_LoadDefaults(char * fileName)570 void M_LoadDefaults(char *fileName)
571 {
572 	int i;
573 	int len;
574 	FILE *f;
575 	char def[80];
576 	char strparm[100];
577 	char *newstring;
578 	int parm;
579 	boolean isstring;
580 
581 	// Set everything to base values
582 	numdefaults = sizeof(defaults)/sizeof(defaults[0]);
583 	for(i = 0; i < numdefaults; i++)
584 	{
585 		*defaults[i].location = defaults[i].defaultvalue;
586 	}
587 
588 	// Check for a custom config file
589 	i = M_CheckParm("-config");
590 	if(i && i < myargc-1)
591 	{
592 		strcpy(defaultfile, myargv[i+1]);
593 		ST_Message("config file: %s\n", defaultfile);
594 	}
595 	else if(cdrom)
596 	{
597 		sprintf(defaultfile, "/cdrom/hexndata/%s", fileName);
598 	}
599 	else
600 	{
601 	 //	strcpy(defaultfile, fileName);
602 	 /* XXX UNIX hack */
603 #ifndef MUSTDIE
604 	 char *home;
605 	 home=getenv("HOME");
606 	 if (!home) I_Error("M_LoadDefaults: cannot localte home dir!");
607 	 strcpy(defaultfile,home);
608 	 strcat(defaultfile,"/.hexenrc");
609 #else
610 	 strcpy(defaultfile,"HEXEN.RC");
611 #endif
612 	}
613 
614 	// Scan the config file
615 	f = fopen(defaultfile, "r");
616 	if(f)
617 	{
618 		while(!feof(f))
619 		{
620 			isstring = false;
621 			if(fscanf(f, "%79s %[^\n]\n", def, strparm) == 2)
622 			{
623 				if(strparm[0] == '"')
624 				{
625 					 // Get a string default
626 					 isstring = true;
627 					 len = strlen(strparm);
628 					 newstring = (char *)malloc(len);
629 					 if (newstring == NULL) I_Error("can't malloc newstring");
630 					 strparm[len-1] = 0;
631 					 strcpy(newstring, strparm+1);
632 				}
633 				else if(strparm[0] == '0' && strparm[1] == 'x')
634 				{
635 					sscanf(strparm+2, "%x", &parm);
636 				}
637 				else
638 				{
639 					sscanf(strparm, "%i", &parm);
640 				}
641 				for(i = 0; i < numdefaults; i++)
642 				{
643 					if(!strcmp(def, defaults[i].name))
644 					{
645 						if(!isstring)
646 						{
647 							*defaults[i].location = parm;
648 						}
649 						else
650 						{
651 							*defaults[i].location = (int)newstring;
652 						}
653 						break;
654 					}
655 				}
656 			}
657 		}
658 		fclose (f);
659 	}
660 
661 #ifdef __WATCOMC__
662 	// Translate the key scancodes
663 	for(i = 0; i < numdefaults; i++)
664 	{
665 		if(defaults[i].scantranslate)
666 		{
667 			parm = *defaults[i].location;
668 			defaults[i].untranslated = parm;
669 			*defaults[i].location = scantokey[parm];
670 		}
671 	}
672 #endif
673 }
674 
675 /*
676 ==============================================================================
677 
678 						SCREEN SHOTS
679 
680 ==============================================================================
681 */
682 
683 
684 typedef struct
685 {
686 	char    manufacturer;
687 	char    version;
688 	char    encoding;
689 	char    bits_per_pixel;
690 	unsigned short  xmin,ymin,xmax,ymax;
691 	unsigned short  hres,vres;
692 	unsigned char   palette[48];
693 	char    reserved;
694 	char    color_planes;
695 	unsigned short  bytes_per_line;
696 	unsigned short  palette_type;
697 	char    filler[58];
698 	unsigned char   data;           // unbounded
699 } pcx_t;
700 
701 /*
702 ==============
703 =
704 = WritePCXfile
705 =
706 ==============
707 */
708 
WritePCXfile(char * filename,byte * data,int width,int height,byte * palette)709 void WritePCXfile (char *filename, byte *data, int width, int height, byte *palette)
710 {
711 	int     i, length;
712 	pcx_t   *pcx;
713 	byte        *pack;
714 
715 	pcx = Z_Malloc (width*height*2+1000, PU_STATIC, NULL);
716 
717 	pcx->manufacturer = 0x0a;   // PCX id
718 	pcx->version = 5;           // 256 color
719 	pcx->encoding = 1;      // uncompressed
720 	pcx->bits_per_pixel = 8;        // 256 color
721 	pcx->xmin = 0;
722 	pcx->ymin = 0;
723 	pcx->xmax = SHORT(width-1);
724 	pcx->ymax = SHORT(height-1);
725 	pcx->hres = SHORT(width);
726 	pcx->vres = SHORT(height);
727 	memset (pcx->palette,0,sizeof(pcx->palette));
728 	pcx->color_planes = 1;      // chunky image
729 	pcx->bytes_per_line = SHORT(width);
730 	pcx->palette_type = SHORT(2);       // not a grey scale
731 	memset (pcx->filler,0,sizeof(pcx->filler));
732 
733 //
734 // pack the image
735 //
736 	pack = &pcx->data;
737 
738 	for (i=0 ; i<width*height ; i++)
739 		if ( (*data & 0xc0) != 0xc0)
740 			*pack++ = *data++;
741 		else
742 		{
743 			*pack++ = 0xc1;
744 			*pack++ = *data++;
745 		}
746 
747 //
748 // write the palette
749 //
750 	*pack++ = 0x0c; // palette ID byte
751 	for (i=0 ; i<768 ; i++)
752 		*pack++ = *palette++;
753 
754 //
755 // write output file
756 //
757 	length = pack - (byte *)pcx;
758 	M_WriteFile (filename, pcx, length);
759 
760 	Z_Free (pcx);
761 }
762 
763 
764 //==============================================================================
765 
766 /*
767 ==================
768 =
769 = M_ScreenShot
770 =
771 ==================
772 */
773 
M_ScreenShot(void)774 void M_ScreenShot (void)
775 {
776 	int     i;
777 	byte    *linear;
778 	char    lbmname[12];
779 	byte *pal;
780 
781 #ifdef _WATCOMC_
782 	extern  byte *pcscreen;
783 #endif
784 
785 #if 0
786     for gl
787     if (use_gl) return;
788 #endif
789 
790 //
791 // munge planar buffer to linear
792 //
793 #ifdef _WATCOMC_
794 	linear = pcscreen;
795 #else
796 	linear = screen;
797 #endif
798 //
799 // find a file name to save it to
800 //
801 	strcpy(lbmname,"HEXEN00.pcx");
802 
803 	for (i=0 ; i<=99 ; i++)
804 	{
805 		lbmname[5] = i/10 + '0';
806 		lbmname[6] = i%10 + '0';
807 		if (access(lbmname,0) == -1)
808 			break;  // file doesn't exist
809 	}
810 	if (i==100)
811 		I_Error ("M_ScreenShot: Couldn't create a PCX");
812 
813 //
814 // save the pcx file
815 //
816 #ifdef __WATCOMC__
817 	pal = (byte *)Z_Malloc(768, PU_STATIC, NULL);
818 	outp(0x3c7, 0);
819 	for(i = 0; i < 768; i++)
820 	{
821 		*(pal+i) = inp(0x3c9)<<2;
822 	}
823 #else
824 	pal = (byte *)W_CacheLumpName("PLAYPAL", PU_CACHE);
825 #endif
826 
827 	WritePCXfile (lbmname, linear, SCREENWIDTH, SCREENHEIGHT
828 		, pal);
829 
830 	P_SetMessage(&players[consoleplayer], "SCREEN SHOT", false);
831 #ifdef __WATCOMC__
832 	Z_Free(pal);
833 #endif
834 }
835