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