The quakefs similarization.. Essentially, we're now using qw's quakefs in

nq, with the exception that some things were removed and others added.  I
could have merged this, but I don't feel the system's ready for merging at
the moment.  The quakefs code needs a bit of a cleanup and a tuneup before
it goes common.  Like so many other things, that's dependant on other bits
of the puzzle being completed first.
This commit is contained in:
Joseph Carter 2001-03-09 07:58:10 +00:00
parent 055fe8d222
commit 3ac2bc72aa
4 changed files with 246 additions and 144 deletions

View file

@ -32,7 +32,6 @@
#include "qtypes.h" #include "qtypes.h"
#include "cvar.h" #include "cvar.h"
extern qboolean standard_quake;
extern qboolean noclip_anglehack; extern qboolean noclip_anglehack;
typedef struct typedef struct

View file

@ -38,6 +38,7 @@
#include "game.h" #include "game.h"
#include "cmd.h" #include "cmd.h"
cvar_t *registered;
cvar_t *cmdline; cvar_t *cmdline;
int static_registered = 1; int static_registered = 1;

View file

@ -1438,6 +1438,8 @@ DEBUGGING TOOLS
=============================================================================== ===============================================================================
*/ */
// FIXME: This cheat should be re-implemented OUTSIDE the engine!
#if 0
/* /*
================== ==================
Host_Give_f Host_Give_f
@ -1579,6 +1581,8 @@ Host_Give_f (void)
break; break;
} }
} }
#endif
edict_t * edict_t *
FindViewthing (void) FindViewthing (void)
@ -1824,7 +1828,6 @@ Host_InitCommands (void)
Cmd_AddCommand ("ping", Host_Ping_f, "No Description"); Cmd_AddCommand ("ping", Host_Ping_f, "No Description");
Cmd_AddCommand ("load", Host_Loadgame_f, "No Description"); Cmd_AddCommand ("load", Host_Loadgame_f, "No Description");
Cmd_AddCommand ("save", Host_Savegame_f, "No Description"); Cmd_AddCommand ("save", Host_Savegame_f, "No Description");
Cmd_AddCommand ("give", Host_Give_f, "No Description");
Cmd_AddCommand ("startdemos", Host_Startdemos_f, "No Description"); Cmd_AddCommand ("startdemos", Host_Startdemos_f, "No Description");
Cmd_AddCommand ("demos", Host_Demos_f, "No Description"); Cmd_AddCommand ("demos", Host_Demos_f, "No Description");

View file

@ -1,4 +1,3 @@
/* /*
quakefs.c quakefs.c
@ -28,51 +27,59 @@
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <config.h> # include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <stdarg.h>
#include <limits.h>
#include <ctype.h> #include <ctype.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include <fcntl.h> #include <fcntl.h>
#include <dirent.h> #include <dirent.h>
#ifdef HAVE_FNMATCH_H #ifdef HAVE_FNMATCH_H
#include <fnmatch.h> # define model_t sunmodel_t
# include <fnmatch.h>
# undef model_t
#endif #endif
#ifdef WIN32 #ifdef WIN32
#include <io.h> # include <io.h>
#endif #endif
#ifdef _MSC_VER #ifdef _MSC_VER
#define _POSIX_ # define _POSIX_
#endif #endif
#include <limits.h>
#include "cmd.h"
#include "console.h"
#include "cvar.h"
#include "draw.h"
#include "hash.h"
#include "host.h" #include "host.h"
#include "info.h"
#include "qargs.h"
#include "qendian.h"
#include "qtypes.h" #include "qtypes.h"
#include "quakefs.h" #include "quakefs.h"
#include "sys.h"
#include "console.h"
#include "draw.h"
#include "cmd.h"
#include "cvar.h"
#include "qendian.h"
#include "info.h"
#include "server.h" #include "server.h"
#include "sys.h"
#include "va.h" #include "va.h"
#include "qargs.h"
#include "compat.h"
qboolean standard_quake = true, abyss, rogue, hipnotic; #ifndef HAVE_FNMATCH_PROTO
cvar_t *registered; int fnmatch (const char *__pattern, const char *__string, int __flags);
#endif
/* /*
All of Quake's data access is through a hierchical file system, but the All of Quake's data access is through a hierchical file system, but the
@ -80,9 +87,8 @@ cvar_t *registered;
sources. sources.
The "user directory" is the path to the directory holding the quake.exe The "user directory" is the path to the directory holding the quake.exe
and all game directories. The sys_* files pass this to host_init in and all game directories. This can be overridden with the "fs_sharepath"
quakeparms_t->basedir. This can be overridden with the "-basedir" and "fs_userpath" cvars to allow code debugging in a different directory.
command line parm to allow code debugging in a different directory.
The base directory is only used during filesystem initialization. The base directory is only used during filesystem initialization.
The "game directory" is the first tree on the search path and directory The "game directory" is the first tree on the search path and directory
@ -99,11 +105,7 @@ cvar_t *registered;
*/ */
/* /*
============================================================================= QUAKE FILESYSTEM
QUAKE FILESYSTEM
=============================================================================
*/ */
char gamedirfile[MAX_OSPATH]; char gamedirfile[MAX_OSPATH];
@ -112,7 +114,6 @@ cvar_t *fs_userpath;
cvar_t *fs_sharepath; cvar_t *fs_sharepath;
cvar_t *fs_basegame; cvar_t *fs_basegame;
int com_filesize; int com_filesize;
/* /*
@ -129,6 +130,7 @@ typedef struct pack_s {
QFile *handle; QFile *handle;
int numfiles; int numfiles;
packfile_t *files; packfile_t *files;
hashtab_t *file_hash;
} pack_t; } pack_t;
/* /*
@ -165,21 +167,27 @@ searchpath_t *com_base_searchpaths; // without gamedirs
void void
COM_FileBase (char *in, char *out) COM_FileBase (char *in, char *out)
{ {
char *s, *s2; char *slash, *dot;
char *s;
s = in + strlen (in) - 1; slash = in;
dot = NULL;
while (s != in && *s != '.') s = in;
s--; while (*s) {
if (*s == '/')
for (s2 = s; *s2 && *s2 != '/'; s2--); slash = s + 1;
if (*s == '.')
if (s - s2 < 2) dot = s;
s++;
}
if (dot == NULL)
dot = s;
if (dot - slash < 2)
strcpy (out, "?model?"); strcpy (out, "?model?");
else { else {
s--; while (slash < dot)
strncpy (out, s2 + 1, s - s2); *out++ = *slash++;
out[s - s2] = 0; *out++ = 0;
} }
} }
@ -251,7 +259,7 @@ struct maplist {
}; };
static struct maplist * static struct maplist *
maplist_new () maplist_new (void)
{ {
return calloc (1, sizeof (struct maplist)); return calloc (1, sizeof (struct maplist));
} }
@ -259,6 +267,10 @@ maplist_new ()
static void static void
maplist_free (struct maplist *maplist) maplist_free (struct maplist *maplist)
{ {
int i;
for (i = 0; i < maplist->count; i++)
free (maplist->list[i]);
free (maplist->list); free (maplist->list);
free (maplist); free (maplist);
} }
@ -278,7 +290,7 @@ maplist_add_map (struct maplist *maplist, char *fname)
} }
maplist->list = new_list; maplist->list = new_list;
} }
maplist->list[maplist->count++] = fname; maplist->list[maplist->count++] = strdup (fname);
} }
static int static int
@ -302,16 +314,19 @@ maplist_print (struct maplist *maplist)
char *end; char *end;
char *name; char *name;
if (maplist->count) {
qsort (maplist->list, maplist->count, sizeof (char *), maplist_cmp); qsort (maplist->list, maplist->count, sizeof (char *), maplist_cmp);
for (i = 0; i < maplist->count - 1; i++) { for (i = 0; i < maplist->count - 1; i++) {
name = maplist->list[i]; name = maplist->list[i];
end = strstr (name, ".bsp"); end = strstr (name, ".bsp");
Con_Printf ("%-8.*s%c", end - name, name, ((i + 1) % 4) ? ' ' : '\n'); Con_Printf ("%-8.*s%c", end - name, name,
((i + 1) % 4) ? ' ' : '\n');
} }
name = maplist->list[i]; name = maplist->list[i];
end = strstr (name, ".bsp"); end = strstr (name, ".bsp");
Con_Printf ("%-9.*s\n", end - name, name); Con_Printf ("%-9.*s\n", end - name, name);
}
} }
void void
@ -383,6 +398,41 @@ COM_WriteFile (char *filename, void *data, int len)
Qclose (f); Qclose (f);
} }
/*
COM_WriteBuffers
The filename will be prefixed by the current game directory
*/
void
COM_WriteBuffers (const char *filename, int count, ...)
{
QFile *f;
char name[MAX_OSPATH];
va_list args;
va_start (args, count);
snprintf (name, sizeof (name), "%s/%s", com_gamedir, filename);
f = Qopen (name, "wb");
if (!f) {
Sys_mkdir (com_gamedir);
f = Qopen (name, "wb");
if (!f)
Sys_Error ("Error opening %s", filename);
}
Sys_Printf ("COM_WriteBuffers: %s\n", name);
while (count--) {
void *data = va_arg (args, void *);
int len = va_arg (args, int);
Qwrite (f, data, len);
}
Qclose (f);
va_end (args);
}
/* /*
COM_CreatePath COM_CreatePath
@ -393,7 +443,7 @@ void
COM_CreatePath (char *path) COM_CreatePath (char *path)
{ {
char *ofs; char *ofs;
char e_path[PATH_MAX]; char e_path[MAX_OSPATH];
Qexpand_squiggle (path, e_path); Qexpand_squiggle (path, e_path);
path = e_path; path = e_path;
@ -424,8 +474,6 @@ COM_CopyFile (char *netpath, char *cachepath)
remaining = COM_FileOpenRead (netpath, &in); remaining = COM_FileOpenRead (netpath, &in);
COM_CreatePath (cachepath); // create directories up to the cache COM_CreatePath (cachepath); // create directories up to the cache
//
//
// file // file
out = Qopen (cachepath, "wb"); out = Qopen (cachepath, "wb");
if (!out) if (!out)
@ -504,8 +552,6 @@ _COM_FOpenFile (char *filename, QFile **gzfile, char *foundname, int zip)
{ {
searchpath_t *search; searchpath_t *search;
char netpath[MAX_OSPATH]; char netpath[MAX_OSPATH];
pack_t *pak;
int i;
int findtime; int findtime;
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
@ -514,7 +560,7 @@ _COM_FOpenFile (char *filename, QFile **gzfile, char *foundname, int zip)
filenamelen = strlen (filename); filenamelen = strlen (filename);
strncpy (gzfilename, filename, sizeof (gzfilename)); strncpy (gzfilename, filename, sizeof (gzfilename));
strncat (gzfilename, ".gz", sizeof (gzfilename)); strncat (gzfilename, ".gz", sizeof (gzfilename) - strlen (gzfilename));
#endif #endif
file_from_pak = 0; file_from_pak = 0;
@ -525,34 +571,26 @@ _COM_FOpenFile (char *filename, QFile **gzfile, char *foundname, int zip)
for (search = com_searchpaths; search; search = search->next) { for (search = com_searchpaths; search; search = search->next) {
// is the element a pak file? // is the element a pak file?
if (search->pack) { if (search->pack) {
// look through all the pak file elements packfile_t *packfile;
pak = search->pack;
for (i = 0; i < pak->numfiles; i++) {
char *fn = 0;
packfile = (packfile_t *) Hash_Find (search->pack->file_hash,
filename);
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
if (!strncmp (pak->files[i].name, filename, filenamelen)) { if (!packfile)
if (!pak->files[i].name[filenamelen]) packfile = (packfile_t *) Hash_Find (search->pack->file_hash,
fn = filename; gzfilename);
else if (!strcmp (pak->files[i].name, gzfilename))
fn = gzfilename;
}
#else
if (!strcmp (pak->files[i].name, filename))
fn = filename;
#endif #endif
if (fn) { // found it! if (packfile) {
if (developer->int_val) Con_DPrintf ("PackFile: %s : %s\n", search->pack->filename,
Sys_Printf ("PackFile: %s : %s\n", pak->filename, fn); packfile->name);
// open a new file on the pakfile // open a new file on the pakfile
strncpy (foundname, fn, MAX_OSPATH); strncpy (foundname, packfile->name, MAX_OSPATH);
*gzfile = *gzfile =
COM_OpenRead (pak->filename, pak->files[i].filepos, COM_OpenRead (search->pack->filename, packfile->filepos,
pak->files[i].filelen, zip); packfile->filelen, zip);
file_from_pak = 1; file_from_pak = 1;
return com_filesize; return com_filesize;
} }
}
} else { } else {
// check a file in the directory tree // check a file in the directory tree
snprintf (netpath, sizeof (netpath), "%s/%s", search->filename, snprintf (netpath, sizeof (netpath), "%s/%s", search->filename,
@ -571,8 +609,7 @@ _COM_FOpenFile (char *filename, QFile **gzfile, char *foundname, int zip)
continue; continue;
} }
if (developer->int_val) Con_DPrintf ("FindFile: %s\n", netpath);
Sys_Printf ("FindFile: %s\n", netpath);
*gzfile = COM_OpenRead (netpath, -1, -1, zip); *gzfile = COM_OpenRead (netpath, -1, -1, zip);
return com_filesize; return com_filesize;
@ -580,8 +617,7 @@ _COM_FOpenFile (char *filename, QFile **gzfile, char *foundname, int zip)
} }
if (developer->int_val) Con_DPrintf ("FindFile: can't find %s\n", filename);
Sys_Printf ("FindFile: can't find %s\n", filename);
*gzfile = NULL; *gzfile = NULL;
com_filesize = -1; com_filesize = -1;
@ -610,18 +646,16 @@ byte *
COM_LoadFile (char *path, int usehunk) COM_LoadFile (char *path, int usehunk)
{ {
QFile *h; QFile *h;
byte *buf; byte *buf = NULL;
char base[32]; char base[32];
int len; int len;
buf = NULL; // quiet compiler warning // look for it in the filesystem or pack files
// look for it in the filesystem or pack files
len = com_filesize = COM_FOpenFile (path, &h); len = com_filesize = COM_FOpenFile (path, &h);
if (!h) if (!h)
return NULL; return NULL;
// extract the filename base name for hunk tag // extract the filename base name for hunk tag
COM_FileBase (path, base); COM_FileBase (path, base);
if (usehunk == 1) if (usehunk == 1)
@ -684,6 +718,14 @@ COM_LoadStackFile (char *path, void *buffer, int bufsize)
return buf; return buf;
} }
static char *
pack_get_key (void *_p, void *unused)
{
packfile_t *p = (packfile_t *) _p;
return p->name;
}
/* /*
COM_LoadPackFile COM_LoadPackFile
@ -702,6 +744,7 @@ COM_LoadPackFile (char *packfile)
pack_t *pack; pack_t *pack;
QFile *packhandle; QFile *packhandle;
dpackfile_t info[MAX_FILES_IN_PACK]; dpackfile_t info[MAX_FILES_IN_PACK];
hashtab_t *hash;
if (COM_FileOpenRead (packfile, &packhandle) == -1) if (COM_FileOpenRead (packfile, &packhandle) == -1)
return NULL; return NULL;
@ -719,16 +762,18 @@ COM_LoadPackFile (char *packfile)
Sys_Error ("%s has %i files", packfile, numpackfiles); Sys_Error ("%s has %i files", packfile, numpackfiles);
newfiles = calloc (1, numpackfiles * sizeof (packfile_t)); newfiles = calloc (1, numpackfiles * sizeof (packfile_t));
hash = Hash_NewTable (1021, pack_get_key, 0, 0);
Qseek (packhandle, header.dirofs, SEEK_SET); Qseek (packhandle, header.dirofs, SEEK_SET);
Qread (packhandle, info, header.dirlen); Qread (packhandle, info, header.dirlen);
// parse the directory // parse the directory
for (i = 0; i < numpackfiles; i++) { for (i = 0; i < numpackfiles; i++) {
strcpy (newfiles[i].name, info[i].name); strcpy (newfiles[i].name, info[i].name);
newfiles[i].filepos = LittleLong (info[i].filepos); newfiles[i].filepos = LittleLong (info[i].filepos);
newfiles[i].filelen = LittleLong (info[i].filelen); newfiles[i].filelen = LittleLong (info[i].filelen);
Hash_Add (hash, &newfiles[i]);
} }
pack = calloc (1, sizeof (pack_t)); pack = calloc (1, sizeof (pack_t));
@ -736,6 +781,7 @@ COM_LoadPackFile (char *packfile)
pack->handle = packhandle; pack->handle = packhandle;
pack->numfiles = numpackfiles; pack->numfiles = numpackfiles;
pack->files = newfiles; pack->files = newfiles;
pack->file_hash = hash;
Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles); Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
return pack; return pack;
@ -778,7 +824,6 @@ qstrcmp (char **os1, char **os2)
} }
} }
void void
COM_LoadGameDirectory (char *dir) COM_LoadGameDirectory (char *dir)
{ {
@ -861,7 +906,7 @@ COM_AddDirectory (char *dir)
{ {
searchpath_t *search; searchpath_t *search;
char *p; char *p;
char e_dir[PATH_MAX]; char e_dir[MAX_OSPATH];
Qexpand_squiggle (dir, e_dir); Qexpand_squiggle (dir, e_dir);
dir = e_dir; dir = e_dir;
@ -874,18 +919,13 @@ COM_AddDirectory (char *dir)
strcpy (com_gamedir, va ("%s/%s", fs_userpath->string, dir)); strcpy (com_gamedir, va ("%s/%s", fs_userpath->string, dir));
} }
// // add the directory to the search path
// add the directory to the search path
//
search = calloc (1, sizeof (searchpath_t)); search = calloc (1, sizeof (searchpath_t));
strcpy (search->filename, dir); strcpy (search->filename, dir);
search->next = com_searchpaths; search->next = com_searchpaths;
com_searchpaths = search; com_searchpaths = search;
// // add any pak files in the format pak0.pak pak1.pak, ...
// add any pak files in the format pak0.pak pak1.pak, ...
//
COM_LoadGameDirectory (dir); COM_LoadGameDirectory (dir);
} }
@ -900,6 +940,12 @@ COM_AddDirectory (char *dir)
void void
COM_AddGameDirectory (char *dir) COM_AddGameDirectory (char *dir)
{ {
// FIXME: make this dependant on QF metadata in the mission packs
if (strequal (dir, "hipnotic") || strequal (dir, "rogue"))
standard_quake = false;
else
standard_quake = true;
Con_DPrintf ("COM_AddGameDirectory (\"%s/%s\")\n", Con_DPrintf ("COM_AddGameDirectory (\"%s/%s\")\n",
fs_sharepath->string, dir); fs_sharepath->string, dir);
@ -908,6 +954,48 @@ COM_AddGameDirectory (char *dir)
COM_AddDirectory (va ("%s/%s", fs_userpath->string, dir)); COM_AddDirectory (va ("%s/%s", fs_userpath->string, dir));
} }
/*
COM_Gamedir
Sets the gamedir and path to a different directory.
*/
void
COM_Gamedir (char *dir)
{
searchpath_t *next;
if (strstr (dir, "..") || strstr (dir, "/")
|| strstr (dir, "\\") || strstr (dir, ":")) {
Con_Printf ("Gamedir should be a single filename, not a path\n");
return;
}
if (strcmp (gamedirfile, dir) == 0)
return; // still the same
strcpy (gamedirfile, dir);
//
// free up any current game dir info
//
while (com_searchpaths != com_base_searchpaths) {
if (com_searchpaths->pack) {
Qclose (com_searchpaths->pack->handle);
free (com_searchpaths->pack->files);
free (com_searchpaths->pack);
}
next = com_searchpaths->next;
free (com_searchpaths);
com_searchpaths = next;
}
//
// flush all data, so it will be forced to reload
//
Cache_Flush ();
COM_AddGameDirectory (dir);
}
/* /*
COM_CreateGameDirectory COM_CreateGameDirectory
*/ */
@ -920,31 +1008,14 @@ COM_CreateGameDirectory (char *gamename)
} }
/* /*
COM_Filesystem_Init_Cvars COM_InitFilesystem
*/
void
COM_Filesystem_Init_Cvars (void)
{
}
/*
COM_Filesystem_Init
*/ */
void void
COM_Filesystem_Init (void) COM_Filesystem_Init (void)
{ {
int i; int i;
fs_sharepath = Cvar_Get ("fs_sharepath", FS_SHAREPATH, CVAR_ROM, // start up with basegame->string by default
"location of shared (read only) game directories");
fs_userpath = Cvar_Get ("fs_userpath", FS_USERPATH, CVAR_ROM,
"location of your game directories");
fs_basegame = Cvar_Get ("fs_basegame", "id1", CVAR_ROM,
"game to use by default");
/*
start up with basegame->string by default
*/
COM_CreateGameDirectory (fs_basegame->string); COM_CreateGameDirectory (fs_basegame->string);
if ((i = COM_CheckParm ("-game")) && i < com_argc - 1) { if ((i = COM_CheckParm ("-game")) && i < com_argc - 1) {
@ -959,26 +1030,32 @@ COM_Filesystem_Init (void)
} }
free (gamedirs); free (gamedirs);
} }
if ((i = COM_CheckParm ("-game")) && i < com_argc - 1) { if ((i = COM_CheckParm ("-hipnotic"))) {
COM_CreateGameDirectory (com_argv[i + 1]);
}
if (hipnotic) {
COM_CreateGameDirectory ("hipnotic"); COM_CreateGameDirectory ("hipnotic");
} }
if (rogue) { if ((i = COM_CheckParm ("-rogue"))) {
COM_CreateGameDirectory ("rogue"); COM_CreateGameDirectory ("rogue");
} }
if (abyss) { if ((i = COM_CheckParm ("-abyss"))) {
COM_CreateGameDirectory ("abyss"); COM_CreateGameDirectory ("abyss");
} }
// any set gamedirs will be freed up to here // any set gamedirs will be freed up to here
com_base_searchpaths = com_searchpaths; com_base_searchpaths = com_searchpaths;
} }
void
COM_Filesystem_Init_Cvars (void)
{
fs_sharepath = Cvar_Get ("fs_sharepath", FS_SHAREPATH, CVAR_ROM,
"location of shared (read only) game directories");
fs_userpath = Cvar_Get ("fs_userpath", FS_USERPATH, CVAR_ROM,
"location of your game directories");
fs_basegame = Cvar_Get ("fs_basegame", "id1", CVAR_ROM,
"game to use by default");
}
/* /*
============ COM_SkipPath
COM_SkipPath
============
*/ */
char * char *
COM_SkipPath (char *pathname) COM_SkipPath (char *pathname)
@ -995,9 +1072,7 @@ COM_SkipPath (char *pathname)
} }
/* /*
============ COM_StripExtension
COM_StripExtension
============
*/ */
void void
COM_StripExtension (char *in, char *out) COM_StripExtension (char *in, char *out)
@ -1008,9 +1083,7 @@ COM_StripExtension (char *in, char *out)
} }
/* /*
============ COM_FileExtension
COM_FileExtension
============
*/ */
char * char *
COM_FileExtension (char *in) COM_FileExtension (char *in)
@ -1031,9 +1104,7 @@ COM_FileExtension (char *in)
/* /*
================== COM_DefaultExtension
COM_DefaultExtension
==================
*/ */
void void
COM_DefaultExtension (char *path, char *extension) COM_DefaultExtension (char *path, char *extension)
@ -1052,5 +1123,33 @@ COM_DefaultExtension (char *path, char *extension)
src--; src--;
} }
strcat (path, extension); strncat (path, extension, MAX_OSPATH - strlen (path));
}
/*
COM_NextFileName
*/
int
COM_NextFilename (char *filename, const char *prefix, const char *ext)
{
char *digits;
char checkname[MAX_OSPATH];
int i;
strncpy (filename, prefix, MAX_OSPATH - 4);
filename[MAX_OSPATH - 4] = 0;
digits = filename + strlen (filename);
strcat (filename, "000");
strncat (filename, ext, MAX_OSPATH - strlen (filename));
for (i = 0; i <= 999; i++) {
digits[0] = i / 100 + '0';
digits[1] = i / 10 % 10 + '0';
digits[2] = i % 10 + '0';
snprintf (checkname, sizeof (checkname), "%s/%s", com_gamedir,
filename);
if (Sys_FileTime (checkname) == -1)
return 1; // file doesn't exist
}
return 0;
} }