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 = {CVAR_CLIENT | CVAR_SERVER, "registered","0", "indicates if this is running registered quake (whether gfx/pop.lmp was found)"};
32 cvar_t cmdline = {CVAR_CLIENT | CVAR_SERVER, "cmdline","0", "contains commandline the engine was launched with"};
34 char com_token[MAX_INPUTLINE];
38 const char *gamenetworkfiltername; // same as gamename currently but with _ in place of spaces so that "getservers" packets parse correctly (this also means the
39 const char *gamedirname1;
40 const char *gamedirname2;
41 const char *gamescreenshotname;
42 const char *gameuserdirname;
43 char com_modname[MAX_OSPATH] = "";
47 ============================================================================
51 ============================================================================
55 float BuffBigFloat (const unsigned char *buffer)
63 u.i = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
67 int BuffBigLong (const unsigned char *buffer)
69 return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
72 short BuffBigShort (const unsigned char *buffer)
74 return (buffer[0] << 8) | buffer[1];
77 float BuffLittleFloat (const unsigned char *buffer)
85 u.i = (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
89 int BuffLittleLong (const unsigned char *buffer)
91 return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
94 short BuffLittleShort (const unsigned char *buffer)
96 return (buffer[1] << 8) | buffer[0];
99 void StoreBigLong (unsigned char *buffer, unsigned int i)
101 buffer[0] = (i >> 24) & 0xFF;
102 buffer[1] = (i >> 16) & 0xFF;
103 buffer[2] = (i >> 8) & 0xFF;
104 buffer[3] = i & 0xFF;
107 void StoreBigShort (unsigned char *buffer, unsigned short i)
109 buffer[0] = (i >> 8) & 0xFF;
110 buffer[1] = i & 0xFF;
113 void StoreLittleLong (unsigned char *buffer, unsigned int i)
115 buffer[0] = i & 0xFF;
116 buffer[1] = (i >> 8) & 0xFF;
117 buffer[2] = (i >> 16) & 0xFF;
118 buffer[3] = (i >> 24) & 0xFF;
121 void StoreLittleShort (unsigned char *buffer, unsigned short i)
123 buffer[0] = i & 0xFF;
124 buffer[1] = (i >> 8) & 0xFF;
128 ============================================================================
132 ============================================================================
135 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
136 // and the initial and final xor values shown below... in other words, the
137 // CCITT standard CRC used by XMODEM
139 #define CRC_INIT_VALUE 0xffff
140 #define CRC_XOR_VALUE 0x0000
142 static unsigned short crctable[256] =
144 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
145 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
146 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
147 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
148 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
149 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
150 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
151 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
152 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
153 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
154 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
155 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
156 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
157 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
158 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
159 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
160 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
161 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
162 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
163 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
164 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
165 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
166 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
167 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
168 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
169 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
170 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
171 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
172 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
173 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
174 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
175 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
178 unsigned short CRC_Block(const unsigned char *data, size_t size)
180 unsigned short crc = CRC_INIT_VALUE;
182 crc = (crc << 8) ^ crctable[(crc >> 8) ^ (*data++)];
183 return crc ^ CRC_XOR_VALUE;
186 unsigned short CRC_Block_CaseInsensitive(const unsigned char *data, size_t size)
188 unsigned short crc = CRC_INIT_VALUE;
190 crc = (crc << 8) ^ crctable[(crc >> 8) ^ (tolower(*data++))];
191 return crc ^ CRC_XOR_VALUE;
195 static unsigned char chktbl[1024 + 4] =
197 0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01,
198 0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a,
199 0x64,0xed,0x5c,0x99,0x29,0x87,0xa8,0x78,0x59,0x0d,0xaa,0x0f,0x25,0x0a,0x5c,0x58,
200 0xfb,0x00,0xa7,0xa8,0x8a,0x1d,0x86,0x80,0xc5,0x1f,0xd2,0x28,0x69,0x71,0x58,0xc3,
201 0x51,0x90,0xe1,0xf8,0x6a,0xf3,0x8f,0xb0,0x68,0xdf,0x95,0x40,0x5c,0xe4,0x24,0x6b,
202 0x29,0x19,0x71,0x3f,0x42,0x63,0x6c,0x48,0xe7,0xad,0xa8,0x4b,0x91,0x8f,0x42,0x36,
203 0x34,0xe7,0x32,0x55,0x59,0x2d,0x36,0x38,0x38,0x59,0x9b,0x08,0x16,0x4d,0x8d,0xf8,
204 0x0a,0xa4,0x52,0x01,0xbb,0x52,0xa9,0xfd,0x40,0x18,0x97,0x37,0xff,0xc9,0x82,0x27,
205 0xb2,0x64,0x60,0xce,0x00,0xd9,0x04,0xf0,0x9e,0x99,0xbd,0xce,0x8f,0x90,0x4a,0xdd,
206 0xe1,0xec,0x19,0x14,0xb1,0xfb,0xca,0x1e,0x98,0x0f,0xd4,0xcb,0x80,0xd6,0x05,0x63,
207 0xfd,0xa0,0x74,0xa6,0x86,0xf6,0x19,0x98,0x76,0x27,0x68,0xf7,0xe9,0x09,0x9a,0xf2,
208 0x2e,0x42,0xe1,0xbe,0x64,0x48,0x2a,0x74,0x30,0xbb,0x07,0xcc,0x1f,0xd4,0x91,0x9d,
209 0xac,0x55,0x53,0x25,0xb9,0x64,0xf7,0x58,0x4c,0x34,0x16,0xbc,0xf6,0x12,0x2b,0x65,
210 0x68,0x25,0x2e,0x29,0x1f,0xbb,0xb9,0xee,0x6d,0x0c,0x8e,0xbb,0xd2,0x5f,0x1d,0x8f,
211 0xc1,0x39,0xf9,0x8d,0xc0,0x39,0x75,0xcf,0x25,0x17,0xbe,0x96,0xaf,0x98,0x9f,0x5f,
212 0x65,0x15,0xc4,0x62,0xf8,0x55,0xfc,0xab,0x54,0xcf,0xdc,0x14,0x06,0xc8,0xfc,0x42,
213 0xd3,0xf0,0xad,0x10,0x08,0xcd,0xd4,0x11,0xbb,0xca,0x67,0xc6,0x48,0x5f,0x9d,0x59,
214 0xe3,0xe8,0x53,0x67,0x27,0x2d,0x34,0x9e,0x9e,0x24,0x29,0xdb,0x69,0x99,0x86,0xf9,
215 0x20,0xb5,0xbb,0x5b,0xb0,0xf9,0xc3,0x67,0xad,0x1c,0x9c,0xf7,0xcc,0xef,0xce,0x69,
216 0xe0,0x26,0x8f,0x79,0xbd,0xca,0x10,0x17,0xda,0xa9,0x88,0x57,0x9b,0x15,0x24,0xba,
217 0x84,0xd0,0xeb,0x4d,0x14,0xf5,0xfc,0xe6,0x51,0x6c,0x6f,0x64,0x6b,0x73,0xec,0x85,
218 0xf1,0x6f,0xe1,0x67,0x25,0x10,0x77,0x32,0x9e,0x85,0x6e,0x69,0xb1,0x83,0x00,0xe4,
219 0x13,0xa4,0x45,0x34,0x3b,0x40,0xff,0x41,0x82,0x89,0x79,0x57,0xfd,0xd2,0x8e,0xe8,
220 0xfc,0x1d,0x19,0x21,0x12,0x00,0xd7,0x66,0xe5,0xc7,0x10,0x1d,0xcb,0x75,0xe8,0xfa,
221 0xb6,0xee,0x7b,0x2f,0x1a,0x25,0x24,0xb9,0x9f,0x1d,0x78,0xfb,0x84,0xd0,0x17,0x05,
222 0x71,0xb3,0xc8,0x18,0xff,0x62,0xee,0xed,0x53,0xab,0x78,0xd3,0x65,0x2d,0xbb,0xc7,
223 0xc1,0xe7,0x70,0xa2,0x43,0x2c,0x7c,0xc7,0x16,0x04,0xd2,0x45,0xd5,0x6b,0x6c,0x7a,
224 0x5e,0xa1,0x50,0x2e,0x31,0x5b,0xcc,0xe8,0x65,0x8b,0x16,0x85,0xbf,0x82,0x83,0xfb,
225 0xde,0x9f,0x36,0x48,0x32,0x79,0xd6,0x9b,0xfb,0x52,0x45,0xbf,0x43,0xf7,0x0b,0x0b,
226 0x19,0x19,0x31,0xc3,0x85,0xec,0x1d,0x8c,0x20,0xf0,0x3a,0xfa,0x80,0x4d,0x2c,0x7d,
227 0xac,0x60,0x09,0xc0,0x40,0xee,0xb9,0xeb,0x13,0x5b,0xe8,0x2b,0xb1,0x20,0xf0,0xce,
228 0x4c,0xbd,0xc6,0x04,0x86,0x70,0xc6,0x33,0xc3,0x15,0x0f,0x65,0x19,0xfd,0xc2,0xd3,
230 // map checksum goes here
235 unsigned char COM_BlockSequenceCRCByteQW(unsigned char *base, int length, int sequence)
238 unsigned char chkb[60 + 4];
240 p = chktbl + (sequence % (sizeof(chktbl) - 8));
244 memcpy(chkb, base, length);
246 chkb[length] = (sequence & 0xff) ^ p[0];
247 chkb[length+1] = p[1];
248 chkb[length+2] = ((sequence>>8) & 0xff) ^ p[2];
249 chkb[length+3] = p[3];
251 return CRC_Block(chkb, length + 4) & 0xff;
255 ==============================================================================
259 Handles byte ordering and avoids alignment errors
260 ==============================================================================
267 void MSG_WriteChar (sizebuf_t *sb, int c)
271 buf = SZ_GetSpace (sb, 1);
275 void MSG_WriteByte (sizebuf_t *sb, int c)
279 buf = SZ_GetSpace (sb, 1);
283 void MSG_WriteShort (sizebuf_t *sb, int c)
287 buf = SZ_GetSpace (sb, 2);
292 void MSG_WriteLong (sizebuf_t *sb, int c)
296 buf = SZ_GetSpace (sb, 4);
298 buf[1] = (c>>8)&0xff;
299 buf[2] = (c>>16)&0xff;
303 void MSG_WriteFloat (sizebuf_t *sb, float f)
313 dat.l = LittleLong (dat.l);
315 SZ_Write (sb, (unsigned char *)&dat.l, 4);
318 void MSG_WriteString (sizebuf_t *sb, const char *s)
321 MSG_WriteChar (sb, 0);
323 SZ_Write (sb, (unsigned char *)s, (int)strlen(s)+1);
326 void MSG_WriteUnterminatedString (sizebuf_t *sb, const char *s)
329 SZ_Write (sb, (unsigned char *)s, (int)strlen(s));
332 void MSG_WriteCoord13i (sizebuf_t *sb, float f)
335 MSG_WriteShort (sb, (int)(f * 8.0 + 0.5));
337 MSG_WriteShort (sb, (int)(f * 8.0 - 0.5));
340 void MSG_WriteCoord16i (sizebuf_t *sb, float f)
343 MSG_WriteShort (sb, (int)(f + 0.5));
345 MSG_WriteShort (sb, (int)(f - 0.5));
348 void MSG_WriteCoord32f (sizebuf_t *sb, float f)
350 MSG_WriteFloat (sb, f);
353 void MSG_WriteCoord (sizebuf_t *sb, float f, protocolversion_t protocol)
355 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD)
356 MSG_WriteCoord13i (sb, f);
357 else if (protocol == PROTOCOL_DARKPLACES1)
358 MSG_WriteCoord32f (sb, f);
359 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
360 MSG_WriteCoord16i (sb, f);
362 MSG_WriteCoord32f (sb, f);
365 void MSG_WriteVector (sizebuf_t *sb, const vec3_t v, protocolversion_t protocol)
367 MSG_WriteCoord (sb, v[0], protocol);
368 MSG_WriteCoord (sb, v[1], protocol);
369 MSG_WriteCoord (sb, v[2], protocol);
372 // LadyHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
373 void MSG_WriteAngle8i (sizebuf_t *sb, float f)
376 MSG_WriteByte (sb, (int)(f*(256.0/360.0) + 0.5) & 255);
378 MSG_WriteByte (sb, (int)(f*(256.0/360.0) - 0.5) & 255);
381 void MSG_WriteAngle16i (sizebuf_t *sb, float f)
384 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) + 0.5) & 65535);
386 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) - 0.5) & 65535);
389 void MSG_WriteAngle32f (sizebuf_t *sb, float f)
391 MSG_WriteFloat (sb, f);
394 void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol)
396 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)
397 MSG_WriteAngle8i (sb, f);
399 MSG_WriteAngle16i (sb, f);
406 void MSG_InitReadBuffer (sizebuf_t *buf, unsigned char *data, int size)
408 memset(buf, 0, sizeof(*buf));
410 buf->maxsize = buf->cursize = size;
411 MSG_BeginReading(buf);
414 void MSG_BeginReading(sizebuf_t *sb)
420 int MSG_ReadLittleShort(sizebuf_t *sb)
422 if (sb->readcount+2 > sb->cursize)
428 return (short)(sb->data[sb->readcount-2] | (sb->data[sb->readcount-1]<<8));
431 int MSG_ReadBigShort (sizebuf_t *sb)
433 if (sb->readcount+2 > sb->cursize)
439 return (short)((sb->data[sb->readcount-2]<<8) + sb->data[sb->readcount-1]);
442 int MSG_ReadLittleLong (sizebuf_t *sb)
444 if (sb->readcount+4 > sb->cursize)
450 return sb->data[sb->readcount-4] | (sb->data[sb->readcount-3]<<8) | (sb->data[sb->readcount-2]<<16) | (sb->data[sb->readcount-1]<<24);
453 int MSG_ReadBigLong (sizebuf_t *sb)
455 if (sb->readcount+4 > sb->cursize)
461 return (sb->data[sb->readcount-4]<<24) + (sb->data[sb->readcount-3]<<16) + (sb->data[sb->readcount-2]<<8) + sb->data[sb->readcount-1];
464 float MSG_ReadLittleFloat (sizebuf_t *sb)
471 if (sb->readcount+4 > sb->cursize)
477 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);
481 float MSG_ReadBigFloat (sizebuf_t *sb)
488 if (sb->readcount+4 > sb->cursize)
494 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];
498 char *MSG_ReadString (sizebuf_t *sb, char *string, size_t maxstring)
502 // read string into sbfer, but only store as many characters as will fit
503 while ((c = MSG_ReadByte(sb)) > 0)
504 if (l < maxstring - 1)
510 int MSG_ReadBytes (sizebuf_t *sb, int numbytes, unsigned char *out)
513 for (l = 0;l < numbytes && (c = MSG_ReadByte(sb)) != -1;l++)
518 float MSG_ReadCoord13i (sizebuf_t *sb)
520 return MSG_ReadLittleShort(sb) * (1.0/8.0);
523 float MSG_ReadCoord16i (sizebuf_t *sb)
525 return (signed short) MSG_ReadLittleShort(sb);
528 float MSG_ReadCoord32f (sizebuf_t *sb)
530 return MSG_ReadLittleFloat(sb);
533 float MSG_ReadCoord (sizebuf_t *sb, protocolversion_t protocol)
535 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD)
536 return MSG_ReadCoord13i(sb);
537 else if (protocol == PROTOCOL_DARKPLACES1)
538 return MSG_ReadCoord32f(sb);
539 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
540 return MSG_ReadCoord16i(sb);
542 return MSG_ReadCoord32f(sb);
545 void MSG_ReadVector (sizebuf_t *sb, vec3_t v, protocolversion_t protocol)
547 v[0] = MSG_ReadCoord(sb, protocol);
548 v[1] = MSG_ReadCoord(sb, protocol);
549 v[2] = MSG_ReadCoord(sb, protocol);
552 // LadyHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
553 float MSG_ReadAngle8i (sizebuf_t *sb)
555 return (signed char) MSG_ReadByte (sb) * (360.0/256.0);
558 float MSG_ReadAngle16i (sizebuf_t *sb)
560 return (signed short)MSG_ReadShort (sb) * (360.0/65536.0);
563 float MSG_ReadAngle32f (sizebuf_t *sb)
565 return MSG_ReadFloat (sb);
568 float MSG_ReadAngle (sizebuf_t *sb, protocolversion_t protocol)
570 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)
571 return MSG_ReadAngle8i (sb);
573 return MSG_ReadAngle16i (sb);
577 //===========================================================================
579 void SZ_Clear (sizebuf_t *buf)
584 unsigned char *SZ_GetSpace (sizebuf_t *buf, int length)
588 if (buf->cursize + length > buf->maxsize)
590 if (!buf->allowoverflow)
591 Host_Error ("SZ_GetSpace: overflow without allowoverflow set");
593 if (length > buf->maxsize)
594 Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
596 buf->overflowed = true;
597 Con_Print("SZ_GetSpace: overflow\n");
601 data = buf->data + buf->cursize;
602 buf->cursize += length;
607 void SZ_Write (sizebuf_t *buf, const unsigned char *data, int length)
609 memcpy (SZ_GetSpace(buf,length),data,length);
612 // LadyHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
613 // attention, it has been eradicated from here, its only (former) use in
614 // all of darkplaces.
616 static const char *hexchar = "0123456789ABCDEF";
617 void Com_HexDumpToConsole(const unsigned char *data, int size)
621 char *cur, *flushpointer;
622 const unsigned char *d;
624 flushpointer = text + 512;
625 for (i = 0;i < size;)
632 *cur++ = hexchar[(i >> 12) & 15];
633 *cur++ = hexchar[(i >> 8) & 15];
634 *cur++ = hexchar[(i >> 4) & 15];
635 *cur++ = hexchar[(i >> 0) & 15];
638 for (j = 0;j < 16;j++)
642 *cur++ = hexchar[(d[j] >> 4) & 15];
643 *cur++ = hexchar[(d[j] >> 0) & 15];
654 for (j = 0;j < 16;j++)
658 // color change prefix character has to be treated specially
659 if (d[j] == STRING_COLOR_TAG)
661 *cur++ = STRING_COLOR_TAG;
662 *cur++ = STRING_COLOR_TAG;
664 else if (d[j] >= (unsigned char) ' ')
674 if (cur >= flushpointer || i >= size)
683 void SZ_HexDumpToConsole(const sizebuf_t *buf)
685 Com_HexDumpToConsole(buf->data, buf->cursize);
689 //============================================================================
695 Word wraps a string. The wordWidth function is guaranteed to be called exactly
696 once for each word in the string, so it may be stateful, no idea what that
697 would be good for any more. At the beginning of the string, it will be called
698 for the char 0 to initialize a clean state, and then once with the string " "
699 (a space) so the routine knows how long a space is.
701 In case no single character fits into the given width, the wordWidth function
702 must return the width of exactly one character.
704 Wrapped lines get the isContinuation flag set and are continuationWidth less wide.
706 The sum of the return values of the processLine function will be returned.
709 int COM_Wordwrap(const char *string, size_t length, float continuationWidth, float maxWidth, COM_WordWidthFunc_t wordWidth, void *passthroughCW, COM_LineProcessorFunc processLine, void *passthroughPL)
711 // Logic is as follows:
713 // For each word or whitespace:
714 // Newline found? Output current line, advance to next line. This is not a continuation. Continue.
715 // Space found? Always add it to the current line, no matter if it fits.
716 // Word found? Check if current line + current word fits.
717 // If it fits, append it. Continue.
718 // If it doesn't fit, output current line, advance to next line. Append the word. This is a continuation. Continue.
720 qboolean isContinuation = false;
722 const char *startOfLine = string;
723 const char *cursor = string;
724 const char *end = string + length;
725 float spaceUsedInLine = 0;
726 float spaceUsedForWord;
732 wordWidth(passthroughCW, NULL, &dummy, -1);
734 spaceWidth = wordWidth(passthroughCW, " ", &dummy, -1);
738 char ch = (cursor < end) ? *cursor : 0;
741 case 0: // end of string
742 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
744 case '\n': // end of line
745 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
746 isContinuation = false;
748 startOfLine = cursor;
752 spaceUsedInLine += spaceWidth;
756 while(cursor + wordLen < end)
758 switch(cursor[wordLen])
770 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
771 if(wordLen < 1) // cannot happen according to current spec of wordWidth
774 spaceUsedForWord = maxWidth + 1; // too high, forces it in a line of itself
776 if(spaceUsedInLine + spaceUsedForWord <= maxWidth || cursor == startOfLine)
778 // we can simply append it
780 spaceUsedInLine += spaceUsedForWord;
784 // output current line
785 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
786 isContinuation = true;
787 startOfLine = cursor;
789 spaceUsedInLine = continuationWidth + spaceUsedForWord;
798 qboolean isContinuation = false;
799 float currentWordSpace = 0;
800 const char *currentWord = 0;
801 float minReserve = 0;
803 float spaceUsedInLine = 0;
804 const char *currentLine = 0;
805 const char *currentLineEnd = 0;
806 float currentLineFinalWhitespace = 0;
810 minReserve = charWidth(passthroughCW, 0);
811 minReserve += charWidth(passthroughCW, ' ');
813 if(maxWidth < continuationWidth + minReserve)
814 maxWidth = continuationWidth + minReserve;
816 charWidth(passthroughCW, 0);
818 for(p = string; p < string + length; ++p)
821 float w = charWidth(passthroughCW, c);
826 currentWordSpace = 0;
832 spaceUsedInLine = isContinuation ? continuationWidth : 0;
838 // 1. I can add the word AND a space - then just append it.
839 if(spaceUsedInLine + currentWordSpace + w <= maxWidth)
841 currentLineEnd = p; // note: space not included here
842 currentLineFinalWhitespace = w;
843 spaceUsedInLine += currentWordSpace + w;
845 // 2. I can just add the word - then append it, output current line and go to next one.
846 else if(spaceUsedInLine + currentWordSpace <= maxWidth)
848 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
850 isContinuation = true;
852 // 3. Otherwise, output current line and go to next one, where I can add the word.
853 else if(continuationWidth + currentWordSpace + w <= maxWidth)
856 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
857 currentLine = currentWord;
858 spaceUsedInLine = continuationWidth + currentWordSpace + w;
860 currentLineFinalWhitespace = w;
861 isContinuation = true;
863 // 4. We can't even do that? Then output both current and next word as new lines.
868 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
869 isContinuation = true;
871 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
873 isContinuation = true;
879 // 1. I can add the word - then do it.
880 if(spaceUsedInLine + currentWordSpace <= maxWidth)
882 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
884 // 2. Otherwise, output current line, next one and make tabula rasa.
889 processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
890 isContinuation = true;
892 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
896 isContinuation = false;
900 currentWordSpace += w;
902 spaceUsedInLine + currentWordSpace > maxWidth // can't join this line...
904 continuationWidth + currentWordSpace > maxWidth // can't join any other line...
907 // this word cannot join ANY line...
908 // so output the current line...
911 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
912 isContinuation = true;
915 // then this word's beginning...
918 // it may not fit, but we know we have to split it into maxWidth - continuationWidth pieces
919 float pieceWidth = maxWidth - continuationWidth;
920 const char *pos = currentWord;
921 currentWordSpace = 0;
923 // reset the char width function to a state where no kerning occurs (start of word)
924 charWidth(passthroughCW, ' ');
927 float w = charWidth(passthroughCW, *pos);
928 if(currentWordSpace + w > pieceWidth) // this piece won't fit any more
930 // print everything until it
931 result += processLine(passthroughPL, currentWord, pos - currentWord, currentWordSpace, true);
934 currentWordSpace = 0;
936 currentWordSpace += w;
939 // now we have a currentWord that fits... set up its next line
940 // currentWordSpace has been set
941 // currentWord has been set
942 spaceUsedInLine = continuationWidth;
943 currentLine = currentWord;
945 isContinuation = true;
949 // we have a guarantee that it will fix (see if clause)
950 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace - w, isContinuation);
952 // and use the rest of this word as new start of a line
953 currentWordSpace = w;
955 spaceUsedInLine = continuationWidth;
958 isContinuation = true;
967 currentWordSpace = 0;
970 if(currentLine) // Same procedure as \n
972 // Can I append the current word?
973 if(spaceUsedInLine + currentWordSpace <= maxWidth)
974 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
979 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
980 isContinuation = true;
982 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
992 COM_ParseToken_Simple
994 Parse a token out of a string
997 int COM_ParseToken_Simple(const char **datapointer, qboolean returnnewline, qboolean parsebackslash, qboolean parsecomments)
1001 const char *data = *datapointer;
1008 *datapointer = NULL;
1018 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1023 *datapointer = NULL;
1028 // handle Windows line ending
1029 if (data[0] == '\r' && data[1] == '\n')
1032 if (parsecomments && data[0] == '/' && data[1] == '/')
1035 while (*data && *data != '\n' && *data != '\r')
1039 else if (parsecomments && data[0] == '/' && data[1] == '*')
1043 while (*data && (data[0] != '*' || data[1] != '/'))
1051 else if (*data == '\"')
1054 for (data++;*data && *data != '\"';data++)
1057 if (*data == '\\' && parsebackslash)
1066 if (len < (int)sizeof(com_token) - 1)
1067 com_token[len++] = c;
1072 *datapointer = data;
1075 else if (*data == '\r')
1077 // translate Mac line ending to UNIX
1078 com_token[len++] = '\n';data++;
1080 *datapointer = data;
1083 else if (*data == '\n')
1086 com_token[len++] = *data++;
1088 *datapointer = data;
1094 for (;!ISWHITESPACE(*data);data++)
1095 if (len < (int)sizeof(com_token) - 1)
1096 com_token[len++] = *data;
1098 *datapointer = data;
1105 COM_ParseToken_QuakeC
1107 Parse a token out of a string
1110 int COM_ParseToken_QuakeC(const char **datapointer, qboolean returnnewline)
1114 const char *data = *datapointer;
1121 *datapointer = NULL;
1131 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1136 *datapointer = NULL;
1141 // handle Windows line ending
1142 if (data[0] == '\r' && data[1] == '\n')
1145 if (data[0] == '/' && data[1] == '/')
1148 while (*data && *data != '\n' && *data != '\r')
1152 else if (data[0] == '/' && data[1] == '*')
1156 while (*data && (data[0] != '*' || data[1] != '/'))
1164 else if (*data == '\"' || *data == '\'')
1168 for (data++;*data && *data != quote;data++)
1180 if (len < (int)sizeof(com_token) - 1)
1181 com_token[len++] = c;
1186 *datapointer = data;
1189 else if (*data == '\r')
1191 // translate Mac line ending to UNIX
1192 com_token[len++] = '\n';data++;
1194 *datapointer = data;
1197 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';')
1200 com_token[len++] = *data++;
1202 *datapointer = data;
1208 for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++)
1209 if (len < (int)sizeof(com_token) - 1)
1210 com_token[len++] = *data;
1212 *datapointer = data;
1219 COM_ParseToken_VM_Tokenize
1221 Parse a token out of a string
1224 int COM_ParseToken_VM_Tokenize(const char **datapointer, qboolean returnnewline)
1228 const char *data = *datapointer;
1235 *datapointer = NULL;
1245 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1250 *datapointer = NULL;
1255 // handle Windows line ending
1256 if (data[0] == '\r' && data[1] == '\n')
1259 if (data[0] == '/' && data[1] == '/')
1262 while (*data && *data != '\n' && *data != '\r')
1266 else if (data[0] == '/' && data[1] == '*')
1270 while (*data && (data[0] != '*' || data[1] != '/'))
1278 else if (*data == '\"' || *data == '\'')
1282 for (data++;*data && *data != quote;data++)
1294 if (len < (int)sizeof(com_token) - 1)
1295 com_token[len++] = c;
1300 *datapointer = data;
1303 else if (*data == '\r')
1305 // translate Mac line ending to UNIX
1306 com_token[len++] = '\n';data++;
1308 *datapointer = data;
1311 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';')
1314 com_token[len++] = *data++;
1316 *datapointer = data;
1322 for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++)
1323 if (len < (int)sizeof(com_token) - 1)
1324 com_token[len++] = *data;
1326 *datapointer = data;
1333 COM_ParseToken_Console
1335 Parse a token out of a string, behaving like the qwcl console
1338 int COM_ParseToken_Console(const char **datapointer)
1341 const char *data = *datapointer;
1348 *datapointer = NULL;
1354 for (;ISWHITESPACE(*data);data++)
1359 *datapointer = NULL;
1364 if (*data == '/' && data[1] == '/')
1367 while (*data && *data != '\n' && *data != '\r')
1371 else if (*data == '\"')
1374 for (data++;*data && *data != '\"';data++)
1376 // allow escaped " and \ case
1377 if (*data == '\\' && (data[1] == '\"' || data[1] == '\\'))
1379 if (len < (int)sizeof(com_token) - 1)
1380 com_token[len++] = *data;
1385 *datapointer = data;
1390 for (;!ISWHITESPACE(*data);data++)
1391 if (len < (int)sizeof(com_token) - 1)
1392 com_token[len++] = *data;
1394 *datapointer = data;
1405 Returns the position (1 to argc-1) in the program's argument list
1406 where the given parameter apears, or 0 if not present
1409 int COM_CheckParm (const char *parm)
1413 for (i=1 ; i<sys.argc ; i++)
1416 continue; // NEXTSTEP sometimes clears appkit vars.
1417 if (!strcmp (parm,sys.argv[i]))
1424 //===========================================================================
1428 gamemode_t com_startupgamemode;
1429 gamemode_t com_startupgamegroup;
1431 typedef struct gamemode_info_s
1433 gamemode_t mode; // this gamemode
1434 gamemode_t group; // different games with same group can switch automatically when gamedirs change
1435 const char* prog_name; // not null
1436 const char* cmdline; // not null
1437 const char* gamename; // not null
1438 const char* gamenetworkfiltername; // not null
1439 const char* gamedirname1; // not null
1440 const char* gamedirname2; // null
1441 const char* gamescreenshotname; // not nul
1442 const char* gameuserdirname; // not null
1445 static const gamemode_info_t gamemode_info [GAME_COUNT] =
1446 {// game basegame prog_name cmdline gamename gamenetworkfilername basegame modgame screenshot userdir // commandline option
1447 { GAME_NORMAL, GAME_NORMAL, "", "-quake", "DarkPlaces-Quake", "DarkPlaces-Quake", "id1", NULL, "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -quake runs the game Quake (default)
1448 { GAME_HIPNOTIC, GAME_NORMAL, "hipnotic", "-hipnotic", "Darkplaces-Hipnotic", "Darkplaces-Hipnotic", "id1", "hipnotic", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -hipnotic runs Quake mission pack 1: The Scourge of Armagon
1449 { GAME_ROGUE, GAME_NORMAL, "rogue", "-rogue", "Darkplaces-Rogue", "Darkplaces-Rogue", "id1", "rogue", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -rogue runs Quake mission pack 2: The Dissolution of Eternity
1450 { GAME_NEHAHRA, GAME_NORMAL, "nehahra", "-nehahra", "DarkPlaces-Nehahra", "DarkPlaces-Nehahra", "id1", "nehahra", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -nehahra runs The Seal of Nehahra movie and game
1451 { GAME_QUOTH, GAME_NORMAL, "quoth", "-quoth", "Darkplaces-Quoth", "Darkplaces-Quoth", "id1", "quoth", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -quoth runs the Quoth mod for playing community maps made for it
1452 { GAME_NEXUIZ, GAME_NEXUIZ, "nexuiz", "-nexuiz", "Nexuiz", "Nexuiz", "data", NULL, "nexuiz", "nexuiz" }, // COMMANDLINEOPTION: Game: -nexuiz runs the multiplayer game Nexuiz
1453 { GAME_XONOTIC, GAME_XONOTIC, "xonotic", "-xonotic", "Xonotic", "Xonotic", "data", NULL, "xonotic", "xonotic" }, // COMMANDLINEOPTION: Game: -xonotic runs the multiplayer game Xonotic
1454 { GAME_TRANSFUSION, GAME_TRANSFUSION, "transfusion", "-transfusion", "Transfusion", "Transfusion", "basetf", NULL, "transfusion", "transfusion" }, // COMMANDLINEOPTION: Game: -transfusion runs Transfusion (the recreation of Blood in Quake)
1455 { GAME_GOODVSBAD2, GAME_GOODVSBAD2, "gvb2", "-goodvsbad2", "GoodVs.Bad2", "GoodVs.Bad2", "rts", NULL, "gvb2", "gvb2" }, // COMMANDLINEOPTION: Game: -goodvsbad2 runs the psychadelic RTS FPS game Good Vs Bad 2
1456 { GAME_TEU, GAME_TEU, "teu", "-teu", "TheEvilUnleashed", "TheEvilUnleashed", "baseteu", NULL, "teu", "teu" }, // COMMANDLINEOPTION: Game: -teu runs The Evil Unleashed (this option is obsolete as they are not using darkplaces)
1457 { GAME_BATTLEMECH, GAME_BATTLEMECH, "battlemech", "-battlemech", "Battlemech", "Battlemech", "base", NULL, "battlemech", "battlemech" }, // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech
1458 { GAME_ZYMOTIC, GAME_ZYMOTIC, "zymotic", "-zymotic", "Zymotic", "Zymotic", "basezym", NULL, "zymotic", "zymotic" }, // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
1459 { GAME_SETHERAL, GAME_SETHERAL, "setheral", "-setheral", "Setheral", "Setheral", "data", NULL, "setheral", "setheral" }, // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral
1460 { GAME_TENEBRAE, GAME_NORMAL, "tenebrae", "-tenebrae", "DarkPlaces-Tenebrae", "DarkPlaces-Tenebrae", "id1", "tenebrae", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -tenebrae runs the graphics test mod known as Tenebrae (some features not implemented)
1461 { GAME_NEOTERIC, GAME_NORMAL, "neoteric", "-neoteric", "Neoteric", "Neoteric", "id1", "neobase", "neo", "darkplaces" }, // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
1462 { GAME_OPENQUARTZ, GAME_NORMAL, "openquartz", "-openquartz", "OpenQuartz", "OpenQuartz", "id1", NULL, "openquartz", "darkplaces" }, // COMMANDLINEOPTION: Game: -openquartz runs the game OpenQuartz, a standalone GPL replacement of the quake content
1463 { GAME_PRYDON, GAME_NORMAL, "prydon", "-prydon", "PrydonGate", "PrydonGate", "id1", "prydon", "prydon", "darkplaces" }, // COMMANDLINEOPTION: Game: -prydon runs the topdown point and click action-RPG Prydon Gate
1464 { GAME_DELUXEQUAKE, GAME_DELUXEQUAKE, "dq", "-dq", "Deluxe Quake", "Deluxe_Quake", "basedq", "extradq", "basedq", "dq" }, // COMMANDLINEOPTION: Game: -dq runs the game Deluxe Quake
1465 { GAME_THEHUNTED, GAME_THEHUNTED, "thehunted", "-thehunted", "The Hunted", "The_Hunted", "thdata", NULL, "th", "thehunted" }, // COMMANDLINEOPTION: Game: -thehunted runs the game The Hunted
1466 { GAME_DEFEATINDETAIL2, GAME_DEFEATINDETAIL2, "did2", "-did2", "Defeat In Detail 2", "Defeat_In_Detail_2", "data", NULL, "did2_", "did2" }, // COMMANDLINEOPTION: Game: -did2 runs the game Defeat In Detail 2
1467 { GAME_DARSANA, GAME_DARSANA, "darsana", "-darsana", "Darsana", "Darsana", "ddata", NULL, "darsana", "darsana" }, // COMMANDLINEOPTION: Game: -darsana runs the game Darsana
1468 { GAME_CONTAGIONTHEORY, GAME_CONTAGIONTHEORY, "contagiontheory", "-contagiontheory", "Contagion Theory", "Contagion_Theory", "ctdata", NULL, "ct", "contagiontheory" }, // COMMANDLINEOPTION: Game: -contagiontheory runs the game Contagion Theory
1469 { GAME_EDU2P, GAME_EDU2P, "edu2p", "-edu2p", "EDU2 Prototype", "EDU2_Prototype", "id1", "edu2", "edu2_p", "edu2prototype" }, // COMMANDLINEOPTION: Game: -edu2p runs the game Edu2 prototype
1470 { GAME_PROPHECY, GAME_PROPHECY, "prophecy", "-prophecy", "Prophecy", "Prophecy", "gamedata", NULL, "phcy", "prophecy" }, // COMMANDLINEOPTION: Game: -prophecy runs the game Prophecy
1471 { GAME_BLOODOMNICIDE, GAME_BLOODOMNICIDE, "omnicide", "-omnicide", "Blood Omnicide", "Blood_Omnicide", "kain", NULL, "omnicide", "omnicide" }, // COMMANDLINEOPTION: Game: -omnicide runs the game Blood Omnicide
1472 { GAME_STEELSTORM, GAME_STEELSTORM, "steelstorm", "-steelstorm", "Steel-Storm", "Steel-Storm", "gamedata", NULL, "ss", "steelstorm" }, // COMMANDLINEOPTION: Game: -steelstorm runs the game Steel Storm
1473 { GAME_STEELSTORM2, GAME_STEELSTORM2, "steelstorm2", "-steelstorm2", "Steel Storm 2", "Steel_Storm_2", "gamedata", NULL, "ss2", "steelstorm2" }, // COMMANDLINEOPTION: Game: -steelstorm2 runs the game Steel Storm 2
1474 { GAME_SSAMMO, GAME_SSAMMO, "steelstorm-ammo", "-steelstormammo", "Steel Storm A.M.M.O.", "Steel_Storm_A.M.M.O.", "gamedata", NULL, "ssammo", "steelstorm-ammo" }, // COMMANDLINEOPTION: Game: -steelstormammo runs the game Steel Storm A.M.M.O.
1475 { GAME_STEELSTORMREVENANTS, GAME_STEELSTORMREVENANTS, "steelstorm-revenants", "-steelstormrev", "Steel Storm: Revenants", "Steel_Storm_Revenants", "base", NULL, "ssrev", "steelstorm-revenants" }, // COMMANDLINEOPTION: Game: -steelstormrev runs the game Steel Storm: Revenants
1476 { GAME_TOMESOFMEPHISTOPHELES, GAME_TOMESOFMEPHISTOPHELES, "tomesofmephistopheles","-tomesofmephistopheles", "Tomes of Mephistopheles", "Tomes_of_Mephistopheles", "gamedata", NULL, "tom", "tomesofmephistopheles" }, // COMMANDLINEOPTION: Game: -tomesofmephistopheles runs the game Tomes of Mephistopheles
1477 { GAME_STRAPBOMB, GAME_STRAPBOMB, "strapbomb", "-strapbomb", "Strap-on-bomb Car", "Strap-on-bomb_Car", "id1", NULL, "strap", "strapbomb" }, // COMMANDLINEOPTION: Game: -strapbomb runs the game Strap-on-bomb Car
1478 { GAME_MOONHELM, GAME_MOONHELM, "moonhelm", "-moonhelm", "MoonHelm", "MoonHelm", "data", NULL, "mh", "moonhelm" }, // COMMANDLINEOPTION: Game: -moonhelm runs the game MoonHelm
1479 { GAME_VORETOURNAMENT, GAME_VORETOURNAMENT, "voretournament", "-voretournament", "Vore Tournament", "Vore_Tournament", "data", NULL, "voretournament", "voretournament" }, // COMMANDLINEOPTION: Game: -voretournament runs the multiplayer game Vore Tournament
1482 static void COM_SetGameType(int index);
1483 void COM_InitGameType (void)
1485 char name [MAX_OSPATH];
1490 COM_ToLowerString(FORCEGAME, name, sizeof (name));
1492 // check executable filename for keywords, but do it SMARTLY - only check the last path element
1493 FS_StripExtension(FS_FileWithoutPath(sys.argv[0]), name, sizeof (name));
1494 COM_ToLowerString(name, name, sizeof (name));
1496 for (i = 1;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1497 if (gamemode_info[i].prog_name && gamemode_info[i].prog_name[0] && strstr (name, gamemode_info[i].prog_name))
1500 // check commandline options for keywords
1501 for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1502 if (COM_CheckParm (gamemode_info[i].cmdline))
1505 com_startupgamemode = gamemode_info[index].mode;
1506 com_startupgamegroup = gamemode_info[index].group;
1507 COM_SetGameType(index);
1510 void COM_ChangeGameTypeForGameDirs(void)
1514 // this will not not change the gamegroup
1515 // first check if a base game (single gamedir) matches
1516 for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1518 if (gamemode_info[i].group == com_startupgamegroup && !(gamemode_info[i].gamedirname2 && gamemode_info[i].gamedirname2[0]))
1524 // now that we have a base game, see if there is a matching derivative game (two gamedirs)
1527 for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1529 if (gamemode_info[i].group == com_startupgamegroup && (gamemode_info[i].gamedirname2 && gamemode_info[i].gamedirname2[0]) && !strcasecmp(fs_gamedirs[0], gamemode_info[i].gamedirname2))
1536 // we now have a good guess at which game this is meant to be...
1537 if (index >= 0 && gamemode != gamemode_info[index].mode)
1538 COM_SetGameType(index);
1541 static void COM_SetGameType(int index)
1543 static char gamenetworkfilternamebuffer[64];
1545 if (index < 0 || index >= (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0])))
1547 gamemode = gamemode_info[index].mode;
1548 gamename = gamemode_info[index].gamename;
1549 gamenetworkfiltername = gamemode_info[index].gamenetworkfiltername;
1550 gamedirname1 = gamemode_info[index].gamedirname1;
1551 gamedirname2 = gamemode_info[index].gamedirname2;
1552 gamescreenshotname = gamemode_info[index].gamescreenshotname;
1553 gameuserdirname = gamemode_info[index].gameuserdirname;
1555 if (gamemode == com_startupgamemode)
1557 if((t = COM_CheckParm("-customgamename")) && t + 1 < sys.argc)
1558 gamename = gamenetworkfiltername = sys.argv[t+1];
1559 if((t = COM_CheckParm("-customgamenetworkfiltername")) && t + 1 < sys.argc)
1560 gamenetworkfiltername = sys.argv[t+1];
1561 if((t = COM_CheckParm("-customgamedirname1")) && t + 1 < sys.argc)
1562 gamedirname1 = sys.argv[t+1];
1563 if((t = COM_CheckParm("-customgamedirname2")) && t + 1 < sys.argc)
1564 gamedirname2 = *sys.argv[t+1] ? sys.argv[t+1] : NULL;
1565 if((t = COM_CheckParm("-customgamescreenshotname")) && t + 1 < sys.argc)
1566 gamescreenshotname = sys.argv[t+1];
1567 if((t = COM_CheckParm("-customgameuserdirname")) && t + 1 < sys.argc)
1568 gameuserdirname = sys.argv[t+1];
1571 if (gamedirname2 && gamedirname2[0])
1572 Con_Printf("Game is %s using base gamedirs %s %s", gamename, gamedirname1, gamedirname2);
1574 Con_Printf("Game is %s using base gamedir %s", gamename, gamedirname1);
1575 for (i = 0;i < fs_numgamedirs;i++)
1578 Con_Printf(", with mod gamedirs");
1579 Con_Printf(" %s", fs_gamedirs[i]);
1583 if (strchr(gamenetworkfiltername, ' '))
1586 // if there are spaces in the game's network filter name it would
1587 // cause parse errors in getservers in dpmaster, so we need to replace
1588 // them with _ characters
1589 strlcpy(gamenetworkfilternamebuffer, gamenetworkfiltername, sizeof(gamenetworkfilternamebuffer));
1590 while ((s = strchr(gamenetworkfilternamebuffer, ' ')) != NULL)
1592 gamenetworkfiltername = gamenetworkfilternamebuffer;
1595 Con_Printf("gamename for server filtering: %s\n", gamenetworkfiltername);
1604 void COM_Init_Commands (void)
1607 char com_cmdline[MAX_INPUTLINE];
1609 Cvar_RegisterVariable (®istered);
1610 Cvar_RegisterVariable (&cmdline);
1612 // reconstitute the command line for the cmdline externally visible cvar
1614 for (j = 0;(j < MAX_NUM_ARGVS) && (j < sys.argc);j++)
1617 if (strstr(sys.argv[j], " "))
1619 // arg contains whitespace, store quotes around it
1620 // This condition checks whether we can allow to put
1621 // in two quote characters.
1622 if (n >= ((int)sizeof(com_cmdline) - 2))
1624 com_cmdline[n++] = '\"';
1625 // This condition checks whether we can allow one
1626 // more character and a quote character.
1627 while ((n < ((int)sizeof(com_cmdline) - 2)) && sys.argv[j][i])
1628 // FIXME: Doesn't quote special characters.
1629 com_cmdline[n++] = sys.argv[j][i++];
1630 com_cmdline[n++] = '\"';
1634 // This condition checks whether we can allow one
1636 while ((n < ((int)sizeof(com_cmdline) - 1)) && sys.argv[j][i])
1637 com_cmdline[n++] = sys.argv[j][i++];
1639 if (n < ((int)sizeof(com_cmdline) - 1))
1640 com_cmdline[n++] = ' ';
1645 Cvar_SetQuick(&cmdline, com_cmdline);
1652 varargs print into provided buffer, returns buffer (so that it can be called in-line, unlike dpsnprintf)
1655 char *va(char *buf, size_t buflen, const char *format, ...)
1659 va_start (argptr, format);
1660 dpvsnprintf (buf, buflen, format,argptr);
1667 //======================================
1669 // snprintf and vsnprintf are NOT portable. Use their DP counterparts instead
1675 # define snprintf _snprintf
1676 # define vsnprintf _vsnprintf
1680 int dpsnprintf (char *buffer, size_t buffersize, const char *format, ...)
1685 va_start (args, format);
1686 result = dpvsnprintf (buffer, buffersize, format, args);
1693 int dpvsnprintf (char *buffer, size_t buffersize, const char *format, va_list args)
1697 #if _MSC_VER >= 1400
1698 result = _vsnprintf_s (buffer, buffersize, _TRUNCATE, format, args);
1700 result = vsnprintf (buffer, buffersize, format, args);
1702 if (result < 0 || (size_t)result >= buffersize)
1704 buffer[buffersize - 1] = '\0';
1712 //======================================
1714 void COM_ToLowerString (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_tolower(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 void COM_ToUpperString (const char *in, char *out, size_t size_out)
1752 if(utf8_enable.integer)
1755 while(*in && size_out > 1)
1758 Uchar ch = u8_getchar_utf8_enabled(in, &in);
1759 ch = u8_toupper(ch);
1760 n = u8_fromchar(ch, out, size_out);
1769 while (*in && size_out > 1)
1771 if (*in >= 'a' && *in <= 'z')
1772 *out++ = *in++ + 'A' - 'a';
1780 int COM_StringBeginsWith(const char *s, const char *match)
1782 for (;*s && *match;s++, match++)
1788 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
1790 int argc, commentprefixlength;
1794 tokenbufend = tokenbuf + tokenbufsize;
1796 commentprefixlength = 0;
1798 commentprefixlength = (int)strlen(commentprefix);
1799 while (*l && *l != '\n' && *l != '\r')
1801 if (!ISWHITESPACE(*l))
1803 if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
1805 while (*l && *l != '\n' && *l != '\r')
1809 if (argc >= maxargc)
1811 argv[argc++] = tokenbuf;
1815 while (*l && *l != '"')
1817 if (tokenbuf >= tokenbufend)
1826 while (!ISWHITESPACE(*l))
1828 if (tokenbuf >= tokenbufend)
1833 if (tokenbuf >= tokenbufend)
1854 COM_StringLengthNoColors
1856 calculates the visible width of a color coded string.
1858 *valid is filled with TRUE if the string is a valid colored string (that is, if
1859 it does not end with an unfinished color code). If it gets filled with FALSE, a
1860 fix would be adding a STRING_COLOR_TAG at the end of the string.
1862 valid can be set to NULL if the caller doesn't care.
1864 For size_s, specify the maximum number of characters from s to use, or 0 to use
1865 all characters until the zero terminator.
1869 COM_StringLengthNoColors(const char *s, size_t size_s, qboolean *valid)
1871 const char *end = size_s ? (s + size_s) : NULL;
1875 switch((s == end) ? 0 : *s)
1881 case STRING_COLOR_TAG:
1883 switch((s == end) ? 0 : *s)
1885 case STRING_COLOR_RGB_TAG_CHAR:
1886 if (s+1 != end && isxdigit(s[1]) &&
1887 s+2 != end && isxdigit(s[2]) &&
1888 s+3 != end && isxdigit(s[3]) )
1893 ++len; // STRING_COLOR_TAG
1894 ++len; // STRING_COLOR_RGB_TAG_CHAR
1896 case 0: // ends with unfinished color code!
1901 case STRING_COLOR_TAG: // escaped ^
1904 case '0': case '1': case '2': case '3': case '4':
1905 case '5': case '6': case '7': case '8': case '9': // color code
1907 default: // not a color code
1908 ++len; // STRING_COLOR_TAG
1909 ++len; // the character
1924 COM_StringDecolorize
1926 removes color codes from a string.
1928 If escape_carets is true, the resulting string will be safe for printing. If
1929 escape_carets is false, the function will just strip color codes (for logging
1932 If the output buffer size did not suffice for converting, the function returns
1933 FALSE. Generally, if escape_carets is false, the output buffer needs
1934 strlen(str)+1 bytes, and if escape_carets is true, it can need strlen(str)*1.5+2
1935 bytes. In any case, the function makes sure that the resulting string is
1938 For size_in, specify the maximum number of characters from in to use, or 0 to use
1939 all characters until the zero terminator.
1943 COM_StringDecolorize(const char *in, size_t size_in, char *out, size_t size_out, qboolean escape_carets)
1945 #define APPEND(ch) do { if(--size_out) { *out++ = (ch); } else { *out++ = 0; return false; } } while(0)
1946 const char *end = size_in ? (in + size_in) : NULL;
1951 switch((in == end) ? 0 : *in)
1956 case STRING_COLOR_TAG:
1958 switch((in == end) ? 0 : *in)
1960 case STRING_COLOR_RGB_TAG_CHAR:
1961 if (in+1 != end && isxdigit(in[1]) &&
1962 in+2 != end && isxdigit(in[2]) &&
1963 in+3 != end && isxdigit(in[3]) )
1968 APPEND(STRING_COLOR_TAG);
1970 APPEND(STRING_COLOR_TAG);
1971 APPEND(STRING_COLOR_RGB_TAG_CHAR);
1973 case 0: // ends with unfinished color code!
1974 APPEND(STRING_COLOR_TAG);
1975 // finish the code by appending another caret when escaping
1977 APPEND(STRING_COLOR_TAG);
1980 case STRING_COLOR_TAG: // escaped ^
1981 APPEND(STRING_COLOR_TAG);
1982 // append a ^ twice when escaping
1984 APPEND(STRING_COLOR_TAG);
1986 case '0': case '1': case '2': case '3': case '4':
1987 case '5': case '6': case '7': case '8': case '9': // color code
1989 default: // not a color code
1990 APPEND(STRING_COLOR_TAG);
2005 char *InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuelength)
2011 keylength = strlen(key);
2012 if (valuelength < 1 || !value)
2014 Con_Printf("InfoString_GetValue: no room in value\n");
2018 if (strchr(key, '\\'))
2020 Con_Printf("InfoString_GetValue: key name \"%s\" contains \\ which is not possible in an infostring\n", key);
2023 if (strchr(key, '\"'))
2025 Con_Printf("InfoString_SetValue: key name \"%s\" contains \" which is not allowed in an infostring\n", key);
2030 Con_Printf("InfoString_GetValue: can not look up a key with no name\n");
2033 while (buffer[pos] == '\\')
2035 if (!memcmp(buffer + pos+1, key, keylength) &&
2036 (buffer[pos+1 + keylength] == 0 ||
2037 buffer[pos+1 + keylength] == '\\'))
2039 pos += 1 + (int)keylength; // Skip \key
2040 if (buffer[pos] == '\\') pos++; // Skip \ before value.
2041 for (j = 0;buffer[pos+j] && buffer[pos+j] != '\\' && j < (int)valuelength - 1;j++)
2042 value[j] = buffer[pos+j];
2046 if (buffer[pos] == '\\') pos++; // Skip \ before value.
2047 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2048 if (buffer[pos] == '\\') pos++; // Skip \ before value.
2049 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2051 // if we reach this point the key was not found
2055 void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, const char *value)
2063 keylength = strlen(key);
2064 if (strchr(key, '\\') || strchr(value, '\\'))
2066 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \\ which is not possible to store in an infostring\n", key, value);
2069 if (strchr(key, '\"') || strchr(value, '\"'))
2071 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \" which is not allowed in an infostring\n", key, value);
2076 Con_Printf("InfoString_SetValue: can not set a key with no name\n");
2079 while (buffer[pos] == '\\')
2081 if (!memcmp(buffer + pos+1, key, keylength) &&
2082 (buffer[pos+1 + keylength] == 0 ||
2083 buffer[pos+1 + keylength] == '\\'))
2085 if (buffer[pos] == '\\') pos++; // Skip \ before value.
2086 for (;buffer[pos] && buffer[pos] != '\\';pos++);
2087 if (buffer[pos] == '\\') pos++; // Skip \ before value.
2088 for (;buffer[pos] && buffer[pos] != '\\';pos++);
2090 // if we found the key, find the end of it because we will be replacing it
2092 if (buffer[pos] == '\\')
2094 pos2 += 1 + (int)keylength; // Skip \key
2095 if (buffer[pos2] == '\\') pos2++; // Skip \ before value.
2096 for (;buffer[pos2] && buffer[pos2] != '\\';pos2++);
2098 if (bufferlength <= pos + 1 + strlen(key) + 1 + strlen(value) + strlen(buffer + pos2))
2100 Con_Printf("InfoString_SetValue: no room for \"%s\" \"%s\" in infostring\n", key, value);
2105 // set the key/value and append the remaining text
2106 char tempbuffer[MAX_INPUTLINE];
2107 strlcpy(tempbuffer, buffer + pos2, sizeof(tempbuffer));
2108 dpsnprintf(buffer + pos, bufferlength - pos, "\\%s\\%s%s", key, value, tempbuffer);
2112 // just remove the key from the text
2113 strlcpy(buffer + pos, buffer + pos2, bufferlength - pos);
2117 void InfoString_Print(char *buffer)
2120 char key[MAX_INPUTLINE];
2121 char value[MAX_INPUTLINE];
2124 if (*buffer != '\\')
2126 Con_Printf("InfoString_Print: corrupt string\n");
2129 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
2130 if (i < (int)sizeof(key)-1)
2133 if (*buffer != '\\')
2135 Con_Printf("InfoString_Print: corrupt string\n");
2138 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
2139 if (i < (int)sizeof(value)-1)
2140 value[i++] = *buffer;
2142 // empty value is an error case
2143 Con_Printf("%20s %s\n", key, value[0] ? value : "NO VALUE");
2147 //========================================================
2148 // strlcat and strlcpy, from OpenBSD
2151 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
2153 * Permission to use, copy, modify, and distribute this software for any
2154 * purpose with or without fee is hereby granted, provided that the above
2155 * copyright notice and this permission notice appear in all copies.
2157 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2158 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2159 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
2160 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2161 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2162 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2163 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2166 /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
2167 /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
2170 #ifndef HAVE_STRLCAT
2172 strlcat(char *dst, const char *src, size_t siz)
2174 register char *d = dst;
2175 register const char *s = src;
2176 register size_t n = siz;
2179 /* Find the end of dst and adjust bytes left but don't go past end */
2180 while (n-- != 0 && *d != '\0')
2186 return(dlen + strlen(s));
2187 while (*s != '\0') {
2196 return(dlen + (s - src)); /* count does not include NUL */
2198 #endif // #ifndef HAVE_STRLCAT
2201 #ifndef HAVE_STRLCPY
2203 strlcpy(char *dst, const char *src, size_t siz)
2205 register char *d = dst;
2206 register const char *s = src;
2207 register size_t n = siz;
2209 /* Copy as many bytes as will fit */
2210 if (n != 0 && --n != 0) {
2212 if ((*d++ = *s++) == 0)
2217 /* Not enough room in dst, add NUL and traverse rest of src */
2220 *d = '\0'; /* NUL-terminate dst */
2225 return(s - src - 1); /* count does not include NUL */
2228 #endif // #ifndef HAVE_STRLCPY
2230 void FindFraction(double val, int *num, int *denom, int denomMax)
2235 bestdiff = fabs(val);
2239 for(i = 1; i <= denomMax; ++i)
2241 int inum = (int) floor(0.5 + val * i);
2242 double diff = fabs(val - inum / (double)i);
2252 // decodes an XPM from C syntax
2253 char **XPM_DecodeString(const char *in)
2255 static char *tokens[257];
2256 static char lines[257][512];
2259 // skip until "{" token
2260 while(COM_ParseToken_QuakeC(&in, false) && strcmp(com_token, "{"));
2262 // now, read in succession: string, comma-or-}
2263 while(COM_ParseToken_QuakeC(&in, false))
2265 tokens[line] = lines[line];
2266 strlcpy(lines[line++], com_token, sizeof(lines[0]));
2267 if(!COM_ParseToken_QuakeC(&in, false))
2269 if(!strcmp(com_token, "}"))
2271 if(strcmp(com_token, ","))
2273 if(line >= sizeof(tokens) / sizeof(tokens[0]))
2280 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2281 static void base64_3to4(const unsigned char *in, unsigned char *out, int bytes)
2283 unsigned char i0 = (bytes > 0) ? in[0] : 0;
2284 unsigned char i1 = (bytes > 1) ? in[1] : 0;
2285 unsigned char i2 = (bytes > 2) ? in[2] : 0;
2286 unsigned char o0 = base64[i0 >> 2];
2287 unsigned char o1 = base64[((i0 << 4) | (i1 >> 4)) & 077];
2288 unsigned char o2 = base64[((i1 << 2) | (i2 >> 6)) & 077];
2289 unsigned char o3 = base64[i2 & 077];
2290 out[0] = (bytes > 0) ? o0 : '?';
2291 out[1] = (bytes > 0) ? o1 : '?';
2292 out[2] = (bytes > 1) ? o2 : '=';
2293 out[3] = (bytes > 2) ? o3 : '=';
2296 size_t base64_encode(unsigned char *buf, size_t buflen, size_t outbuflen)
2299 // expand the out-buffer
2300 blocks = (buflen + 2) / 3;
2301 if(blocks*4 > outbuflen)
2303 for(i = blocks; i > 0; )
2306 base64_3to4(buf + 3*i, buf + 4*i, (int)(buflen - 3*i));