Home | History | Annotate | Download | only in client
      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 <ctype.h>
     23 
     24 #ifdef SERVERONLY
     25 #include "qwsvdef.h"
     26 #else
     27 #include "quakedef.h"
     28 #endif
     29 
     30 #define MAX_NUM_ARGVS	50
     31 #define NUM_SAFE_ARGVS	6
     32 
     33 usercmd_t nullcmd; // guarenteed to be zero
     34 
     35 static char	*largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
     36 static char	*argvdummy = " ";
     37 
     38 static char	*safeargvs[NUM_SAFE_ARGVS] =
     39 	{"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse"};
     40 
     41 cvar_t	registered = CVAR2("registered","0");
     42 
     43 qboolean	com_modified;	// set true if using non-id files
     44 
     45 int		static_registered = 1;	// only for startup check, then set
     46 
     47 qboolean		msg_suppress_1 = 0;
     48 
     49 void COM_InitFilesystem (void);
     50 void COM_Path_f (void);
     51 
     52 
     53 // if a packfile directory differs from this, it is assumed to be hacked
     54 #define	PAK0_COUNT		339
     55 #define	PAK0_CRC		52883
     56 
     57 qboolean		standard_quake = true, rogue, hipnotic;
     58 
     59 char	gamedirfile[MAX_OSPATH];
     60 
     61 // this graphic needs to be in the pak file to use registered features
     62 unsigned short pop[] =
     63 {
     64  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
     65 ,0x0000,0x0000,0x6600,0x0000,0x0000,0x0000,0x6600,0x0000
     66 ,0x0000,0x0066,0x0000,0x0000,0x0000,0x0000,0x0067,0x0000
     67 ,0x0000,0x6665,0x0000,0x0000,0x0000,0x0000,0x0065,0x6600
     68 ,0x0063,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6563
     69 ,0x0064,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6564
     70 ,0x0064,0x6564,0x0000,0x6469,0x6969,0x6400,0x0064,0x6564
     71 ,0x0063,0x6568,0x6200,0x0064,0x6864,0x0000,0x6268,0x6563
     72 ,0x0000,0x6567,0x6963,0x0064,0x6764,0x0063,0x6967,0x6500
     73 ,0x0000,0x6266,0x6769,0x6a68,0x6768,0x6a69,0x6766,0x6200
     74 ,0x0000,0x0062,0x6566,0x6666,0x6666,0x6666,0x6562,0x0000
     75 ,0x0000,0x0000,0x0062,0x6364,0x6664,0x6362,0x0000,0x0000
     76 ,0x0000,0x0000,0x0000,0x0062,0x6662,0x0000,0x0000,0x0000
     77 ,0x0000,0x0000,0x0000,0x0061,0x6661,0x0000,0x0000,0x0000
     78 ,0x0000,0x0000,0x0000,0x0000,0x6500,0x0000,0x0000,0x0000
     79 ,0x0000,0x0000,0x0000,0x0000,0x6400,0x0000,0x0000,0x0000
     80 };
     81 
     82 /*
     83 
     84 
     85 All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources.
     86 
     87 The "base directory" is the path to the directory holding the quake.exe and all game directories.  The sys_* files pass this to host_init in quakeparms_t->basedir.  This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory.  The base directory is
     88 only used during filesystem initialization.
     89 
     90 The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to.  This can be overridden with the "-game" command line parameter.  The game directory can never be changed while quake is executing.  This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't.
     91 
     92 The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines.  If there is a cache directory
     93 specified, when a file is found by the normal search path, it will be mirrored
     94 into the cache directory, then opened there.
     95 
     96 */
     97 
     98 //============================================================================
     99 
    100 
    101 // ClearLink is used for new headnodes
    102 void ClearLink (link_t *l)
    103 {
    104 	l->prev = l->next = l;
    105 }
    106 
    107 void RemoveLink (link_t *l)
    108 {
    109 	l->next->prev = l->prev;
    110 	l->prev->next = l->next;
    111 }
    112 
    113 void InsertLinkBefore (link_t *l, link_t *before)
    114 {
    115 	l->next = before;
    116 	l->prev = before->prev;
    117 	l->prev->next = l;
    118 	l->next->prev = l;
    119 }
    120 void InsertLinkAfter (link_t *l, link_t *after)
    121 {
    122 	l->next = after->next;
    123 	l->prev = after;
    124 	l->prev->next = l;
    125 	l->next->prev = l;
    126 }
    127 
    128 /*
    129 ============================================================================
    130 
    131 					LIBRARY REPLACEMENT FUNCTIONS
    132 
    133 ============================================================================
    134 */
    135 
    136 #if 0
    137 void Q_memset (void *dest, int fill, int count)
    138 {
    139 	int		i;
    140 
    141 	if ( (((long)dest | count) & 3) == 0)
    142 	{
    143 		count >>= 2;
    144 		fill = fill | (fill<<8) | (fill<<16) | (fill<<24);
    145 		for (i=0 ; i<count ; i++)
    146 			((int *)dest)[i] = fill;
    147 	}
    148 	else
    149 		for (i=0 ; i<count ; i++)
    150 			((byte *)dest)[i] = fill;
    151 }
    152 
    153 void Q_memcpy (void *dest, void *src, int count)
    154 {
    155 	int		i;
    156 
    157 	if (( ( (long)dest | (long)src | count) & 3) == 0 )
    158 	{
    159 		count>>=2;
    160 		for (i=0 ; i<count ; i++)
    161 			((int *)dest)[i] = ((int *)src)[i];
    162 	}
    163 	else
    164 		for (i=0 ; i<count ; i++)
    165 			((byte *)dest)[i] = ((byte *)src)[i];
    166 }
    167 
    168 int Q_memcmp (void *m1, void *m2, int count)
    169 {
    170 	while(count)
    171 	{
    172 		count--;
    173 		if (((byte *)m1)[count] != ((byte *)m2)[count])
    174 			return -1;
    175 	}
    176 	return 0;
    177 }
    178 
    179 void Q_strcpy (char *dest, char *src)
    180 {
    181 	while (*src)
    182 	{
    183 		*dest++ = *src++;
    184 	}
    185 	*dest++ = 0;
    186 }
    187 
    188 void Q_strncpy (char *dest, char *src, int count)
    189 {
    190 	while (*src && count--)
    191 	{
    192 		*dest++ = *src++;
    193 	}
    194 	if (count)
    195 		*dest++ = 0;
    196 }
    197 
    198 int Q_strlen (char *str)
    199 {
    200 	int		count;
    201 
    202 	count = 0;
    203 	while (str[count])
    204 		count++;
    205 
    206 	return count;
    207 }
    208 
    209 char *Q_strrchr(char *s, char c)
    210 {
    211     int len = Q_strlen(s);
    212     s += len;
    213     while (len--)
    214         if (*--s == c) return s;
    215     return 0;
    216 }
    217 
    218 void Q_strcat (char *dest, char *src)
    219 {
    220 	dest += Q_strlen(dest);
    221 	Q_strcpy (dest, src);
    222 }
    223 
    224 int Q_strcmp (char *s1, char *s2)
    225 {
    226 	while (1)
    227 	{
    228 		if (*s1 != *s2)
    229 			return -1;		// strings not equal
    230 		if (!*s1)
    231 			return 0;		// strings are equal
    232 		s1++;
    233 		s2++;
    234 	}
    235 
    236 	return -1;
    237 }
    238 
    239 int Q_strncmp (char *s1, char *s2, int count)
    240 {
    241 	while (1)
    242 	{
    243 		if (!count--)
    244 			return 0;
    245 		if (*s1 != *s2)
    246 			return -1;		// strings not equal
    247 		if (!*s1)
    248 			return 0;		// strings are equal
    249 		s1++;
    250 		s2++;
    251 	}
    252 
    253 	return -1;
    254 }
    255 
    256 int Q_strncasecmp (char *s1, char *s2, int n)
    257 {
    258 	int		c1, c2;
    259 
    260 	while (1)
    261 	{
    262 		c1 = *s1++;
    263 		c2 = *s2++;
    264 
    265 		if (!n--)
    266 			return 0;		// strings are equal until end point
    267 
    268 		if (c1 != c2)
    269 		{
    270 			if (c1 >= 'a' && c1 <= 'z')
    271 				c1 -= ('a' - 'A');
    272 			if (c2 >= 'a' && c2 <= 'z')
    273 				c2 -= ('a' - 'A');
    274 			if (c1 != c2)
    275 				return -1;		// strings not equal
    276 		}
    277 		if (!c1)
    278 			return 0;		// strings are equal
    279 //		s1++;
    280 //		s2++;
    281 	}
    282 
    283 	return -1;
    284 }
    285 
    286 int Q_strcasecmp (char *s1, char *s2)
    287 {
    288 	return Q_strncasecmp (s1, s2, 99999);
    289 }
    290 
    291 #endif
    292 
    293 int Q_atoi (char *str)
    294 {
    295 	int		val;
    296 	int		sign;
    297 	int		c;
    298 
    299 	if (*str == '-')
    300 	{
    301 		sign = -1;
    302 		str++;
    303 	}
    304 	else
    305 		sign = 1;
    306 
    307 	val = 0;
    308 
    309 //
    310 // check for hex
    311 //
    312 	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
    313 	{
    314 		str += 2;
    315 		while (1)
    316 		{
    317 			c = *str++;
    318 			if (c >= '0' && c <= '9')
    319 				val = (val<<4) + c - '0';
    320 			else if (c >= 'a' && c <= 'f')
    321 				val = (val<<4) + c - 'a' + 10;
    322 			else if (c >= 'A' && c <= 'F')
    323 				val = (val<<4) + c - 'A' + 10;
    324 			else
    325 				return val*sign;
    326 		}
    327 	}
    328 
    329 //
    330 // check for character
    331 //
    332 	if (str[0] == '\'')
    333 	{
    334 		return sign * str[1];
    335 	}
    336 
    337 //
    338 // assume decimal
    339 //
    340 	while (1)
    341 	{
    342 		c = *str++;
    343 		if (c <'0' || c > '9')
    344 			return val*sign;
    345 		val = val*10 + c - '0';
    346 	}
    347 
    348 	return 0;
    349 }
    350 
    351 
    352 float Q_atof (char *str)
    353 {
    354 	double	val;
    355 	int		sign;
    356 	int		c;
    357 	int		decimal, total;
    358 
    359 	if (*str == '-')
    360 	{
    361 		sign = -1;
    362 		str++;
    363 	}
    364 	else
    365 		sign = 1;
    366 
    367 	val = 0;
    368 
    369 //
    370 // check for hex
    371 //
    372 	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
    373 	{
    374 		str += 2;
    375 		while (1)
    376 		{
    377 			c = *str++;
    378 			if (c >= '0' && c <= '9')
    379 				val = (val*16) + c - '0';
    380 			else if (c >= 'a' && c <= 'f')
    381 				val = (val*16) + c - 'a' + 10;
    382 			else if (c >= 'A' && c <= 'F')
    383 				val = (val*16) + c - 'A' + 10;
    384 			else
    385 				return val*sign;
    386 		}
    387 	}
    388 
    389 //
    390 // check for character
    391 //
    392 	if (str[0] == '\'')
    393 	{
    394 		return sign * str[1];
    395 	}
    396 
    397 //
    398 // assume decimal
    399 //
    400 	decimal = -1;
    401 	total = 0;
    402 	while (1)
    403 	{
    404 		c = *str++;
    405 		if (c == '.')
    406 		{
    407 			decimal = total;
    408 			continue;
    409 		}
    410 		if (c <'0' || c > '9')
    411 			break;
    412 		val = val*10 + c - '0';
    413 		total++;
    414 	}
    415 
    416 	if (decimal == -1)
    417 		return val*sign;
    418 	while (total > decimal)
    419 	{
    420 		val /= 10;
    421 		total--;
    422 	}
    423 
    424 	return val*sign;
    425 }
    426 
    427 /*
    428 ============================================================================
    429 
    430 					BYTE ORDER FUNCTIONS
    431 
    432 ============================================================================
    433 */
    434 
    435 qboolean	bigendien;
    436 
    437 short	(*BigShort) (short l);
    438 short	(*LittleShort) (short l);
    439 int	(*BigLong) (int l);
    440 int	(*LittleLong) (int l);
    441 float	(*BigFloat) (float l);
    442 float	(*LittleFloat) (float l);
    443 
    444 short   ShortSwap (short l)
    445 {
    446 	byte    b1,b2;
    447 
    448 	b1 = l&255;
    449 	b2 = (l>>8)&255;
    450 
    451 	return (b1<<8) + b2;
    452 }
    453 
    454 short	ShortNoSwap (short l)
    455 {
    456 	return l;
    457 }
    458 
    459 int    LongSwap (int l)
    460 {
    461 	byte    b1,b2,b3,b4;
    462 
    463 	b1 = l&255;
    464 	b2 = (l>>8)&255;
    465 	b3 = (l>>16)&255;
    466 	b4 = (l>>24)&255;
    467 
    468 	return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
    469 }
    470 
    471 int	LongNoSwap (int l)
    472 {
    473 	return l;
    474 }
    475 
    476 float FloatSwap (float f)
    477 {
    478 	union
    479 	{
    480 		float	f;
    481 		byte	b[4];
    482 	} dat1, dat2;
    483 
    484 
    485 	dat1.f = f;
    486 	dat2.b[0] = dat1.b[3];
    487 	dat2.b[1] = dat1.b[2];
    488 	dat2.b[2] = dat1.b[1];
    489 	dat2.b[3] = dat1.b[0];
    490 	return dat2.f;
    491 }
    492 
    493 float FloatNoSwap (float f)
    494 {
    495 	return f;
    496 }
    497 
    498 /*
    499 ==============================================================================
    500 
    501 			MESSAGE IO FUNCTIONS
    502 
    503 Handles byte ordering and avoids alignment errors
    504 ==============================================================================
    505 */
    506 
    507 //
    508 // writing functions
    509 //
    510 
    511 void MSG_WriteChar (sizebuf_t *sb, int c)
    512 {
    513 	byte	*buf;
    514 
    515 #ifdef PARANOID
    516 	if (c < -128 || c > 127)
    517 		Sys_Error ("MSG_WriteChar: range error");
    518 #endif
    519 
    520 	buf = SZ_GetSpace (sb, 1);
    521 	buf[0] = c;
    522 }
    523 
    524 void MSG_WriteByte (sizebuf_t *sb, int c)
    525 {
    526 	byte	*buf;
    527 
    528 #ifdef PARANOID
    529 	if (c < 0 || c > 255)
    530 		Sys_Error ("MSG_WriteByte: range error");
    531 #endif
    532 
    533 	buf = SZ_GetSpace (sb, 1);
    534 	buf[0] = c;
    535 }
    536 
    537 void MSG_WriteShort (sizebuf_t *sb, int c)
    538 {
    539 	byte	*buf;
    540 
    541 #ifdef PARANOID
    542 	if (c < ((short)0x8000) || c > (short)0x7fff)
    543 		Sys_Error ("MSG_WriteShort: range error");
    544 #endif
    545 
    546 	buf = SZ_GetSpace (sb, 2);
    547 	buf[0] = c&0xff;
    548 	buf[1] = c>>8;
    549 }
    550 
    551 void MSG_WriteLong (sizebuf_t *sb, int c)
    552 {
    553 	byte	*buf;
    554 
    555 	buf = SZ_GetSpace (sb, 4);
    556 	buf[0] = c&0xff;
    557 	buf[1] = (c>>8)&0xff;
    558 	buf[2] = (c>>16)&0xff;
    559 	buf[3] = c>>24;
    560 }
    561 
    562 void MSG_WriteFloat (sizebuf_t *sb, float f)
    563 {
    564 	union
    565 	{
    566 		float	f;
    567 		int	l;
    568 	} dat;
    569 
    570 
    571 	dat.f = f;
    572 	dat.l = LittleLong (dat.l);
    573 
    574 	SZ_Write (sb, &dat.l, 4);
    575 }
    576 
    577 void MSG_WriteString (sizebuf_t *sb, char *s)
    578 {
    579 	if (!s)
    580 		SZ_Write (sb, "", 1);
    581 	else
    582 		SZ_Write (sb, s, Q_strlen(s)+1);
    583 }
    584 
    585 void MSG_WriteCoord (sizebuf_t *sb, float f)
    586 {
    587 	MSG_WriteShort (sb, (int)(f*8));
    588 }
    589 
    590 void MSG_WriteAngle (sizebuf_t *sb, float f)
    591 {
    592 	MSG_WriteByte (sb, (int)(f*256/360) & 255);
    593 }
    594 
    595 void MSG_WriteAngle16 (sizebuf_t *sb, float f)
    596 {
    597 	MSG_WriteShort (sb, (int)(f*65536/360) & 65535);
    598 }
    599 
    600 void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd)
    601 {
    602 	int		bits;
    603 
    604 //
    605 // send the movement message
    606 //
    607 	bits = 0;
    608 	if (cmd->angles[0] != from->angles[0])
    609 		bits |= CM_ANGLE1;
    610 	if (cmd->angles[1] != from->angles[1])
    611 		bits |= CM_ANGLE2;
    612 	if (cmd->angles[2] != from->angles[2])
    613 		bits |= CM_ANGLE3;
    614 	if (cmd->forwardmove != from->forwardmove)
    615 		bits |= CM_FORWARD;
    616 	if (cmd->sidemove != from->sidemove)
    617 		bits |= CM_SIDE;
    618 	if (cmd->upmove != from->upmove)
    619 		bits |= CM_UP;
    620 	if (cmd->buttons != from->buttons)
    621 		bits |= CM_BUTTONS;
    622 	if (cmd->impulse != from->impulse)
    623 		bits |= CM_IMPULSE;
    624 
    625     MSG_WriteByte (buf, bits);
    626 
    627 	if (bits & CM_ANGLE1)
    628 		MSG_WriteAngle16 (buf, cmd->angles[0]);
    629 	if (bits & CM_ANGLE2)
    630 		MSG_WriteAngle16 (buf, cmd->angles[1]);
    631 	if (bits & CM_ANGLE3)
    632 		MSG_WriteAngle16 (buf, cmd->angles[2]);
    633 
    634 	if (bits & CM_FORWARD)
    635 		MSG_WriteShort (buf, cmd->forwardmove);
    636 	if (bits & CM_SIDE)
    637 	  	MSG_WriteShort (buf, cmd->sidemove);
    638 	if (bits & CM_UP)
    639 		MSG_WriteShort (buf, cmd->upmove);
    640 
    641  	if (bits & CM_BUTTONS)
    642 	  	MSG_WriteByte (buf, cmd->buttons);
    643  	if (bits & CM_IMPULSE)
    644 	    MSG_WriteByte (buf, cmd->impulse);
    645 	MSG_WriteByte (buf, cmd->msec);
    646 }
    647 
    648 
    649 //
    650 // reading functions
    651 //
    652 int			msg_readcount;
    653 qboolean	msg_badread;
    654 
    655 void MSG_BeginReading (void)
    656 {
    657 	msg_readcount = 0;
    658 	msg_badread = false;
    659 }
    660 
    661 int MSG_GetReadCount(void)
    662 {
    663 	return msg_readcount;
    664 }
    665 
    666 // returns -1 and sets msg_badread if no more characters are available
    667 int MSG_ReadChar (void)
    668 {
    669 	int	c;
    670 
    671 	if (msg_readcount+1 > net_message.cursize)
    672 	{
    673 		msg_badread = true;
    674 		return -1;
    675 	}
    676 
    677 	c = (signed char)net_message.data[msg_readcount];
    678 	msg_readcount++;
    679 
    680 	return c;
    681 }
    682 
    683 int MSG_ReadByte (void)
    684 {
    685 	int	c;
    686 
    687 	if (msg_readcount+1 > net_message.cursize)
    688 	{
    689 		msg_badread = true;
    690 		return -1;
    691 	}
    692 
    693 	c = (unsigned char)net_message.data[msg_readcount];
    694 	msg_readcount++;
    695 
    696 	return c;
    697 }
    698 
    699 int MSG_ReadShort (void)
    700 {
    701 	int	c;
    702 
    703 	if (msg_readcount+2 > net_message.cursize)
    704 	{
    705 		msg_badread = true;
    706 		return -1;
    707 	}
    708 
    709 	c = (short)(net_message.data[msg_readcount]
    710 	+ (net_message.data[msg_readcount+1]<<8));
    711 
    712 	msg_readcount += 2;
    713 
    714 	return c;
    715 }
    716 
    717 int MSG_ReadLong (void)
    718 {
    719 	int	c;
    720 
    721 	if (msg_readcount+4 > net_message.cursize)
    722 	{
    723 		msg_badread = true;
    724 		return -1;
    725 	}
    726 
    727 	c = net_message.data[msg_readcount]
    728 	+ (net_message.data[msg_readcount+1]<<8)
    729 	+ (net_message.data[msg_readcount+2]<<16)
    730 	+ (net_message.data[msg_readcount+3]<<24);
    731 
    732 	msg_readcount += 4;
    733 
    734 	return c;
    735 }
    736 
    737 float MSG_ReadFloat (void)
    738 {
    739 	union
    740 	{
    741 		byte	b[4];
    742 		float	f;
    743 		int	l;
    744 	} dat;
    745 
    746 	dat.b[0] =	net_message.data[msg_readcount];
    747 	dat.b[1] =	net_message.data[msg_readcount+1];
    748 	dat.b[2] =	net_message.data[msg_readcount+2];
    749 	dat.b[3] =	net_message.data[msg_readcount+3];
    750 	msg_readcount += 4;
    751 
    752 	dat.l = LittleLong (dat.l);
    753 
    754 	return dat.f;
    755 }
    756 
    757 char *MSG_ReadString (void)
    758 {
    759 	static char	string[2048];
    760 	int		l,c;
    761 
    762 	l = 0;
    763 	do
    764 	{
    765 		c = MSG_ReadChar ();
    766 		if (c == -1 || c == 0)
    767 			break;
    768 		string[l] = c;
    769 		l++;
    770 	} while (l < (int) sizeof(string)-1);
    771 
    772 	string[l] = 0;
    773 
    774 	return string;
    775 }
    776 
    777 char *MSG_ReadStringLine (void)
    778 {
    779 	static char	string[2048];
    780 	int		l,c;
    781 
    782 	l = 0;
    783 	do
    784 	{
    785 		c = MSG_ReadChar ();
    786 		if (c == -1 || c == 0 || c == '\n')
    787 			break;
    788 		string[l] = c;
    789 		l++;
    790 	} while (l < (int) sizeof(string)-1);
    791 
    792 	string[l] = 0;
    793 
    794 	return string;
    795 }
    796 
    797 float MSG_ReadCoord (void)
    798 {
    799 	return MSG_ReadShort() * (1.0/8);
    800 }
    801 
    802 float MSG_ReadAngle (void)
    803 {
    804 	return MSG_ReadChar() * (360.0/256);
    805 }
    806 
    807 float MSG_ReadAngle16 (void)
    808 {
    809 	return MSG_ReadShort() * (360.0/65536);
    810 }
    811 
    812 void MSG_ReadDeltaUsercmd (usercmd_t *from, usercmd_t *move)
    813 {
    814 	int bits;
    815 
    816 	memcpy (move, from, sizeof(*move));
    817 
    818 	bits = MSG_ReadByte ();
    819 
    820 // read current angles
    821 	if (bits & CM_ANGLE1)
    822 		move->angles[0] = MSG_ReadAngle16 ();
    823 	if (bits & CM_ANGLE2)
    824 		move->angles[1] = MSG_ReadAngle16 ();
    825 	if (bits & CM_ANGLE3)
    826 		move->angles[2] = MSG_ReadAngle16 ();
    827 
    828 // read movement
    829 	if (bits & CM_FORWARD)
    830 		move->forwardmove = MSG_ReadShort ();
    831 	if (bits & CM_SIDE)
    832 		move->sidemove = MSG_ReadShort ();
    833 	if (bits & CM_UP)
    834 		move->upmove = MSG_ReadShort ();
    835 
    836 // read buttons
    837 	if (bits & CM_BUTTONS)
    838 		move->buttons = MSG_ReadByte ();
    839 
    840 	if (bits & CM_IMPULSE)
    841 		move->impulse = MSG_ReadByte ();
    842 
    843 // read time to run command
    844 	move->msec = MSG_ReadByte ();
    845 }
    846 
    847 
    848 //===========================================================================
    849 
    850 void SZ_Clear (sizebuf_t *buf)
    851 {
    852 	buf->cursize = 0;
    853 	buf->overflowed = false;
    854 }
    855 
    856 void *SZ_GetSpace (sizebuf_t *buf, int length)
    857 {
    858 	void	*data;
    859 
    860 	if (buf->cursize + length > buf->maxsize)
    861 	{
    862 		if (!buf->allowoverflow)
    863 			Sys_Error ("SZ_GetSpace: overflow without allowoverflow set (%d)", buf->maxsize);
    864 
    865 		if (length > buf->maxsize)
    866 			Sys_Error ("SZ_GetSpace: %i is > full buffer size", length);
    867 
    868 		Sys_Printf ("SZ_GetSpace: overflow\n");	// because Con_Printf may be redirected
    869 		SZ_Clear (buf);
    870 		buf->overflowed = true;
    871 	}
    872 
    873 	data = buf->data + buf->cursize;
    874 	buf->cursize += length;
    875 
    876 	return data;
    877 }
    878 
    879 void SZ_Write (sizebuf_t *buf, void *data, int length)
    880 {
    881 	Q_memcpy (SZ_GetSpace(buf,length),data,length);
    882 }
    883 
    884 void SZ_Print (sizebuf_t *buf, char *data)
    885 {
    886 	int		len;
    887 
    888 	len = Q_strlen(data)+1;
    889 
    890 	if (!buf->cursize || buf->data[buf->cursize-1])
    891 		Q_memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
    892 	else
    893 		Q_memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
    894 }
    895 
    896 
    897 //============================================================================
    898 
    899 
    900 /*
    901 ============
    902 COM_SkipPath
    903 ============
    904 */
    905 char *COM_SkipPath (char *pathname)
    906 {
    907 	char	*last;
    908 
    909 	last = pathname;
    910 	while (*pathname)
    911 	{
    912 		if (*pathname=='/')
    913 			last = pathname+1;
    914 		pathname++;
    915 	}
    916 	return last;
    917 }
    918 
    919 /*
    920 ============
    921 COM_StripExtension
    922 ============
    923 */
    924 void COM_StripExtension (char *in, char *out)
    925 {
    926 	while (*in && *in != '.')
    927 		*out++ = *in++;
    928 	*out = 0;
    929 }
    930 
    931 /*
    932 ============
    933 COM_FileExtension
    934 ============
    935 */
    936 char *COM_FileExtension (char *in)
    937 {
    938 	static char exten[8];
    939 	int		i;
    940 
    941 	while (*in && *in != '.')
    942 		in++;
    943 	if (!*in)
    944 		return "";
    945 	in++;
    946 	for (i=0 ; i<7 && *in ; i++,in++)
    947 		exten[i] = *in;
    948 	exten[i] = 0;
    949 	return exten;
    950 }
    951 
    952 /*
    953 ============
    954 COM_FileBase
    955 ============
    956 */
    957 void COM_FileBase (char *in, char *out)
    958 {
    959 	char *s, *s2;
    960 
    961 	s = in + strlen(in) - 1;
    962 
    963 	while (s != in && *s != '.')
    964 		s--;
    965 
    966 	for (s2 = s ; *s2 && *s2 != '/' ; s2--)
    967 	;
    968 
    969 	if (s-s2 < 2)
    970 		strcpy (out,"?model?");
    971 	else
    972 	{
    973 		s--;
    974 		strncpy (out,s2+1, s-s2);
    975 		out[s-s2] = 0;
    976 	}
    977 }
    978 
    979 
    980 /*
    981 ==================
    982 COM_DefaultExtension
    983 ==================
    984 */
    985 void COM_DefaultExtension (char *path, char *extension)
    986 {
    987 	char    *src;
    988 //
    989 // if path doesn't have a .EXT, append extension
    990 // (extension should include the .)
    991 //
    992 	src = path + strlen(path) - 1;
    993 
    994 	while (*src != '/' && src != path)
    995 	{
    996 		if (*src == '.')
    997 			return;                 // it has an extension
    998 		src--;
    999 	}
   1000 
   1001 	strcat (path, extension);
   1002 }
   1003 
   1004 //============================================================================
   1005 
   1006 char		com_token[1024];
   1007 int		com_argc;
   1008 char	**com_argv;
   1009 
   1010 
   1011 /*
   1012 ==============
   1013 COM_Parse
   1014 
   1015 Parse a token out of a string
   1016 ==============
   1017 */
   1018 char *COM_Parse (char *data)
   1019 {
   1020 	int		c;
   1021 	int		len;
   1022 
   1023 	len = 0;
   1024 	com_token[0] = 0;
   1025 
   1026 	if (!data)
   1027 		return NULL;
   1028 
   1029 // skip whitespace
   1030 skipwhite:
   1031 	while ( (c = *data) <= ' ')
   1032 	{
   1033 		if (c == 0)
   1034 			return NULL;			// end of file;
   1035 		data++;
   1036 	}
   1037 
   1038 // skip // comments
   1039 	if (c=='/' && data[1] == '/')
   1040 	{
   1041 		while (*data && *data != '\n')
   1042 			data++;
   1043 		goto skipwhite;
   1044 	}
   1045 
   1046 
   1047 // handle quoted strings specially
   1048 	if (c == '\"')
   1049 	{
   1050 		data++;
   1051 		while (1)
   1052 		{
   1053 			c = *data++;
   1054 			if (c=='\"' || !c)
   1055 			{
   1056 				com_token[len] = 0;
   1057 				return data;
   1058 			}
   1059 			com_token[len] = c;
   1060 			len++;
   1061 		}
   1062 	}
   1063 
   1064 // parse a regular word
   1065 	do
   1066 	{
   1067 		com_token[len] = c;
   1068 		data++;
   1069 		len++;
   1070 		c = *data;
   1071 	} while (c>32);
   1072 
   1073 	com_token[len] = 0;
   1074 	return data;
   1075 }
   1076 
   1077 
   1078 /*
   1079 ================
   1080 COM_CheckParm
   1081 
   1082 Returns the position (1 to argc-1) in the program's argument list
   1083 where the given parameter apears, or 0 if not present
   1084 ================
   1085 */
   1086 int COM_CheckParm (char *parm)
   1087 {
   1088 	int		i;
   1089 
   1090 	for (i=1 ; i<com_argc ; i++)
   1091 	{
   1092 		if (!com_argv[i])
   1093 			continue;		// NEXTSTEP sometimes clears appkit vars.
   1094 		if (!Q_strcmp (parm,com_argv[i]))
   1095 			return i;
   1096 	}
   1097 
   1098 	return 0;
   1099 }
   1100 
   1101 /*
   1102 ================
   1103 COM_CheckRegistered
   1104 
   1105 Looks for the pop.txt file and verifies it.
   1106 Sets the "registered" cvar.
   1107 Immediately exits out if an alternate game was attempted to be started without
   1108 being registered.
   1109 ================
   1110 */
   1111 void COM_CheckRegistered (void)
   1112 {
   1113 	FILE		*h;
   1114 	unsigned short	check[128];
   1115 	int			i;
   1116 
   1117 	COM_FOpenFile("gfx/pop.lmp", &h);
   1118 	static_registered = 0;
   1119 
   1120 	if (!h)
   1121 	{
   1122 		Con_Printf ("Playing shareware version.\n");
   1123 #if 0
   1124 #ifndef SERVERONLY
   1125 // FIXME DEBUG -- only temporary
   1126 		if (com_modified)
   1127 			Sys_Error ("You must have the registered version to play QuakeWorld");
   1128 #endif
   1129 #endif
   1130 		return;
   1131 	}
   1132 
   1133 	fread (check, 1, sizeof(check), h);
   1134 	fclose (h);
   1135 
   1136 	for (i=0 ; i<128 ; i++)
   1137 		if (pop[i] != (unsigned short)BigShort (check[i]))
   1138 			Sys_Error ("Corrupted data file.");
   1139 
   1140 	Cvar_Set ("registered", "1");
   1141 	static_registered = 1;
   1142 	Con_Printf ("Playing registered version.\n");
   1143 }
   1144 
   1145 
   1146 
   1147 /*
   1148 ================
   1149 COM_InitArgv
   1150 ================
   1151 */
   1152 void COM_InitArgv (int argc, char **argv)
   1153 {
   1154 	qboolean	safe;
   1155 	int			i;
   1156 
   1157 	safe = false;
   1158 
   1159 	for (com_argc=0 ; (com_argc<MAX_NUM_ARGVS) && (com_argc < argc) ;
   1160 		 com_argc++)
   1161 	{
   1162 		largv[com_argc] = argv[com_argc];
   1163 		if (!Q_strcmp ("-safe", argv[com_argc]))
   1164 			safe = true;
   1165 	}
   1166 
   1167 	if (safe)
   1168 	{
   1169 	// force all the safe-mode switches. Note that we reserved extra space in
   1170 	// case we need to add these, so we don't need an overflow check
   1171 		for (i=0 ; i<NUM_SAFE_ARGVS ; i++)
   1172 		{
   1173 			largv[com_argc] = safeargvs[i];
   1174 			com_argc++;
   1175 		}
   1176 	}
   1177 
   1178 	largv[com_argc] = argvdummy;
   1179 	com_argv = largv;
   1180 }
   1181 
   1182 /*
   1183 ================
   1184 COM_AddParm
   1185 
   1186 Adds the given string at the end of the current argument list
   1187 ================
   1188 */
   1189 void COM_AddParm (char *parm)
   1190 {
   1191 	largv[com_argc++] = parm;
   1192 }
   1193 
   1194 
   1195 /*
   1196 ================
   1197 COM_Init
   1198 ================
   1199 */
   1200 void COM_Init (void)
   1201 {
   1202 	byte	swaptest[2] = {1,0};
   1203 
   1204 // set the byte swapping variables in a portable manner
   1205 	if ( *(short *)swaptest == 1)
   1206 	{
   1207 		bigendien = false;
   1208 		BigShort = ShortSwap;
   1209 		LittleShort = ShortNoSwap;
   1210 		BigLong = LongSwap;
   1211 		LittleLong = LongNoSwap;
   1212 		BigFloat = FloatSwap;
   1213 		LittleFloat = FloatNoSwap;
   1214 	}
   1215 	else
   1216 	{
   1217 		bigendien = true;
   1218 		BigShort = ShortNoSwap;
   1219 		LittleShort = ShortSwap;
   1220 		BigLong = LongNoSwap;
   1221 		LittleLong = LongSwap;
   1222 		BigFloat = FloatNoSwap;
   1223 		LittleFloat = FloatSwap;
   1224 	}
   1225 
   1226 	Cvar_RegisterVariable (&registered);
   1227 	Cmd_AddCommand ("path", COM_Path_f);
   1228 
   1229 	COM_InitFilesystem ();
   1230 	COM_CheckRegistered ();
   1231 }
   1232 
   1233 
   1234 /*
   1235 ============
   1236 va
   1237 
   1238 does a varargs printf into a temp buffer, so I don't need to have
   1239 varargs versions of all text functions.
   1240 FIXME: make this buffer size safe someday
   1241 ============
   1242 */
   1243 char	*va(char *format, ...)
   1244 {
   1245 	va_list		argptr;
   1246 	static char		string[1024];
   1247 
   1248 	va_start (argptr, format);
   1249 	vsprintf (string, format,argptr);
   1250 	va_end (argptr);
   1251 
   1252 	return string;
   1253 }
   1254 
   1255 
   1256 /// just for debugging
   1257 int	memsearch (byte *start, int count, int search)
   1258 {
   1259 	int		i;
   1260 
   1261 	for (i=0 ; i<count ; i++)
   1262 		if (start[i] == search)
   1263 			return i;
   1264 	return -1;
   1265 }
   1266 
   1267 /*
   1268 =============================================================================
   1269 
   1270 QUAKE FILESYSTEM
   1271 
   1272 =============================================================================
   1273 */
   1274 
   1275 int	com_filesize;
   1276 
   1277 
   1278 //
   1279 // in memory
   1280 //
   1281 
   1282 typedef struct
   1283 {
   1284 	char	name[MAX_QPATH];
   1285 	int		filepos, filelen;
   1286 } packfile_t;
   1287 
   1288 typedef struct pack_s
   1289 {
   1290 	char	filename[MAX_OSPATH];
   1291 	FILE	*handle;
   1292 	int		numfiles;
   1293 	packfile_t	*files;
   1294 } pack_t;
   1295 
   1296 //
   1297 // on disk
   1298 //
   1299 typedef struct
   1300 {
   1301 	char	name[56];
   1302 	int		filepos, filelen;
   1303 } dpackfile_t;
   1304 
   1305 typedef struct
   1306 {
   1307 	char	id[4];
   1308 	int		dirofs;
   1309 	int		dirlen;
   1310 } dpackheader_t;
   1311 
   1312 #define	MAX_FILES_IN_PACK	2048
   1313 
   1314 char	com_gamedir[MAX_OSPATH];
   1315 char	com_basedir[MAX_OSPATH];
   1316 
   1317 typedef struct searchpath_s
   1318 {
   1319 	char	filename[MAX_OSPATH];
   1320 	pack_t	*pack;		// only one of filename / pack will be used
   1321 	struct searchpath_s *next;
   1322 } searchpath_t;
   1323 
   1324 searchpath_t	*com_searchpaths;
   1325 searchpath_t	*com_base_searchpaths;	// without gamedirs
   1326 
   1327 /*
   1328 ================
   1329 COM_filelength
   1330 ================
   1331 */
   1332 int COM_filelength (FILE *f)
   1333 {
   1334 	int		pos;
   1335 	int		end;
   1336 
   1337 	pos = ftell (f);
   1338 	fseek (f, 0, SEEK_END);
   1339 	end = ftell (f);
   1340 	fseek (f, pos, SEEK_SET);
   1341 
   1342 	return end;
   1343 }
   1344 
   1345 int COM_FileOpenRead (char *path, FILE **hndl)
   1346 {
   1347 	FILE	*f;
   1348 
   1349 	f = fopen(path, "rb");
   1350 	if (!f)
   1351 	{
   1352 		*hndl = NULL;
   1353 		return -1;
   1354 	}
   1355 	*hndl = f;
   1356 
   1357 	return COM_filelength(f);
   1358 }
   1359 
   1360 /*
   1361 ============
   1362 COM_Path_f
   1363 
   1364 ============
   1365 */
   1366 void COM_Path_f (void)
   1367 {
   1368 	searchpath_t	*s;
   1369 
   1370 	Con_Printf ("Current search path:\n");
   1371 	for (s=com_searchpaths ; s ; s=s->next)
   1372 	{
   1373 		if (s == com_base_searchpaths)
   1374 			Con_Printf ("----------\n");
   1375 		if (s->pack)
   1376 			Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
   1377 		else
   1378 			Con_Printf ("%s\n", s->filename);
   1379 	}
   1380 }
   1381 
   1382 /*
   1383 ============
   1384 COM_WriteFile
   1385 
   1386 The filename will be prefixed by the current game directory
   1387 ============
   1388 */
   1389 void COM_WriteFile (char *filename, void *data, int len)
   1390 {
   1391 	FILE	*f;
   1392 	char	name[MAX_OSPATH];
   1393 
   1394 	sprintf (name, "%s/%s", com_gamedir, filename);
   1395 
   1396 	f = fopen (name, "wb");
   1397 	if (!f) {
   1398 		Sys_mkdir(com_gamedir);
   1399 		f = fopen (name, "wb");
   1400 		if (!f)
   1401 			Sys_Error ("Error opening %s", filename);
   1402 	}
   1403 
   1404 	Sys_Printf ("COM_WriteFile: %s\n", name);
   1405 	fwrite (data, 1, len, f);
   1406 	fclose (f);
   1407 }
   1408 
   1409 
   1410 /*
   1411 ============
   1412 COM_CreatePath
   1413 
   1414 Only used for CopyFile and download
   1415 ============
   1416 */
   1417 void	COM_CreatePath (char *path)
   1418 {
   1419 	char	*ofs;
   1420 
   1421 	for (ofs = path+1 ; *ofs ; ofs++)
   1422 	{
   1423 		if (*ofs == '/')
   1424 		{	// create the directory
   1425 			*ofs = 0;
   1426 			Sys_mkdir (path);
   1427 			*ofs = '/';
   1428 		}
   1429 	}
   1430 }
   1431 
   1432 
   1433 /*
   1434 ===========
   1435 COM_CopyFile
   1436 
   1437 Copies a file over from the net to the local cache, creating any directories
   1438 needed.  This is for the convenience of developers using ISDN from home.
   1439 ===========
   1440 */
   1441 void COM_CopyFile (char *netpath, char *cachepath)
   1442 {
   1443 	FILE	*in, *out;
   1444 	int		remaining, count;
   1445 	char	buf[4096];
   1446 
   1447 	remaining = COM_FileOpenRead (netpath, &in);
   1448 	COM_CreatePath (cachepath);	// create directories up to the cache file
   1449 	out = fopen(cachepath, "wb");
   1450 	if (!out)
   1451 		Sys_Error ("Error opening %s", cachepath);
   1452 
   1453 	while (remaining)
   1454 	{
   1455 		if (remaining < (int) sizeof(buf))
   1456 			count = remaining;
   1457 		else
   1458 			count = sizeof(buf);
   1459 		fread (buf, 1, count, in);
   1460 		fwrite (buf, 1, count, out);
   1461 		remaining -= count;
   1462 	}
   1463 
   1464 	fclose (in);
   1465 	fclose (out);
   1466 }
   1467 
   1468 /*
   1469 ===========
   1470 COM_FindFile
   1471 
   1472 Finds the file in the search path.
   1473 Sets com_filesize and one of handle or file
   1474 ===========
   1475 */
   1476 int file_from_pak; // global indicating file came from pack file ZOID
   1477 
   1478 int COM_FOpenFile (char *filename, FILE **file)
   1479 {
   1480 	searchpath_t	*search;
   1481 	char		netpath[MAX_OSPATH];
   1482 	pack_t		*pak;
   1483 	int			i;
   1484 	int			findtime;
   1485 
   1486 	file_from_pak = 0;
   1487 
   1488 //
   1489 // search through the path, one element at a time
   1490 //
   1491 	for (search = com_searchpaths ; search ; search = search->next)
   1492 	{
   1493 	// is the element a pak file?
   1494 		if (search->pack)
   1495 		{
   1496 		// look through all the pak file elements
   1497 			pak = search->pack;
   1498 			for (i=0 ; i<pak->numfiles ; i++)
   1499 				if (!strcmp (pak->files[i].name, filename))
   1500 				{	// found it!
   1501 					Sys_Printf ("PackFile: %s : %s\n",pak->filename, filename);
   1502 				// open a new file on the pakfile
   1503 					*file = fopen (pak->filename, "rb");
   1504 					if (!*file)
   1505 						Sys_Error ("Couldn't reopen %s", pak->filename);
   1506 					fseek (*file, pak->files[i].filepos, SEEK_SET);
   1507 					com_filesize = pak->files[i].filelen;
   1508 					file_from_pak = 1;
   1509 					return com_filesize;
   1510 				}
   1511 		}
   1512 		else
   1513 		{
   1514 	// check a file in the directory tree
   1515 			if (!static_registered)
   1516 			{	// if not a registered version, don't ever go beyond base
   1517 				if ( strchr (filename, '/') || strchr (filename,'\\'))
   1518 					continue;
   1519 			}
   1520 
   1521 			sprintf (netpath, "%s/%s",search->filename, filename);
   1522 
   1523 			findtime = Sys_FileTime (netpath);
   1524 			if (findtime == -1)
   1525 				continue;
   1526 
   1527 			Sys_Printf ("FindFile: %s\n",netpath);
   1528 
   1529 			*file = fopen (netpath, "rb");
   1530 			return COM_filelength (*file);
   1531 		}
   1532 
   1533 	}
   1534 
   1535 	Sys_Printf ("FindFile: can't find %s\n", filename);
   1536 
   1537 	*file = NULL;
   1538 	com_filesize = -1;
   1539 	return -1;
   1540 }
   1541 
   1542 /*
   1543 ============
   1544 COM_LoadFile
   1545 
   1546 Filename are reletive to the quake directory.
   1547 Allways appends a 0 byte to the loaded data.
   1548 ============
   1549 */
   1550 cache_user_t *loadcache;
   1551 byte	*loadbuf;
   1552 int		loadsize;
   1553 byte *COM_LoadFile (char *path, int usehunk)
   1554 {
   1555 	FILE	*h;
   1556 	byte	*buf;
   1557 	char	base[32];
   1558 	int		len;
   1559 
   1560 	buf = NULL;	// quiet compiler warning
   1561 
   1562 // look for it in the filesystem or pack files
   1563 	len = com_filesize = COM_FOpenFile (path, &h);
   1564 	if (!h)
   1565 		return NULL;
   1566 
   1567 // extract the filename base name for hunk tag
   1568 	COM_FileBase (path, base);
   1569 
   1570 	if (usehunk == 1)
   1571 		buf = Hunk_AllocName (len+1, base);
   1572 	else if (usehunk == 2)
   1573 		buf = Hunk_TempAlloc (len+1);
   1574 	else if (usehunk == 0)
   1575 		buf = Z_Malloc (len+1);
   1576 	else if (usehunk == 3)
   1577 		buf = Cache_Alloc (loadcache, len+1, base);
   1578 	else if (usehunk == 4)
   1579 	{
   1580 		if (len+1 > loadsize)
   1581 			buf = Hunk_TempAlloc (len+1);
   1582 		else
   1583 			buf = loadbuf;
   1584 	}
   1585 	else
   1586 		Sys_Error ("COM_LoadFile: bad usehunk");
   1587 
   1588 	if (!buf)
   1589 		Sys_Error ("COM_LoadFile: not enough space for %s", path);
   1590 
   1591 	((byte *)buf)[len] = 0;
   1592 #ifndef SERVERONLY
   1593 	Draw_BeginDisc ();
   1594 #endif
   1595 	fread (buf, 1, len, h);
   1596 	fclose (h);
   1597 #ifndef SERVERONLY
   1598 	Draw_EndDisc ();
   1599 #endif
   1600 
   1601 	return buf;
   1602 }
   1603 
   1604 byte *COM_LoadHunkFile (char *path)
   1605 {
   1606 	return COM_LoadFile (path, 1);
   1607 }
   1608 
   1609 byte *COM_LoadTempFile (char *path)
   1610 {
   1611 	return COM_LoadFile (path, 2);
   1612 }
   1613 
   1614 void COM_LoadCacheFile (char *path, struct cache_user_s *cu)
   1615 {
   1616 	loadcache = cu;
   1617 	COM_LoadFile (path, 3);
   1618 }
   1619 
   1620 // uses temp hunk if larger than bufsize
   1621 byte *COM_LoadStackFile (char *path, void *buffer, int bufsize)
   1622 {
   1623 	byte	*buf;
   1624 
   1625 	loadbuf = (byte *)buffer;
   1626 	loadsize = bufsize;
   1627 	buf = COM_LoadFile (path, 4);
   1628 
   1629 	return buf;
   1630 }
   1631 
   1632 /*
   1633 =================
   1634 COM_LoadPackFile
   1635 
   1636 Takes an explicit (not game tree related) path to a pak file.
   1637 
   1638 Loads the header and directory, adding the files at the beginning
   1639 of the list so they override previous pack files.
   1640 =================
   1641 */
   1642 pack_t *COM_LoadPackFile (char *packfile)
   1643 {
   1644 	dpackheader_t	header;
   1645 	int				i;
   1646 	packfile_t		*newfiles;
   1647 	int				numpackfiles;
   1648 	pack_t			*pack;
   1649 	FILE			*packhandle;
   1650 	dpackfile_t		info[MAX_FILES_IN_PACK];
   1651 	unsigned short		crc;
   1652 
   1653 	if (COM_FileOpenRead (packfile, &packhandle) == -1)
   1654 		return NULL;
   1655 
   1656 	fread (&header, 1, sizeof(header), packhandle);
   1657 	if (header.id[0] != 'P' || header.id[1] != 'A'
   1658 	|| header.id[2] != 'C' || header.id[3] != 'K')
   1659 		Sys_Error ("%s is not a packfile", packfile);
   1660 	header.dirofs = LittleLong (header.dirofs);
   1661 	header.dirlen = LittleLong (header.dirlen);
   1662 
   1663 	numpackfiles = header.dirlen / sizeof(dpackfile_t);
   1664 
   1665 	if (numpackfiles > MAX_FILES_IN_PACK)
   1666 		Sys_Error ("%s has %i files", packfile, numpackfiles);
   1667 
   1668 	if (numpackfiles != PAK0_COUNT)
   1669 		com_modified = true;	// not the original file
   1670 
   1671 	newfiles = Z_Malloc (numpackfiles * sizeof(packfile_t));
   1672 
   1673 	fseek (packhandle, header.dirofs, SEEK_SET);
   1674 	fread (&info, 1, header.dirlen, packhandle);
   1675 
   1676 // crc the directory to check for modifications
   1677 	crc = CRC_Block((byte *)info, header.dirlen);
   1678 
   1679 //	CRC_Init (&crc);
   1680 //	for (i=0 ; i<header.dirlen ; i++)
   1681 //		CRC_ProcessByte (&crc, ((byte *)info)[i]);
   1682 	if (crc != PAK0_CRC)
   1683 		com_modified = true;
   1684 
   1685 // parse the directory
   1686 	for (i=0 ; i<numpackfiles ; i++)
   1687 	{
   1688 		strcpy (newfiles[i].name, info[i].name);
   1689 		newfiles[i].filepos = LittleLong(info[i].filepos);
   1690 		newfiles[i].filelen = LittleLong(info[i].filelen);
   1691 	}
   1692 
   1693 	pack = Z_Malloc (sizeof (pack_t));
   1694 	strcpy (pack->filename, packfile);
   1695 	pack->handle = packhandle;
   1696 	pack->numfiles = numpackfiles;
   1697 	pack->files = newfiles;
   1698 
   1699 	Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
   1700 	return pack;
   1701 }
   1702 
   1703 
   1704 /*
   1705 ================
   1706 COM_AddGameDirectory
   1707 
   1708 Sets com_gamedir, adds the directory to the head of the path,
   1709 then loads and adds pak1.pak pak2.pak ...
   1710 ================
   1711 */
   1712 void COM_AddGameDirectory (char *dir)
   1713 {
   1714 	int				i;
   1715 	searchpath_t	*search;
   1716 	pack_t			*pak;
   1717 	char			pakfile[MAX_OSPATH];
   1718 	char			*p;
   1719 
   1720 	if ((p = strrchr(dir, '/')) != NULL)
   1721 		strcpy(gamedirfile, ++p);
   1722 	else
   1723 		strcpy(gamedirfile, p);
   1724 	strcpy (com_gamedir, dir);
   1725 
   1726 //
   1727 // add the directory to the search path
   1728 //
   1729 	search = Hunk_Alloc (sizeof(searchpath_t));
   1730 	strcpy (search->filename, dir);
   1731 	search->next = com_searchpaths;
   1732 	com_searchpaths = search;
   1733 
   1734 //
   1735 // add any pak files in the format pak0.pak pak1.pak, ...
   1736 //
   1737 	for (i=0 ; ; i++)
   1738 	{
   1739 		sprintf (pakfile, "%s/pak%i.pak", dir, i);
   1740 		pak = COM_LoadPackFile (pakfile);
   1741 		if (!pak)
   1742 			break;
   1743 		search = Hunk_Alloc (sizeof(searchpath_t));
   1744 		search->pack = pak;
   1745 		search->next = com_searchpaths;
   1746 		com_searchpaths = search;
   1747 	}
   1748 
   1749 }
   1750 
   1751 /*
   1752 ================
   1753 COM_Gamedir
   1754 
   1755 Sets the gamedir and path to a different directory.
   1756 ================
   1757 */
   1758 void COM_Gamedir (char *dir)
   1759 {
   1760 	searchpath_t	*search, *next;
   1761 	int				i;
   1762 	pack_t			*pak;
   1763 	char			pakfile[MAX_OSPATH];
   1764 
   1765 	if (strstr(dir, "..") || strstr(dir, "/")
   1766 		|| strstr(dir, "\\") || strstr(dir, ":") )
   1767 	{
   1768 		Con_Printf ("Gamedir should be a single filename, not a path\n");
   1769 		return;
   1770 	}
   1771 
   1772 	if (!strcmp(gamedirfile, dir))
   1773 		return;		// still the same
   1774 	strcpy (gamedirfile, dir);
   1775 
   1776 	//
   1777 	// free up any current game dir info
   1778 	//
   1779 	while (com_searchpaths != com_base_searchpaths)
   1780 	{
   1781 		if (com_searchpaths->pack)
   1782 		{
   1783 			fclose (com_searchpaths->pack->handle);
   1784 			Z_Free (com_searchpaths->pack->files);
   1785 			Z_Free (com_searchpaths->pack);
   1786 		}
   1787 		next = com_searchpaths->next;
   1788 		Z_Free (com_searchpaths);
   1789 		com_searchpaths = next;
   1790 	}
   1791 
   1792 	//
   1793 	// flush all data, so it will be forced to reload
   1794 	//
   1795 	Cache_Flush ();
   1796 
   1797 	if (!strcmp(dir,"id1") || !strcmp(dir, "qw"))
   1798 		return;
   1799 
   1800 	sprintf (com_gamedir, "%s/%s", com_basedir, dir);
   1801 
   1802 	//
   1803 	// add the directory to the search path
   1804 	//
   1805 	search = Z_Malloc (sizeof(searchpath_t));
   1806 	strcpy (search->filename, com_gamedir);
   1807 	search->next = com_searchpaths;
   1808 	com_searchpaths = search;
   1809 
   1810 	//
   1811 	// add any pak files in the format pak0.pak pak1.pak, ...
   1812 	//
   1813 	for (i=0 ; ; i++)
   1814 	{
   1815 		sprintf (pakfile, "%s/pak%i.pak", com_gamedir, i);
   1816 		pak = COM_LoadPackFile (pakfile);
   1817 		if (!pak)
   1818 			break;
   1819 		search = Z_Malloc (sizeof(searchpath_t));
   1820 		search->pack = pak;
   1821 		search->next = com_searchpaths;
   1822 		com_searchpaths = search;
   1823 	}
   1824 }
   1825 
   1826 /*
   1827 ================
   1828 COM_InitFilesystem
   1829 ================
   1830 */
   1831 void COM_InitFilesystem (void)
   1832 {
   1833 	int		i;
   1834 
   1835 //
   1836 // -basedir <path>
   1837 // Overrides the system supplied base directory (under id1)
   1838 //
   1839 	i = COM_CheckParm ("-basedir");
   1840 	if (i && i < com_argc-1)
   1841 		strcpy (com_basedir, com_argv[i+1]);
   1842 	else
   1843 		strcpy (com_basedir, host_parms.basedir);
   1844 
   1845 //
   1846 // start up with id1 by default
   1847 //
   1848 	COM_AddGameDirectory (va("%s/id1", com_basedir) );
   1849 	COM_AddGameDirectory (va("%s/qw", com_basedir) );
   1850 
   1851 	// any set gamedirs will be freed up to here
   1852 	com_base_searchpaths = com_searchpaths;
   1853 }
   1854 
   1855 
   1856 
   1857 /*
   1858 =====================================================================
   1859 
   1860   INFO STRINGS
   1861 
   1862 =====================================================================
   1863 */
   1864 
   1865 /*
   1866 ===============
   1867 Info_ValueForKey
   1868 
   1869 Searches the string for the given
   1870 key and returns the associated value, or an empty string.
   1871 ===============
   1872 */
   1873 char *Info_ValueForKey (char *s, char *key)
   1874 {
   1875 	char	pkey[512];
   1876 	static	char value[4][512];	// use two buffers so compares
   1877 								// work without stomping on each other
   1878 	static	int	valueindex;
   1879 	char	*o;
   1880 
   1881 	valueindex = (valueindex + 1) % 4;
   1882 	if (*s == '\\')
   1883 		s++;
   1884 	while (1)
   1885 	{
   1886 		o = pkey;
   1887 		while (*s != '\\')
   1888 		{
   1889 			if (!*s)
   1890 				return "";
   1891 			*o++ = *s++;
   1892 		}
   1893 		*o = 0;
   1894 		s++;
   1895 
   1896 		o = value[valueindex];
   1897 
   1898 		while (*s != '\\' && *s)
   1899 		{
   1900 			if (!*s)
   1901 				return "";
   1902 			*o++ = *s++;
   1903 		}
   1904 		*o = 0;
   1905 
   1906 		if (!strcmp (key, pkey) )
   1907 			return value[valueindex];
   1908 
   1909 		if (!*s)
   1910 			return "";
   1911 		s++;
   1912 	}
   1913 }
   1914 
   1915 void Info_RemoveKey (char *s, char *key)
   1916 {
   1917 	char	*start;
   1918 	char	pkey[512];
   1919 	char	value[512];
   1920 	char	*o;
   1921 
   1922 	if (strstr (key, "\\"))
   1923 	{
   1924 		Con_Printf ("Can't use a key with a \\\n");
   1925 		return;
   1926 	}
   1927 
   1928 	while (1)
   1929 	{
   1930 		start = s;
   1931 		if (*s == '\\')
   1932 			s++;
   1933 		o = pkey;
   1934 		while (*s != '\\')
   1935 		{
   1936 			if (!*s)
   1937 				return;
   1938 			*o++ = *s++;
   1939 		}
   1940 		*o = 0;
   1941 		s++;
   1942 
   1943 		o = value;
   1944 		while (*s != '\\' && *s)
   1945 		{
   1946 			if (!*s)
   1947 				return;
   1948 			*o++ = *s++;
   1949 		}
   1950 		*o = 0;
   1951 
   1952 		if (!strcmp (key, pkey) )
   1953 		{
   1954 			strcpy (start, s);	// remove this part
   1955 			return;
   1956 		}
   1957 
   1958 		if (!*s)
   1959 			return;
   1960 	}
   1961 
   1962 }
   1963 
   1964 void Info_RemovePrefixedKeys (char *start, char prefix)
   1965 {
   1966 	char	*s;
   1967 	char	pkey[512];
   1968 	char	value[512];
   1969 	char	*o;
   1970 
   1971 	s = start;
   1972 
   1973 	while (1)
   1974 	{
   1975 		if (*s == '\\')
   1976 			s++;
   1977 		o = pkey;
   1978 		while (*s != '\\')
   1979 		{
   1980 			if (!*s)
   1981 				return;
   1982 			*o++ = *s++;
   1983 		}
   1984 		*o = 0;
   1985 		s++;
   1986 
   1987 		o = value;
   1988 		while (*s != '\\' && *s)
   1989 		{
   1990 			if (!*s)
   1991 				return;
   1992 			*o++ = *s++;
   1993 		}
   1994 		*o = 0;
   1995 
   1996 		if (pkey[0] == prefix)
   1997 		{
   1998 			Info_RemoveKey (start, pkey);
   1999 			s = start;
   2000 		}
   2001 
   2002 		if (!*s)
   2003 			return;
   2004 	}
   2005 
   2006 }
   2007 
   2008 
   2009 void Info_SetValueForStarKey (char *s, char *key, char *value, int maxsize)
   2010 {
   2011 	char	new[1024], *v;
   2012 	int		c;
   2013 #ifdef SERVERONLY
   2014 	extern cvar_t sv_highchars;
   2015 #endif
   2016 
   2017 	if (strstr (key, "\\") || strstr (value, "\\") )
   2018 	{
   2019 		Con_Printf ("Can't use keys or values with a \\\n");
   2020 		return;
   2021 	}
   2022 
   2023 	if (strstr (key, "\"") || strstr (value, "\"") )
   2024 	{
   2025 		Con_Printf ("Can't use keys or values with a \"\n");
   2026 		return;
   2027 	}
   2028 
   2029 	if (strlen(key) > 63 || strlen(value) > 63)
   2030 	{
   2031 		Con_Printf ("Keys and values must be < 64 characters.\n");
   2032 		return;
   2033 	}
   2034 
   2035 	// this next line is kinda trippy
   2036 	if (*(v = Info_ValueForKey(s, key))) {
   2037 		// key exists, make sure we have enough room for new value, if we don't,
   2038 		// don't change it!
   2039 		if ((int) (strlen(value) - strlen(v) + strlen(s)) > maxsize) {
   2040 			Con_Printf ("Info string length exceeded\n");
   2041 			return;
   2042 		}
   2043 	}
   2044 	Info_RemoveKey (s, key);
   2045 	if (!value || !strlen(value))
   2046 		return;
   2047 
   2048 	sprintf (new, "\\%s\\%s", key, value);
   2049 
   2050 	if ((int)(strlen(new) + strlen(s)) > maxsize)
   2051 	{
   2052 		Con_Printf ("Info string length exceeded\n");
   2053 		return;
   2054 	}
   2055 
   2056 	// only copy ascii values
   2057 	s += strlen(s);
   2058 	v = new;
   2059 	while (*v)
   2060 	{
   2061 		c = (unsigned char)*v++;
   2062 #ifndef SERVERONLY
   2063 		// client only allows highbits on name
   2064 		if (stricmp(key, "name") != 0) {
   2065 			c &= 127;
   2066 			if (c < 32 || c > 127)
   2067 				continue;
   2068 			// auto lowercase team
   2069 			if (stricmp(key, "team") == 0)
   2070 				c = tolower(c);
   2071 		}
   2072 #else
   2073 		if (!sv_highchars.value) {
   2074 			c &= 127;
   2075 			if (c < 32 || c > 127)
   2076 				continue;
   2077 		}
   2078 #endif
   2079 //		c &= 127;		// strip high bits
   2080 		if (c > 13) // && c < 127)
   2081 			*s++ = c;
   2082 	}
   2083 	*s = 0;
   2084 }
   2085 
   2086 void Info_SetValueForKey (char *s, char *key, char *value, int maxsize)
   2087 {
   2088 	if (key[0] == '*')
   2089 	{
   2090 		Con_Printf ("Can't set * keys\n");
   2091 		return;
   2092 	}
   2093 
   2094 	Info_SetValueForStarKey (s, key, value, maxsize);
   2095 }
   2096 
   2097 void Info_Print (char *s)
   2098 {
   2099 	char	key[512];
   2100 	char	value[512];
   2101 	char	*o;
   2102 	int		l;
   2103 
   2104 	if (*s == '\\')
   2105 		s++;
   2106 	while (*s)
   2107 	{
   2108 		o = key;
   2109 		while (*s && *s != '\\')
   2110 			*o++ = *s++;
   2111 
   2112 		l = o - key;
   2113 		if (l < 20)
   2114 		{
   2115 			memset (o, ' ', 20-l);
   2116 			key[20] = 0;
   2117 		}
   2118 		else
   2119 			*o = 0;
   2120 		Con_Printf ("%s", key);
   2121 
   2122 		if (!*s)
   2123 		{
   2124 			Con_Printf ("MISSING VALUE\n");
   2125 			return;
   2126 		}
   2127 
   2128 		o = value;
   2129 		s++;
   2130 		while (*s && *s != '\\')
   2131 			*o++ = *s++;
   2132 		*o = 0;
   2133 
   2134 		if (*s)
   2135 			s++;
   2136 		Con_Printf ("%s\n", value);
   2137 	}
   2138 }
   2139 
   2140 static byte chktbl[1024 + 4] = {
   2141 0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01,
   2142 0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a,
   2143 0x64,0xed,0x5c,0x99,0x29,0x87,0xa8,0x78,0x59,0x0d,0xaa,0x0f,0x25,0x0a,0x5c,0x58,
   2144 0xfb,0x00,0xa7,0xa8,0x8a,0x1d,0x86,0x80,0xc5,0x1f,0xd2,0x28,0x69,0x71,0x58,0xc3,
   2145 0x51,0x90,0xe1,0xf8,0x6a,0xf3,0x8f,0xb0,0x68,0xdf,0x95,0x40,0x5c,0xe4,0x24,0x6b,
   2146 0x29,0x19,0x71,0x3f,0x42,0x63,0x6c,0x48,0xe7,0xad,0xa8,0x4b,0x91,0x8f,0x42,0x36,
   2147 0x34,0xe7,0x32,0x55,0x59,0x2d,0x36,0x38,0x38,0x59,0x9b,0x08,0x16,0x4d,0x8d,0xf8,
   2148 0x0a,0xa4,0x52,0x01,0xbb,0x52,0xa9,0xfd,0x40,0x18,0x97,0x37,0xff,0xc9,0x82,0x27,
   2149 0xb2,0x64,0x60,0xce,0x00,0xd9,0x04,0xf0,0x9e,0x99,0xbd,0xce,0x8f,0x90,0x4a,0xdd,
   2150 0xe1,0xec,0x19,0x14,0xb1,0xfb,0xca,0x1e,0x98,0x0f,0xd4,0xcb,0x80,0xd6,0x05,0x63,
   2151 0xfd,0xa0,0x74,0xa6,0x86,0xf6,0x19,0x98,0x76,0x27,0x68,0xf7,0xe9,0x09,0x9a,0xf2,
   2152 0x2e,0x42,0xe1,0xbe,0x64,0x48,0x2a,0x74,0x30,0xbb,0x07,0xcc,0x1f,0xd4,0x91,0x9d,
   2153 0xac,0x55,0x53,0x25,0xb9,0x64,0xf7,0x58,0x4c,0x34,0x16,0xbc,0xf6,0x12,0x2b,0x65,
   2154 0x68,0x25,0x2e,0x29,0x1f,0xbb,0xb9,0xee,0x6d,0x0c,0x8e,0xbb,0xd2,0x5f,0x1d,0x8f,
   2155 0xc1,0x39,0xf9,0x8d,0xc0,0x39,0x75,0xcf,0x25,0x17,0xbe,0x96,0xaf,0x98,0x9f,0x5f,
   2156 0x65,0x15,0xc4,0x62,0xf8,0x55,0xfc,0xab,0x54,0xcf,0xdc,0x14,0x06,0xc8,0xfc,0x42,
   2157 0xd3,0xf0,0xad,0x10,0x08,0xcd,0xd4,0x11,0xbb,0xca,0x67,0xc6,0x48,0x5f,0x9d,0x59,
   2158 0xe3,0xe8,0x53,0x67,0x27,0x2d,0x34,0x9e,0x9e,0x24,0x29,0xdb,0x69,0x99,0x86,0xf9,
   2159 0x20,0xb5,0xbb,0x5b,0xb0,0xf9,0xc3,0x67,0xad,0x1c,0x9c,0xf7,0xcc,0xef,0xce,0x69,
   2160 0xe0,0x26,0x8f,0x79,0xbd,0xca,0x10,0x17,0xda,0xa9,0x88,0x57,0x9b,0x15,0x24,0xba,
   2161 0x84,0xd0,0xeb,0x4d,0x14,0xf5,0xfc,0xe6,0x51,0x6c,0x6f,0x64,0x6b,0x73,0xec,0x85,
   2162 0xf1,0x6f,0xe1,0x67,0x25,0x10,0x77,0x32,0x9e,0x85,0x6e,0x69,0xb1,0x83,0x00,0xe4,
   2163 0x13,0xa4,0x45,0x34,0x3b,0x40,0xff,0x41,0x82,0x89,0x79,0x57,0xfd,0xd2,0x8e,0xe8,
   2164 0xfc,0x1d,0x19,0x21,0x12,0x00,0xd7,0x66,0xe5,0xc7,0x10,0x1d,0xcb,0x75,0xe8,0xfa,
   2165 0xb6,0xee,0x7b,0x2f,0x1a,0x25,0x24,0xb9,0x9f,0x1d,0x78,0xfb,0x84,0xd0,0x17,0x05,
   2166 0x71,0xb3,0xc8,0x18,0xff,0x62,0xee,0xed,0x53,0xab,0x78,0xd3,0x65,0x2d,0xbb,0xc7,
   2167 0xc1,0xe7,0x70,0xa2,0x43,0x2c,0x7c,0xc7,0x16,0x04,0xd2,0x45,0xd5,0x6b,0x6c,0x7a,
   2168 0x5e,0xa1,0x50,0x2e,0x31,0x5b,0xcc,0xe8,0x65,0x8b,0x16,0x85,0xbf,0x82,0x83,0xfb,
   2169 0xde,0x9f,0x36,0x48,0x32,0x79,0xd6,0x9b,0xfb,0x52,0x45,0xbf,0x43,0xf7,0x0b,0x0b,
   2170 0x19,0x19,0x31,0xc3,0x85,0xec,0x1d,0x8c,0x20,0xf0,0x3a,0xfa,0x80,0x4d,0x2c,0x7d,
   2171 0xac,0x60,0x09,0xc0,0x40,0xee,0xb9,0xeb,0x13,0x5b,0xe8,0x2b,0xb1,0x20,0xf0,0xce,
   2172 0x4c,0xbd,0xc6,0x04,0x86,0x70,0xc6,0x33,0xc3,0x15,0x0f,0x65,0x19,0xfd,0xc2,0xd3,
   2173 
   2174 // map checksum goes here
   2175 0x00,0x00,0x00,0x00
   2176 };
   2177 
   2178 static byte chkbuf[16 + 60 + 4];
   2179 
   2180 static unsigned last_mapchecksum = 0;
   2181 
   2182 #if 0
   2183 /*
   2184 ====================
   2185 COM_BlockSequenceCheckByte
   2186 
   2187 For proxy protecting
   2188 ====================
   2189 */
   2190 byte	COM_BlockSequenceCheckByte (byte *base, int length, int sequence, unsigned mapchecksum)
   2191 {
   2192 	int		checksum;
   2193 	byte	*p;
   2194 
   2195 	if (last_mapchecksum != mapchecksum) {
   2196 		last_mapchecksum = mapchecksum;
   2197 		chktbl[1024] = (mapchecksum & 0xff000000) >> 24;
   2198 		chktbl[1025] = (mapchecksum & 0x00ff0000) >> 16;
   2199 		chktbl[1026] = (mapchecksum & 0x0000ff00) >> 8;
   2200 		chktbl[1027] = (mapchecksum & 0x000000ff);
   2201 
   2202 		Com_BlockFullChecksum (chktbl, sizeof(chktbl), chkbuf);
   2203 	}
   2204 
   2205 	p = chktbl + (sequence % (sizeof(chktbl) - 8));
   2206 
   2207 	if (length > 60)
   2208 		length = 60;
   2209 	memcpy (chkbuf + 16, base, length);
   2210 
   2211 	length += 16;
   2212 
   2213 	chkbuf[length] = (sequence & 0xff) ^ p[0];
   2214 	chkbuf[length+1] = p[1];
   2215 	chkbuf[length+2] = ((sequence>>8) & 0xff) ^ p[2];
   2216 	chkbuf[length+3] = p[3];
   2217 
   2218 	length += 4;
   2219 
   2220 	checksum = LittleLong(Com_BlockChecksum (chkbuf, length));
   2221 
   2222 	checksum &= 0xff;
   2223 
   2224 	return checksum;
   2225 }
   2226 #endif
   2227 
   2228 /*
   2229 ====================
   2230 COM_BlockSequenceCRCByte
   2231 
   2232 For proxy protecting
   2233 ====================
   2234 */
   2235 byte	COM_BlockSequenceCRCByte (byte *base, int length, int sequence)
   2236 {
   2237 	unsigned short crc;
   2238 	byte	*p;
   2239 	byte chkb[60 + 4];
   2240 
   2241 	p = chktbl + (sequence % (sizeof(chktbl) - 8));
   2242 
   2243 	if (length > 60)
   2244 		length = 60;
   2245 	memcpy (chkb, base, length);
   2246 
   2247 	chkb[length] = (sequence & 0xff) ^ p[0];
   2248 	chkb[length+1] = p[1];
   2249 	chkb[length+2] = ((sequence>>8) & 0xff) ^ p[2];
   2250 	chkb[length+3] = p[3];
   2251 
   2252 	length += 4;
   2253 
   2254 	crc = CRC_Block(chkb, length);
   2255 
   2256 	crc &= 0xff;
   2257 
   2258 	return crc;
   2259 }
   2260 
   2261 // char *date = "Oct 24 1996";
   2262 static char *date = __DATE__ ;
   2263 static char *mon[12] =
   2264 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
   2265 static char mond[12] =
   2266 { 31,    28,    31,    30,    31,    30,    31,    31,    30,    31,    30,    31 };
   2267 
   2268 // returns days since Oct 24 1996
   2269 int build_number( void )
   2270 {
   2271 	int m = 0;
   2272 	int d = 0;
   2273 	int y = 0;
   2274 	static int b = 0;
   2275 
   2276 	if (b != 0)
   2277 		return b;
   2278 
   2279 	for (m = 0; m < 11; m++)
   2280 	{
   2281 		if (Q_strncasecmp( &date[0], mon[m], 3 ) == 0)
   2282 			break;
   2283 		d += mond[m];
   2284 	}
   2285 
   2286 	d += atoi( &date[4] ) - 1;
   2287 
   2288 	y = atoi( &date[7] ) - 1900;
   2289 
   2290 	b = d + (int)((y - 1) * 365.25);
   2291 
   2292 	if (((y % 4) == 0) && m > 1)
   2293 	{
   2294 		b += 1;
   2295 	}
   2296 
   2297 	b -= 35778; // Dec 16 1998
   2298 
   2299 	return b;
   2300 }
   2301 
   2302