// main.cpp: initialisation & main loop #include "cube.h" void cleanup(char *msg) // single program exit point; { if(!msg) { cleanupclient(); audiomgr.soundcleanup(); cleanupserver(); extern void cleargamma(); cleargamma(); } SDL_ShowCursor(1); if(msg) { #ifdef WIN32 MessageBox(NULL, msg, "AssaultCube fatal error", MB_OK|MB_SYSTEMMODAL|MB_ICONERROR); #else printf("%s", msg); #endif } SDL_Quit(); } VAR(resetcfg, 0, 0, 1); void quit() // normal exit { const char *onquit = getalias("onQuit"); if(onquit && onquit[0]) { execute(onquit); alias("onQuit", ""); } extern void writeinitcfg(); writeinitcfg(); writeservercfg(); if(resetcfg) deletecfg(); else writecfg(); cleanup(NULL); popscontext(); exit(EXIT_SUCCESS); } void fatal(const char *s, ...) // failure exit { static int errors = 0; errors++; if(errors <= 2) { defvformatstring(msg,s,s); if(errors <= 1) { defvformatstring(msg,s,s); defformatstring(msgerr)("%s (%s)\n", msg, SDL_GetError()); cleanup(msgerr); } else puts(msg); } exit(EXIT_FAILURE); } SDL_Surface *screen = NULL; static int initing = NOT_INITING; static bool restoredinits = false; bool initwarning(const char *desc, int level, int type) { if(initing < level) { addchange(desc, type); return true; } return false; } VARF(scr_w, 320, 1024, 10000, initwarning("screen resolution")); VARF(scr_h, 200, 768, 10000, initwarning("screen resolution")); VARF(colorbits, 0, 0, 32, initwarning("color depth")); VARF(depthbits, 0, 0, 32, initwarning("depth-buffer precision")); VARF(stencilbits, 0, 0, 32, initwarning("stencil-buffer precision")); VARF(fsaa, -1, -1, 16, initwarning("anti-aliasing")); VARF(vsync, -1, -1, 1, initwarning("vertical sync")); static bool grabinput = false, minimized = false; void inputgrab(bool on) { #ifndef WIN32 if(!(screen->flags & SDL_FULLSCREEN)) SDL_WM_GrabInput(SDL_GRAB_OFF); else #endif SDL_WM_GrabInput(on ? SDL_GRAB_ON : SDL_GRAB_OFF); SDL_ShowCursor(on ? SDL_DISABLE : SDL_ENABLE); } void setfullscreen(bool enable) { if(!screen) return; #if defined(WIN32) || defined(__APPLE__) initwarning(enable ? "fullscreen" : "windowed"); #else if(enable == !(screen->flags&SDL_FULLSCREEN)) { SDL_WM_ToggleFullScreen(screen); inputgrab(grabinput); } #endif } #ifdef _DEBUG VARF(fullscreen, 0, 0, 1, setfullscreen(fullscreen!=0)); #else VARF(fullscreen, 0, 1, 1, setfullscreen(fullscreen!=0)); #endif void writeinitcfg() { if(!restoredinits) return; stream *f = openfile(path("config/init.cfg", true), "w"); if(!f) return; f->printf("// automatically written on exit, DO NOT MODIFY\n// modify settings in game\n"); extern int fullscreen; f->printf("fullscreen %d\n", fullscreen); f->printf("scr_w %d\n", scr_w); f->printf("scr_h %d\n", scr_h); f->printf("colorbits %d\n", colorbits); f->printf("depthbits %d\n", depthbits); f->printf("stencilbits %d\n", stencilbits); f->printf("fsaa %d\n", fsaa); f->printf("vsync %d\n", vsync); extern int audio, soundchannels; f->printf("audio %d\n", audio > 0 ? 1 : 0); f->printf("soundchannels %d\n", soundchannels); f->printf("lang %s\n", lang); delete f; } #if 0 VARP(highprocesspriority, 0, 1, 1); void setprocesspriority(bool high) { #if defined(WIN32) && !defined(_DEBUG) SetPriorityClass(GetCurrentProcess(), high && highprocesspriority && fullscreen ? HIGH_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS); #endif } #endif const char *screenshotpath(const char *imagepath, const char *suffix) { static string buf; if(imagepath && imagepath[0]) copystring(buf, imagepath); else { if(getclientmap()[0]) formatstring(buf)("screenshots/%s_%s_%s.%s", timestring(), behindpath(getclientmap()), modestr(gamemode, true), suffix); else formatstring(buf)("screenshots/%s.%s", timestring(), suffix); } path(buf); return buf; } FVARP(screenshotscale, 0.1f, 1.0f, 1.0f); void bmp_screenshot(const char *imagepath, bool mapshot = false) { extern int minimaplastsize; int iw = mapshot?minimaplastsize:screen->w; int ih = mapshot?minimaplastsize:screen->h; int tw = mapshot ? iw : iw*screenshotscale; int th = mapshot ? ih : ih*screenshotscale; SDL_Surface *image = creatergbsurface(tw, th); if(!image) return; uchar *tmp = new uchar[iw*ih*3]; uchar *dst = (uchar *)image->pixels; if(mapshot) { extern GLuint minimaptex; if(minimaptex) { glPixelStorei(GL_PACK_ALIGNMENT, 1); glBindTexture(GL_TEXTURE_2D, minimaptex); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, tmp); } else { conoutf("no mapshot prepared!"); return; } } else { glPixelStorei(GL_PACK_ALIGNMENT, 1); if(screenshotscale != 1.0f) { uchar *buf = new uchar[iw*ih*3]; glReadPixels(0, 0, iw, ih, GL_RGB, GL_UNSIGNED_BYTE, buf); //screen->w//screen->h scaletexture(buf, iw, ih, 3, tmp, tw, th); delete[] buf; } else glReadPixels(0, 0, tw, th, GL_RGB, GL_UNSIGNED_BYTE, tmp); } loopi(th) { memcpy(dst, &tmp[3*tw*(th-i-1)], 3*tw); dst += image->pitch; } delete[] tmp; const char *filename = screenshotpath(imagepath, "bmp"); stream *file = openfile(filename, "wb"); if(!file) conoutf("failed to create: %s", filename); else { SDL_SaveBMP_RW(image, file->rwops(), 1); delete file; } SDL_FreeSurface(image); } // best: 100 - good: 85 [default] - bad: 70 - terrible: 50 VARP(jpegquality, 10, 85, 100); #include "jpegenc.h" void jpeg_screenshot(const char *imagepath, bool mapshot = false) { extern int minimaplastsize; int iw = mapshot?minimaplastsize:screen->w; int ih = mapshot?minimaplastsize:screen->h; int tw = mapshot ? iw : iw*screenshotscale; int th = mapshot ? ih : ih*screenshotscale; uchar *pixels = new uchar[3*tw*th]; if(mapshot) { extern GLuint minimaptex; if(minimaptex) { glPixelStorei(GL_PACK_ALIGNMENT, 1); glBindTexture(GL_TEXTURE_2D, minimaptex); glGetTexImage(GL_TEXTURE_2D, 0, GL_BGR, GL_UNSIGNED_BYTE, pixels); } else { conoutf("no mapshot prepared!"); delete[] pixels; return; } } else { glPixelStorei(GL_PACK_ALIGNMENT, 1); if(screenshotscale != 1.0f) { uchar *buf = new uchar[iw*ih*3]; glReadPixels(0, 0, iw, ih, GL_BGR, GL_UNSIGNED_BYTE, buf); scaletexture(buf, iw, ih, 3, pixels, tw, th); delete[] buf; } else glReadPixels(0, 0, tw, th, GL_BGR, GL_UNSIGNED_BYTE, pixels); int stride = 3*tw; GLubyte *swapline = (GLubyte *) malloc(stride); for(int row = 0; row < th/2; row++) { memcpy(swapline, pixels + row * stride, stride); memcpy(pixels + row * stride, pixels + (th - row - 1) * stride, stride); memcpy(pixels + (th - row -1) * stride, swapline, stride); } free(swapline); } const char *filename = findfile(screenshotpath(imagepath, "jpg"), "wb"); conoutf("writing to file: %s", filename); jpegenc *jpegencoder = new jpegenc; jpegencoder->encode(filename, (colorRGB *)pixels, tw, th, jpegquality); delete jpegencoder; delete[] pixels; } VARP(pngcompress, 0, 9, 9); void writepngchunk(stream *f, const char *type, uchar *data = NULL, uint len = 0) { f->putbig(len); f->write(type, 4); f->write(data, len); uint crc = crc32(0, Z_NULL, 0); crc = crc32(crc, (const Bytef *)type, 4); if(data) crc = crc32(crc, data, len); f->putbig(crc); } int save_png(const char *filename, SDL_Surface *image) { uchar *data = (uchar *)image->pixels; int iw = image->w, ih = image->h, pitch = image->pitch; stream *f = openfile(filename, "wb"); if(!f) { conoutf("could not write to %s", filename); return -1; } uchar signature[] = { 137, 80, 78, 71, 13, 10, 26, 10 }; f->write(signature, sizeof(signature)); struct pngihdr { uint width, height; uchar bitdepth, colortype, compress, filter, interlace; } ihdr = { bigswap(iw), bigswap(ih), 8, 2, 0, 0, 0 }; writepngchunk(f, "IHDR", (uchar *)&ihdr, 13); int idat = f->tell(); uint len = 0; f->write("\0\0\0\0IDAT", 8); uint crc = crc32(0, Z_NULL, 0); crc = crc32(crc, (const Bytef *)"IDAT", 4); z_stream z; z.zalloc = NULL; z.zfree = NULL; z.opaque = NULL; if(deflateInit(&z, pngcompress) != Z_OK) goto error; uchar buf[1<<12]; z.next_out = (Bytef *)buf; z.avail_out = sizeof(buf); loopi(ih) { uchar filter = 0; loopj(2) { z.next_in = j ? (Bytef *)data + i*pitch : (Bytef *)&filter; z.avail_in = j ? iw*3 : 1; while(z.avail_in > 0) { if(deflate(&z, Z_NO_FLUSH) != Z_OK) goto cleanuperror; #define FLUSHZ do { \ int flush = sizeof(buf) - z.avail_out; \ crc = crc32(crc, buf, flush); \ len += flush; \ f->write(buf, flush); \ z.next_out = (Bytef *)buf; \ z.avail_out = sizeof(buf); \ } while(0) FLUSHZ; } } } for(;;) { int err = deflate(&z, Z_FINISH); if(err != Z_OK && err != Z_STREAM_END) goto cleanuperror; FLUSHZ; if(err == Z_STREAM_END) break; } deflateEnd(&z); f->seek(idat, SEEK_SET); f->putbig(len); f->seek(0, SEEK_END); f->putbig(crc); writepngchunk(f, "IEND"); delete f; return 0; cleanuperror: deflateEnd(&z); error: delete f; return -1; } void png_screenshot(const char *imagepath, bool mapshot = false) { extern int minimaplastsize; int iw = mapshot?minimaplastsize:screen->w; int ih = mapshot?minimaplastsize:screen->h; int tw = mapshot ? iw : iw*screenshotscale; int th = mapshot ? ih : ih*screenshotscale; SDL_Surface *image = creatergbsurface(tw, th); if(!image) return; uchar *tmp = new uchar[tw*th*3]; uchar *dst = (uchar *)image->pixels; if(mapshot) { extern GLuint minimaptex; if(minimaptex) { glPixelStorei(GL_PACK_ALIGNMENT, 1); glBindTexture(GL_TEXTURE_2D, minimaptex); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, tmp); } else { conoutf("no mapshot prepared!"); return; } } else { glPixelStorei(GL_PACK_ALIGNMENT, 1); if(screenshotscale != 1.0f) { uchar *buf = new uchar[iw*ih*3]; glReadPixels(0, 0, iw, ih, GL_RGB, GL_UNSIGNED_BYTE, buf); scaletexture(buf, iw, ih, 3, tmp, tw, th); delete[] buf; } else glReadPixels(0, 0, tw, th, GL_RGB, GL_UNSIGNED_BYTE, tmp); } loopi(th) { memcpy(dst, &tmp[3*tw*(th-i-1)], 3*tw); dst += image->pitch; } delete[] tmp; const char *filename = screenshotpath(imagepath, "png"); if(save_png(filename, image) < 0) conoutf("\f3Error saving png file"); SDL_FreeSurface(image); } VARP(screenshottype, 0, 1, 2); void screenshot(const char *imagepath) { switch(screenshottype) { case 2: png_screenshot(imagepath,false); break; case 1: jpeg_screenshot(imagepath,false); break; case 0: default: bmp_screenshot(imagepath,false); break; } } void mapshot() { string suffix; switch(screenshottype) { case 2: copystring(suffix, "png"); break; case 1: copystring(suffix, "jpg"); break; case 0: default: copystring(suffix, "bmp"); break; } defformatstring(buf)("screenshots/mapshot_%s_%s.%s", behindpath(getclientmap()), timestring(), suffix); switch(screenshottype) { case 2: png_screenshot(buf,true); break; case 1: jpeg_screenshot(buf,true); break; case 0: default: bmp_screenshot(buf,true); break; } } bool needsautoscreenshot = false; COMMAND(screenshot, "s"); COMMAND(mapshot, ""); COMMAND(quit, ""); void screenres(int w, int h) { #if !defined(WIN32) && !defined(__APPLE__) if(initing >= INIT_RESET) { #endif scr_w = w; scr_h = h; #if defined(WIN32) || defined(__APPLE__) initwarning("screen resolution"); #else return; } SDL_Surface *surf = SDL_SetVideoMode(w, h, 0, SDL_OPENGL|SDL_RESIZABLE|(screen->flags&SDL_FULLSCREEN)); if(!surf) return; screen = surf; scr_w = screen->w; scr_h = screen->h; glViewport(0, 0, scr_w, scr_h); VIRTW = scr_w*VIRTH/scr_h; #endif } #if defined(WIN32) || defined(__APPLE__) || !defined(WIN32) void setresdata(char *s, enet_uint32 c) { extern hashtable &resdata; resdata[newstring(s)] = c; } #endif COMMANDF(screenres, "ii", (int *w, int *h) { screenres(*w, *h); }); static int curgamma = 100; VARFP(gamma, 30, 100, 300, { if(gamma == curgamma) return; curgamma = gamma; float f = gamma/100.0f; if(SDL_SetGamma(f,f,f)==-1) conoutf("Could not set gamma: %s", SDL_GetError()); }); void cleargamma() { if(curgamma != 100) SDL_SetGamma(1, 1, 1); } void restoregamma() { if(curgamma == 100) return; float f = curgamma/100.0f; SDL_SetGamma(1, 1, 1); SDL_SetGamma(f, f, f); } void setupscreen(int &usedcolorbits, int &useddepthbits, int &usedfsaa) { int flags = SDL_RESIZABLE; #if defined(WIN32) || defined(__APPLE__) flags = 0; putenv("SDL_VIDEO_CENTERED=1"); //Center window #endif if(fullscreen) flags |= SDL_FULLSCREEN; SDL_Rect **modes = SDL_ListModes(NULL, SDL_OPENGL|flags); if(modes && modes!=(SDL_Rect **)-1) { bool hasmode = false; for(int i = 0; modes[i]; i++) { if(scr_w <= modes[i]->w && scr_h <= modes[i]->h) { hasmode = true; break; } } if(!hasmode) { scr_w = modes[0]->w; scr_h = modes[0]->h; } } bool hasbpp = true; if(colorbits && modes) hasbpp = SDL_VideoModeOK(modes!=(SDL_Rect **)-1 ? modes[0]->w : scr_w, modes!=(SDL_Rect **)-1 ? modes[0]->h : scr_h, colorbits, SDL_OPENGL|flags)==colorbits; SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); #if SDL_VERSION_ATLEAST(1, 2, 11) if(vsync>=0) SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, vsync); #endif static int configs[] = { 0x7, /* try everything */ 0x6, 0x5, 0x3, /* try disabling one at a time */ 0x4, 0x2, 0x1, /* try disabling two at a time */ 0 /* try disabling everything */ }; int config = 0; SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0); if(!depthbits) SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); if(!fsaa) { SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); } loopi(sizeof(configs)/sizeof(configs[0])) { config = configs[i]; if(!depthbits && config&1) continue; if(!stencilbits && config&2) continue; if(fsaa<=0 && config&4) continue; if(depthbits) SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, config&1 ? depthbits : 16); if(stencilbits) { SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, config&2 ? stencilbits : 0); hasstencil = (config&2)!=0; } else hasstencil = false; if(fsaa>0) { SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, config&4 ? 1 : 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, config&4 ? fsaa : 0); } screen = SDL_SetVideoMode(scr_w, scr_h, hasbpp ? colorbits : 0, SDL_OPENGL|flags); if(screen) break; } if(!screen) fatal("Unable to create OpenGL screen"); else { if(!hasbpp) conoutf("%d bit color buffer not supported - disabling", colorbits); if(depthbits && (config&1)==0) conoutf("%d bit z-buffer not supported - disabling", depthbits); if(stencilbits && (config&2)==0) conoutf("%d bit stencil buffer not supported - disabling", stencilbits); if(fsaa>0 && (config&4)==0) conoutf("%dx anti-aliasing not supported - disabling", fsaa); } scr_w = screen->w; scr_h = screen->h; VIRTW = scr_w*VIRTH/scr_h; #ifdef WIN32 SDL_WM_GrabInput(SDL_GRAB_ON); #else SDL_WM_GrabInput(fullscreen ? SDL_GRAB_ON : SDL_GRAB_OFF); #endif usedcolorbits = hasbpp ? colorbits : 0; useddepthbits = config&1 ? depthbits : 0; usedfsaa = config&2 ? fsaa : 0; } extern int hirestextures; void resetgl() { clearchanges(CHANGE_GFX); loadingscreen(); extern void cleanupparticles(); extern void cleanupmodels(); extern void cleanuptextures(); extern void cleanuptmus(); extern void cleanupgl(); cleanupparticles(); cleanupmodels(); cleanuptextures(); cleanuptmus(); cleanupgl(); uniformtexres = !hirestextures; c2skeepalive(); SDL_SetVideoMode(0, 0, 0, 0); int usedcolorbits = 0, useddepthbits = 0, usedfsaa = 0; setupscreen(usedcolorbits, useddepthbits, usedfsaa); gl_init(scr_w, scr_h, usedcolorbits, useddepthbits, usedfsaa); extern void reloadfonts(); extern void reloadtextures(); c2skeepalive(); if(!reloadtexture(*notexture) || !reloadtexture("packages/misc/startscreen.png")) fatal("failed to reload core texture"); loadingscreen(); c2skeepalive(); restoregamma(); c2skeepalive(); reloadfonts(); reloadtextures(); c2skeepalive(); drawscope(true); // 2011feb05:ft: preload scope.png preload_playermodels(); c2skeepalive(); preload_hudguns(); c2skeepalive(); preload_entmodels(); c2skeepalive(); preload_mapmodels(); c2skeepalive(); } COMMAND(resetgl, ""); VARFP(maxfps, 0, 200, 1000, if(maxfps && maxfps < 25) maxfps = 25); void limitfps(int &millis, int curmillis) { if(!maxfps) return; static int fpserror = 0; int delay = 1000/maxfps - (millis-curmillis); if(delay < 0) fpserror = 0; else { fpserror += 1000%maxfps; if(fpserror >= maxfps) { ++delay; fpserror -= maxfps; } if(delay > 0) { SDL_Delay(delay); millis += delay; } } } int lowfps = 30, highfps = 40; void fpsrange(int *low, int *high) { if(*low>*high || *low<1) return; lowfps = *low; highfps = *high; } COMMAND(fpsrange, "ii"); void keyrepeat(bool on) { SDL_EnableKeyRepeat(on ? SDL_DEFAULT_REPEAT_DELAY : 0, SDL_DEFAULT_REPEAT_INTERVAL); } vector events; void pushevent(const SDL_Event &e) { events.add(e); } bool interceptkey(int sym) { static int lastintercept = SDLK_UNKNOWN; int len = lastintercept == sym ? events.length() : 0; SDL_Event event; while(SDL_PollEvent(&event)) switch(event.type) { case SDL_MOUSEMOTION: break; default: pushevent(event); break; } lastintercept = sym; if(sym != SDLK_UNKNOWN) for(int i = len; i < events.length(); i++) { if(events[i].type == SDL_KEYDOWN && events[i].key.keysym.sym == sym) { events.remove(i); return true; } } return false; } static void resetmousemotion() { #ifndef WIN32 if(!(screen->flags&SDL_FULLSCREEN)) { SDL_WarpMouse(screen->w / 2, screen->h / 2); } #endif } static inline bool skipmousemotion(SDL_Event &event) { if(event.type != SDL_MOUSEMOTION) return true; #ifndef WIN32 if(!(screen->flags&SDL_FULLSCREEN)) { #ifdef __APPLE__ if(event.motion.y == 0) return true; // let mac users drag windows via the title bar #endif if(event.motion.x == screen->w / 2 && event.motion.y == screen->h / 2) return true; // ignore any motion events generated SDL_WarpMouse } #endif return false; } static void checkmousemotion(int &dx, int &dy) { loopv(events) { SDL_Event &event = events[i]; if(skipmousemotion(event)) { if(i > 0) events.remove(0, i); return; } dx += event.motion.xrel; dy += event.motion.yrel; } events.setsize(0); SDL_Event event; while(SDL_PollEvent(&event)) { if(skipmousemotion(event)) { events.add(event); return; } dx += event.motion.xrel; dy += event.motion.yrel; } } static int ignoremouse = 5; void checkinput() { SDL_Event event; int lasttype = 0, lastbut = 0; int tdx=0,tdy=0; while(events.length() || SDL_PollEvent(&event)) { if(events.length()) event = events.remove(0); switch(event.type) { case SDL_QUIT: quit(); break; #if !defined(WIN32) && !defined(__APPLE__) case SDL_VIDEORESIZE: screenres(event.resize.w, event.resize.h); break; #endif case SDL_KEYDOWN: case SDL_KEYUP: extern bool senst; if (event.key.keysym.sym <= SDLK_5 && event.key.keysym.sym >= SDLK_1 && senst) { if (event.key.state==SDL_PRESSED) { extern int tsens(int x); tsens(event.key.keysym.sym); } } else { keypress(event.key.keysym.sym, event.key.state==SDL_PRESSED, event.key.keysym.unicode, event.key.keysym.mod); } break; case SDL_ACTIVEEVENT: if(event.active.state & SDL_APPINPUTFOCUS) inputgrab(grabinput = event.active.gain!=0); if(event.active.state & SDL_APPACTIVE) minimized = !event.active.gain; #if 0 if(event.active.state==SDL_APPMOUSEFOCUS) setprocesspriority(event.active.gain > 0); // switch priority on focus change #endif break; case SDL_MOUSEMOTION: if(ignoremouse) { ignoremouse--; break; } if(grabinput && !skipmousemotion(event)) { int dx = event.motion.xrel, dy = event.motion.yrel; checkmousemotion(dx, dy); resetmousemotion(); tdx+=dx;tdy+=dy; } break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: if(lasttype==event.type && lastbut==event.button.button) break; keypress(-event.button.button, event.button.state!=0, 0); lasttype = event.type; lastbut = event.button.button; break; } } mousemove(tdx, tdy); } VARF(gamespeed, 10, 100, 1000, if(multiplayer()) gamespeed = 100); VARF(paused, 0, 0, 1, if(multiplayer()) paused = 0); bool firstrun = false, inmainloop = false; static int clockrealbase = 0, clockvirtbase = 0; static void clockreset() { clockrealbase = SDL_GetTicks(); clockvirtbase = totalmillis; } VARFP(clockerror, 990000, 1000000, 1010000, clockreset()); VARFP(clockfix, 0, 0, 1, clockreset()); const char *rndmapname() { // "ac_depot_classic", static const char * const mapnames[] = { "ac_aqueous", "ac_arabian", "ac_arctic", "ac_arid", "ac_avenue", "ac_complex", "ac_depot", "ac_desert", "ac_desert2", "ac_desert3", "ac_douze", "ac_edifice", "ac_elevation", "ac_gothic", "ac_iceroad", "ac_industrial", "ac_ingress", "ac_keller", "ac_mines", "ac_outpost", "ac_power", "ac_rattrap", "ac_scaffold", "ac_shine", "ac_snow", "ac_stellar", "ac_sunset", "ac_toxic", "ac_urban", "ac_werk", }; int l = sizeof(mapnames)/sizeof(mapnames[0]); int n = rnd(l); return mapnames[n]; } extern void connectserv(char *, int *, char *); void connectprotocol(char *protocolstring, string &servername, int &serverport, string &password, bool &direct_connect) { const char *c = &protocolstring[14], *p = c; int len = 0; direct_connect = false; string sp; servername[0] = password[0] = '\0'; serverport = 0; while(*c && *c!='/' && *c!='?' && *c!=':') { len++; c++; } if(!len) { conoutf("\f3bad commandline syntax", protocolstring); return; } copystring(servername, p, min(len+1, MAXSTRLEN)); direct_connect = true; if(*c && *c==':') { c++; p = c; len = 0; while(*c && *c!='/' && *c!='?') { len++; c++; } if(len) { copystring(sp, p, min(len+1, MAXSTRLEN)); serverport = atoi(sp); } } if(*c && *c=='/') c++; if(!*c || *c!='?') return; do { if(*c) c++; if(!strncmp(c, "port=", 5)) { c += 5; p = c; len = 0; while(*c && *c!='&' && *c!='/') { len++; c++; } if(len) { copystring(sp, p, min(len+1, MAXSTRLEN)); serverport = atoi(sp); } } else if(!strncmp(c, "password=", 9)) { c += 9; p = c; len = 0; while(*c && *c!='&' && *c!='/') { len++, c++; } if(len) copystring(password, p, min(len+1, MAXSTRLEN)); } else break; } while(*c && *c=='&' && *c!='/'); } #ifdef WIN32 static char *parsecommandline(const char *src, vector &args) { char *buf = new char[strlen(src) + 1], *dst = buf; for(;;) { while(isspace(*src)) src++; if(!*src) break; args.add(dst); for(bool quoted = false; *src && (quoted || !isspace(*src)); src++) { if(*src != '"') *dst++ = *src; else if(dst > buf && src[-1] == '\\') dst[-1] = '"'; else quoted = !quoted; } *dst++ = '\0'; } args.add(NULL); return buf; } int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) { vector args; char *buf = parsecommandline(GetCommandLine(), args); SDL_SetModuleHandle(hInst); int status = SDL_main(args.length()-1, args.getbuf()); delete[] buf; exit(status); return 0; } #endif VARP(compatibilitymode, 0, 1, 1); // FIXME : find a better place to put this ? int main(int argc, char **argv) { extern struct servercommandline scl; #ifdef WIN32 //atexit((void (__cdecl *)(void))_CrtDumpMemoryLeaks); #ifndef _DEBUG #ifndef __GNUC__ __try { #endif #endif #endif bool dedicated = false; bool quitdirectly = false; char *initscript = NULL; char *initdemo = NULL; bool direct_connect = false; // to connect via assaultcube:// browser switch string servername, password; int serverport; const char *initmap = rndmapname(); pushscontext(IEXC_CFG); #define initlog(s) clientlogf("init: " s) initing = INIT_RESET; for(int i = 1; igetlil(); loopi(n) { string s; f->read(s, sizeof(string)); enet_uint32 c = f->getlil(); setresdata(s, c); } delete f; } initing = INIT_LOAD; if(!execfile("config/saved.cfg")) { exec("config/defaults.cfg"); firstrun = true; } if(identexists("afterinit")) execute("afterinit"); if(compatibilitymode) { persistidents = false; exec("config/compatibility.cfg"); // exec after saved.cfg to get "compatibilitymode", but before user scripts.. persistidents = true; } execfile("config/autoexec.cfg"); execfile("config/auth.cfg"); execute("addallfavcatmenus"); // exec here, to add all categories (including those defined in autoexec.cfg) initing = NOT_INITING; uniformtexres = !hirestextures; initlog("models"); preload_playermodels(); preload_hudguns(); preload_entmodels(); initlog("docs"); persistidents = false; execfile("config/docs.cfg"); persistidents = true; initlog("localconnect"); extern string clientmap; if(initdemo) { extern int gamemode; gamemode = -1; copystring(clientmap, initdemo); } else copystring(clientmap, initmap); // ac_complex for 1.0, ac_shine for 1.1, .. localconnect(); if(initscript) execute(initscript); initlog("mainloop"); inputgrab(grabinput = true); inmainloop = true; #ifdef _DEBUG int lastflush = 0; #endif for(;;) { static int frames = 0; static float fps = 10.0f; int millis = SDL_GetTicks() - clockrealbase; if(clockfix) millis = int(millis*(double(clockerror)/1000000)); millis += clockvirtbase; if(milliso.x, camera1->o.y, dynfov()); if(frames>3 && !minimized) { gl_drawframe(screen->w, screen->h, fpshighfps ? fps/highfps : 1.0f), fps); if(frames>4) SDL_GL_SwapBuffers(); } #ifdef _DEBUG if(millis>lastflush+60000) { fflush(stdout); lastflush = millis; } #endif if (direct_connect) { direct_connect = false; connectserv(servername, &serverport, password); } } quit(); return EXIT_SUCCESS; #if defined(WIN32) && !defined(_DEBUG) && !defined(__GNUC__) } __except(stackdumper(0, GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH) { return 0; } #endif } VAR(version, 1, AC_VERSION, 0);