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
30 cvar_t registered = {0, "registered","0"};
31 cvar_t cmdline = {0, "cmdline","0"};
33 extern qboolean fs_modified; // set true if using non-id files
37 const char **com_argv;
39 // LordHavoc: made commandline 1024 characters instead of 256
40 #define CMDLINE_LENGTH 1024
41 char com_cmdline[CMDLINE_LENGTH];
45 const char *gamedirname1;
46 const char *gamedirname2;
47 const char *gamescreenshotname;
48 const char *gameuserdirname;
49 char com_modname[MAX_OSPATH] = "";
53 ============================================================================
57 ============================================================================
60 short ShortSwap (short l)
79 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
82 float FloatSwap (float f)
92 dat2.b[0] = dat1.b[3];
93 dat2.b[1] = dat1.b[2];
94 dat2.b[2] = dat1.b[1];
95 dat2.b[3] = dat1.b[0];
100 // Extract integers from buffers
102 unsigned int BuffBigLong (const qbyte *buffer)
104 return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
107 unsigned short BuffBigShort (const qbyte *buffer)
109 return (buffer[0] << 8) | buffer[1];
112 unsigned int BuffLittleLong (const qbyte *buffer)
114 return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
117 unsigned short BuffLittleShort (const qbyte *buffer)
119 return (buffer[1] << 8) | buffer[0];
124 ============================================================================
128 ============================================================================
131 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
132 // and the initial and final xor values shown below... in other words, the
133 // CCITT standard CRC used by XMODEM
135 #define CRC_INIT_VALUE 0xffff
136 #define CRC_XOR_VALUE 0x0000
138 static unsigned short crctable[256] =
140 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
141 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
142 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
143 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
144 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
145 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
146 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
147 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
148 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
149 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
150 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
151 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
152 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
153 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
154 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
155 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
156 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
157 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
158 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
159 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
160 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
161 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
162 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
163 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
164 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
165 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
166 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
167 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
168 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
169 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
170 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
171 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
174 unsigned short CRC_Block(const qbyte *data, size_t size)
176 unsigned short crc = CRC_INIT_VALUE;
178 crc = (crc << 8) ^ crctable[(crc >> 8) ^ (*data++)];
179 return crc ^ CRC_XOR_VALUE;
184 ==============================================================================
188 Handles byte ordering and avoids alignment errors
189 ==============================================================================
196 void MSG_WriteChar (sizebuf_t *sb, int c)
200 buf = SZ_GetSpace (sb, 1);
204 void MSG_WriteByte (sizebuf_t *sb, int c)
208 buf = SZ_GetSpace (sb, 1);
212 void MSG_WriteShort (sizebuf_t *sb, int c)
216 buf = SZ_GetSpace (sb, 2);
221 void MSG_WriteLong (sizebuf_t *sb, int c)
225 buf = SZ_GetSpace (sb, 4);
227 buf[1] = (c>>8)&0xff;
228 buf[2] = (c>>16)&0xff;
232 void MSG_WriteFloat (sizebuf_t *sb, float f)
242 dat.l = LittleLong (dat.l);
244 SZ_Write (sb, &dat.l, 4);
247 void MSG_WriteString (sizebuf_t *sb, const char *s)
250 SZ_Write (sb, "", 1);
252 SZ_Write (sb, s, (int)strlen(s)+1);
255 void MSG_WriteUnterminatedString (sizebuf_t *sb, const char *s)
258 SZ_Write (sb, s, (int)strlen(s));
261 void MSG_WriteCoord13i (sizebuf_t *sb, float f)
264 MSG_WriteShort (sb, (int)(f * 8.0 + 0.5));
266 MSG_WriteShort (sb, (int)(f * 8.0 - 0.5));
269 void MSG_WriteCoord16i (sizebuf_t *sb, float f)
272 MSG_WriteShort (sb, (int)(f + 0.5));
274 MSG_WriteShort (sb, (int)(f - 0.5));
277 void MSG_WriteCoord32f (sizebuf_t *sb, float f)
279 MSG_WriteFloat (sb, f);
282 void MSG_WriteCoord (sizebuf_t *sb, float f, protocolversion_t protocol)
284 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE)
285 MSG_WriteCoord13i (sb, f);
286 else if (protocol == PROTOCOL_DARKPLACES1)
287 MSG_WriteCoord32f (sb, f);
288 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
289 MSG_WriteCoord16i (sb, f);
291 MSG_WriteCoord32f (sb, f);
294 void MSG_WriteVector (sizebuf_t *sb, float *v, protocolversion_t protocol)
296 MSG_WriteCoord (sb, v[0], protocol);
297 MSG_WriteCoord (sb, v[1], protocol);
298 MSG_WriteCoord (sb, v[2], protocol);
301 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
302 void MSG_WriteAngle8i (sizebuf_t *sb, float f)
305 MSG_WriteByte (sb, (int)(f*(256.0/360.0) + 0.5) & 255);
307 MSG_WriteByte (sb, (int)(f*(256.0/360.0) - 0.5) & 255);
310 void MSG_WriteAngle16i (sizebuf_t *sb, float f)
313 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) + 0.5) & 65535);
315 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) - 0.5) & 65535);
318 void MSG_WriteAngle32f (sizebuf_t *sb, float f)
320 MSG_WriteFloat (sb, f);
323 void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol)
325 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
326 MSG_WriteAngle8i (sb, f);
328 MSG_WriteAngle16i (sb, f);
335 qboolean msg_badread;
337 void MSG_BeginReading (void)
343 int MSG_ReadLittleShort (void)
345 if (msg_readcount+2 > net_message.cursize)
351 return (short)(net_message.data[msg_readcount-2] | (net_message.data[msg_readcount-1]<<8));
354 int MSG_ReadBigShort (void)
356 if (msg_readcount+2 > net_message.cursize)
362 return (short)((net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1]);
365 int MSG_ReadLittleLong (void)
367 if (msg_readcount+4 > net_message.cursize)
373 return net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
376 int MSG_ReadBigLong (void)
378 if (msg_readcount+4 > net_message.cursize)
384 return (net_message.data[msg_readcount-4]<<24) + (net_message.data[msg_readcount-3]<<16) + (net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1];
387 float MSG_ReadLittleFloat (void)
394 if (msg_readcount+4 > net_message.cursize)
400 dat.l = net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
404 float MSG_ReadBigFloat (void)
411 if (msg_readcount+4 > net_message.cursize)
417 dat.l = (net_message.data[msg_readcount-4]<<24) | (net_message.data[msg_readcount-3]<<16) | (net_message.data[msg_readcount-2]<<8) | net_message.data[msg_readcount-1];
421 char *MSG_ReadString (void)
423 static char string[2048];
425 for (l = 0;l < (int) sizeof(string) - 1 && (c = MSG_ReadChar()) != -1 && c != 0;l++)
431 int MSG_ReadBytes (int numbytes, unsigned char *out)
434 for (l = 0;l < numbytes && (c = MSG_ReadChar()) != -1;l++)
439 float MSG_ReadCoord13i (void)
441 return MSG_ReadLittleShort() * (1.0/8.0);
444 float MSG_ReadCoord16i (void)
446 return (signed short) MSG_ReadLittleShort();
449 float MSG_ReadCoord32f (void)
451 return MSG_ReadLittleFloat();
454 float MSG_ReadCoord (protocolversion_t protocol)
456 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE)
457 return MSG_ReadCoord13i();
458 else if (protocol == PROTOCOL_DARKPLACES1)
459 return MSG_ReadCoord32f();
460 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
461 return MSG_ReadCoord16i();
463 return MSG_ReadCoord32f();
466 void MSG_ReadVector (float *v, protocolversion_t protocol)
468 v[0] = MSG_ReadCoord(protocol);
469 v[1] = MSG_ReadCoord(protocol);
470 v[2] = MSG_ReadCoord(protocol);
473 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
474 float MSG_ReadAngle8i (void)
476 return (signed char) MSG_ReadByte () * (360.0/256.0);
479 float MSG_ReadAngle16i (void)
481 return (signed short)MSG_ReadShort () * (360.0/65536.0);
484 float MSG_ReadAngle32f (void)
486 return MSG_ReadFloat ();
489 float MSG_ReadAngle (protocolversion_t protocol)
491 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
492 return MSG_ReadAngle8i ();
494 return MSG_ReadAngle16i ();
498 //===========================================================================
500 void SZ_Clear (sizebuf_t *buf)
505 void *SZ_GetSpace (sizebuf_t *buf, int length)
509 if (buf->cursize + length > buf->maxsize)
511 if (!buf->allowoverflow)
512 Host_Error ("SZ_GetSpace: overflow without allowoverflow set\n");
514 if (length > buf->maxsize)
515 Host_Error ("SZ_GetSpace: %i is > full buffer size\n", length);
517 buf->overflowed = true;
518 Con_Print("SZ_GetSpace: overflow\n");
522 data = buf->data + buf->cursize;
523 buf->cursize += length;
528 void SZ_Write (sizebuf_t *buf, const void *data, int length)
530 memcpy (SZ_GetSpace(buf,length),data,length);
533 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
534 // attention, it has been eradicated from here, its only (former) use in
535 // all of darkplaces.
537 static char *hexchar = "0123456789ABCDEF";
538 void Com_HexDumpToConsole(const qbyte *data, int size)
542 char *cur, *flushpointer;
545 flushpointer = text + 512;
546 for (i = 0;i < size;)
553 *cur++ = hexchar[(i >> 12) & 15];
554 *cur++ = hexchar[(i >> 8) & 15];
555 *cur++ = hexchar[(i >> 4) & 15];
556 *cur++ = hexchar[(i >> 0) & 15];
559 for (j = 0;j < 16;j++)
563 *cur++ = hexchar[(d[j] >> 4) & 15];
564 *cur++ = hexchar[(d[j] >> 0) & 15];
575 for (j = 0;j < 16;j++)
579 if (d[j] >= ' ' && d[j] <= 127)
589 if (cur >= flushpointer || i >= size)
598 void SZ_HexDumpToConsole(const sizebuf_t *buf)
600 Com_HexDumpToConsole(buf->data, buf->cursize);
604 //============================================================================
611 Parse a token out of a string
614 int COM_ParseToken(const char **datapointer, int returnnewline)
617 const char *data = *datapointer;
634 for (;*data <= ' ' && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
644 // handle Windows line ending
645 if (data[0] == '\r' && data[1] == '\n')
648 if (data[0] == '/' && data[1] == '/')
651 while (*data && *data != '\n' && *data != '\r')
655 else if (data[0] == '/' && data[1] == '*')
659 while (*data && (data[0] != '*' || data[1] != '/'))
664 else if (*data == '\"')
667 for (data++;*data != '\"';data++)
669 if (*data == '\\' && data[1] == '"' )
671 if (!*data || len >= (int)sizeof(com_token) - 1)
677 com_token[len++] = *data;
680 *datapointer = data+1;
683 else if (*data == '\'')
686 for (data++;*data != '\'';data++)
688 if (*data == '\\' && data[1] == '\'' )
690 if (!*data || len >= (int)sizeof(com_token) - 1)
696 com_token[len++] = *data;
699 *datapointer = data+1;
702 else if (*data == '\r')
704 // translate Mac line ending to UNIX
705 com_token[len++] = '\n';
710 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == '\'' || *data == ':' || *data == ',' || *data == ';')
713 com_token[len++] = *data++;
721 for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != '\'' && *data != ':' && *data != ',' && *data != ';' && *data != '\'' && *data != '"';data++)
723 if (len >= (int)sizeof(com_token) - 1)
729 com_token[len++] = *data;
739 COM_ParseTokenConsole
741 Parse a token out of a string, behaving like the qwcl console
744 int COM_ParseTokenConsole(const char **datapointer)
747 const char *data = *datapointer;
760 for (;*data <= ' ';data++)
770 if (*data == '/' && data[1] == '/')
773 while (*data && *data != '\n' && *data != '\r')
777 else if (*data == '\"')
780 for (data++;*data != '\"';data++)
782 if (!*data || len >= (int)sizeof(com_token) - 1)
788 com_token[len++] = *data;
791 *datapointer = data+1;
796 for (;*data > ' ';data++)
798 if (len >= (int)sizeof(com_token) - 1)
804 com_token[len++] = *data;
818 Returns the position (1 to argc-1) in the program's argument list
819 where the given parameter apears, or 0 if not present
822 int COM_CheckParm (const char *parm)
826 for (i=1 ; i<com_argc ; i++)
829 continue; // NEXTSTEP sometimes clears appkit vars.
830 if (!strcmp (parm,com_argv[i]))
841 Looks for the pop.txt file and verifies it.
842 Sets the "registered" cvar.
843 Immediately exits out if an alternate game was attempted to be started without
847 void COM_CheckRegistered (void)
849 Cvar_Set ("cmdline", com_cmdline);
851 if (gamemode == GAME_NORMAL && !FS_FileExists("gfx/pop.lmp"))
854 Con_Print("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
856 Con_Print("Playing shareware version.\n");
860 Cvar_Set ("registered", "1");
861 Con_Print("Playing registered version.\n");
870 void COM_InitArgv (void)
873 // reconstitute the command line for the cmdline externally visible cvar
875 for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
878 if (strstr(com_argv[j], " "))
880 // arg contains whitespace, store quotes around it
881 com_cmdline[n++] = '\"';
882 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
883 com_cmdline[n++] = com_argv[j][i++];
884 com_cmdline[n++] = '\"';
888 while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
889 com_cmdline[n++] = com_argv[j][i++];
891 if (n < (CMDLINE_LENGTH - 1))
892 com_cmdline[n++] = ' ';
900 //===========================================================================
906 const char* prog_name;
908 const char* gamename;
909 const char* gamedirname1;
910 const char* gamedirname2;
911 const char* gamescreenshotname;
912 const char* gameuserdirname;
915 static const gamemode_info_t gamemode_info [] =
916 {// prog_name cmdline gamename gamedirname gamescreenshotname
919 // COMMANDLINEOPTION: Game: -quake runs the game Quake (default)
920 { "", "-quake", "DarkPlaces-Quake", "id1", NULL, "dp", "darkplaces" },
922 // COMMANDLINEOPTION: Game: -hipnotic runs Quake mission pack 1: The Scourge of Armagon
923 { "hipnotic", "-hipnotic", "Darkplaces-Hipnotic", "id1", "hipnotic", "dp", "darkplaces" },
925 // COMMANDLINEOPTION: Game: -rogue runs Quake mission pack 2: The Dissolution of Eternity
926 { "rogue", "-rogue", "Darkplaces-Rogue", "id1", "rogue", "dp", "darkplaces" },
928 // COMMANDLINEOPTION: Game: -nehahra runs The Seal of Nehahra movie and game
929 { "nehahra", "-nehahra", "DarkPlaces-Nehahra", "id1", "nehahra", "dp", "darkplaces" },
931 // COMMANDLINEOPTION: Game: -nexuiz runs the multiplayer game Nexuiz
932 { "nexuiz", "-nexuiz", "Nexuiz", "data", NULL, "nexuiz", "nexuiz" },
934 // COMMANDLINEOPTION: Game: -transfusion runs Transfusion (the recreation of Blood in Quake)
935 { "transfusion", "-transfusion", "Transfusion", "basetf", NULL, "transfusion", "transfusion" },
937 // COMMANDLINEOPTION: Game: -goodvsbad2 runs the psychadelic RTS FPS game Good Vs Bad 2
938 { "gvb2", "-goodvsbad2", "GoodVs.Bad2", "rts", NULL, "gvb2", "gvb2" },
940 // COMMANDLINEOPTION: Game: -teu runs The Evil Unleashed (this option is obsolete as they are not using darkplaces)
941 { "teu", "-teu", "TheEvilUnleashed", "baseteu", NULL, "teu", "teu" },
943 // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech
944 { "battlemech", "-battlemech", "Battlemech", "base", NULL, "battlemech", "battlemech" },
946 // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
947 { "zymotic", "-zymotic", "Zymotic", "basezym", NULL, "zymotic", "zymotic" },
949 // COMMANDLINEOPTION: Game: -fniggium runs the post apocalyptic melee RPG Fniggium
950 { "fniggium", "-fniggium", "Fniggium", "data", NULL, "fniggium", "fniggium" },
952 // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral
953 { "setheral", "-setheral", "Setheral", "data", NULL, "setheral", "setheral" },
955 // COMMANDLINEOPTION: Game: -som runs the multiplayer game Son Of Man
956 { "som", "-som", "Son of Man", "id1", "sonofman", "som", "darkplaces" },
958 // COMMANDLINEOPTION: Game: -tenebrae runs the graphics test mod known as Tenebrae (some features not implemented)
959 { "tenebrae", "-tenebrae", "DarkPlaces-Tenebrae", "id1", "tenebrae", "dp", "darkplaces" },
961 // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
962 { "neoteric", "-neoteric", "Neoteric", "id1", "neobase", "neo", "darkplaces" },
964 // COMMANDLINEOPTION: Game: -openquartz runs the game OpenQuartz, a standalone GPL replacement of the quake content
965 { "openquartz", "-openquartz", "OpenQuartz", "id1", NULL, "openquartz", "darkplaces" },
967 // COMMANDLINEOPTION: Game: -prydon runs the topdown point and click action-RPG Prydon Gate
968 { "prydon", "-prydon", "PrydonGate", "id1", "prydon", "prydon", "darkplaces" },
970 // COMMANDLINEOPTION: Game: -netherworld runs the game Netherworld: Dark Master
971 { "netherworld", "-netherworld", "Netherworld: Dark Master", "id1", "netherworld", "nw", "darkplaces" },
973 // COMMANDLINEOPTION: Game: -thehunted runs the game The Hunted
974 { "thehunted", "-thehunted", "The Hunted", "thdata", NULL, "th", "thehunted" },
975 // GAME_DEFEATINDETAIL2
976 // COMMANDLINEOPTION: Game: -did2 runs the game Defeat In Detail 2
977 { "did2", "-did2", "Defeat In Detail 2", "data", NULL, "did2_", "did2" },
980 void COM_InitGameType (void)
982 char name [MAX_OSPATH];
985 FS_StripExtension (com_argv[0], name, sizeof (name));
986 COM_ToLowerString (name, name, sizeof (name));
988 // Check the binary name; default to GAME_NORMAL (0)
989 gamemode = GAME_NORMAL;
990 for (i = 1; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
991 if (strstr (name, gamemode_info[i].prog_name))
997 // Look for a command-line option
998 for (i = 0; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
999 if (COM_CheckParm (gamemode_info[i].cmdline))
1005 gamename = gamemode_info[gamemode].gamename;
1006 gamedirname1 = gamemode_info[gamemode].gamedirname1;
1007 gamedirname2 = gamemode_info[gamemode].gamedirname2;
1008 gamescreenshotname = gamemode_info[gamemode].gamescreenshotname;
1009 gameuserdirname = gamemode_info[gamemode].gameuserdirname;
1018 void COM_Init_Commands (void)
1020 Cvar_RegisterVariable (®istered);
1021 Cvar_RegisterVariable (&cmdline);
1028 does a varargs printf into a temp buffer, so I don't need to have
1029 varargs versions of all text functions.
1030 FIXME: make this buffer size safe someday
1033 char *va(const char *format, ...)
1036 // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
1037 static char string[8][1024], *s;
1038 static int stringindex = 0;
1040 s = string[stringindex];
1041 stringindex = (stringindex + 1) & 7;
1042 va_start (argptr, format);
1043 dpvsnprintf (s, sizeof (string[0]), format,argptr);
1050 //======================================
1052 // snprintf and vsnprintf are NOT portable. Use their DP counterparts instead
1058 # define snprintf _snprintf
1059 # define vsnprintf _vsnprintf
1063 int dpsnprintf (char *buffer, size_t buffersize, const char *format, ...)
1068 va_start (args, format);
1069 result = dpvsnprintf (buffer, buffersize, format, args);
1076 int dpvsnprintf (char *buffer, size_t buffersize, const char *format, va_list args)
1080 result = vsnprintf (buffer, buffersize, format, args);
1081 if (result < 0 || (size_t)result >= buffersize)
1083 buffer[buffersize - 1] = '\0';
1091 //======================================
1093 void COM_ToLowerString (const char *in, char *out, size_t size_out)
1098 while (*in && size_out > 1)
1100 if (*in >= 'A' && *in <= 'Z')
1101 *out++ = *in++ + 'a' - 'A';
1109 void COM_ToUpperString (const char *in, char *out, size_t size_out)
1114 while (*in && size_out > 1)
1116 if (*in >= 'a' && *in <= 'z')
1117 *out++ = *in++ + 'A' - 'a';
1125 int COM_StringBeginsWith(const char *s, const char *match)
1127 for (;*s && *match;s++, match++)
1133 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
1135 int argc, commentprefixlength;
1139 tokenbufend = tokenbuf + tokenbufsize;
1141 commentprefixlength = 0;
1143 commentprefixlength = (int)strlen(commentprefix);
1144 while (*l && *l != '\n' && *l != '\r')
1148 if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
1150 while (*l && *l != '\n' && *l != '\r')
1154 if (argc >= maxargc)
1156 argv[argc++] = tokenbuf;
1160 while (*l && *l != '"')
1162 if (tokenbuf >= tokenbufend)
1173 if (tokenbuf >= tokenbufend)
1178 if (tokenbuf >= tokenbufend)
1197 // written by Elric, thanks Elric!
1198 char *SearchInfostring(const char *infostring, const char *key)
1200 static char value [256];
1202 size_t value_ind, key_ind;
1205 if (*infostring++ != '\\')
1220 if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1222 crt_key[key_ind] = '\0';
1226 crt_key[key_ind++] = c;
1229 // If it's the key we are looking for, save it in "value"
1230 if (!strcmp(crt_key, key))
1236 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1238 value[value_ind] = '\0';
1242 value[value_ind++] = c;
1246 // Else, skip the value
1260 //========================================================
1261 // strlcat and strlcpy, from OpenBSD
1264 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1266 * Permission to use, copy, modify, and distribute this software for any
1267 * purpose with or without fee is hereby granted, provided that the above
1268 * copyright notice and this permission notice appear in all copies.
1270 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1271 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1272 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1273 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1274 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1275 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1276 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1279 /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
1280 /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
1283 #ifndef HAVE_STRLCAT
1285 strlcat(char *dst, const char *src, size_t siz)
1287 register char *d = dst;
1288 register const char *s = src;
1289 register size_t n = siz;
1292 /* Find the end of dst and adjust bytes left but don't go past end */
1293 while (n-- != 0 && *d != '\0')
1299 return(dlen + strlen(s));
1300 while (*s != '\0') {
1309 return(dlen + (s - src)); /* count does not include NUL */
1311 #endif // #ifndef HAVE_STRLCAT
1314 #ifndef HAVE_STRLCPY
1316 strlcpy(char *dst, const char *src, size_t siz)
1318 register char *d = dst;
1319 register const char *s = src;
1320 register size_t n = siz;
1322 /* Copy as many bytes as will fit */
1323 if (n != 0 && --n != 0) {
1325 if ((*d++ = *s++) == 0)
1330 /* Not enough room in dst, add NUL and traverse rest of src */
1333 *d = '\0'; /* NUL-terminate dst */
1338 return(s - src - 1); /* count does not include NUL */
1341 #endif // #ifndef HAVE_STRLCPY