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