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