]> icculus.org git repositories - divverent/darkplaces.git/blob - common.c
-The mouse wheels now work in Windows (now button presses are detected event-based)
[divverent/darkplaces.git] / common.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // common.c -- misc functions used in client and server
21
22 #include <stdlib.h>
23 #include <fcntl.h>
24 #ifndef WIN32
25 #include <unistd.h>
26 #endif
27
28 #include "quakedef.h"
29
30 cvar_t registered = {0, "registered","0"};
31 cvar_t cmdline = {0, "cmdline","0"};
32
33 extern qboolean fs_modified;   // set true if using non-id files
34
35 char com_token[1024];
36 int com_argc;
37 const char **com_argv;
38
39 // LordHavoc: made commandline 1024 characters instead of 256
40 #define CMDLINE_LENGTH  1024
41 char com_cmdline[CMDLINE_LENGTH];
42
43 int gamemode;
44 char *gamename;
45 char *gamedirname;
46 char *gamescreenshotname;
47 char com_modname[MAX_OSPATH] = "";
48
49
50 /*
51 ============================================================================
52
53                                         BYTE ORDER FUNCTIONS
54
55 ============================================================================
56 */
57
58 short   ShortSwap (short l)
59 {
60         qbyte    b1,b2;
61
62         b1 = l&255;
63         b2 = (l>>8)&255;
64
65         return (b1<<8) + b2;
66 }
67
68 int    LongSwap (int l)
69 {
70         qbyte    b1,b2,b3,b4;
71
72         b1 = l&255;
73         b2 = (l>>8)&255;
74         b3 = (l>>16)&255;
75         b4 = (l>>24)&255;
76
77         return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
78 }
79
80 float FloatSwap (float f)
81 {
82         union
83         {
84                 float   f;
85                 qbyte    b[4];
86         } dat1, dat2;
87
88
89         dat1.f = f;
90         dat2.b[0] = dat1.b[3];
91         dat2.b[1] = dat1.b[2];
92         dat2.b[2] = dat1.b[1];
93         dat2.b[3] = dat1.b[0];
94         return dat2.f;
95 }
96
97
98 // Extract integers from buffers
99
100 unsigned int BuffBigLong (const qbyte *buffer)
101 {
102         return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
103 }
104
105 unsigned short BuffBigShort (const qbyte *buffer)
106 {
107         return (buffer[0] << 8) | buffer[1];
108 }
109
110 unsigned int BuffLittleLong (const qbyte *buffer)
111 {
112         return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
113 }
114
115 unsigned short BuffLittleShort (const qbyte *buffer)
116 {
117         return (buffer[1] << 8) | buffer[0];
118 }
119
120
121 /*
122 ==============================================================================
123
124                         MESSAGE IO FUNCTIONS
125
126 Handles byte ordering and avoids alignment errors
127 ==============================================================================
128 */
129
130 //
131 // writing functions
132 //
133
134 void MSG_WriteChar (sizebuf_t *sb, int c)
135 {
136         qbyte    *buf;
137
138         buf = SZ_GetSpace (sb, 1);
139         buf[0] = c;
140 }
141
142 void MSG_WriteByte (sizebuf_t *sb, int c)
143 {
144         qbyte    *buf;
145
146         buf = SZ_GetSpace (sb, 1);
147         buf[0] = c;
148 }
149
150 void MSG_WriteShort (sizebuf_t *sb, int c)
151 {
152         qbyte    *buf;
153
154         buf = SZ_GetSpace (sb, 2);
155         buf[0] = c&0xff;
156         buf[1] = c>>8;
157 }
158
159 void MSG_WriteLong (sizebuf_t *sb, int c)
160 {
161         qbyte    *buf;
162
163         buf = SZ_GetSpace (sb, 4);
164         buf[0] = c&0xff;
165         buf[1] = (c>>8)&0xff;
166         buf[2] = (c>>16)&0xff;
167         buf[3] = c>>24;
168 }
169
170 void MSG_WriteFloat (sizebuf_t *sb, float f)
171 {
172         union
173         {
174                 float   f;
175                 int     l;
176         } dat;
177
178
179         dat.f = f;
180         dat.l = LittleLong (dat.l);
181
182         SZ_Write (sb, &dat.l, 4);
183 }
184
185 void MSG_WriteString (sizebuf_t *sb, const char *s)
186 {
187         if (!s)
188                 SZ_Write (sb, "", 1);
189         else
190                 SZ_Write (sb, s, strlen(s)+1);
191 }
192
193 // used by server (always latest PROTOCOL_DARKPLACES)
194 void MSG_WriteDPCoord (sizebuf_t *sb, float f)
195 {
196         if (f >= 0)
197                 MSG_WriteShort (sb, (int)(f + 0.5f));
198         else
199                 MSG_WriteShort (sb, (int)(f - 0.5f));
200 }
201
202 void MSG_WritePreciseAngle (sizebuf_t *sb, float f)
203 {
204         if (f >= 0)
205                 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
206         else
207                 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535);
208 }
209
210 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
211 void MSG_WriteAngle (sizebuf_t *sb, float f)
212 {
213         if (f >= 0)
214                 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
215         else
216                 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) - 0.5f) & 255);
217 }
218
219 //
220 // reading functions
221 //
222 int msg_readcount;
223 qboolean msg_badread;
224
225 void MSG_BeginReading (void)
226 {
227         msg_readcount = 0;
228         msg_badread = false;
229 }
230
231 int MSG_ReadLittleShort (void)
232 {
233         if (msg_readcount+2 > net_message.cursize)
234         {
235                 msg_badread = true;
236                 return -1;
237         }
238         msg_readcount += 2;
239         return (short)(net_message.data[msg_readcount-2] | (net_message.data[msg_readcount-1]<<8));
240 }
241
242 int MSG_ReadBigShort (void)
243 {
244         if (msg_readcount+2 > net_message.cursize)
245         {
246                 msg_badread = true;
247                 return -1;
248         }
249         msg_readcount += 2;
250         return (short)((net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1]);
251 }
252
253 int MSG_ReadLittleLong (void)
254 {
255         if (msg_readcount+4 > net_message.cursize)
256         {
257                 msg_badread = true;
258                 return -1;
259         }
260         msg_readcount += 4;
261         return net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
262 }
263
264 int MSG_ReadBigLong (void)
265 {
266         if (msg_readcount+4 > net_message.cursize)
267         {
268                 msg_badread = true;
269                 return -1;
270         }
271         msg_readcount += 4;
272         return (net_message.data[msg_readcount-4]<<24) + (net_message.data[msg_readcount-3]<<16) + (net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1];
273 }
274
275 float MSG_ReadLittleFloat (void)
276 {
277         union
278         {
279                 float f;
280                 int l;
281         } dat;
282         if (msg_readcount+4 > net_message.cursize)
283         {
284                 msg_badread = true;
285                 return -1;
286         }
287         msg_readcount += 4;
288         dat.l = net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
289         return dat.f;
290 }
291
292 float MSG_ReadBigFloat (void)
293 {
294         union
295         {
296                 float f;
297                 int l;
298         } dat;
299         if (msg_readcount+4 > net_message.cursize)
300         {
301                 msg_badread = true;
302                 return -1;
303         }
304         msg_readcount += 4;
305         dat.l = (net_message.data[msg_readcount-4]<<24) | (net_message.data[msg_readcount-3]<<16) | (net_message.data[msg_readcount-2]<<8) | net_message.data[msg_readcount-1];
306         return dat.f;
307 }
308
309 char *MSG_ReadString (void)
310 {
311         static char string[2048];
312         int l,c;
313         for (l = 0;l < (int) sizeof(string) - 1 && (c = MSG_ReadChar()) != -1 && c != 0;l++)
314                 string[l] = c;
315         string[l] = 0;
316         return string;
317 }
318
319 int MSG_ReadBytes (int numbytes, unsigned char *out)
320 {
321         int l, c;
322         for (l = 0;l < numbytes && (c = MSG_ReadChar()) != -1;l++)
323                 out[l] = c;
324         return l;
325 }
326
327 // used by client
328 float MSG_ReadCoord (void)
329 {
330         if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
331                 return (signed short) MSG_ReadLittleShort();
332         else if (cl.protocol == PROTOCOL_DARKPLACES1)
333                 return MSG_ReadLittleFloat();
334         else
335                 return MSG_ReadLittleShort() * (1.0f/8.0f);
336 }
337
338
339 //===========================================================================
340
341 void SZ_Alloc (sizebuf_t *buf, int startsize, const char *name)
342 {
343         if (startsize < 256)
344                 startsize = 256;
345         buf->mempool = Mem_AllocPool(name);
346         buf->data = Mem_Alloc(buf->mempool, startsize);
347         buf->maxsize = startsize;
348         buf->cursize = 0;
349 }
350
351
352 void SZ_Free (sizebuf_t *buf)
353 {
354         Mem_FreePool(&buf->mempool);
355         buf->data = NULL;
356         buf->maxsize = 0;
357         buf->cursize = 0;
358 }
359
360 void SZ_Clear (sizebuf_t *buf)
361 {
362         buf->cursize = 0;
363 }
364
365 void *SZ_GetSpace (sizebuf_t *buf, int length)
366 {
367         void *data;
368
369         if (buf->cursize + length > buf->maxsize)
370         {
371                 if (!buf->allowoverflow)
372                         Host_Error ("SZ_GetSpace: overflow without allowoverflow set\n");
373
374                 if (length > buf->maxsize)
375                         Host_Error ("SZ_GetSpace: %i is > full buffer size\n", length);
376
377                 buf->overflowed = true;
378                 Con_Print("SZ_GetSpace: overflow\n");
379                 SZ_Clear (buf);
380         }
381
382         data = buf->data + buf->cursize;
383         buf->cursize += length;
384
385         return data;
386 }
387
388 void SZ_Write (sizebuf_t *buf, const void *data, int length)
389 {
390         memcpy (SZ_GetSpace(buf,length),data,length);
391 }
392
393 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
394 // attention, it has been eradicated from here, its only (former) use in
395 // all of darkplaces.
396
397 static char *hexchar = "0123456789ABCDEF";
398 void Com_HexDumpToConsole(const qbyte *data, int size)
399 {
400         int i, j, n;
401         char text[1024];
402         char *cur, *flushpointer;
403         const qbyte *d;
404         cur = text;
405         flushpointer = text + 512;
406         for (i = 0;i < size;)
407         {
408                 n = 16;
409                 if (n > size - i)
410                         n = size - i;
411                 d = data + i;
412                 // print offset
413                 *cur++ = hexchar[(i >> 12) & 15];
414                 *cur++ = hexchar[(i >>  8) & 15];
415                 *cur++ = hexchar[(i >>  4) & 15];
416                 *cur++ = hexchar[(i >>  0) & 15];
417                 *cur++ = ':';
418                 // print hex
419                 for (j = 0;j < 16;j++)
420                 {
421                         if (j < n)
422                         {
423                                 *cur++ = hexchar[(d[j] >> 4) & 15];
424                                 *cur++ = hexchar[(d[j] >> 0) & 15];
425                         }
426                         else
427                         {
428                                 *cur++ = ' ';
429                                 *cur++ = ' ';
430                         }
431                         if ((j & 3) == 0)
432                                 *cur++ = ' ';
433                 }
434                 // print text
435                 for (j = 0;j < 16;j++)
436                 {
437                         if (j < n)
438                         {
439                                 if (d[j] >= ' ' && d[j] <= 127)
440                                         *cur++ = d[j];
441                                 else
442                                         *cur++ = '.';
443                         }
444                         else
445                                 *cur++ = ' ';
446                 }
447                 *cur++ = '\n';
448                 i += n;
449                 if (cur >= flushpointer || i >= size)
450                 {
451                         *cur++ = 0;
452                         Con_Print(text);
453                         cur = text;
454                 }
455         }
456 }
457
458 void SZ_HexDumpToConsole(const sizebuf_t *buf)
459 {
460         Com_HexDumpToConsole(buf->data, buf->cursize);
461 }
462
463
464 //============================================================================
465
466
467 /*
468 ==============
469 COM_ParseToken
470
471 Parse a token out of a string
472 ==============
473 */
474 int COM_ParseToken(const char **datapointer, int returnnewline)
475 {
476         int len;
477         const char *data = *datapointer;
478
479         len = 0;
480         com_token[0] = 0;
481
482         if (!data)
483         {
484                 *datapointer = NULL;
485                 return false;
486         }
487
488 // skip whitespace
489 skipwhite:
490         for (;*data <= ' ' && (*data != '\n' || !returnnewline);data++)
491         {
492                 if (*data == 0)
493                 {
494                         // end of file
495                         *datapointer = NULL;
496                         return false;
497                 }
498         }
499
500         if (data[0] == '/' && data[1] == '/')
501         {
502                 // comment
503                 while (*data && *data != '\n')
504                         data++;
505                 goto skipwhite;
506         }
507         else if (data[0] == '/' && data[1] == '*')
508         {
509                 // comment
510                 data++;
511                 while (*data && (data[0] != '*' || data[1] != '/'))
512                         data++;
513                 data += 2;
514                 goto skipwhite;
515         }
516         else if (*data == '\"')
517         {
518                 // quoted string
519                 for (data++;*data != '\"';data++)
520                 {
521                         if (!*data || len >= (int)sizeof(com_token) - 1)
522                         {
523                                 com_token[0] = 0;
524                                 *datapointer = NULL;
525                                 return false;
526                         }
527                         com_token[len++] = *data;
528                 }
529                 com_token[len] = 0;
530                 *datapointer = data+1;
531                 return true;
532         }
533         else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == '\'' || *data == ':' || *data == ',' || *data == ';')
534         {
535                 // single character
536                 com_token[len++] = *data++;
537                 com_token[len] = 0;
538                 *datapointer = data;
539                 return true;
540         }
541         else
542         {
543                 // regular word
544                 for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != '\'' && *data != ':' && *data != ',' && *data != ';';data++)
545                 {
546                         if (len >= (int)sizeof(com_token) - 1)
547                         {
548                                 com_token[0] = 0;
549                                 *datapointer = NULL;
550                                 return false;
551                         }
552                         com_token[len++] = *data;
553                 }
554                 com_token[len] = 0;
555                 *datapointer = data;
556                 return true;
557         }
558 }
559
560 /*
561 ==============
562 COM_ParseTokenConsole
563
564 Parse a token out of a string, behaving like the qwcl console
565 ==============
566 */
567 int COM_ParseTokenConsole(const char **datapointer)
568 {
569         int len;
570         const char *data = *datapointer;
571
572         len = 0;
573         com_token[0] = 0;
574
575         if (!data)
576         {
577                 *datapointer = NULL;
578                 return false;
579         }
580
581 // skip whitespace
582 skipwhite:
583         for (;*data <= ' ';data++)
584         {
585                 if (*data == 0)
586                 {
587                         // end of file
588                         *datapointer = NULL;
589                         return false;
590                 }
591         }
592
593         if (*data == '/' && data[1] == '/')
594         {
595                 // comment
596                 while (*data && *data != '\n')
597                         data++;
598                 goto skipwhite;
599         }
600         else if (*data == '\"')
601         {
602                 // quoted string
603                 for (data++;*data != '\"';data++)
604                 {
605                         if (!*data || len >= (int)sizeof(com_token) - 1)
606                         {
607                                 com_token[0] = 0;
608                                 *datapointer = NULL;
609                                 return false;
610                         }
611                         com_token[len++] = *data;
612                 }
613                 com_token[len] = 0;
614                 *datapointer = data+1;
615                 return true;
616         }
617         else
618         {
619                 // regular word
620                 for (;*data > ' ';data++)
621                 {
622                         if (len >= (int)sizeof(com_token) - 1)
623                         {
624                                 com_token[0] = 0;
625                                 *datapointer = NULL;
626                                 return false;
627                         }
628                         com_token[len++] = *data;
629                 }
630                 com_token[len] = 0;
631                 *datapointer = data;
632                 return true;
633         }
634 }
635
636
637 /*
638 ================
639 COM_CheckParm
640
641 Returns the position (1 to argc-1) in the program's argument list
642 where the given parameter apears, or 0 if not present
643 ================
644 */
645 int COM_CheckParm (const char *parm)
646 {
647         int i;
648
649         for (i=1 ; i<com_argc ; i++)
650         {
651                 if (!com_argv[i])
652                         continue;               // NEXTSTEP sometimes clears appkit vars.
653                 if (!strcmp (parm,com_argv[i]))
654                         return i;
655         }
656
657         return 0;
658 }
659
660 /*
661 ================
662 COM_CheckRegistered
663
664 Looks for the pop.txt file and verifies it.
665 Sets the "registered" cvar.
666 Immediately exits out if an alternate game was attempted to be started without
667 being registered.
668 ================
669 */
670 void COM_CheckRegistered (void)
671 {
672         Cvar_Set ("cmdline", com_cmdline);
673
674         if (!FS_FileExists("gfx/pop.lmp"))
675         {
676                 if (fs_modified)
677                         Con_Print("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
678                 else
679                         Con_Print("Playing shareware version.\n");
680                 return;
681         }
682
683         Cvar_Set ("registered", "1");
684         Con_Print("Playing registered version.\n");
685 }
686
687
688 /*
689 ================
690 COM_InitArgv
691 ================
692 */
693 void COM_InitArgv (void)
694 {
695         int i, j, n;
696         // reconstitute the command line for the cmdline externally visible cvar
697         n = 0;
698         for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
699         {
700                 i = 0;
701                 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
702                         com_cmdline[n++] = com_argv[j][i++];
703                 if (n < (CMDLINE_LENGTH - 1))
704                         com_cmdline[n++] = ' ';
705                 else
706                         break;
707         }
708         com_cmdline[n] = 0;
709 }
710
711 void COM_InitGameType (void)
712 {
713         char name[MAX_OSPATH];
714         FS_StripExtension (com_argv[0], name, sizeof (name));
715         COM_ToLowerString (name, name, sizeof (name));
716
717         if (strstr(name, "transfusion"))
718                 gamemode = GAME_TRANSFUSION;
719         else if (strstr(name, "nexuiz"))
720                 gamemode = GAME_NEXUIZ;
721         else if (strstr(name, "nehahra"))
722                 gamemode = GAME_NEHAHRA;
723         else if (strstr(name, "hipnotic"))
724                 gamemode = GAME_HIPNOTIC;
725         else if (strstr(name, "rogue"))
726                 gamemode = GAME_ROGUE;
727         else if (strstr(name, "gvb2"))
728                 gamemode = GAME_GOODVSBAD2;
729         else if (strstr(name, "teu"))
730                 gamemode = GAME_TEU;
731         else if (strstr(name, "battlemech"))
732                 gamemode = GAME_BATTLEMECH;
733         else if (strstr(name, "zymotic"))
734                 gamemode = GAME_ZYMOTIC;
735         else if (strstr(name, "fniggium"))
736                 gamemode = GAME_FNIGGIUM;
737         else if (strstr(name, "setheral"))
738                 gamemode = GAME_SETHERAL;
739         else if (strstr(name, "som"))
740                 gamemode = GAME_SOM;
741         else if (strstr(name, "tenebrae"))
742                 gamemode = GAME_TENEBRAE;
743         else if (strstr(name, "neoteric"))
744                 gamemode = GAME_NEOTERIC;
745         else if (strstr(name, "openquartz"))
746                 gamemode = GAME_OPENQUARTZ;
747         else
748                 gamemode = GAME_NORMAL;
749
750         if (COM_CheckParm ("-transfusion"))
751                 gamemode = GAME_TRANSFUSION;
752         else if (COM_CheckParm ("-nexuiz"))
753                 gamemode = GAME_NEXUIZ;
754         else if (COM_CheckParm ("-nehahra"))
755                 gamemode = GAME_NEHAHRA;
756         else if (COM_CheckParm ("-hipnotic"))
757                 gamemode = GAME_HIPNOTIC;
758         else if (COM_CheckParm ("-rogue"))
759                 gamemode = GAME_ROGUE;
760         else if (COM_CheckParm ("-quake"))
761                 gamemode = GAME_NORMAL;
762         else if (COM_CheckParm ("-goodvsbad2"))
763                 gamemode = GAME_GOODVSBAD2;
764         else if (COM_CheckParm ("-teu"))
765                 gamemode = GAME_TEU;
766         else if (COM_CheckParm ("-battlemech"))
767                 gamemode = GAME_BATTLEMECH;
768         else if (COM_CheckParm ("-zymotic"))
769                 gamemode = GAME_ZYMOTIC;
770         else if (COM_CheckParm ("-fniggium"))
771                 gamemode = GAME_FNIGGIUM;
772         else if (COM_CheckParm ("-setheral"))
773                 gamemode = GAME_SETHERAL;
774         else if (COM_CheckParm ("-som"))
775                 gamemode = GAME_SOM;
776         else if (COM_CheckParm ("-tenebrae"))
777                 gamemode = GAME_TENEBRAE;
778         else if (COM_CheckParm ("-neoteric"))
779                 gamemode = GAME_NEOTERIC;
780         else if (COM_CheckParm ("-openquartz"))
781                 gamemode = GAME_OPENQUARTZ;
782
783         switch(gamemode)
784         {
785         case GAME_NORMAL:
786                 gamename = "DarkPlaces-Quake";
787                 gamedirname = "";
788                 gamescreenshotname = "dp";
789                 break;
790         case GAME_HIPNOTIC:
791                 gamename = "Darkplaces-Hipnotic";
792                 gamedirname = "hipnotic";
793                 gamescreenshotname = "dp";
794                 break;
795         case GAME_ROGUE:
796                 gamename = "Darkplaces-Rogue";
797                 gamedirname = "rogue";
798                 gamescreenshotname = "dp";
799                 break;
800         case GAME_NEHAHRA:
801                 gamename = "DarkPlaces-Nehahra";
802                 gamedirname = "nehahra";
803                 gamescreenshotname = "dp";
804                 break;
805         case GAME_NEXUIZ:
806                 gamename = "Nexuiz";
807                 gamedirname = "data";
808                 gamescreenshotname = "nexuiz";
809                 break;
810         case GAME_TRANSFUSION:
811                 gamename = "Transfusion";
812                 gamedirname = "basetf";
813                 gamescreenshotname = "transfusion";
814                 break;
815         case GAME_GOODVSBAD2:
816                 gamename = "GoodVs.Bad2";
817                 gamedirname = "rts";
818                 gamescreenshotname = "gvb2";
819                 break;
820         case GAME_TEU:
821                 gamename = "TheEvilUnleashed";
822                 gamedirname = "baseteu";
823                 gamescreenshotname = "teu";
824                 break;
825         case GAME_BATTLEMECH:
826                 gamename = "Battlemech";
827                 gamedirname = "base";
828                 gamescreenshotname = "battlemech";
829                 break;
830         case GAME_ZYMOTIC:
831                 gamename = "Zymotic";
832                 gamedirname = "data";
833                 gamescreenshotname = "zymotic";
834                 break;
835         case GAME_FNIGGIUM:
836                 gamename = "Fniggium";
837                 gamedirname = "data";
838                 gamescreenshotname = "fniggium";
839                 break;
840         case GAME_SETHERAL:
841                 gamename = "Setheral";
842                 gamedirname = "data";
843                 gamescreenshotname = "setheral";
844                 break;
845         case GAME_SOM:
846                 gamename = "Son of Man";
847                 gamedirname = "sonofman";
848                 gamescreenshotname = "som";
849                 break;
850         case GAME_TENEBRAE:
851                 gamename = "DarkPlaces-Tenebrae";
852                 gamedirname = "tenebrae";
853                 gamescreenshotname = "dp";
854                 break;
855         case GAME_NEOTERIC:
856                 gamename = "Neoteric";
857                 gamedirname = "neobase";
858                 gamescreenshotname = "neo";
859                 break;
860         case GAME_OPENQUARTZ:
861                 gamename = "OpenQuartz";
862                 gamedirname = "id1";
863                 gamescreenshotname = "openquartz";
864                 break;
865         default:
866                 Sys_Error("COM_InitGameType: unknown gamemode %i\n", gamemode);
867                 break;
868         }
869 }
870
871
872 extern void Mathlib_Init(void);
873 extern void FS_Init (void);
874
875 /*
876 ================
877 COM_Init
878 ================
879 */
880 void COM_Init (void)
881 {
882         Cvar_RegisterVariable (&registered);
883         Cvar_RegisterVariable (&cmdline);
884
885         Mathlib_Init();
886
887         FS_Init ();
888         Log_Init ();
889         COM_CheckRegistered ();
890 }
891
892
893 /*
894 ============
895 va
896
897 does a varargs printf into a temp buffer, so I don't need to have
898 varargs versions of all text functions.
899 FIXME: make this buffer size safe someday
900 ============
901 */
902 char *va(const char *format, ...)
903 {
904         va_list argptr;
905         // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
906         static char string[8][1024], *s;
907         static int stringindex = 0;
908
909         s = string[stringindex];
910         stringindex = (stringindex + 1) & 7;
911         va_start (argptr, format);
912         vsnprintf (s, sizeof (string[0]), format,argptr);
913         va_end (argptr);
914
915         return s;
916 }
917
918
919 //======================================
920
921 void COM_ToLowerString (const char *in, char *out, size_t size_out)
922 {
923         if (size_out == 0)
924                 return;
925
926         while (*in && size_out > 1)
927         {
928                 if (*in >= 'A' && *in <= 'Z')
929                         *out++ = *in++ + 'a' - 'A';
930                 else
931                         *out++ = *in++;
932                 size_out--;
933         }
934         *out = '\0';
935 }
936
937 void COM_ToUpperString (const char *in, char *out, size_t size_out)
938 {
939         if (size_out == 0)
940                 return;
941
942         while (*in && size_out > 1)
943         {
944                 if (*in >= 'a' && *in <= 'z')
945                         *out++ = *in++ + 'A' - 'a';
946                 else
947                         *out++ = *in++;
948                 size_out--;
949         }
950         *out = '\0';
951 }
952
953 int COM_StringBeginsWith(const char *s, const char *match)
954 {
955         for (;*s && *match;s++, match++)
956                 if (*s != *match)
957                         return false;
958         return true;
959 }
960
961 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
962 {
963         int argc, commentprefixlength;
964         char *tokenbufend;
965         const char *l;
966         argc = 0;
967         tokenbufend = tokenbuf + tokenbufsize;
968         l = *text;
969         commentprefixlength = 0;
970         if (commentprefix)
971                 commentprefixlength = strlen(commentprefix);
972         while (*l && *l != '\n')
973         {
974                 if (*l > ' ')
975                 {
976                         if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
977                         {
978                                 while (*l && *l != '\n')
979                                         l++;
980                                 break;
981                         }
982                         if (argc >= maxargc)
983                                 return -1;
984                         argv[argc++] = tokenbuf;
985                         if (*l == '"')
986                         {
987                                 l++;
988                                 while (*l && *l != '"')
989                                 {
990                                         if (tokenbuf >= tokenbufend)
991                                                 return -1;
992                                         *tokenbuf++ = *l++;
993                                 }
994                                 if (*l == '"')
995                                         l++;
996                         }
997                         else
998                         {
999                                 while (*l > ' ')
1000                                 {
1001                                         if (tokenbuf >= tokenbufend)
1002                                                 return -1;
1003                                         *tokenbuf++ = *l++;
1004                                 }
1005                         }
1006                         if (tokenbuf >= tokenbufend)
1007                                 return -1;
1008                         *tokenbuf++ = 0;
1009                 }
1010                 else
1011                         l++;
1012         }
1013         if (*l == '\n')
1014                 l++;
1015         *text = l;
1016         return argc;
1017 }
1018
1019 // written by Elric, thanks Elric!
1020 char *SearchInfostring(const char *infostring, const char *key)
1021 {
1022         static char value [256];
1023         char crt_key [256];
1024         size_t value_ind, key_ind;
1025         char c;
1026
1027         if (*infostring++ != '\\')
1028                 return NULL;
1029
1030         value_ind = 0;
1031         for (;;)
1032         {
1033                 key_ind = 0;
1034
1035                 // Get the key name
1036                 for (;;)
1037                 {
1038                         c = *infostring++;
1039
1040                         if (c == '\0')
1041                                 return NULL;
1042                         if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1043                         {
1044                                 crt_key[key_ind] = '\0';
1045                                 break;
1046                         }
1047
1048                         crt_key[key_ind++] = c;
1049                 }
1050
1051                 // If it's the key we are looking for, save it in "value"
1052                 if (!strcmp(crt_key, key))
1053                 {
1054                         for (;;)
1055                         {
1056                                 c = *infostring++;
1057
1058                                 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1059                                 {
1060                                         value[value_ind] = '\0';
1061                                         return value;
1062                                 }
1063
1064                                 value[value_ind++] = c;
1065                         }
1066                 }
1067
1068                 // Else, skip the value
1069                 for (;;)
1070                 {
1071                         c = *infostring++;
1072
1073                         if (c == '\0')
1074                                 return NULL;
1075                         if (c == '\\')
1076                                 break;
1077                 }
1078         }
1079 }
1080
1081
1082 //========================================================
1083 // strlcat and strlcpy, from OpenBSD
1084
1085 /*
1086  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1087  *
1088  * Permission to use, copy, modify, and distribute this software for any
1089  * purpose with or without fee is hereby granted, provided that the above
1090  * copyright notice and this permission notice appear in all copies.
1091  *
1092  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1093  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1094  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1095  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1096  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1097  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1098  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1099  */
1100
1101 /*      $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $    */
1102 /*      $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $     */
1103
1104
1105 #ifndef HAVE_STRLCAT
1106 size_t
1107 strlcat(char *dst, const char *src, size_t siz)
1108 {
1109         register char *d = dst;
1110         register const char *s = src;
1111         register size_t n = siz;
1112         size_t dlen;
1113
1114         /* Find the end of dst and adjust bytes left but don't go past end */
1115         while (n-- != 0 && *d != '\0')
1116                 d++;
1117         dlen = d - dst;
1118         n = siz - dlen;
1119
1120         if (n == 0)
1121                 return(dlen + strlen(s));
1122         while (*s != '\0') {
1123                 if (n != 1) {
1124                         *d++ = *s;
1125                         n--;
1126                 }
1127                 s++;
1128         }
1129         *d = '\0';
1130
1131         return(dlen + (s - src));       /* count does not include NUL */
1132 }
1133 #endif  // #ifndef HAVE_STRLCAT
1134
1135
1136 #ifndef HAVE_STRLCPY
1137 size_t
1138 strlcpy(char *dst, const char *src, size_t siz)
1139 {
1140         register char *d = dst;
1141         register const char *s = src;
1142         register size_t n = siz;
1143
1144         /* Copy as many bytes as will fit */
1145         if (n != 0 && --n != 0) {
1146                 do {
1147                         if ((*d++ = *s++) == 0)
1148                                 break;
1149                 } while (--n != 0);
1150         }
1151
1152         /* Not enough room in dst, add NUL and traverse rest of src */
1153         if (n == 0) {
1154                 if (siz != 0)
1155                         *d = '\0';              /* NUL-terminate dst */
1156                 while (*s++)
1157                         ;
1158         }
1159
1160         return(s - src - 1);    /* count does not include NUL */
1161 }
1162
1163 #endif  // #ifndef HAVE_STRLCPY