2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // common.c -- misc functions used in client and server
31 cvar_t registered = {0, "registered","0", "indicates if this is running registered quake (whether gfx/pop.lmp was found)"};
32 cvar_t cmdline = {0, "cmdline","0", "contains commandline the engine was launched with"};
34 char com_token[MAX_INPUTLINE];
36 const char **com_argv;
41 const char *gamedirname1;
42 const char *gamedirname2;
43 const char *gamescreenshotname;
44 const char *gameuserdirname;
45 char com_modname[MAX_OSPATH] = "";
49 ============================================================================
53 ============================================================================
57 float BuffBigFloat (const unsigned char *buffer)
65 u.i = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
69 int BuffBigLong (const unsigned char *buffer)
71 return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
74 short BuffBigShort (const unsigned char *buffer)
76 return (buffer[0] << 8) | buffer[1];
79 float BuffLittleFloat (const unsigned char *buffer)
87 u.i = (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
91 int BuffLittleLong (const unsigned char *buffer)
93 return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
96 short BuffLittleShort (const unsigned char *buffer)
98 return (buffer[1] << 8) | buffer[0];
101 void StoreBigLong (unsigned char *buffer, unsigned int i)
103 buffer[0] = (i >> 24) & 0xFF;
104 buffer[1] = (i >> 16) & 0xFF;
105 buffer[2] = (i >> 8) & 0xFF;
106 buffer[3] = i & 0xFF;
109 void StoreBigShort (unsigned char *buffer, unsigned short i)
111 buffer[0] = (i >> 8) & 0xFF;
112 buffer[1] = i & 0xFF;
115 void StoreLittleLong (unsigned char *buffer, unsigned int i)
117 buffer[0] = i & 0xFF;
118 buffer[1] = (i >> 8) & 0xFF;
119 buffer[2] = (i >> 16) & 0xFF;
120 buffer[3] = (i >> 24) & 0xFF;
123 void StoreLittleShort (unsigned char *buffer, unsigned short i)
125 buffer[0] = i & 0xFF;
126 buffer[1] = (i >> 8) & 0xFF;
130 ============================================================================
134 ============================================================================
137 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
138 // and the initial and final xor values shown below... in other words, the
139 // CCITT standard CRC used by XMODEM
141 #define CRC_INIT_VALUE 0xffff
142 #define CRC_XOR_VALUE 0x0000
144 static unsigned short crctable[256] =
146 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
147 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
148 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
149 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
150 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
151 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
152 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
153 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
154 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
155 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
156 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
157 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
158 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
159 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
160 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
161 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
162 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
163 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
164 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
165 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
166 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
167 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
168 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
169 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
170 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
171 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
172 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
173 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
174 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
175 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
176 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
177 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
180 unsigned short CRC_Block(const unsigned char *data, size_t size)
182 unsigned short crc = CRC_INIT_VALUE;
184 crc = (crc << 8) ^ crctable[(crc >> 8) ^ (*data++)];
185 return crc ^ CRC_XOR_VALUE;
188 unsigned short CRC_Block_CaseInsensitive(const unsigned char *data, size_t size)
190 unsigned short crc = CRC_INIT_VALUE;
192 crc = (crc << 8) ^ crctable[(crc >> 8) ^ (tolower(*data++))];
193 return crc ^ CRC_XOR_VALUE;
197 static unsigned char chktbl[1024 + 4] =
199 0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01,
200 0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a,
201 0x64,0xed,0x5c,0x99,0x29,0x87,0xa8,0x78,0x59,0x0d,0xaa,0x0f,0x25,0x0a,0x5c,0x58,
202 0xfb,0x00,0xa7,0xa8,0x8a,0x1d,0x86,0x80,0xc5,0x1f,0xd2,0x28,0x69,0x71,0x58,0xc3,
203 0x51,0x90,0xe1,0xf8,0x6a,0xf3,0x8f,0xb0,0x68,0xdf,0x95,0x40,0x5c,0xe4,0x24,0x6b,
204 0x29,0x19,0x71,0x3f,0x42,0x63,0x6c,0x48,0xe7,0xad,0xa8,0x4b,0x91,0x8f,0x42,0x36,
205 0x34,0xe7,0x32,0x55,0x59,0x2d,0x36,0x38,0x38,0x59,0x9b,0x08,0x16,0x4d,0x8d,0xf8,
206 0x0a,0xa4,0x52,0x01,0xbb,0x52,0xa9,0xfd,0x40,0x18,0x97,0x37,0xff,0xc9,0x82,0x27,
207 0xb2,0x64,0x60,0xce,0x00,0xd9,0x04,0xf0,0x9e,0x99,0xbd,0xce,0x8f,0x90,0x4a,0xdd,
208 0xe1,0xec,0x19,0x14,0xb1,0xfb,0xca,0x1e,0x98,0x0f,0xd4,0xcb,0x80,0xd6,0x05,0x63,
209 0xfd,0xa0,0x74,0xa6,0x86,0xf6,0x19,0x98,0x76,0x27,0x68,0xf7,0xe9,0x09,0x9a,0xf2,
210 0x2e,0x42,0xe1,0xbe,0x64,0x48,0x2a,0x74,0x30,0xbb,0x07,0xcc,0x1f,0xd4,0x91,0x9d,
211 0xac,0x55,0x53,0x25,0xb9,0x64,0xf7,0x58,0x4c,0x34,0x16,0xbc,0xf6,0x12,0x2b,0x65,
212 0x68,0x25,0x2e,0x29,0x1f,0xbb,0xb9,0xee,0x6d,0x0c,0x8e,0xbb,0xd2,0x5f,0x1d,0x8f,
213 0xc1,0x39,0xf9,0x8d,0xc0,0x39,0x75,0xcf,0x25,0x17,0xbe,0x96,0xaf,0x98,0x9f,0x5f,
214 0x65,0x15,0xc4,0x62,0xf8,0x55,0xfc,0xab,0x54,0xcf,0xdc,0x14,0x06,0xc8,0xfc,0x42,
215 0xd3,0xf0,0xad,0x10,0x08,0xcd,0xd4,0x11,0xbb,0xca,0x67,0xc6,0x48,0x5f,0x9d,0x59,
216 0xe3,0xe8,0x53,0x67,0x27,0x2d,0x34,0x9e,0x9e,0x24,0x29,0xdb,0x69,0x99,0x86,0xf9,
217 0x20,0xb5,0xbb,0x5b,0xb0,0xf9,0xc3,0x67,0xad,0x1c,0x9c,0xf7,0xcc,0xef,0xce,0x69,
218 0xe0,0x26,0x8f,0x79,0xbd,0xca,0x10,0x17,0xda,0xa9,0x88,0x57,0x9b,0x15,0x24,0xba,
219 0x84,0xd0,0xeb,0x4d,0x14,0xf5,0xfc,0xe6,0x51,0x6c,0x6f,0x64,0x6b,0x73,0xec,0x85,
220 0xf1,0x6f,0xe1,0x67,0x25,0x10,0x77,0x32,0x9e,0x85,0x6e,0x69,0xb1,0x83,0x00,0xe4,
221 0x13,0xa4,0x45,0x34,0x3b,0x40,0xff,0x41,0x82,0x89,0x79,0x57,0xfd,0xd2,0x8e,0xe8,
222 0xfc,0x1d,0x19,0x21,0x12,0x00,0xd7,0x66,0xe5,0xc7,0x10,0x1d,0xcb,0x75,0xe8,0xfa,
223 0xb6,0xee,0x7b,0x2f,0x1a,0x25,0x24,0xb9,0x9f,0x1d,0x78,0xfb,0x84,0xd0,0x17,0x05,
224 0x71,0xb3,0xc8,0x18,0xff,0x62,0xee,0xed,0x53,0xab,0x78,0xd3,0x65,0x2d,0xbb,0xc7,
225 0xc1,0xe7,0x70,0xa2,0x43,0x2c,0x7c,0xc7,0x16,0x04,0xd2,0x45,0xd5,0x6b,0x6c,0x7a,
226 0x5e,0xa1,0x50,0x2e,0x31,0x5b,0xcc,0xe8,0x65,0x8b,0x16,0x85,0xbf,0x82,0x83,0xfb,
227 0xde,0x9f,0x36,0x48,0x32,0x79,0xd6,0x9b,0xfb,0x52,0x45,0xbf,0x43,0xf7,0x0b,0x0b,
228 0x19,0x19,0x31,0xc3,0x85,0xec,0x1d,0x8c,0x20,0xf0,0x3a,0xfa,0x80,0x4d,0x2c,0x7d,
229 0xac,0x60,0x09,0xc0,0x40,0xee,0xb9,0xeb,0x13,0x5b,0xe8,0x2b,0xb1,0x20,0xf0,0xce,
230 0x4c,0xbd,0xc6,0x04,0x86,0x70,0xc6,0x33,0xc3,0x15,0x0f,0x65,0x19,0xfd,0xc2,0xd3,
232 // map checksum goes here
237 unsigned char COM_BlockSequenceCRCByteQW(unsigned char *base, int length, int sequence)
240 unsigned char chkb[60 + 4];
242 p = chktbl + (sequence % (sizeof(chktbl) - 8));
246 memcpy(chkb, base, length);
248 chkb[length] = (sequence & 0xff) ^ p[0];
249 chkb[length+1] = p[1];
250 chkb[length+2] = ((sequence>>8) & 0xff) ^ p[2];
251 chkb[length+3] = p[3];
253 return CRC_Block(chkb, length + 4) & 0xff;
257 ==============================================================================
261 Handles byte ordering and avoids alignment errors
262 ==============================================================================
269 void MSG_WriteChar (sizebuf_t *sb, int c)
273 buf = SZ_GetSpace (sb, 1);
277 void MSG_WriteByte (sizebuf_t *sb, int c)
281 buf = SZ_GetSpace (sb, 1);
285 void MSG_WriteShort (sizebuf_t *sb, int c)
289 buf = SZ_GetSpace (sb, 2);
294 void MSG_WriteLong (sizebuf_t *sb, int c)
298 buf = SZ_GetSpace (sb, 4);
300 buf[1] = (c>>8)&0xff;
301 buf[2] = (c>>16)&0xff;
305 void MSG_WriteFloat (sizebuf_t *sb, float f)
315 dat.l = LittleLong (dat.l);
317 SZ_Write (sb, (unsigned char *)&dat.l, 4);
320 void MSG_WriteString (sizebuf_t *sb, const char *s)
323 MSG_WriteChar (sb, 0);
325 SZ_Write (sb, (unsigned char *)s, (int)strlen(s)+1);
328 void MSG_WriteUnterminatedString (sizebuf_t *sb, const char *s)
331 SZ_Write (sb, (unsigned char *)s, (int)strlen(s));
334 void MSG_WriteCoord13i (sizebuf_t *sb, float f)
337 MSG_WriteShort (sb, (int)(f * 8.0 + 0.5));
339 MSG_WriteShort (sb, (int)(f * 8.0 - 0.5));
342 void MSG_WriteCoord16i (sizebuf_t *sb, float f)
345 MSG_WriteShort (sb, (int)(f + 0.5));
347 MSG_WriteShort (sb, (int)(f - 0.5));
350 void MSG_WriteCoord32f (sizebuf_t *sb, float f)
352 MSG_WriteFloat (sb, f);
355 void MSG_WriteCoord (sizebuf_t *sb, float f, protocolversion_t protocol)
357 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD)
358 MSG_WriteCoord13i (sb, f);
359 else if (protocol == PROTOCOL_DARKPLACES1)
360 MSG_WriteCoord32f (sb, f);
361 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
362 MSG_WriteCoord16i (sb, f);
364 MSG_WriteCoord32f (sb, f);
367 void MSG_WriteVector (sizebuf_t *sb, const vec3_t v, protocolversion_t protocol)
369 MSG_WriteCoord (sb, v[0], protocol);
370 MSG_WriteCoord (sb, v[1], protocol);
371 MSG_WriteCoord (sb, v[2], protocol);
374 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
375 void MSG_WriteAngle8i (sizebuf_t *sb, float f)
378 MSG_WriteByte (sb, (int)(f*(256.0/360.0) + 0.5) & 255);
380 MSG_WriteByte (sb, (int)(f*(256.0/360.0) - 0.5) & 255);
383 void MSG_WriteAngle16i (sizebuf_t *sb, float f)
386 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) + 0.5) & 65535);
388 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) - 0.5) & 65535);
391 void MSG_WriteAngle32f (sizebuf_t *sb, float f)
393 MSG_WriteFloat (sb, f);
396 void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol)
398 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4 || protocol == PROTOCOL_QUAKEWORLD)
399 MSG_WriteAngle8i (sb, f);
401 MSG_WriteAngle16i (sb, f);
408 void MSG_InitReadBuffer (sizebuf_t *buf, unsigned char *data, int size)
410 memset(buf, 0, sizeof(*buf));
412 buf->maxsize = buf->cursize = size;
413 MSG_BeginReading(buf);
416 void MSG_BeginReading(sizebuf_t *sb)
422 int MSG_ReadLittleShort(sizebuf_t *sb)
424 if (sb->readcount+2 > sb->cursize)
430 return (short)(sb->data[sb->readcount-2] | (sb->data[sb->readcount-1]<<8));
433 int MSG_ReadBigShort (sizebuf_t *sb)
435 if (sb->readcount+2 > sb->cursize)
441 return (short)((sb->data[sb->readcount-2]<<8) + sb->data[sb->readcount-1]);
444 int MSG_ReadLittleLong (sizebuf_t *sb)
446 if (sb->readcount+4 > sb->cursize)
452 return sb->data[sb->readcount-4] | (sb->data[sb->readcount-3]<<8) | (sb->data[sb->readcount-2]<<16) | (sb->data[sb->readcount-1]<<24);
455 int MSG_ReadBigLong (sizebuf_t *sb)
457 if (sb->readcount+4 > sb->cursize)
463 return (sb->data[sb->readcount-4]<<24) + (sb->data[sb->readcount-3]<<16) + (sb->data[sb->readcount-2]<<8) + sb->data[sb->readcount-1];
466 float MSG_ReadLittleFloat (sizebuf_t *sb)
473 if (sb->readcount+4 > sb->cursize)
479 dat.l = sb->data[sb->readcount-4] | (sb->data[sb->readcount-3]<<8) | (sb->data[sb->readcount-2]<<16) | (sb->data[sb->readcount-1]<<24);
483 float MSG_ReadBigFloat (sizebuf_t *sb)
490 if (sb->readcount+4 > sb->cursize)
496 dat.l = (sb->data[sb->readcount-4]<<24) | (sb->data[sb->readcount-3]<<16) | (sb->data[sb->readcount-2]<<8) | sb->data[sb->readcount-1];
500 char *MSG_ReadString (sizebuf_t *sb, char *string, size_t maxstring)
504 // read string into sbfer, but only store as many characters as will fit
505 while ((c = MSG_ReadByte(sb)) > 0)
506 if (l < maxstring - 1)
512 int MSG_ReadBytes (sizebuf_t *sb, int numbytes, unsigned char *out)
515 for (l = 0;l < numbytes && (c = MSG_ReadByte(sb)) != -1;l++)
520 float MSG_ReadCoord13i (sizebuf_t *sb)
522 return MSG_ReadLittleShort(sb) * (1.0/8.0);
525 float MSG_ReadCoord16i (sizebuf_t *sb)
527 return (signed short) MSG_ReadLittleShort(sb);
530 float MSG_ReadCoord32f (sizebuf_t *sb)
532 return MSG_ReadLittleFloat(sb);
535 float MSG_ReadCoord (sizebuf_t *sb, protocolversion_t protocol)
537 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD)
538 return MSG_ReadCoord13i(sb);
539 else if (protocol == PROTOCOL_DARKPLACES1)
540 return MSG_ReadCoord32f(sb);
541 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
542 return MSG_ReadCoord16i(sb);
544 return MSG_ReadCoord32f(sb);
547 void MSG_ReadVector (sizebuf_t *sb, vec3_t v, protocolversion_t protocol)
549 v[0] = MSG_ReadCoord(sb, protocol);
550 v[1] = MSG_ReadCoord(sb, protocol);
551 v[2] = MSG_ReadCoord(sb, protocol);
554 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
555 float MSG_ReadAngle8i (sizebuf_t *sb)
557 return (signed char) MSG_ReadByte (sb) * (360.0/256.0);
560 float MSG_ReadAngle16i (sizebuf_t *sb)
562 return (signed short)MSG_ReadShort (sb) * (360.0/65536.0);
565 float MSG_ReadAngle32f (sizebuf_t *sb)
567 return MSG_ReadFloat (sb);
570 float MSG_ReadAngle (sizebuf_t *sb, protocolversion_t protocol)
572 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4 || protocol == PROTOCOL_QUAKEWORLD)
573 return MSG_ReadAngle8i (sb);
575 return MSG_ReadAngle16i (sb);
579 //===========================================================================
581 void SZ_Clear (sizebuf_t *buf)
586 unsigned char *SZ_GetSpace (sizebuf_t *buf, int length)
590 if (buf->cursize + length > buf->maxsize)
592 if (!buf->allowoverflow)
593 Host_Error ("SZ_GetSpace: overflow without allowoverflow set");
595 if (length > buf->maxsize)
596 Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
598 buf->overflowed = true;
599 Con_Print("SZ_GetSpace: overflow\n");
603 data = buf->data + buf->cursize;
604 buf->cursize += length;
609 void SZ_Write (sizebuf_t *buf, const unsigned char *data, int length)
611 memcpy (SZ_GetSpace(buf,length),data,length);
614 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
615 // attention, it has been eradicated from here, its only (former) use in
616 // all of darkplaces.
618 static const char *hexchar = "0123456789ABCDEF";
619 void Com_HexDumpToConsole(const unsigned char *data, int size)
623 char *cur, *flushpointer;
624 const unsigned char *d;
626 flushpointer = text + 512;
627 for (i = 0;i < size;)
634 *cur++ = hexchar[(i >> 12) & 15];
635 *cur++ = hexchar[(i >> 8) & 15];
636 *cur++ = hexchar[(i >> 4) & 15];
637 *cur++ = hexchar[(i >> 0) & 15];
640 for (j = 0;j < 16;j++)
644 *cur++ = hexchar[(d[j] >> 4) & 15];
645 *cur++ = hexchar[(d[j] >> 0) & 15];
656 for (j = 0;j < 16;j++)
660 // color change prefix character has to be treated specially
661 if (d[j] == STRING_COLOR_TAG)
663 *cur++ = STRING_COLOR_TAG;
664 *cur++ = STRING_COLOR_TAG;
666 else if (d[j] >= (unsigned char) ' ')
676 if (cur >= flushpointer || i >= size)
685 void SZ_HexDumpToConsole(const sizebuf_t *buf)
687 Com_HexDumpToConsole(buf->data, buf->cursize);
691 //============================================================================
697 Word wraps a string. The wordWidth function is guaranteed to be called exactly
698 once for each word in the string, so it may be stateful, no idea what that
699 would be good for any more. At the beginning of the string, it will be called
700 for the char 0 to initialize a clean state, and then once with the string " "
701 (a space) so the routine knows how long a space is.
703 In case no single character fits into the given width, the wordWidth function
704 must return the width of exactly one character.
706 Wrapped lines get the isContinuation flag set and are continuationWidth less wide.
708 The sum of the return values of the processLine function will be returned.
711 int COM_Wordwrap(const char *string, size_t length, float continuationWidth, float maxWidth, COM_WordWidthFunc_t wordWidth, void *passthroughCW, COM_LineProcessorFunc processLine, void *passthroughPL)
713 // Logic is as follows:
715 // For each word or whitespace:
716 // Newline found? Output current line, advance to next line. This is not a continuation. Continue.
717 // Space found? Always add it to the current line, no matter if it fits.
718 // Word found? Check if current line + current word fits.
719 // If it fits, append it. Continue.
720 // If it doesn't fit, output current line, advance to next line. Append the word. This is a continuation. Continue.
722 qboolean isContinuation = false;
724 const char *startOfLine = string;
725 const char *cursor = string;
726 const char *end = string + length;
727 float spaceUsedInLine = 0;
728 float spaceUsedForWord;
734 wordWidth(passthroughCW, NULL, &dummy, -1);
736 spaceWidth = wordWidth(passthroughCW, " ", &dummy, -1);
740 char ch = (cursor < end) ? *cursor : 0;
743 case 0: // end of string
744 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
746 case '\n': // end of line
747 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
748 isContinuation = false;
750 startOfLine = cursor;
754 spaceUsedInLine += spaceWidth;
758 while(cursor + wordLen < end)
760 switch(cursor[wordLen])
772 spaceUsedForWord = wordWidth(passthroughCW, cursor, &wordLen, maxWidth - continuationWidth); // this may have reduced wordLen when it won't fit - but this is GOOD. TODO fix words that do fit in a non-continuation line
773 if(wordLen < 1) // cannot happen according to current spec of wordWidth
776 spaceUsedForWord = maxWidth + 1; // too high, forces it in a line of itself
778 if(spaceUsedInLine + spaceUsedForWord <= maxWidth || cursor == startOfLine)
780 // we can simply append it
782 spaceUsedInLine += spaceUsedForWord;
786 // output current line
787 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
788 isContinuation = true;
789 startOfLine = cursor;
791 spaceUsedInLine = continuationWidth + spaceUsedForWord;
800 qboolean isContinuation = false;
801 float currentWordSpace = 0;
802 const char *currentWord = 0;
803 float minReserve = 0;
805 float spaceUsedInLine = 0;
806 const char *currentLine = 0;
807 const char *currentLineEnd = 0;
808 float currentLineFinalWhitespace = 0;
812 minReserve = charWidth(passthroughCW, 0);
813 minReserve += charWidth(passthroughCW, ' ');
815 if(maxWidth < continuationWidth + minReserve)
816 maxWidth = continuationWidth + minReserve;
818 charWidth(passthroughCW, 0);
820 for(p = string; p < string + length; ++p)
823 float w = charWidth(passthroughCW, c);
828 currentWordSpace = 0;
834 spaceUsedInLine = isContinuation ? continuationWidth : 0;
840 // 1. I can add the word AND a space - then just append it.
841 if(spaceUsedInLine + currentWordSpace + w <= maxWidth)
843 currentLineEnd = p; // note: space not included here
844 currentLineFinalWhitespace = w;
845 spaceUsedInLine += currentWordSpace + w;
847 // 2. I can just add the word - then append it, output current line and go to next one.
848 else if(spaceUsedInLine + currentWordSpace <= maxWidth)
850 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
852 isContinuation = true;
854 // 3. Otherwise, output current line and go to next one, where I can add the word.
855 else if(continuationWidth + currentWordSpace + w <= maxWidth)
858 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
859 currentLine = currentWord;
860 spaceUsedInLine = continuationWidth + currentWordSpace + w;
862 currentLineFinalWhitespace = w;
863 isContinuation = true;
865 // 4. We can't even do that? Then output both current and next word as new lines.
870 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
871 isContinuation = true;
873 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
875 isContinuation = true;
881 // 1. I can add the word - then do it.
882 if(spaceUsedInLine + currentWordSpace <= maxWidth)
884 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
886 // 2. Otherwise, output current line, next one and make tabula rasa.
891 processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
892 isContinuation = true;
894 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
898 isContinuation = false;
902 currentWordSpace += w;
904 spaceUsedInLine + currentWordSpace > maxWidth // can't join this line...
906 continuationWidth + currentWordSpace > maxWidth // can't join any other line...
909 // this word cannot join ANY line...
910 // so output the current line...
913 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
914 isContinuation = true;
917 // then this word's beginning...
920 // it may not fit, but we know we have to split it into maxWidth - continuationWidth pieces
921 float pieceWidth = maxWidth - continuationWidth;
922 const char *pos = currentWord;
923 currentWordSpace = 0;
925 // reset the char width function to a state where no kerning occurs (start of word)
926 charWidth(passthroughCW, ' ');
929 float w = charWidth(passthroughCW, *pos);
930 if(currentWordSpace + w > pieceWidth) // this piece won't fit any more
932 // print everything until it
933 result += processLine(passthroughPL, currentWord, pos - currentWord, currentWordSpace, true);
936 currentWordSpace = 0;
938 currentWordSpace += w;
941 // now we have a currentWord that fits... set up its next line
942 // currentWordSpace has been set
943 // currentWord has been set
944 spaceUsedInLine = continuationWidth;
945 currentLine = currentWord;
947 isContinuation = true;
951 // we have a guarantee that it will fix (see if clause)
952 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace - w, isContinuation);
954 // and use the rest of this word as new start of a line
955 currentWordSpace = w;
957 spaceUsedInLine = continuationWidth;
960 isContinuation = true;
969 currentWordSpace = 0;
972 if(currentLine) // Same procedure as \n
974 // Can I append the current word?
975 if(spaceUsedInLine + currentWordSpace <= maxWidth)
976 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
981 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
982 isContinuation = true;
984 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
994 COM_ParseToken_Simple
996 Parse a token out of a string
999 int COM_ParseToken_Simple(const char **datapointer, qboolean returnnewline, qboolean parsebackslash, qboolean parsecomments)
1003 const char *data = *datapointer;
1010 *datapointer = NULL;
1020 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1025 *datapointer = NULL;
1030 // handle Windows line ending
1031 if (data[0] == '\r' && data[1] == '\n')
1034 if (parsecomments && data[0] == '/' && data[1] == '/')
1037 while (*data && *data != '\n' && *data != '\r')
1041 else if (parsecomments && data[0] == '/' && data[1] == '*')
1045 while (*data && (data[0] != '*' || data[1] != '/'))
1053 else if (*data == '\"')
1056 for (data++;*data && *data != '\"';data++)
1059 if (*data == '\\' && parsebackslash)
1068 if (len < (int)sizeof(com_token) - 1)
1069 com_token[len++] = c;
1074 *datapointer = data;
1077 else if (*data == '\r')
1079 // translate Mac line ending to UNIX
1080 com_token[len++] = '\n';data++;
1082 *datapointer = data;
1085 else if (*data == '\n')
1088 com_token[len++] = *data++;
1090 *datapointer = data;
1096 for (;!ISWHITESPACE(*data);data++)
1097 if (len < (int)sizeof(com_token) - 1)
1098 com_token[len++] = *data;
1100 *datapointer = data;
1107 COM_ParseToken_QuakeC
1109 Parse a token out of a string
1112 int COM_ParseToken_QuakeC(const char **datapointer, qboolean returnnewline)
1116 const char *data = *datapointer;
1123 *datapointer = NULL;
1133 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1138 *datapointer = NULL;
1143 // handle Windows line ending
1144 if (data[0] == '\r' && data[1] == '\n')
1147 if (data[0] == '/' && data[1] == '/')
1150 while (*data && *data != '\n' && *data != '\r')
1154 else if (data[0] == '/' && data[1] == '*')
1158 while (*data && (data[0] != '*' || data[1] != '/'))
1166 else if (*data == '\"' || *data == '\'')
1170 for (data++;*data && *data != quote;data++)
1182 if (len < (int)sizeof(com_token) - 1)
1183 com_token[len++] = c;
1188 *datapointer = data;
1191 else if (*data == '\r')
1193 // translate Mac line ending to UNIX
1194 com_token[len++] = '\n';data++;
1196 *datapointer = data;
1199 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';')
1202 com_token[len++] = *data++;
1204 *datapointer = data;
1210 for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++)
1211 if (len < (int)sizeof(com_token) - 1)
1212 com_token[len++] = *data;
1214 *datapointer = data;
1221 COM_ParseToken_VM_Tokenize
1223 Parse a token out of a string
1226 int COM_ParseToken_VM_Tokenize(const char **datapointer, qboolean returnnewline)
1230 const char *data = *datapointer;
1237 *datapointer = NULL;
1247 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1252 *datapointer = NULL;
1257 // handle Windows line ending
1258 if (data[0] == '\r' && data[1] == '\n')
1261 if (data[0] == '/' && data[1] == '/')
1264 while (*data && *data != '\n' && *data != '\r')
1268 else if (data[0] == '/' && data[1] == '*')
1272 while (*data && (data[0] != '*' || data[1] != '/'))
1280 else if (*data == '\"' || *data == '\'')
1284 for (data++;*data && *data != quote;data++)
1296 if (len < (int)sizeof(com_token) - 1)
1297 com_token[len++] = c;
1302 *datapointer = data;
1305 else if (*data == '\r')
1307 // translate Mac line ending to UNIX
1308 com_token[len++] = '\n';data++;
1310 *datapointer = data;
1313 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';')
1316 com_token[len++] = *data++;
1318 *datapointer = data;
1324 for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++)
1325 if (len < (int)sizeof(com_token) - 1)
1326 com_token[len++] = *data;
1328 *datapointer = data;
1335 COM_ParseToken_Console
1337 Parse a token out of a string, behaving like the qwcl console
1340 int COM_ParseToken_Console(const char **datapointer)
1343 const char *data = *datapointer;
1350 *datapointer = NULL;
1356 for (;ISWHITESPACE(*data);data++)
1361 *datapointer = NULL;
1366 if (*data == '/' && data[1] == '/')
1369 while (*data && *data != '\n' && *data != '\r')
1373 else if (*data == '\"')
1376 for (data++;*data && *data != '\"';data++)
1378 // allow escaped " and \ case
1379 if (*data == '\\' && (data[1] == '\"' || data[1] == '\\'))
1381 if (len < (int)sizeof(com_token) - 1)
1382 com_token[len++] = *data;
1387 *datapointer = data;
1392 for (;!ISWHITESPACE(*data);data++)
1393 if (len < (int)sizeof(com_token) - 1)
1394 com_token[len++] = *data;
1396 *datapointer = data;
1407 Returns the position (1 to argc-1) in the program's argument list
1408 where the given parameter apears, or 0 if not present
1411 int COM_CheckParm (const char *parm)
1415 for (i=1 ; i<com_argc ; i++)
1418 continue; // NEXTSTEP sometimes clears appkit vars.
1419 if (!strcmp (parm,com_argv[i]))
1426 //===========================================================================
1430 gamemode_t com_startupgamemode;
1431 gamemode_t com_startupgamegroup;
1433 typedef struct gamemode_info_s
1435 gamemode_t mode; // this gamemode
1436 gamemode_t group; // different games with same group can switch automatically when gamedirs change
1437 const char* prog_name; // not null
1438 const char* cmdline; // not null
1439 const char* gamename; // not null
1440 const char* gamedirname1; // not null
1441 const char* gamedirname2; // null
1442 const char* gamescreenshotname; // not nul
1443 const char* gameuserdirname; // not null
1446 static const gamemode_info_t gamemode_info [GAME_COUNT] =
1447 {// game basegame prog_name cmdline gamename basegame modgame screenshot userdir // commandline option
1448 { GAME_NORMAL, GAME_NORMAL, "", "-quake", "DarkPlaces-Quake", "id1", NULL, "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -quake runs the game Quake (default)
1449 { GAME_HIPNOTIC, GAME_NORMAL, "hipnotic", "-hipnotic", "Darkplaces-Hipnotic", "id1", "hipnotic", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -hipnotic runs Quake mission pack 1: The Scourge of Armagon
1450 { GAME_ROGUE, GAME_NORMAL, "rogue", "-rogue", "Darkplaces-Rogue", "id1", "rogue", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -rogue runs Quake mission pack 2: The Dissolution of Eternity
1451 { GAME_NEHAHRA, GAME_NORMAL, "nehahra", "-nehahra", "DarkPlaces-Nehahra", "id1", "nehahra", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -nehahra runs The Seal of Nehahra movie and game
1452 { GAME_QUOTH, GAME_NORMAL, "quoth", "-quoth", "Darkplaces-Quoth", "id1", "quoth", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -quoth runs the Quoth mod for playing community maps made for it
1453 { GAME_NEXUIZ, GAME_NEXUIZ, "nexuiz", "-nexuiz", "Nexuiz", "data", NULL, "nexuiz", "nexuiz" }, // COMMANDLINEOPTION: Game: -nexuiz runs the multiplayer game Nexuiz
1454 { GAME_XONOTIC, GAME_XONOTIC, "xonotic", "-xonotic", "Xonotic", "data", NULL, "xonotic", "xonotic" }, // COMMANDLINEOPTION: Game: -xonotic runs the multiplayer game Xonotic
1455 { GAME_TRANSFUSION, GAME_TRANSFUSION, "transfusion", "-transfusion", "Transfusion", "basetf", NULL, "transfusion", "transfusion" }, // COMMANDLINEOPTION: Game: -transfusion runs Transfusion (the recreation of Blood in Quake)
1456 { GAME_GOODVSBAD2, GAME_GOODVSBAD2, "gvb2", "-goodvsbad2", "GoodVs.Bad2", "rts", NULL, "gvb2", "gvb2" }, // COMMANDLINEOPTION: Game: -goodvsbad2 runs the psychadelic RTS FPS game Good Vs Bad 2
1457 { GAME_TEU, GAME_TEU, "teu", "-teu", "TheEvilUnleashed", "baseteu", NULL, "teu", "teu" }, // COMMANDLINEOPTION: Game: -teu runs The Evil Unleashed (this option is obsolete as they are not using darkplaces)
1458 { GAME_BATTLEMECH, GAME_BATTLEMECH, "battlemech", "-battlemech", "Battlemech", "base", NULL, "battlemech", "battlemech" }, // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech
1459 { GAME_ZYMOTIC, GAME_ZYMOTIC, "zymotic", "-zymotic", "Zymotic", "basezym", NULL, "zymotic", "zymotic" }, // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
1460 { GAME_SETHERAL, GAME_SETHERAL, "setheral", "-setheral", "Setheral", "data", NULL, "setheral", "setheral" }, // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral
1461 { GAME_TENEBRAE, GAME_NORMAL, "tenebrae", "-tenebrae", "DarkPlaces-Tenebrae", "id1", "tenebrae", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -tenebrae runs the graphics test mod known as Tenebrae (some features not implemented)
1462 { GAME_NEOTERIC, GAME_NORMAL, "neoteric", "-neoteric", "Neoteric", "id1", "neobase", "neo", "darkplaces" }, // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
1463 { GAME_OPENQUARTZ, GAME_NORMAL, "openquartz", "-openquartz", "OpenQuartz", "id1", NULL, "openquartz", "darkplaces" }, // COMMANDLINEOPTION: Game: -openquartz runs the game OpenQuartz, a standalone GPL replacement of the quake content
1464 { GAME_PRYDON, GAME_NORMAL, "prydon", "-prydon", "PrydonGate", "id1", "prydon", "prydon", "darkplaces" }, // COMMANDLINEOPTION: Game: -prydon runs the topdown point and click action-RPG Prydon Gate
1465 { GAME_DELUXEQUAKE, GAME_DELUXEQUAKE, "dq", "-dq", "Deluxe Quake", "basedq", "extradq", "basedq", "dq" }, // COMMANDLINEOPTION: Game: -dq runs the game Deluxe Quake
1466 { GAME_THEHUNTED, GAME_THEHUNTED, "thehunted", "-thehunted", "The Hunted", "thdata", NULL, "th", "thehunted" }, // COMMANDLINEOPTION: Game: -thehunted runs the game The Hunted
1467 { GAME_DEFEATINDETAIL2, GAME_DEFEATINDETAIL2, "did2", "-did2", "Defeat In Detail 2", "data", NULL, "did2_", "did2" }, // COMMANDLINEOPTION: Game: -did2 runs the game Defeat In Detail 2
1468 { GAME_DARSANA, GAME_DARSANA, "darsana", "-darsana", "Darsana", "ddata", NULL, "darsana", "darsana" }, // COMMANDLINEOPTION: Game: -darsana runs the game Darsana
1469 { GAME_CONTAGIONTHEORY, GAME_CONTAGIONTHEORY, "contagiontheory", "-contagiontheory", "Contagion Theory", "ctdata", NULL, "ct", "contagiontheory" }, // COMMANDLINEOPTION: Game: -contagiontheory runs the game Contagion Theory
1470 { GAME_EDU2P, GAME_EDU2P, "edu2p", "-edu2p", "EDU2 Prototype", "id1", "edu2", "edu2_p", "edu2prototype" }, // COMMANDLINEOPTION: Game: -edu2p runs the game Edu2 prototype
1471 { GAME_PROPHECY, GAME_PROPHECY, "prophecy", "-prophecy", "Prophecy", "gamedata", NULL, "phcy", "prophecy" }, // COMMANDLINEOPTION: Game: -prophecy runs the game Prophecy
1472 { GAME_BLOODOMNICIDE, GAME_BLOODOMNICIDE, "omnicide", "-omnicide", "Blood Omnicide", "kain", NULL, "omnicide", "omnicide" }, // COMMANDLINEOPTION: Game: -omnicide runs the game Blood Omnicide
1473 { GAME_STEELSTORM, GAME_STEELSTORM, "steelstorm", "-steelstorm", "Steel-Storm", "gamedata", NULL, "ss", "steelstorm" }, // COMMANDLINEOPTION: Game: -steelstorm runs the game Steel Storm
1474 { GAME_STEELSTORM2, GAME_STEELSTORM2, "steelstorm2", "-steelstorm2", "Steel Storm 2", "gamedata", NULL, "ss2", "steelstorm2" }, // COMMANDLINEOPTION: Game: -steelstorm2 runs the game Steel Storm 2
1475 { GAME_TOMESOFMEPHISTOPHELES, GAME_TOMESOFMEPHISTOPHELES, "tomesofmephistopheles", "-tomesofmephistopheles", "Tomes of Mephistopheles", "gamedata", NULL, "tom", "tomesofmephistopheles" }, // COMMANDLINEOPTION: Game: -steelstorm runs the game Steel Storm
1476 { GAME_STRAPBOMB, GAME_STRAPBOMB, "strapbomb", "-strapbomb", "Strap-on-bomb Car", "id1", NULL, "strap", "strapbomb" }, // COMMANDLINEOPTION: Game: -strapbomb runs the game Strap-on-bomb Car
1477 { GAME_MOONHELM, GAME_MOONHELM, "moonhelm", "-moonhelm", "MoonHelm", "data", NULL, "mh", "moonhelm" }, // COMMANDLINEOPTION: Game: -moonhelm runs the game MoonHelm
1480 static void COM_SetGameType(int index);
1481 void COM_InitGameType (void)
1483 char name [MAX_OSPATH];
1487 // check executable filename for keywords, but do it SMARTLY - only check the last path element
1488 FS_StripExtension(FS_FileWithoutPath(com_argv[0]), name, sizeof (name));
1489 COM_ToLowerString(name, name, sizeof (name));
1490 for (i = 1;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1491 if (gamemode_info[i].prog_name && gamemode_info[i].prog_name[0] && strstr (name, gamemode_info[i].prog_name))
1494 // check commandline options for keywords
1495 for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1496 if (COM_CheckParm (gamemode_info[i].cmdline))
1499 com_startupgamemode = gamemode_info[index].mode;
1500 com_startupgamegroup = gamemode_info[index].group;
1501 COM_SetGameType(index);
1504 void COM_ChangeGameTypeForGameDirs(void)
1508 // this will not not change the gamegroup
1509 // first check if a base game (single gamedir) matches
1510 for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1512 if (gamemode_info[i].group == com_startupgamegroup && !(gamemode_info[i].gamedirname2 && gamemode_info[i].gamedirname2[0]))
1518 // now that we have a base game, see if there is a matching derivative game (two gamedirs)
1521 for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1523 if (gamemode_info[i].group == com_startupgamegroup && (gamemode_info[i].gamedirname2 && gamemode_info[i].gamedirname2[0]) && !strcasecmp(fs_gamedirs[0], gamemode_info[i].gamedirname2))
1530 // we now have a good guess at which game this is meant to be...
1531 if (index >= 0 && gamemode != gamemode_info[index].mode)
1532 COM_SetGameType(index);
1535 static void COM_SetGameType(int index)
1538 if (index < 0 || index >= (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0])))
1540 gamemode = gamemode_info[index].mode;
1541 gamename = gamemode_info[index].gamename;
1542 gamedirname1 = gamemode_info[index].gamedirname1;
1543 gamedirname2 = gamemode_info[index].gamedirname2;
1544 gamescreenshotname = gamemode_info[index].gamescreenshotname;
1545 gameuserdirname = gamemode_info[index].gameuserdirname;
1547 if (gamemode == com_startupgamemode)
1549 if((t = COM_CheckParm("-customgamename")) && t + 1 < com_argc)
1550 gamename = com_argv[t+1];
1551 if((t = COM_CheckParm("-customgamedirname1")) && t + 1 < com_argc)
1552 gamedirname1 = com_argv[t+1];
1553 if((t = COM_CheckParm("-customgamedirname2")) && t + 1 < com_argc)
1554 gamedirname2 = *com_argv[t+1] ? com_argv[t+1] : NULL;
1555 if((t = COM_CheckParm("-customgamescreenshotname")) && t + 1 < com_argc)
1556 gamescreenshotname = com_argv[t+1];
1557 if((t = COM_CheckParm("-customgameuserdirname")) && t + 1 < com_argc)
1558 gameuserdirname = com_argv[t+1];
1561 if (gamedirname2 && gamedirname2[0])
1562 Con_Printf("Game is %s using base gamedirs %s %s", gamename, gamedirname1, gamedirname2);
1564 Con_Printf("Game is %s using base gamedir %s", gamename, gamedirname1);
1565 for (i = 0;i < fs_numgamedirs;i++)
1568 Con_Printf(", with mod gamedirs");
1569 Con_Printf(" %s", fs_gamedirs[i]);
1580 void COM_Init_Commands (void)
1583 char com_cmdline[MAX_INPUTLINE];
1585 Cvar_RegisterVariable (®istered);
1586 Cvar_RegisterVariable (&cmdline);
1588 // reconstitute the command line for the cmdline externally visible cvar
1590 for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
1593 if (strstr(com_argv[j], " "))
1595 // arg contains whitespace, store quotes around it
1596 com_cmdline[n++] = '\"';
1597 while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
1598 com_cmdline[n++] = com_argv[j][i++];
1599 com_cmdline[n++] = '\"';
1603 while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
1604 com_cmdline[n++] = com_argv[j][i++];
1606 if (n < ((int)sizeof(com_cmdline) - 1))
1607 com_cmdline[n++] = ' ';
1612 Cvar_Set ("cmdline", com_cmdline);
1619 varargs print into provided buffer, returns buffer (so that it can be called in-line, unlike dpsnprintf)
1622 char *va(char *buf, size_t buflen, const char *format, ...)
1626 va_start (argptr, format);
1627 dpvsnprintf (buf, buflen, format,argptr);
1634 //======================================
1636 // snprintf and vsnprintf are NOT portable. Use their DP counterparts instead
1642 # define snprintf _snprintf
1643 # define vsnprintf _vsnprintf
1647 int dpsnprintf (char *buffer, size_t buffersize, const char *format, ...)
1652 va_start (args, format);
1653 result = dpvsnprintf (buffer, buffersize, format, args);
1660 int dpvsnprintf (char *buffer, size_t buffersize, const char *format, va_list args)
1664 #if _MSC_VER >= 1400
1665 result = _vsnprintf_s (buffer, buffersize, _TRUNCATE, format, args);
1667 result = vsnprintf (buffer, buffersize, format, args);
1669 if (result < 0 || (size_t)result >= buffersize)
1671 buffer[buffersize - 1] = '\0';
1679 //======================================
1681 void COM_ToLowerString (const char *in, char *out, size_t size_out)
1686 if(utf8_enable.integer)
1689 while(*in && size_out > 1)
1692 Uchar ch = u8_getchar_utf8_enabled(in, &in);
1693 ch = u8_tolower(ch);
1694 n = u8_fromchar(ch, out, size_out);
1703 while (*in && size_out > 1)
1705 if (*in >= 'A' && *in <= 'Z')
1706 *out++ = *in++ + 'a' - 'A';
1714 void COM_ToUpperString (const char *in, char *out, size_t size_out)
1719 if(utf8_enable.integer)
1722 while(*in && size_out > 1)
1725 Uchar ch = u8_getchar_utf8_enabled(in, &in);
1726 ch = u8_toupper(ch);
1727 n = u8_fromchar(ch, out, size_out);
1736 while (*in && size_out > 1)
1738 if (*in >= 'a' && *in <= 'z')
1739 *out++ = *in++ + 'A' - 'a';
1747 int COM_StringBeginsWith(const char *s, const char *match)
1749 for (;*s && *match;s++, match++)
1755 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
1757 int argc, commentprefixlength;
1761 tokenbufend = tokenbuf + tokenbufsize;
1763 commentprefixlength = 0;
1765 commentprefixlength = (int)strlen(commentprefix);
1766 while (*l && *l != '\n' && *l != '\r')
1768 if (!ISWHITESPACE(*l))
1770 if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
1772 while (*l && *l != '\n' && *l != '\r')
1776 if (argc >= maxargc)
1778 argv[argc++] = tokenbuf;
1782 while (*l && *l != '"')
1784 if (tokenbuf >= tokenbufend)
1793 while (!ISWHITESPACE(*l))
1795 if (tokenbuf >= tokenbufend)
1800 if (tokenbuf >= tokenbufend)
1821 COM_StringLengthNoColors
1823 calculates the visible width of a color coded string.
1825 *valid is filled with TRUE if the string is a valid colored string (that is, if
1826 it does not end with an unfinished color code). If it gets filled with FALSE, a
1827 fix would be adding a STRING_COLOR_TAG at the end of the string.
1829 valid can be set to NULL if the caller doesn't care.
1831 For size_s, specify the maximum number of characters from s to use, or 0 to use
1832 all characters until the zero terminator.
1836 COM_StringLengthNoColors(const char *s, size_t size_s, qboolean *valid)
1838 const char *end = size_s ? (s + size_s) : NULL;
1842 switch((s == end) ? 0 : *s)
1848 case STRING_COLOR_TAG:
1850 switch((s == end) ? 0 : *s)
1852 case STRING_COLOR_RGB_TAG_CHAR:
1853 if (s+1 != end && isxdigit(s[1]) &&
1854 s+2 != end && isxdigit(s[2]) &&
1855 s+3 != end && isxdigit(s[3]) )
1860 ++len; // STRING_COLOR_TAG
1861 ++len; // STRING_COLOR_RGB_TAG_CHAR
1863 case 0: // ends with unfinished color code!
1868 case STRING_COLOR_TAG: // escaped ^
1871 case '0': case '1': case '2': case '3': case '4':
1872 case '5': case '6': case '7': case '8': case '9': // color code
1874 default: // not a color code
1875 ++len; // STRING_COLOR_TAG
1876 ++len; // the character
1891 COM_StringDecolorize
1893 removes color codes from a string.
1895 If escape_carets is true, the resulting string will be safe for printing. If
1896 escape_carets is false, the function will just strip color codes (for logging
1899 If the output buffer size did not suffice for converting, the function returns
1900 FALSE. Generally, if escape_carets is false, the output buffer needs
1901 strlen(str)+1 bytes, and if escape_carets is true, it can need strlen(str)*1.5+2
1902 bytes. In any case, the function makes sure that the resulting string is
1905 For size_in, specify the maximum number of characters from in to use, or 0 to use
1906 all characters until the zero terminator.
1910 COM_StringDecolorize(const char *in, size_t size_in, char *out, size_t size_out, qboolean escape_carets)
1912 #define APPEND(ch) do { if(--size_out) { *out++ = (ch); } else { *out++ = 0; return FALSE; } } while(0)
1913 const char *end = size_in ? (in + size_in) : NULL;
1918 switch((in == end) ? 0 : *in)
1923 case STRING_COLOR_TAG:
1925 switch((in == end) ? 0 : *in)
1927 case STRING_COLOR_RGB_TAG_CHAR:
1928 if (in+1 != end && isxdigit(in[1]) &&
1929 in+2 != end && isxdigit(in[2]) &&
1930 in+3 != end && isxdigit(in[3]) )
1935 APPEND(STRING_COLOR_TAG);
1937 APPEND(STRING_COLOR_TAG);
1938 APPEND(STRING_COLOR_RGB_TAG_CHAR);
1940 case 0: // ends with unfinished color code!
1941 APPEND(STRING_COLOR_TAG);
1942 // finish the code by appending another caret when escaping
1944 APPEND(STRING_COLOR_TAG);
1947 case STRING_COLOR_TAG: // escaped ^
1948 APPEND(STRING_COLOR_TAG);
1949 // append a ^ twice when escaping
1951 APPEND(STRING_COLOR_TAG);
1953 case '0': case '1': case '2': case '3': case '4':
1954 case '5': case '6': case '7': case '8': case '9': // color code
1956 default: // not a color code
1957 APPEND(STRING_COLOR_TAG);
1972 char *InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuelength)
1978 keylength = strlen(key);
1979 if (valuelength < 1 || !value)
1981 Con_Printf("InfoString_GetValue: no room in value\n");
1985 if (strchr(key, '\\'))
1987 Con_Printf("InfoString_GetValue: key name \"%s\" contains \\ which is not possible in an infostring\n", key);
1990 if (strchr(key, '\"'))
1992 Con_Printf("InfoString_SetValue: key name \"%s\" contains \" which is not allowed in an infostring\n", key);
1997 Con_Printf("InfoString_GetValue: can not look up a key with no name\n");
2000 while (buffer[pos] == '\\')
2002 if (!memcmp(buffer + pos+1, key, keylength))
2004 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2006 for (j = 0;buffer[pos+j] && buffer[pos+j] != '\\' && j < (int)valuelength - 1;j++)
2007 value[j] = buffer[pos+j];
2011 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2012 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2014 // if we reach this point the key was not found
2018 void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, const char *value)
2026 keylength = strlen(key);
2027 if (strchr(key, '\\') || strchr(value, '\\'))
2029 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \\ which is not possible to store in an infostring\n", key, value);
2032 if (strchr(key, '\"') || strchr(value, '\"'))
2034 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \" which is not allowed in an infostring\n", key, value);
2039 Con_Printf("InfoString_SetValue: can not set a key with no name\n");
2042 while (buffer[pos] == '\\')
2044 if (!memcmp(buffer + pos+1, key, keylength))
2046 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2047 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2049 // if we found the key, find the end of it because we will be replacing it
2051 if (buffer[pos] == '\\')
2053 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
2054 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
2056 if (bufferlength <= pos + 1 + strlen(key) + 1 + strlen(value) + strlen(buffer + pos2))
2058 Con_Printf("InfoString_SetValue: no room for \"%s\" \"%s\" in infostring\n", key, value);
2061 if (value && value[0])
2063 // set the key/value and append the remaining text
2064 char tempbuffer[MAX_INPUTLINE];
2065 strlcpy(tempbuffer, buffer + pos2, sizeof(tempbuffer));
2066 dpsnprintf(buffer + pos, bufferlength - pos, "\\%s\\%s%s", key, value, tempbuffer);
2070 // just remove the key from the text
2071 strlcpy(buffer + pos, buffer + pos2, bufferlength - pos);
2075 void InfoString_Print(char *buffer)
2078 char key[MAX_INPUTLINE];
2079 char value[MAX_INPUTLINE];
2082 if (*buffer != '\\')
2084 Con_Printf("InfoString_Print: corrupt string\n");
2087 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
2088 if (i < (int)sizeof(key)-1)
2091 if (*buffer != '\\')
2093 Con_Printf("InfoString_Print: corrupt string\n");
2096 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
2097 if (i < (int)sizeof(value)-1)
2098 value[i++] = *buffer;
2100 // empty value is an error case
2101 Con_Printf("%20s %s\n", key, value[0] ? value : "NO VALUE");
2105 //========================================================
2106 // strlcat and strlcpy, from OpenBSD
2109 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
2111 * Permission to use, copy, modify, and distribute this software for any
2112 * purpose with or without fee is hereby granted, provided that the above
2113 * copyright notice and this permission notice appear in all copies.
2115 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2116 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2117 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
2118 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2119 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2120 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2121 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2124 /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
2125 /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
2128 #ifndef HAVE_STRLCAT
2130 strlcat(char *dst, const char *src, size_t siz)
2132 register char *d = dst;
2133 register const char *s = src;
2134 register size_t n = siz;
2137 /* Find the end of dst and adjust bytes left but don't go past end */
2138 while (n-- != 0 && *d != '\0')
2144 return(dlen + strlen(s));
2145 while (*s != '\0') {
2154 return(dlen + (s - src)); /* count does not include NUL */
2156 #endif // #ifndef HAVE_STRLCAT
2159 #ifndef HAVE_STRLCPY
2161 strlcpy(char *dst, const char *src, size_t siz)
2163 register char *d = dst;
2164 register const char *s = src;
2165 register size_t n = siz;
2167 /* Copy as many bytes as will fit */
2168 if (n != 0 && --n != 0) {
2170 if ((*d++ = *s++) == 0)
2175 /* Not enough room in dst, add NUL and traverse rest of src */
2178 *d = '\0'; /* NUL-terminate dst */
2183 return(s - src - 1); /* count does not include NUL */
2186 #endif // #ifndef HAVE_STRLCPY
2188 void FindFraction(double val, int *num, int *denom, int denomMax)
2193 bestdiff = fabs(val);
2197 for(i = 1; i <= denomMax; ++i)
2199 int inum = (int) floor(0.5 + val * i);
2200 double diff = fabs(val - inum / (double)i);
2210 // decodes an XPM from C syntax
2211 char **XPM_DecodeString(const char *in)
2213 static char *tokens[257];
2214 static char lines[257][512];
2217 // skip until "{" token
2218 while(COM_ParseToken_QuakeC(&in, false) && strcmp(com_token, "{"));
2220 // now, read in succession: string, comma-or-}
2221 while(COM_ParseToken_QuakeC(&in, false))
2223 tokens[line] = lines[line];
2224 strlcpy(lines[line++], com_token, sizeof(lines[0]));
2225 if(!COM_ParseToken_QuakeC(&in, false))
2227 if(!strcmp(com_token, "}"))
2229 if(strcmp(com_token, ","))
2231 if(line >= sizeof(tokens) / sizeof(tokens[0]))
2238 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2239 static void base64_3to4(const unsigned char *in, unsigned char *out, int bytes)
2241 unsigned char i0 = (bytes > 0) ? in[0] : 0;
2242 unsigned char i1 = (bytes > 1) ? in[1] : 0;
2243 unsigned char i2 = (bytes > 2) ? in[2] : 0;
2244 unsigned char o0 = base64[i0 >> 2];
2245 unsigned char o1 = base64[((i0 << 4) | (i1 >> 4)) & 077];
2246 unsigned char o2 = base64[((i1 << 2) | (i2 >> 6)) & 077];
2247 unsigned char o3 = base64[i2 & 077];
2248 out[0] = (bytes > 0) ? o0 : '?';
2249 out[1] = (bytes > 0) ? o1 : '?';
2250 out[2] = (bytes > 1) ? o2 : '=';
2251 out[3] = (bytes > 2) ? o3 : '=';
2254 size_t base64_encode(unsigned char *buf, size_t buflen, size_t outbuflen)
2257 // expand the out-buffer
2258 blocks = (buflen + 2) / 3;
2259 if(blocks*4 > outbuflen)
2261 for(i = blocks; i > 0; )
2264 base64_3to4(buf + 3*i, buf + 4*i, buflen - 3*i);