diff --git a/source/src/command.cpp b/source/src/command.cpp index 8d1ebe6f..d7e44b66 100644 --- a/source/src/command.cpp +++ b/source/src/command.cpp @@ -324,7 +324,7 @@ int rndn(int a) { return a>0 ? rnd(a) : 0; } COMMANDN(rnd, rndn, ARG_1EXP); void writecfg() { s_sprintfd(cfgname)("config%csaved.cfg", PATHDIV); - FILE *f = fopen(cfgname, "w"); + FILE *f = openfile(cfgname, "w"); if(!f) return; fprintf(f, "// automatically written on exit, DO NOT MODIFY\n// delete this file to have defaults.cfg overwrite these settings\n// modify settings in game, or put settings in autoexec.cfg to override anything\n\n"); fprintf(f, "name %s\nteam %s\nskin %d\n", player1->name, player1->team, player1->nextskin); diff --git a/source/src/docs.cpp b/source/src/docs.cpp index 73b00a1c..fc7f7282 100644 --- a/source/src/docs.cpp +++ b/source/src/docs.cpp @@ -228,7 +228,7 @@ char *xmlstringenc(char *d, const char *s, size_t len) void docwritebaseref(char *ref, char *schemalocation, char *transformation) { s_sprintfd(outfile)("docs%cautogenerated_base_reference.xml", PATHDIV); - FILE *f = fopen(outfile, "w"); + FILE *f = openfile(outfile, "w"); if(!f) return; char desc[] = "TODO: Description"; diff --git a/source/src/main.cpp b/source/src/main.cpp index 7846cc4b..312ee1ab 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -26,6 +26,8 @@ void quit() // normal exit { extern void stopreset(); if(demoplayback) stopreset(); else stop(); + extern void writeinitcfg(); + writeinitcfg(); writeservercfg(); writecfg(); cleanup(NULL); @@ -39,22 +41,58 @@ void fatal(char *s, char *o) // failure exit exit(EXIT_FAILURE); } -int scr_w = 1024; -int scr_h = 768; +SDL_Surface *screen = NULL; int VIRTW; +static bool initing = false, restoredinits = false; +bool initwarning() +{ + if(!initing) + { + if(restoredinits) conoutf("Please restart AssaultCube for this setting to take effect."); + else conoutf("Please restart AssaultCube with the --init command-line option for this setting to take effect."); + } + return !initing; +} + +VARF(scr_w, 0, 1024, 10000, initwarning()); +VARF(scr_h, 0, 768, 10000, initwarning()); +VARF(colorbits, 0, 0, 32, initwarning()); +VARF(depthbits, 0, 0, 32, initwarning()); +VARF(fsaa, 0, 0, 16, initwarning()); +VARF(vsync, -1, -1, 1, initwarning()); + +void writeinitcfg() +{ + s_sprintfd(fn)("config%cinit.cfg", PATHDIV); + FILE *f = openfile(fn, "w"); + if(!f) return; + fprintf(f, "// automatically written on exit, DO NOT MODIFY\n// modify settings in game\n"); + fprintf(f, "scr_w %d\n", scr_w); + fprintf(f, "scr_h %d\n", scr_h); + fprintf(f, "colorbits %d\n", colorbits); + fprintf(f, "depthbits %d\n", depthbits); + fprintf(f, "fsaa %d\n", fsaa); + fprintf(f, "vsync %d\n", vsync); + extern int soundchans, soundfreq, soundbufferlen; + fprintf(f, "soundchans %d\n", soundchans); + fprintf(f, "soundfreq %d\n", soundfreq); + fprintf(f, "soundbufferlen %d\n", soundbufferlen); + fclose(f); +} + void screenshot(char *imagepath) { - SDL_Surface *image = SDL_CreateRGBSurface(SDL_SWSURFACE, scr_w, scr_h, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0); + SDL_Surface *image = SDL_CreateRGBSurface(SDL_SWSURFACE, screen->w, screen->h, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0); if(!image) return; - uchar *tmp = new uchar[scr_w*scr_h*3]; + uchar *tmp = new uchar[screen->w*screen->h*3]; glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0, 0, scr_w, scr_h, GL_RGB, GL_UNSIGNED_BYTE, tmp); + glReadPixels(0, 0, screen->w, screen->h, GL_RGB, GL_UNSIGNED_BYTE, tmp); uchar *dst = (uchar *)image->pixels; loopi(scr_h) { - memcpy(dst, &tmp[3*scr_w*(scr_h-i-1)], 3*scr_w); - endianswap(dst, 3, scr_w); + memcpy(dst, &tmp[3*screen->w*(screen->h-i-1)], 3*screen->w); + endianswap(dst, 3, screen->w); dst += image->pitch; } delete[] tmp; @@ -64,25 +102,20 @@ void screenshot(char *imagepath) s_sprintf(buf)("screenshots/screenshot_%d.bmp", lastmillis); imagepath = buf; } - SDL_SaveBMP(image, path(imagepath)); + SDL_SaveBMP(image, findfile(path(imagepath), "wb")); SDL_FreeSurface(image); } COMMAND(screenshot, ARG_1STR); COMMAND(quit, ARG_NONE); -SDL_Surface *screen = NULL; - -extern void setfullscreen(bool enable); - -VARF(fullscreen, 0, 0, 1, setfullscreen(fullscreen!=0)); - void setfullscreen(bool enable) { if(enable == !(screen->flags&SDL_FULLSCREEN)) { #if defined(WIN32) || defined(__APPLE__) conoutf("\"fullscreen\" variable not supported on this platform. Use the -t command-line option."); + extern int fullscreen; fullscreen = !enable; #else SDL_WM_ToggleFullScreen(screen); @@ -93,16 +126,26 @@ void setfullscreen(bool enable) void screenres(int w, int h, int bpp = 0) { +#if !defined(WIN32) && !defined(__APPLE__) + if(initing) + { +#endif + scr_w = w; + scr_h = h; + if(bpp) colorbits = bpp; #if defined(WIN32) || defined(__APPLE__) - conoutf("\"screenres\" command not supported on this platform. Use the -w and -h command-line options."); + initwarning(); #else + return; + } SDL_Surface *surf = SDL_SetVideoMode(w, h, bpp, SDL_OPENGL|SDL_RESIZABLE|(screen->flags&SDL_FULLSCREEN)); if(!surf) return; - scr_w = w; - scr_h = h; - VIRTW = scr_w*VIRTH/scr_h; screen = surf; - glViewport(0, 0, w, h); + scr_w = screen->w; + scr_h = screen->h; + if(bpp) colorbits = bpp; + glViewport(0, 0, scr_w, scr_h); + VIRTW = scr_w*VIRTH/scr_h; #endif } #if defined(WIN32) || defined(__APPLE__) || !defined(WIN32) @@ -113,6 +156,8 @@ void setresdata(char *s, enet_uint32 c) } #endif +VARF(fullscreen, 0, 0, 1, setfullscreen(fullscreen!=0)); + COMMAND(screenres, ARG_3INT); VARFP(gamma, 30, 100, 300, @@ -170,23 +215,38 @@ VARF(gamespeed, 10, 100, 1000, if(multiplayer()) gamespeed = 100); int main(int argc, char **argv) { bool dedicated = false; - int fs = SDL_FULLSCREEN, depth = 0, bpp = 0, fsaa = 0, vsync = -1, par = 0, uprate = 0, maxcl = DEFAULTCLIENTS, scthreshold = -5; + int fs = SDL_FULLSCREEN, par = 0, uprate = 0, maxcl = DEFAULTCLIENTS, scthreshold = -5; char *sdesc = "", *ip = "", *master = NULL, *passwd = "", *maprot = NULL, *adminpwd = NULL, *srvmsg = NULL; #define initlog(s) puts("init: " s) initlog("sdl"); + initing = true; for(int i = 1; iw; scr_h = modes[0]->h; } } - screen = SDL_SetVideoMode(scr_w, scr_h, bpp, SDL_OPENGL|resize|fs); - if(screen==NULL) fatal("Unable to create OpenGL screen"); + screen = SDL_SetVideoMode(scr_w, scr_h, colorbits, SDL_OPENGL|resize|fs); + if(!screen) fatal("Unable to create OpenGL screen"); + scr_w = screen->w; + scr_h = screen->h; + fullscreen = fs!=0; VIRTW = scr_w*VIRTH/scr_h; @@ -268,7 +332,7 @@ int main(int argc, char **argv) if(!setfont("default")) fatal("no default font specified"); initlog("gl"); - gl_init(scr_w, scr_h, bpp, depth, fsaa); + gl_init(scr_w, scr_h, colorbits, depthbits, fsaa); crosshair = textureload("packages/misc/crosshairs/default.png"); if(!crosshair) fatal("could not find core textures (hint: run AssaultCube from the parent of the bin directory)"); @@ -370,7 +434,7 @@ int main(int argc, char **argv) computeraytable(camera1->o.x, camera1->o.y); if(frames>4) SDL_GL_SwapBuffers(); extern void updatevol(); updatevol(); - if(frames>3) gl_drawframe(scr_w, scr_h, fpshighfps ? fps/highfps : 1.0f), fps); + if(frames>3) gl_drawframe(screen->w, screen->h, fpshighfps ? fps/highfps : 1.0f), fps); //SDL_Delay(100); SDL_Event event; int lasttype = 0, lastbut = 0; @@ -407,8 +471,8 @@ int main(int argc, char **argv) #ifdef __APPLE__ if(event.motion.y == 0) break; //let mac users drag windows via the title bar #endif - if(event.motion.x == scr_w / 2 && event.motion.y == scr_h / 2) break; - SDL_WarpMouse(scr_w / 2, scr_h / 2); + if(event.motion.x == screen->w / 2 && event.motion.y == screen->h / 2) break; + SDL_WarpMouse(screen->w / 2, screen->h / 2); } #ifndef WIN32 if((screen->flags&SDL_FULLSCREEN) || grabmouse) diff --git a/source/src/md2.h b/source/src/md2.h index 8cfca80a..6230e5d1 100644 --- a/source/src/md2.h +++ b/source/src/md2.h @@ -87,7 +87,7 @@ struct md2 : vertmodel { if(filename) return true; - FILE *file = fopen(path, "rb"); + FILE *file = openfile(path, "rb"); if(!file) return false; md2_header header; @@ -210,12 +210,12 @@ struct md2 : vertmodel parts.add(&mdl); mdl.model = this; mdl.index = 0; - char *pname = parentdir(loadname); + const char *pname = parentdir(loadname); s_sprintfd(name1)("packages/models/%s/tris.md2", loadname); if(!mdl.load(path(name1))) { s_sprintf(name1)("packages/models/%s/tris.md2", pname); // try md2 in parent folder (vert sharing) - if(!mdl.load(path(name1))) { delete[] pname; return false; } + if(!mdl.load(path(name1))) return false; } Texture *skin; loadskin(loadname, pname, skin); @@ -228,7 +228,6 @@ struct md2 : vertmodel s_sprintf(name2)("packages/models/%s/md2.cfg", pname); execfile(name2); } - delete[] pname; loadingmd2 = 0; loopv(parts) parts[i]->scaleverts(scale/16.0f, vec(translate.x, -translate.y, translate.z)); return loaded = true; diff --git a/source/src/md3.h b/source/src/md3.h index bfa1291d..88490e2c 100644 --- a/source/src/md3.h +++ b/source/src/md3.h @@ -53,7 +53,7 @@ struct md3 : vertmodel { if(filename) return true; - FILE *f = fopen(path, "rb"); + FILE *f = openfile(path, "rb"); if(!f) return false; md3header header; fread(&header, sizeof(md3header), 1, f); @@ -182,13 +182,12 @@ struct md3 : vertmodel if(loaded) return true; s_sprintf(md3dir)("packages/models/%s", loadname); - char *pname = parentdir(loadname); + const char *pname = parentdir(loadname); s_sprintfd(cfgname)("packages/models/%s/md3.cfg", loadname); loadingmd3 = this; if(execfile(cfgname) && parts.length()) // configured md3, will call the md3* commands below { - delete[] pname; loadingmd3 = NULL; if(parts.empty()) return false; loopv(parts) if(!parts[i]->filename) return false; @@ -204,7 +203,7 @@ struct md3 : vertmodel if(!mdl.load(path(name1))) { s_sprintf(name1)("packages/models/%s/tris.md3", pname); // try md3 in parent folder (vert sharing) - if(!mdl.load(path(name1))) { delete[] pname; return false; }; + if(!mdl.load(path(name1))) return false; }; Texture *skin; loadskin(loadname, pname, skin); diff --git a/source/src/protos.h b/source/src/protos.h index 70443219..c4ec500a 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -190,6 +190,7 @@ extern int isoccluded(float vx, float vy, float cx, float cy, float csize); // main extern void keyrepeat(bool on); +extern bool initwarning(); // rendertext extern bool setfont(char *name); diff --git a/source/src/savegamedemo.cpp b/source/src/savegamedemo.cpp index 4382f1ab..25447af8 100644 --- a/source/src/savegamedemo.cpp +++ b/source/src/savegamedemo.cpp @@ -44,7 +44,7 @@ void stopifrecording() { if(demorecording) stop(); } void savestate(char *fn) { stop(); - f = gzopen(fn, "wb9"); + f = opengzfile(fn, "wb9"); if(!f) { conoutf("could not write %s", fn); return; } gzwrite(f, (void *)"CUBESAVE", 8); gzputc(f, SDL_BYTEORDER==SDL_LIL_ENDIAN ? 1 : 0); @@ -73,7 +73,7 @@ void loadstate(char *fn) { stop(); if(multiplayer()) return; - f = gzopen(fn, "rb9"); + f = opengzfile(fn, "rb9"); if(!f) { conoutf("could not open %s", fn); return; } string buf; diff --git a/source/src/server.cpp b/source/src/server.cpp index 0906174f..0e0afcd4 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -1305,8 +1305,8 @@ int main(int argc, char **argv) case 'p': passwd = a; break; case 'c': maxcl = atoi(a); break; case 'r': maprot = a; break; - case 'x' : adminpasswd = a; break; - case 'o' : srvmsg = a; break; + case 'x': adminpasswd = a; break; + case 'o': srvmsg = a; break; case 'k': scthreshold = atoi(a); break; default: printf("WARNING: unknown commandline option\n"); } diff --git a/source/src/serverbrowser.cpp b/source/src/serverbrowser.cpp index b4a38837..d6c81a8c 100644 --- a/source/src/serverbrowser.cpp +++ b/source/src/serverbrowser.cpp @@ -473,7 +473,7 @@ COMMAND(updatefrommaster, ARG_NONE); void writeservercfg() { - FILE *f = fopen("config/servers.cfg", "w"); + FILE *f = openfile("config/servers.cfg", "w"); if(!f) return; fprintf(f, "// servers connected to are added here automatically\n\n"); loopvrev(servers) fprintf(f, "addserver %s\n", servers[i].name); diff --git a/source/src/sound.cpp b/source/src/sound.cpp index 474c6f8f..3feef2e2 100644 --- a/source/src/sound.cpp +++ b/source/src/sound.cpp @@ -7,14 +7,11 @@ #define USE_MIXER //#endif -VARP(soundvol, 0, 150, 255); bool nosound = true; #define MAXCHAN 32 #define SOUNDFREQ 22050 -struct soundloc { vec loc; bool inuse; } soundlocs[MAXCHAN]; - #ifdef USE_MIXER #include "SDL_mixer.h" #define MAXVOL MIX_MAX_VOLUME @@ -25,14 +22,27 @@ struct soundloc { vec loc; bool inuse; } soundlocs[MAXCHAN]; #define MAXVOL 255 FMUSIC_MODULE *mod = NULL; FSOUND_STREAM *stream = NULL; + int musicchan; #endif -int musicvol = 125; +struct sample +{ + char *name; + #ifdef USE_MIXER + Mix_Chunk *sound; + #else + FSOUND_SAMPLE *sound; + #endif -void setmusicvol(int vol) + sample(const char *name) : name(newstring(name)), sound(NULL) {} + ~sample() { DELETEA(name); } +}; + +struct soundloc { vec loc; bool inuse; }; +vector soundlocs; + +void setmusicvol(int musicvol) { - if(musicvol > 255 || musicvol < 0) return; - musicvol = vol; if(nosound) return; #ifdef USE_MIXER if(mod) Mix_VolumeMusic((musicvol*MAXVOL)/255); @@ -42,7 +52,8 @@ void setmusicvol(int vol) #endif } -COMMANDN(musicvol, setmusicvol, ARG_1INT); +VARP(soundvol, 0, 150, 255); +VARFP(musicvol, 0, 128, 255, setmusicvol(musicvol)); void stopsound() { @@ -66,21 +77,22 @@ void stopsound() } } -VAR(soundbufferlen, 128, 1024, 4096); +VARF(soundchans, 0, 32, 128, initwarning()); +VARF(soundfreq, 0, MIX_DEFAULT_FREQUENCY, 44100, initwarning()); +VARF(soundbufferlen, 128, 1024, 4096, initwarning()); void initsound() { - memset(soundlocs, 0, sizeof(soundloc)*MAXCHAN); #ifdef USE_MIXER - if(Mix_OpenAudio(SOUNDFREQ, MIX_DEFAULT_FORMAT, 2, soundbufferlen)<0) + if(Mix_OpenAudio(soundfreq, MIX_DEFAULT_FORMAT, 2, soundbufferlen)<0) { conoutf("sound init failed (SDL_mixer): %s", (size_t)Mix_GetError()); return; } - Mix_AllocateChannels(MAXCHAN); + Mix_AllocateChannels(soundchans); #else if(FSOUND_GetVersion()=0) { FSOUND_SetVolume(chan, (musicvol*MAXVOL)/255); FSOUND_SetPaused(chan, false); } + musicchan = FSOUND_Stream_Play(FSOUND_FREE, stream); + if(musicchan>=0) { FSOUND_SetVolume(musicchan, (musicvol*MAXVOL)/255); FSOUND_SetPaused(musicchan, false); } } #endif else @@ -124,20 +137,12 @@ void music(char *name) COMMAND(music, ARG_1STR); - -#ifdef USE_MIXER -vector samples; -#else -vector samples; -#endif - -cvector snames; +vector samples; int registersound(char *name) { - loopv(snames) if(strcmp(snames[i], name)==0) return i; - snames.add(newstring(name)); - samples.add(NULL); + loopv(samples) if(!strcmp(samples[i]->name, name)) return i; + samples.add(new sample(name)); return samples.length()-1; } @@ -183,7 +188,7 @@ void updatechanvol(int chan, vec *loc) void newsoundloc(int chan, vec *loc) { - ASSERT(chan>=0 && chan= soundlocs.length()) soundlocs.add().inuse = false; soundlocs[chan].loc = *loc; soundlocs[chan].inuse = true; } @@ -191,7 +196,7 @@ void newsoundloc(int chan, vec *loc) void updatevol() { if(nosound) return; - loopi(MAXCHAN) if(soundlocs[i].inuse) + loopv(soundlocs) if(soundlocs[i].inuse) { #ifdef USE_MIXER if(Mix_Playing(i)) @@ -210,36 +215,44 @@ void playsoundc(int n) playsound(n); } -int soundsatonce = 0, lastsoundmillis = 0; - void playsound(int n, vec *loc) { if(nosound) return; if(!soundvol) return; if(n==S_NULL) return; if(m_botmode) BotManager.LetBotsHear(n, loc); + + static int soundsatonce = 0, lastsoundmillis = 0; if(lastmillis==lastsoundmillis) soundsatonce++; else soundsatonce = 1; lastsoundmillis = lastmillis; if(soundsatonce>5) return; // avoid bursts of sounds with heavy packetloss and in sp - if(n<0 || n>=samples.length()) { conoutf("unregistered sound: %d", n); return; } - if(!samples[n]) + if(!samples.inrange(n)) { conoutf("unregistered sound: %d", n); return; } + + sample &s = *samples[n]; + if(!s.sound) { - s_sprintfd(buf)("packages/audio/sounds/%s.wav", snames[n]); + s_sprintfd(buf)("packages/audio/sounds/%s", s.name); - #ifdef USE_MIXER - samples[n] = Mix_LoadWAV(path(buf)); - #else - samples[n] = FSOUND_Sample_Load(n, path(buf), FSOUND_LOOP_OFF, 0, 0); - #endif + loopi(2) + { + if(i) s_strcat(buf, ".wav"); + const char *file = findfile(path(buf), "rb"); + #ifdef USE_MIXER + s.sound = Mix_LoadWAV(file); + #else + s.sound = FSOUND_Sample_Load(n, file, FSOUND_LOOP_OFF, 0, 0); + #endif + if(s.sound) break; + } - if(!samples[n]) { conoutf("failed to load sample: %s", buf); return; } + if(!s.sound) { conoutf("failed to load sample: %s", buf); return; } } #ifdef USE_MIXER - int chan = Mix_PlayChannel(-1, samples[n], 0); + int chan = Mix_PlayChannel(-1, s.sound, 0); #else - int chan = FSOUND_PlaySoundEx(FSOUND_FREE, samples[n], NULL, true); + int chan = FSOUND_PlaySoundEx(FSOUND_FREE, s.sound, NULL, true); #endif if(chan<0) return; if(loc) newsoundloc(chan, loc); diff --git a/source/src/texture.cpp b/source/src/texture.cpp index 74ecb020..a61cdc7c 100644 --- a/source/src/texture.cpp +++ b/source/src/texture.cpp @@ -36,7 +36,7 @@ void createtexture(int tnum, int w, int h, void *pixels, int clamp, bool mipmap, GLuint loadsurface(const char *texname, int &xs, int &ys, int clamp) { - SDL_Surface *s = IMG_Load(texname); + SDL_Surface *s = IMG_Load(findfile(texname, "rb")); if(!s) { conoutf("couldn't load texture %s", texname); return 0; } if(s->format->BitsPerPixel!=24 && s->format->BitsPerPixel!=32) { diff --git a/source/src/tools.cpp b/source/src/tools.cpp index 290f152a..67d2c722 100644 --- a/source/src/tools.cpp +++ b/source/src/tools.cpp @@ -2,9 +2,16 @@ #include "cube.h" -//////////////////////////// pool /////////////////////////// +///////////////////////// file system /////////////////////// -///////////////////////// misc tools /////////////////////// +#ifndef WIN32 +#include +#include +#include +#endif + +string homedir = ""; +vector packagedirs; char *path(char *s) { @@ -29,26 +36,122 @@ char *path(char *s) return s; } -char *parentdir(char *directory) +const char *parentdir(const char *directory) { - char *p = strrchr(directory, '/'); + const char *p = strrchr(directory, '/'); + if(!p) p = strrchr(directory, '\\'); if(!p) p = directory; + static string parent; size_t len = p-directory+1; - char *parent = new char[len]; s_strncpy(parent, directory, len); return parent; } -char *loadfile(char *fn, int *size) +bool fileexists(const char *path, const char *mode) { - FILE *f = fopen(fn, "rb"); + bool exists = true; + if(mode[0]=='w' || mode[0]=='a') path = parentdir(path); +#ifdef WIN32 + if(GetFileAttributes(path) == INVALID_FILE_ATTRIBUTES) exists = false; +#else + if(access(path, R_OK | (mode[0]=='w' || mode[0]=='a' ? W_OK : 0)) == -1) exists = false; +#endif + return exists; +} + +bool createdir(const char *path) +{ + int len = strlen(path); + if(path[len-1]==PATHDIV) + { + static string strip; + path = s_strncpy(strip, path, len); + } +#ifdef WIN32 + return CreateDirectory(path, NULL)!=0; +#else + return mkdir(path, 0777)==0; +#endif +} + +static void fixdir(char *dir) +{ + path(dir); + int len = strlen(dir); + if(dir[len-1]!=PATHDIV) + { + dir[len] = PATHDIV; + dir[len+1] = '\0'; + } +} + +void sethomedir(const char *dir) +{ + fixdir(s_strcpy(homedir, dir)); +} + +void addpackagedir(const char *dir) +{ + fixdir(packagedirs.add(newstringbuf(dir))); +} + +const char *findfile(const char *filename, const char *mode) +{ + static string s; + if(homedir[0]) + { + s_sprintf(s)("%s%s", homedir, filename); + if(fileexists(s, mode)) return s; + if(mode[0]=='w' || mode[0]=='a') + { + string dirs; + s_strcpy(dirs, s); + char *dir = strchr(dirs[0]==PATHDIV ? dirs+1 : dirs, PATHDIV); + while(dir) + { + *dir = '\0'; + if(!fileexists(dirs, "r") && !createdir(dirs)) return s; + *dir = PATHDIV; + dir = strchr(dir+1, PATHDIV); + } + return s; + } + } + if(mode[0]=='w' || mode[0]=='a') return filename; + loopv(packagedirs) + { + s_sprintf(s)("%s%s", packagedirs[i], filename); + if(fileexists(s, mode)) return s; + } + return filename; +} + +FILE *openfile(const char *filename, const char *mode) +{ + const char *found = findfile(filename, mode); + if(!found) return NULL; + return fopen(found, mode); +} + +#ifndef STANDALONE +gzFile opengzfile(const char *filename, const char *mode) +{ + const char *found = findfile(filename, mode); + if(!found) return NULL; + return gzopen(found, mode); +} +#endif + +char *loadfile(const char *fn, int *size) +{ + FILE *f = openfile(fn, "rb"); if(!f) return NULL; fseek(f, 0, SEEK_END); int len = ftell(f); - if(len<=0) { fclose(f); return NULL; }; + if(len<=0) { fclose(f); return NULL; } fseek(f, 0, SEEK_SET); char *buf = new char[len+1]; - if(!buf) { fclose(f); return NULL; }; + if(!buf) { fclose(f); return NULL; } buf[len] = 0; size_t rlen = fread(buf, 1, len, f); fclose(f); @@ -61,6 +164,8 @@ char *loadfile(char *fn, int *size) return buf; } +///////////////////////// misc tools /////////////////////// + bool cmpb(void *b, int n, enet_uint32 c) { ENetBuffer buf; diff --git a/source/src/tools.h b/source/src/tools.h index 77c1dc09..62eb238d 100644 --- a/source/src/tools.h +++ b/source/src/tools.h @@ -101,15 +101,21 @@ struct s_sprintf_f template void _swap(T &a, T &b) { T t = a; a = b; b = t; } - extern char *path(char *s); -extern char *parentdir(char *directory); -extern char *loadfile(char *fn, int *size); +extern const char *parentdir(const char *directory); +extern bool fileexists(const char *path, const char *mode); +extern bool createdir(const char *path); +extern void sethomedir(const char *dir); +extern void addpackagedir(const char *dir); +extern const char *findfile(const char *filename, const char *mode); +extern FILE *openfile(const char *filename, const char *mode); +#ifndef STANDALONE +extern gzFile opengzfile(const char *filename, const char *mode); +#endif +extern char *loadfile(const char *fn, int *size); extern bool cmpb(void *b, int n, enet_uint32 c); extern bool cmpf(char *fn, enet_uint32 c); extern void endianswap(void *, int, int); -extern void seedMT(uint seed); -extern uint randomMT(void); #if SDL_BYTEORDER == SDL_BIG_ENDIAN #define CMPB(b, c) (true) @@ -370,22 +376,22 @@ template struct hashtable enum { CHUNKSIZE = 16 }; struct chain { T data; K key; chain *next; }; - struct chainchunk { chain chunks[CHUNKSIZE]; chainchunk *next; }; + struct chainchunk { chain chains[CHUNKSIZE]; chainchunk *next; }; int size; int numelems; chain **table; chain *enumc; - int chunkremain; - chainchunk *lastchunk; + chainchunk *chunks; + chain *unused; hashtable(int size = 1<<10) : size(size) { numelems = 0; - chunkremain = 0; - lastchunk = NULL; + chunks = NULL; + unused = NULL; table = new chain *[size]; loopi(size) table[i] = NULL; } @@ -397,16 +403,19 @@ template struct hashtable chain *insert(const K &key, uint h) { - if(!chunkremain) + if(!unused) { chainchunk *chunk = new chainchunk; - chunk->next = lastchunk; - lastchunk = chunk; - chunkremain = CHUNKSIZE; + chunk->next = chunks; + chunks = chunk; + loopi(CHUNKSIZE-1) chunk->chains[i].next = &chunk->chains[i+1]; + chunk->chains[CHUNKSIZE-1].next = unused; + unused = chunk->chains; } - chain *c = &lastchunk->chunks[--chunkremain]; + chain *c = unused; + unused = unused->next; c->key = key; - c->next = table[h]; + c->next = table[h]; table[h] = c; numelems++; return c; @@ -436,24 +445,36 @@ template struct hashtable return find(key, true)->data; } + bool remove(const K &key) + { + uint h = hthash(key)&(size-1); + for(chain **p = &table[h], *c = table[h]; c; p = &c->next, c = c->next) + { + if(htcmp(key, c->key)) + { + *p = c->next; + c->data.~T(); + c->key.~K(); + new (&c->data) T(); + new (&c->key) K(); + c->next = unused; + unused = c->next; + numelems--; + return true; + } + } + return false; + } + void clear() { - loopi(size) - { - /* - for(chain *c = table[i], *next; c; c = next) - { - next = c->next; - delete c; - }*/ - table[i] = NULL; - } + loopi(size) table[i] = NULL; numelems = 0; - chunkremain = 0; - for(chainchunk *chunk; lastchunk; lastchunk = chunk) + unused = NULL; + for(chainchunk *nextchunk; chunks; chunks = nextchunk) { - chunk = lastchunk->next; - delete lastchunk; + nextchunk = chunks->next; + delete chunks; } } }; diff --git a/source/src/vertmodel.h b/source/src/vertmodel.h index cdbf6eac..40bc388e 100644 --- a/source/src/vertmodel.h +++ b/source/src/vertmodel.h @@ -431,11 +431,11 @@ struct vertmodel : model shadows = new GLuint[numframes]; glGenTextures(numframes, shadows); - extern int scr_w, scr_h; + extern SDL_Surface *screen; int aasize = 1<<(dynshadowsize + aadynshadow); - while(aasize > scr_w || aasize > scr_h) aasize /= 2; + while(aasize > screen->w || aasize > screen->h) aasize /= 2; - gzFile f = filename ? gzopen(filename, "wb9") : NULL; + gzFile f = filename ? opengzfile(filename, "wb9") : NULL; if(f) { shadowheader hdr; @@ -469,14 +469,14 @@ struct vertmodel : model endgenshadow(); glEnable(GL_FOG); - glViewport(0, 0, scr_w, scr_h); + glViewport(0, 0, screen->w, screen->h); if(f) gzclose(f); } bool loadshadows(const char *filename) { - gzFile f = gzopen(filename, "rb9"); + gzFile f = opengzfile(filename, "rb9"); if(!f) return false; shadowheader hdr; if(gzread(f, &hdr, sizeof(shadowheader))!=sizeof(shadowheader)) { gzclose(f); return false; } diff --git a/source/src/worldio.cpp b/source/src/worldio.cpp index 903ca427..5343a06f 100644 --- a/source/src/worldio.cpp +++ b/source/src/worldio.cpp @@ -106,7 +106,7 @@ void writemap(char *mname, int msize, uchar *mdata) { setnames(mname); backup(cgzname, bakname); - FILE *f = fopen(cgzname, "wb"); + FILE *f = openfile(cgzname, "wb"); if(!f) { conoutf("could not write map to %s", cgzname); return; } fwrite(mdata, 1, msize, f); fclose(f); @@ -133,7 +133,7 @@ void save_world(char *mname) toptimize(); setnames(mname); backup(cgzname, bakname); - gzFile f = gzopen(cgzname, "wb9"); + gzFile f = opengzfile(cgzname, "wb9"); if(!f) { conoutf("could not write map to %s", cgzname); return; } hdr.version = MAPVERSION; hdr.numents = 0; @@ -214,7 +214,7 @@ void load_world(char *mname) // still supports all map formats that have cleardlights(); pruneundos(); setnames(mname); - gzFile f = gzopen(cgzname, "rb9"); + gzFile f = opengzfile(cgzname, "rb9"); if(!f) { conoutf("could not read map %s", cgzname); return; } loadingscreen(); gzread(f, &hdr, sizeof(header)-sizeof(int)*16);