upgraded network protocol to DP5, now sends precise entity angles (except for EF_LOWP...
[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 client
357 float MSG_ReadCoord (void)
358 {
359         if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
360                 return (signed short) MSG_ReadLittleShort();
361         else if (cl.protocol == PROTOCOL_DARKPLACES1)
362                 return MSG_ReadLittleFloat();
363         else
364                 return MSG_ReadLittleShort() * (1.0f/8.0f);
365 }
366
367
368 //===========================================================================
369
370 void SZ_Alloc (sizebuf_t *buf, int startsize, const char *name)
371 {
372         if (startsize < 256)
373                 startsize = 256;
374         buf->mempool = Mem_AllocPool(name);
375         buf->data = Mem_Alloc(buf->mempool, startsize);
376         buf->maxsize = startsize;
377         buf->cursize = 0;
378 }
379
380
381 void SZ_Free (sizebuf_t *buf)
382 {
383         Mem_FreePool(&buf->mempool);
384         buf->data = NULL;
385         buf->maxsize = 0;
386         buf->cursize = 0;
387 }
388
389 void SZ_Clear (sizebuf_t *buf)
390 {
391         buf->cursize = 0;
392 }
393
394 void *SZ_GetSpace (sizebuf_t *buf, int length)
395 {
396         void *data;
397
398         if (buf->cursize + length > buf->maxsize)
399         {
400                 if (!buf->allowoverflow)
401                         Host_Error ("SZ_GetSpace: overflow without allowoverflow set\n");
402
403                 if (length > buf->maxsize)
404                         Host_Error ("SZ_GetSpace: %i is > full buffer size\n", length);
405
406                 buf->overflowed = true;
407                 Con_Printf ("SZ_GetSpace: overflow\n");
408                 SZ_Clear (buf);
409         }
410
411         data = buf->data + buf->cursize;
412         buf->cursize += length;
413
414         return data;
415 }
416
417 void SZ_Write (sizebuf_t *buf, const void *data, int length)
418 {
419         memcpy (SZ_GetSpace(buf,length),data,length);
420 }
421
422 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
423 // attention, it has been eradicated from here, its only (former) use in
424 // all of darkplaces.
425
426 static char *hexchar = "0123456789ABCDEF";
427 void Com_HexDumpToConsole(const qbyte *data, int size)
428 {
429         int i, j, n;
430         char text[1024];
431         char *cur, *flushpointer;
432         const qbyte *d;
433         cur = text;
434         flushpointer = text + 512;
435         for (i = 0;i < size;)
436         {
437                 n = 16;
438                 if (n > size - i)
439                         n = size - i;
440                 d = data + i;
441                 *cur++ = hexchar[(i >> 12) & 15];
442                 *cur++ = hexchar[(i >>  8) & 15];
443                 *cur++ = hexchar[(i >>  4) & 15];
444                 *cur++ = hexchar[(i >>  0) & 15];
445                 *cur++ = ':';
446                 for (j = 0;j < n;j++)
447                 {
448                         if (j & 1)
449                         {
450                                 *cur++ = hexchar[(d[j] >> 4) & 15] | 0x80;
451                                 *cur++ = hexchar[(d[j] >> 0) & 15] | 0x80;
452                         }
453                         else
454                         {
455                                 *cur++ = hexchar[(d[j] >> 4) & 15];
456                                 *cur++ = hexchar[(d[j] >> 0) & 15];
457                         }
458                 }
459                 for (;j < 16;j++)
460                 {
461                         *cur++ = ' ';
462                         *cur++ = ' ';
463                 }
464                 for (j = 0;j < n;j++)
465                         *cur++ = (d[j] >= ' ' && d[j] <= 0x7E) ? d[j] : '.';
466                 for (;j < 16;j++)
467                         *cur++ = ' ';
468                 *cur++ = '\n';
469                 i += n;
470                 if (cur >= flushpointer || i >= size)
471                 {
472                         *cur++ = 0;
473                         Con_Printf("%s", text);
474                         cur = text;
475                 }
476         }
477 }
478
479 void SZ_HexDumpToConsole(const sizebuf_t *buf)
480 {
481         Com_HexDumpToConsole(buf->data, buf->cursize);
482 }
483
484
485 //============================================================================
486
487
488 /*
489 ==============
490 COM_ParseToken
491
492 Parse a token out of a string
493 ==============
494 */
495 int COM_ParseToken(const char **datapointer, int returnnewline)
496 {
497         int len;
498         const char *data = *datapointer;
499
500         len = 0;
501         com_token[0] = 0;
502
503         if (!data)
504         {
505                 *datapointer = NULL;
506                 return false;
507         }
508
509 // skip whitespace
510 skipwhite:
511         for (;*data <= ' ' && (*data != '\n' || !returnnewline);data++)
512         {
513                 if (*data == 0)
514                 {
515                         // end of file
516                         *datapointer = NULL;
517                         return false;
518                 }
519         }
520
521         if (data[0] == '/' && data[1] == '/')
522         {
523                 // comment
524                 while (*data && *data != '\n')
525                         data++;
526                 goto skipwhite;
527         }
528         else if (data[0] == '/' && data[1] == '*')
529         {
530                 // comment
531                 data++;
532                 while (*data && (data[0] != '*' || data[1] != '/'))
533                         data++;
534                 data += 2;
535                 goto skipwhite;
536         }
537         else if (*data == '\"')
538         {
539                 // quoted string
540                 for (data++;*data != '\"';data++)
541                 {
542                         if (!*data || len >= (int)sizeof(com_token) - 1)
543                         {
544                                 com_token[0] = 0;
545                                 *datapointer = NULL;
546                                 return false;
547                         }
548                         com_token[len++] = *data;
549                 }
550                 com_token[len] = 0;
551                 *datapointer = data+1;
552                 return true;
553         }
554         else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == '\'' || *data == ':' || *data == ',' || *data == ';')
555         {
556                 // single character
557                 com_token[len++] = *data++;
558                 com_token[len] = 0;
559                 *datapointer = data;
560                 return true;
561         }
562         else
563         {
564                 // regular word
565                 for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != '\'' && *data != ':' && *data != ',' && *data != ';';data++)
566                 {
567                         if (len >= (int)sizeof(com_token) - 1)
568                         {
569                                 com_token[0] = 0;
570                                 *datapointer = NULL;
571                                 return false;
572                         }
573                         com_token[len++] = *data;
574                 }
575                 com_token[len] = 0;
576                 *datapointer = data;
577                 return true;
578         }
579 }
580
581 /*
582 ==============
583 COM_ParseTokenConsole
584
585 Parse a token out of a string, behaving like the qwcl console
586 ==============
587 */
588 int COM_ParseTokenConsole(const char **datapointer)
589 {
590         int len;
591         const char *data = *datapointer;
592
593         len = 0;
594         com_token[0] = 0;
595
596         if (!data)
597         {
598                 *datapointer = NULL;
599                 return false;
600         }
601
602 // skip whitespace
603 skipwhite:
604         for (;*data <= ' ';data++)
605         {
606                 if (*data == 0)
607                 {
608                         // end of file
609                         *datapointer = NULL;
610                         return false;
611                 }
612         }
613
614         if (*data == '/' && data[1] == '/')
615         {
616                 // comment
617                 while (*data && *data != '\n')
618                         data++;
619                 goto skipwhite;
620         }
621         else if (*data == '\"')
622         {
623                 // quoted string
624                 for (data++;*data != '\"';data++)
625                 {
626                         if (!*data || len >= (int)sizeof(com_token) - 1)
627                         {
628                                 com_token[0] = 0;
629                                 *datapointer = NULL;
630                                 return false;
631                         }
632                         com_token[len++] = *data;
633                 }
634                 com_token[len] = 0;
635                 *datapointer = data+1;
636                 return true;
637         }
638         else
639         {
640                 // regular word
641                 for (;*data > ' ';data++)
642                 {
643                         if (len >= (int)sizeof(com_token) - 1)
644                         {
645                                 com_token[0] = 0;
646                                 *datapointer = NULL;
647                                 return false;
648                         }
649                         com_token[len++] = *data;
650                 }
651                 com_token[len] = 0;
652                 *datapointer = data;
653                 return true;
654         }
655 }
656
657
658 /*
659 ================
660 COM_CheckParm
661
662 Returns the position (1 to argc-1) in the program's argument list
663 where the given parameter apears, or 0 if not present
664 ================
665 */
666 int COM_CheckParm (const char *parm)
667 {
668         int i;
669
670         for (i=1 ; i<com_argc ; i++)
671         {
672                 if (!com_argv[i])
673                         continue;               // NEXTSTEP sometimes clears appkit vars.
674                 if (!strcmp (parm,com_argv[i]))
675                         return i;
676         }
677
678         return 0;
679 }
680
681 /*
682 ================
683 COM_CheckRegistered
684
685 Looks for the pop.txt file and verifies it.
686 Sets the "registered" cvar.
687 Immediately exits out if an alternate game was attempted to be started without
688 being registered.
689 ================
690 */
691 void COM_CheckRegistered (void)
692 {
693         Cvar_Set ("cmdline", com_cmdline);
694
695         if (!FS_FileExists("gfx/pop.lmp"))
696         {
697                 if (fs_modified)
698                         Con_Printf ("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
699                 else
700                         Con_Printf ("Playing shareware version.\n");
701                 return;
702         }
703
704         Cvar_Set ("registered", "1");
705         Con_Printf ("Playing registered version.\n");
706 }
707
708
709 /*
710 ================
711 COM_InitArgv
712 ================
713 */
714 void COM_InitArgv (void)
715 {
716         int i, j, n;
717         // reconstitute the command line for the cmdline externally visible cvar
718         n = 0;
719         for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
720         {
721                 i = 0;
722                 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
723                         com_cmdline[n++] = com_argv[j][i++];
724                 if (n < (CMDLINE_LENGTH - 1))
725                         com_cmdline[n++] = ' ';
726                 else
727                         break;
728         }
729         com_cmdline[n] = 0;
730 }
731
732 void COM_InitGameType (void)
733 {
734         char name[MAX_OSPATH];
735         FS_StripExtension (com_argv[0], name, sizeof (name));
736         COM_ToLowerString (name, name, sizeof (name));
737
738         if (strstr(name, "transfusion"))
739                 gamemode = GAME_TRANSFUSION;
740         else if (strstr(name, "nexuiz"))
741                 gamemode = GAME_NEXUIZ;
742         else if (strstr(name, "nehahra"))
743                 gamemode = GAME_NEHAHRA;
744         else if (strstr(name, "hipnotic"))
745                 gamemode = GAME_HIPNOTIC;
746         else if (strstr(name, "rogue"))
747                 gamemode = GAME_ROGUE;
748         else if (strstr(name, "gvb2"))
749                 gamemode = GAME_GOODVSBAD2;
750         else if (strstr(name, "teu"))
751                 gamemode = GAME_TEU;
752         else if (strstr(name, "battlemech"))
753                 gamemode = GAME_BATTLEMECH;
754         else if (strstr(name, "zymotic"))
755                 gamemode = GAME_ZYMOTIC;
756         else if (strstr(name, "fniggium"))
757                 gamemode = GAME_FNIGGIUM;
758         else if (strstr(name, "setheral"))
759                 gamemode = GAME_SETHERAL;
760         else if (strstr(name, "som"))
761                 gamemode = GAME_SOM;
762         else if (strstr(name, "tenebrae"))
763                 gamemode = GAME_TENEBRAE;
764         else
765                 gamemode = GAME_NORMAL;
766
767         if (COM_CheckParm ("-transfusion"))
768                 gamemode = GAME_TRANSFUSION;
769         else if (COM_CheckParm ("-nexuiz"))
770                 gamemode = GAME_NEXUIZ;
771         else if (COM_CheckParm ("-nehahra"))
772                 gamemode = GAME_NEHAHRA;
773         else if (COM_CheckParm ("-hipnotic"))
774                 gamemode = GAME_HIPNOTIC;
775         else if (COM_CheckParm ("-rogue"))
776                 gamemode = GAME_ROGUE;
777         else if (COM_CheckParm ("-quake"))
778                 gamemode = GAME_NORMAL;
779         else if (COM_CheckParm ("-goodvsbad2"))
780                 gamemode = GAME_GOODVSBAD2;
781         else if (COM_CheckParm ("-teu"))
782                 gamemode = GAME_TEU;
783         else if (COM_CheckParm ("-battlemech"))
784                 gamemode = GAME_BATTLEMECH;
785         else if (COM_CheckParm ("-zymotic"))
786                 gamemode = GAME_ZYMOTIC;
787         else if (COM_CheckParm ("-fniggium"))
788                 gamemode = GAME_FNIGGIUM;
789         else if (COM_CheckParm ("-setheral"))
790                 gamemode = GAME_SETHERAL;
791         else if (COM_CheckParm ("-som"))
792                 gamemode = GAME_SOM;
793         else if (COM_CheckParm ("-tenebrae"))
794                 gamemode = GAME_TENEBRAE;
795
796         switch(gamemode)
797         {
798         case GAME_NORMAL:
799                 gamename = "DarkPlaces-Quake";
800                 gamedirname = "";
801                 break;
802         case GAME_HIPNOTIC:
803                 gamename = "Darkplaces-Hipnotic";
804                 gamedirname = "hipnotic";
805                 break;
806         case GAME_ROGUE:
807                 gamename = "Darkplaces-Rogue";
808                 gamedirname = "rogue";
809                 break;
810         case GAME_NEHAHRA:
811                 gamename = "DarkPlaces-Nehahra";
812                 gamedirname = "nehahra";
813                 break;
814         case GAME_NEXUIZ:
815                 gamename = "Nexuiz";
816                 gamedirname = "data";
817                 break;
818         case GAME_TRANSFUSION:
819                 gamename = "Transfusion";
820                 gamedirname = "basetf";
821                 break;
822         case GAME_GOODVSBAD2:
823                 gamename = "GoodVs.Bad2";
824                 gamedirname = "rts";
825                 break;
826         case GAME_TEU:
827                 gamename = "TheEvilUnleashed";
828                 gamedirname = "baseteu";
829                 break;
830         case GAME_BATTLEMECH:
831                 gamename = "Battlemech";
832                 gamedirname = "base";
833                 break;
834         case GAME_ZYMOTIC:
835                 gamename = "Zymotic";
836                 gamedirname = "data";
837                 break;
838         case GAME_FNIGGIUM:
839                 gamename = "Fniggium";
840                 gamedirname = "data";
841                 break;
842         case GAME_SETHERAL:
843                 gamename = "Setheral";
844                 gamedirname = "data";
845                 break;
846         case GAME_SOM:
847                 gamename = "Son of Man";
848                 gamedirname = "data";
849                 break;
850         case GAME_TENEBRAE:
851                 gamename = "DarkPlaces-Tenebrae";
852                 gamedirname = "tenebrae";
853                 break;
854         default:
855                 Sys_Error("COM_InitGameType: unknown gamemode %i\n", gamemode);
856                 break;
857         }
858 }
859
860
861 extern void Mathlib_Init(void);
862 extern void FS_Init (void);
863
864 /*
865 ================
866 COM_Init
867 ================
868 */
869 void COM_Init (void)
870 {
871 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
872         qbyte swaptest[2] = {1,0};
873
874 // set the byte swapping variables in a portable manner
875         if ( *(short *)swaptest == 1)
876         {
877                 BigShort = ShortSwap;
878                 LittleShort = ShortNoSwap;
879                 BigLong = LongSwap;
880                 LittleLong = LongNoSwap;
881                 BigFloat = FloatSwap;
882                 LittleFloat = FloatNoSwap;
883         }
884         else
885         {
886                 BigShort = ShortNoSwap;
887                 LittleShort = ShortSwap;
888                 BigLong = LongNoSwap;
889                 LittleLong = LongSwap;
890                 BigFloat = FloatNoSwap;
891                 LittleFloat = FloatSwap;
892         }
893 #endif
894
895         Cvar_RegisterVariable (&registered);
896         Cvar_RegisterVariable (&cmdline);
897
898         Mathlib_Init();
899
900         FS_Init ();
901         Con_InitLogging();
902         COM_CheckRegistered ();
903
904         COM_InitGameType();
905 }
906
907
908 /*
909 ============
910 va
911
912 does a varargs printf into a temp buffer, so I don't need to have
913 varargs versions of all text functions.
914 FIXME: make this buffer size safe someday
915 ============
916 */
917 char *va(const char *format, ...)
918 {
919         va_list argptr;
920         // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
921         static char string[8][1024], *s;
922         static int stringindex = 0;
923
924         s = string[stringindex];
925         stringindex = (stringindex + 1) & 7;
926         va_start (argptr, format);
927         vsnprintf (s, sizeof (string[0]), format,argptr);
928         va_end (argptr);
929
930         return s;
931 }
932
933
934 //======================================
935
936 void COM_ToLowerString (const char *in, char *out, size_t size_out)
937 {
938         if (size_out == 0)
939                 return;
940
941         while (*in && size_out > 1)
942         {
943                 if (*in >= 'A' && *in <= 'Z')
944                         *out++ = *in++ + 'a' - 'A';
945                 else
946                         *out++ = *in++;
947                 size_out--;
948         }
949         *out = '\0';
950 }
951
952 void COM_ToUpperString (const char *in, char *out, size_t size_out)
953 {
954         if (size_out == 0)
955                 return;
956
957         while (*in && size_out > 1)
958         {
959                 if (*in >= 'a' && *in <= 'z')
960                         *out++ = *in++ + 'A' - 'a';
961                 else
962                         *out++ = *in++;
963                 size_out--;
964         }
965         *out = '\0';
966 }
967
968 int COM_StringBeginsWith(const char *s, const char *match)
969 {
970         for (;*s && *match;s++, match++)
971                 if (*s != *match)
972                         return false;
973         return true;
974 }
975
976 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
977 {
978         int argc, commentprefixlength;
979         char *tokenbufend;
980         const char *l;
981         argc = 0;
982         tokenbufend = tokenbuf + tokenbufsize;
983         l = *text;
984         commentprefixlength = 0;
985         if (commentprefix)
986                 commentprefixlength = strlen(commentprefix);
987         while (*l && *l != '\n')
988         {
989                 if (*l > ' ')
990                 {
991                         if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
992                         {
993                                 while (*l && *l != '\n')
994                                         l++;
995                                 break;
996                         }
997                         if (argc >= maxargc)
998                                 return -1;
999                         argv[argc++] = tokenbuf;
1000                         if (*l == '"')
1001                         {
1002                                 l++;
1003                                 while (*l && *l != '"')
1004                                 {
1005                                         if (tokenbuf >= tokenbufend)
1006                                                 return -1;
1007                                         *tokenbuf++ = *l++;
1008                                 }
1009                                 if (*l == '"')
1010                                         l++;
1011                         }
1012                         else
1013                         {
1014                                 while (*l > ' ')
1015                                 {
1016                                         if (tokenbuf >= tokenbufend)
1017                                                 return -1;
1018                                         *tokenbuf++ = *l++;
1019                                 }
1020                         }
1021                         if (tokenbuf >= tokenbufend)
1022                                 return -1;
1023                         *tokenbuf++ = 0;
1024                 }
1025                 else
1026                         l++;
1027         }
1028         if (*l == '\n')
1029                 l++;
1030         *text = l;
1031         return argc;
1032 }
1033
1034 // written by Elric, thanks Elric!
1035 char *SearchInfostring(const char *infostring, const char *key)
1036 {
1037         static char value [256];
1038         char crt_key [256];
1039         size_t value_ind, key_ind;
1040         char c;
1041
1042         if (*infostring++ != '\\')
1043                 return NULL;
1044
1045         value_ind = 0;
1046         for (;;)
1047         {
1048                 key_ind = 0;
1049
1050                 // Get the key name
1051                 for (;;)
1052                 {
1053                         c = *infostring++;
1054
1055                         if (c == '\0')
1056                                 return NULL;
1057                         if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1058                         {
1059                                 crt_key[key_ind] = '\0';
1060                                 break;
1061                         }
1062
1063                         crt_key[key_ind++] = c;
1064                 }
1065
1066                 // If it's the key we are looking for, save it in "value"
1067                 if (!strcmp(crt_key, key))
1068                 {
1069                         for (;;)
1070                         {
1071                                 c = *infostring++;
1072
1073                                 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1074                                 {
1075                                         value[value_ind] = '\0';
1076                                         return value;
1077                                 }
1078
1079                                 value[value_ind++] = c;
1080                         }
1081                 }
1082
1083                 // Else, skip the value
1084                 for (;;)
1085                 {
1086                         c = *infostring++;
1087
1088                         if (c == '\0')
1089                                 return NULL;
1090                         if (c == '\\')
1091                                 break;
1092                 }
1093         }
1094 }
1095
1096
1097 //========================================================
1098 // strlcat and strlcpy, from OpenBSD
1099
1100 /*
1101  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1102  *
1103  * Permission to use, copy, modify, and distribute this software for any
1104  * purpose with or without fee is hereby granted, provided that the above
1105  * copyright notice and this permission notice appear in all copies.
1106  *
1107  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1108  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1109  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1110  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1111  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1112  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1113  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1114  */
1115
1116 /*      $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $    */
1117 /*      $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $     */
1118
1119
1120 #ifndef HAVE_STRLCAT
1121 size_t
1122 strlcat(char *dst, const char *src, size_t siz)
1123 {
1124         register char *d = dst;
1125         register const char *s = src;
1126         register size_t n = siz;
1127         size_t dlen;
1128
1129         /* Find the end of dst and adjust bytes left but don't go past end */
1130         while (n-- != 0 && *d != '\0')
1131                 d++;
1132         dlen = d - dst;
1133         n = siz - dlen;
1134
1135         if (n == 0)
1136                 return(dlen + strlen(s));
1137         while (*s != '\0') {
1138                 if (n != 1) {
1139                         *d++ = *s;
1140                         n--;
1141                 }
1142                 s++;
1143         }
1144         *d = '\0';
1145
1146         return(dlen + (s - src));       /* count does not include NUL */
1147 }
1148 #endif  // #ifndef HAVE_STRLCAT
1149
1150
1151 #ifndef HAVE_STRLCPY
1152 size_t
1153 strlcpy(char *dst, const char *src, size_t siz)
1154 {
1155         register char *d = dst;
1156         register const char *s = src;
1157         register size_t n = siz;
1158
1159         /* Copy as many bytes as will fit */
1160         if (n != 0 && --n != 0) {
1161                 do {
1162                         if ((*d++ = *s++) == 0)
1163                                 break;
1164                 } while (--n != 0);
1165         }
1166
1167         /* Not enough room in dst, add NUL and traverse rest of src */
1168         if (n == 0) {
1169                 if (siz != 0)
1170                         *d = '\0';              /* NUL-terminate dst */
1171                 while (*s++)
1172                         ;
1173         }
1174
1175         return(s - src - 1);    /* count does not include NUL */
1176 }
1177
1178 #endif  // #ifndef HAVE_STRLCPY