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