/** * @brief Player death menu, appears when player got creamed. */ void menu_death (void) { unsigned int wid; wid = window_create( "Death", -1, -1, DEATH_WIDTH, DEATH_HEIGHT ); /* Propose the player to continue if the samegame exist, if not, propose to restart */ char path[PATH_MAX]; snprintf(path, PATH_MAX, "%ssaves/%s.ns", nfile_basePath(), player_name); if (nfile_fileExists(path)) window_addButton( wid, 20, 20 + BUTTON_HEIGHT*2 + 20*2, BUTTON_WIDTH, BUTTON_HEIGHT, "btnContinue", "Continue", menu_death_continue ); else window_addButton( wid, 20, 20 + BUTTON_HEIGHT*2 + 20*2, BUTTON_WIDTH, BUTTON_HEIGHT, "btnRestart", "Restart", menu_death_restart ); window_addButton( wid, 20, 20 + (BUTTON_HEIGHT+20), BUTTON_WIDTH, BUTTON_HEIGHT, "btnMain", "Main Menu", menu_death_main ); window_addButton( wid, 20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnExit", "Exit Game", menu_exit ); menu_Open(MENU_DEATH); /* Makes it all look cooler since everything still goes on. */ unpause_game(); }
/** * @brief Checks the validity of a nebula. * * @param file Path of the nebula to check (relative to base directory). * @return 0 on success. */ static int nebu_checkCompat( const char* file ) { /* first check to see if file exists */ if (nfile_fileExists("%s"NEBULA_PATH"%s", nfile_cachePath(), file) == 0) return -1; return 0; }
/** * @brief Backup a file, if it exists. * * @param path printf formatted string pointing to the file to backup. * @return 0 on success, or if file does not exist, -1 on error. */ int nfile_backupIfExists( const char* path, ... ) { char file[PATH_MAX]; va_list ap; char backup[PATH_MAX]; FILE *f_in, *f_out; char buf[ 8*1024 ]; size_t lr, lw; if (path == NULL) return -1; va_start(ap, path); vsnprintf(file, PATH_MAX, path, ap); va_end(ap); if (!nfile_fileExists(file)) return 0; nsnprintf(backup, PATH_MAX, "%s.backup", file); /* Open files. */ f_in = fopen( file, "rb" ); f_out = fopen( backup, "wb" ); if ((f_in==NULL) || (f_out==NULL)) { WARN( "Failure to create back up of '%s': %s", file, strerror(errno) ); if (f_in!=NULL) fclose(f_in); return -1; } /* Copy data over. */ do { lr = fread( buf, 1, sizeof(buf), f_in ); if (ferror(f_in)) goto err; else if (!lr) { if (feof(f_in)) break; goto err; } lw = fwrite( buf, 1, lr, f_out ); if (ferror(f_out) || (lr != lw)) goto err; } while (lr > 0); /* Close files. */ fclose( f_in ); fclose( f_out ); return 0; err: WARN( "Failure to create back up of '%s': %s", file, strerror(errno) ); fclose( f_in ); fclose( f_out ); return -1; }
/** * @brief Player death menu, appears when player got creamed. */ void menu_death (void) { unsigned int wid; char path[PATH_MAX]; wid = window_create( "Death", -1, -1, DEATH_WIDTH, DEATH_HEIGHT ); window_onClose( wid, menu_death_close ); /* Allow the player to continue if the savegame exists, if not, propose to restart */ nsnprintf(path, PATH_MAX, "%ssaves/%s.ns", nfile_dataPath(), player.name); if (!player_isTut() && nfile_fileExists(path)) window_addButtonKey( wid, 20, 20 + BUTTON_HEIGHT*2 + 20*2, BUTTON_WIDTH, BUTTON_HEIGHT, "btnContinue", _("Continue"), menu_death_continue, SDLK_c ); else window_addButtonKey( wid, 20, 20 + BUTTON_HEIGHT*2 + 20*2, BUTTON_WIDTH, BUTTON_HEIGHT, "btnRestart", _("Restart"), menu_death_restart, SDLK_r ); window_addButtonKey( wid, 20, 20 + (BUTTON_HEIGHT+20), BUTTON_WIDTH, BUTTON_HEIGHT, "btnMain", _("Main Menu"), menu_death_main, SDLK_m ); window_addButtonKey( wid, 20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnExit", _("Exit Game"), menu_exit, SDLK_x ); menu_Open(MENU_DEATH); /* Makes it all look cooler since everything still goes on. */ unpause_game(); }
/** * @brief Actually loads a new game based on file. * * @param file File that contains the new game. * @return 0 on success. */ static int load_game( const char* file ) { xmlNodePtr node; xmlDocPtr doc; /* Make sure it exists. */ if (!nfile_fileExists(file)) { dialogue_alert("Savegame file seems to have been deleted."); return -1; } /* Load the XML. */ doc = xmlParseFile(file); if (doc == NULL) goto err; node = doc->xmlChildrenNode; /* base node */ if (node == NULL) goto err_doc; /* Clean up possible stuff that should be cleaned. */ player_cleanup(); diff_clear(); var_cleanup(); missions_cleanup(); events_cleanup(); /* Welcome message - must be before space_init. */ player_message( "\egWelcome to "APPNAME"!" ); player_message( "\eg v%d.%d.%d", VMAJOR, VMINOR, VREV ); /* Now begin to load. */ diff_load(node); /* Must load first to work properly. */ pfaction_load(node); /* Must be loaded before player so the messages show up properly. */ player_load(node); var_load(node); missions_loadActive(node); hook_load(node); space_sysLoad(node); /* Initialize the economy. */ economy_init(); /* Need to run takeoff hooks since player just "took off" */ hooks_run("takeoff"); player_addEscorts(); hooks_run("enter"); events_trigger( EVENT_TRIGGER_ENTER ); xmlFreeDoc(doc); xmlCleanupParser(); return 0; err_doc: xmlFreeDoc(doc); xmlCleanupParser(); err: WARN("Savegame '%s' invalid!", file); return -1; }
/** * @brief Would be like "dofile" from the base Lua lib. */ static int cli_script( lua_State *L ) { const char *fname; char buf[PATH_MAX], *bbuf; int n; /* Handle parameters. */ fname = luaL_optstring(L, 1, NULL); n = lua_gettop(L); /* Try to find the file if it exists. */ if (nfile_fileExists(fname)) snprintf( buf, sizeof(buf), "%s", fname ); else { bbuf = strdup( naev_binary() ); snprintf( buf, sizeof(buf), "%s/%s", nfile_dirname( bbuf ), fname ); free(bbuf); } /* Do the file. */ if (luaL_loadfile(L, buf) != 0) lua_error(L); /* Return the stuff. */ lua_call(L, 0, LUA_MULTRET); return lua_gettop(L) - n; }
/** * @brief Renames a file. * * @param oldname Old name of the file. * @param newname New name to set the file to. * @return 0 on success. */ int nfile_rename( const char* oldname, const char* newname ) { if (!nfile_fileExists(oldname)) { WARN("Can not rename non existant file %s",oldname); return -1; } if (newname == NULL) { WARN("Can not rename to NULL file name"); return -1; } if (nfile_fileExists( newname )) { WARN("Error renaming %s to %s. %s already exists",oldname,newname,newname); return -1; } if (rename(oldname,newname)) WARN("Error renaming %s to %s",oldname,newname); return 0; }
/** * @brief Wrapper for gl_loadImagePad that includes transparency mapping. * * @param name Name to load with. * @param surface Surface to load. * @param rw RWops containing data to hash. * @param flags Flags to use. * @param w Non-padded width. * @param h Non-padded height. * @param sx X sprites. * @param sy Y sprites. * @param freesur Whether or not to free the surface. * @return The glTexture for surface. */ glTexture* gl_loadImagePadTrans( const char *name, SDL_Surface* surface, SDL_RWops *rw, unsigned int flags, int w, int h, int sx, int sy, int freesur ) { glTexture *texture; int i, filesize; size_t cachesize, pngsize; uint8_t *trans; char *cachefile, *data; char digest[33]; md5_state_t md5; md5_byte_t *md5val; if (name != NULL) { texture = gl_texExists( name ); if (texture != NULL) return texture; } if (flags & OPENGL_TEX_MAPTRANS) flags ^= OPENGL_TEX_MAPTRANS; /* Appropriate size for the transparency map, see SDL_MapTrans */ cachesize = gl_transSize(w, h); cachefile = NULL; trans = NULL; if (rw != NULL) { md5val = malloc(16); md5_init(&md5); pngsize = SDL_RWseek( rw, 0, SEEK_END ); SDL_RWseek( rw, 0, SEEK_SET ); data = malloc(pngsize); if (data == NULL) WARN("Out of memory!"); else { SDL_RWread( rw, data, pngsize, 1 ); md5_append( &md5, (md5_byte_t*)data, pngsize ); free(data); } md5_finish( &md5, md5val ); for (i=0; i<16; i++) nsnprintf( &digest[i * 2], 3, "%02x", md5val[i] ); free(md5val); cachefile = malloc( PATH_MAX ); nsnprintf( cachefile, PATH_MAX, "%scollisions/%s", nfile_cachePath(), digest ); /* Attempt to find a cached transparency map. */ if (nfile_fileExists(cachefile)) { trans = (uint8_t*)nfile_readFile( &filesize, cachefile ); /* Consider cached data invalid if the length doesn't match. */ if (trans != NULL && cachesize != (unsigned int)filesize) { free(trans); trans = NULL; } /* Cached data matches, no need to overwrite. */ else { free(cachefile); cachefile = NULL; } } } else { /* We could hash raw pixel data here, but that's slower than just * generating the map from scratch. */ WARN("Texture '%s' has no RWops", name); } if (trans == NULL) { SDL_LockSurface(surface); trans = SDL_MapTrans( surface, w, h ); SDL_UnlockSurface(surface); if (cachefile != NULL) { /* Cache newly-generated transparency map. */ nfile_dirMakeExist( "%s/collisions/", nfile_cachePath() ); nfile_writeFile( (char*)trans, cachesize, cachefile ); free(cachefile); } } texture = gl_loadImagePad( name, surface, flags, w, h, sx, sy, freesur ); texture->trans = trans; return texture; }
/** * @brief The entry point of Naev. * * @param[in] argc Number of arguments. * @param[in] argv Array of argc arguments. * @return EXIT_SUCCESS on success. */ int main( int argc, char** argv ) { char buf[PATH_MAX]; /* Save the binary path. */ binary_path = strdup(argv[0]); /* Print the version */ LOG( " "APPNAME" v%s", naev_version(0) ); #ifdef GIT_COMMIT DEBUG( " git HEAD at " GIT_COMMIT ); #endif /* GIT_COMMIT */ /* Initializes SDL for possible warnings. */ SDL_Init(0); /* Initialize the threadpool */ threadpool_init(); /* Set up debug signal handlers. */ debug_sigInit(); /* Must be initialized before input_init is called. */ if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { WARN("Unable to initialize SDL Video: %s", SDL_GetError()); return -1; } /* Get desktop dimensions. */ #if SDL_VERSION_ATLEAST(1,2,10) const SDL_VideoInfo *vidinfo = SDL_GetVideoInfo(); gl_screen.desktop_w = vidinfo->current_w; gl_screen.desktop_h = vidinfo->current_h; #else /* #elif SDL_VERSION_ATLEAST(1,2,10) */ gl_screen.desktop_w = 0; gl_screen.desktop_h = 0; #endif /* #elif SDL_VERSION_ATLEAST(1,2,10) */ /* We'll be parsing XML. */ LIBXML_TEST_VERSION xmlInitParser(); /* Input must be initialized for config to work. */ input_init(); conf_setDefaults(); /* set the default config values */ /* * Attempts to load the data path from datapath.lua * At this early point in the load process, the binary path * is the only place likely to be checked. */ conf_loadConfigPath(); /* Parse the user data path override first. */ conf_parseCLIPath( argc, argv ); /* Create the home directory if needed. */ if (nfile_dirMakeExist("%s", nfile_configPath())) WARN("Unable to create config directory '%s'", nfile_configPath()); /* Set the configuration. */ nsnprintf(buf, PATH_MAX, "%s"CONF_FILE, nfile_configPath()); #if HAS_UNIX /* TODO get rid of this cruft ASAP. */ int oldconfig = 0; if (!nfile_fileExists( buf )) { char *home, buf2[PATH_MAX]; home = SDL_getenv( "HOME" ); if (home != NULL) { nsnprintf( buf2, PATH_MAX, "%s/.naev/"CONF_FILE, home ); if (nfile_fileExists( buf2 )) oldconfig = 1; } } #endif /* HAS_UNIX */ conf_loadConfig(buf); /* Lua to parse the configuration file */ conf_parseCLI( argc, argv ); /* parse CLI arguments */ /* Enable FPU exceptions. */ #if defined(HAVE_FEENABLEEXCEPT) && defined(DEBUGGING) if (conf.fpu_except) feenableexcept( FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW ); #endif /* defined(HAVE_FEENABLEEXCEPT) && defined(DEBUGGING) */ /* Open data. */ if (ndata_open() != 0) ERR("Failed to open ndata."); /* Load the start info. */ if (start_load()) ERR("Failed to load module start data."); /* Load the data basics. */ LOG(" %s", ndata_name()); DEBUG(); /* Display the SDL Version. */ print_SDLversion(); DEBUG(); /* random numbers */ rng_init(); /* * OpenGL */ if (gl_init()) { /* initializes video output */ ERR("Initializing video output failed, exiting..."); SDL_Quit(); exit(EXIT_FAILURE); } window_caption(); gl_fontInit( NULL, NULL, conf.font_size_def ); /* initializes default font to size */ gl_fontInit( &gl_smallFont, NULL, conf.font_size_small ); /* small font */ /* Display the load screen. */ loadscreen_load(); loadscreen_render( 0., "Initializing subsystems..." ); time_ms = SDL_GetTicks(); /* * Input */ if ((conf.joystick_ind >= 0) || (conf.joystick_nam != NULL)) { if (joystick_init()) WARN("Error initializing joystick input"); if (conf.joystick_nam != NULL) { /* use the joystick name to find a joystick */ if (joystick_use(joystick_get(conf.joystick_nam))) { WARN("Failure to open any joystick, falling back to default keybinds"); input_setDefault(); } free(conf.joystick_nam); } else if (conf.joystick_ind >= 0) /* use a joystick id instead */ if (joystick_use(conf.joystick_ind)) { WARN("Failure to open any joystick, falling back to default keybinds"); input_setDefault(); } } /* * OpenAL - Sound */ if (conf.nosound) { LOG("Sound is disabled!"); sound_disabled = 1; music_disabled = 1; } if (sound_init()) WARN("Problem setting up sound!"); music_choose("load"); /* FPS stuff. */ fps_setPos( 15., (double)(gl_screen.h-15-gl_defFont.h) ); /* Misc graphics init */ if (nebu_init() != 0) { /* Initializes the nebula */ /* An error has happened */ ERR("Unable to initialize the Nebula subsystem!"); /* Weirdness will occur... */ } gui_init(); /* initializes the GUI graphics */ toolkit_init(); /* initializes the toolkit */ map_init(); /* initializes the map. */ cond_init(); /* Initialize conditional subsystem. */ cli_init(); /* Initialize console. */ /* Data loading */ load_all(); /* Generate the CSV. */ if (conf.devcsv) dev_csv(); /* Unload load screen. */ loadscreen_unload(); /* Start menu. */ menu_main(); /* Force a minimum delay with loading screen */ if ((SDL_GetTicks() - time_ms) < NAEV_INIT_DELAY) SDL_Delay( NAEV_INIT_DELAY - (SDL_GetTicks() - time_ms) ); fps_init(); /* initializes the time_ms */ #if HAS_UNIX /* Tell the player to migrate their configuration files out of ~/.naev */ /* TODO get rid of this cruft ASAP. */ if ((oldconfig) && (!conf.datapath)) { char path[PATH_MAX], *script, *home; uint32_t scriptsize; int ret; nsnprintf( path, PATH_MAX, "%s/naev-confupdate.sh", ndata_getDirname() ); home = SDL_getenv("HOME"); ret = dialogue_YesNo( "Warning", "Your configuration files are in a deprecated location and must be migrated:\n" " \er%s/.naev/\e0\n\n" "The update script can likely be found in your Naev data directory:\n" " \er%s\e0\n\n" "Would you like to run it automatically?", home, path ); /* Try to run the script. */ if (ret) { ret = -1; /* Running from ndata. */ if (ndata_getPath() != NULL) { script = ndata_read( "naev-confupdate.sh", &scriptsize ); if (script != NULL) ret = system(script); } /* Running from laid-out files or ndata_read failed. */ if ((nfile_fileExists(path)) && (ret == -1)) { script = nfile_readFile( (int*)&scriptsize, path ); if (script != NULL) ret = system(script); } /* We couldn't find the script. */ if (ret == -1) { dialogue_alert( "The update script was not found at:\n\er%s\e0\n\n" "Please locate and run it manually.", path ); } /* Restart, as the script succeeded. */ else if (!ret) { dialogue_msg( "Update Completed", "Configuration files were successfully migrated. Naev will now restart." ); execv(argv[0], argv); } else { /* I sincerely hope this else is never hit. */ dialogue_alert( "The update script encountered an error. Please exit Naev and move your config and save files manually:\n\n" "\er%s/%s\e0 =>\n \eD%s\e0\n\n" "\er%s/%s\e0 =>\n \eD%s\e0\n\n" "\er%s/%s\e0 =>\n \eD%snebula/\e0\n\n", home, ".naev/conf.lua", nfile_configPath(), home, ".naev/{saves,screenshots}/", nfile_dataPath(), home, ".naev/gen/*.png", nfile_cachePath() ); } } else {