/** * @brief Makes the player take off if landed. * * @param delay Whether or not to have time pass as if the player landed normally. */ void takeoff( int delay ) { int h; char *nt; double a, r; if (!landed) return; /* Player's ship is not able to fly. */ if (!player_canTakeoff()) { char message[512]; pilot_reportSpaceworthy( player.p, message, sizeof(message) ); dialogue_msg( _("Ship not fit for flight"), message ); /* Check whether the player needs rescuing. */ land_stranded(); return; } /* Clear queued takeoff. */ land_takeoff = 0; /* Refuel if needed. */ land_refuel(); /* In case we had paused messy sounds. */ sound_stopAll(); /* ze music */ music_choose("takeoff"); /* to randomize the takeoff a bit */ a = RNGF() * 2. * M_PI; r = RNGF() * land_planet->radius; /* no longer authorized to land */ player_rmFlag(PLAYER_LANDACK); pilot_rmFlag(player.p,PILOT_LANDING); /* No longer landing. */ /* set player to another position with random facing direction and no vel */ player_warp( land_planet->pos.x + r * cos(a), land_planet->pos.y + r * sin(a) ); vect_pset( &player.p->solid->vel, 0., 0. ); player.p->solid->dir = RNGF() * 2. * M_PI; cam_setTargetPilot( player.p->id, 0 ); /* heal the player */ pilot_healLanded( player.p ); /* Clear planet target. Allows for easier autonav out of the system. */ player_targetPlanetSet( -1 ); /* initialize the new space */ h = player.p->nav_hyperspace; space_init(NULL); player.p->nav_hyperspace = h; /* cleanup */ if (save_all() < 0) /* must be before cleaning up planet */ dialogue_alert( _("Failed to save game! You should exit and check the log to see what happened and then file a bug report!") ); /* time goes by, triggers hook before takeoff */ if (delay) ntime_inc( ntime_create( 0, 1, 0 ) ); /* 1 STP */ nt = ntime_pretty( 0, 2 ); player_message( _("\apTaking off from %s on %s."), land_planet->name, nt); free(nt); /* Hooks and stuff. */ land_cleanup(); /* Cleanup stuff */ hooks_run("takeoff"); /* Must be run after cleanup since we don't want the missions to think we are landed. */ if (menu_isOpen(MENU_MAIN)) return; player_addEscorts(); hooks_run("enter"); if (menu_isOpen(MENU_MAIN)) return; events_trigger( EVENT_TRIGGER_ENTER ); missions_run( MIS_AVAIL_SPACE, -1, NULL, NULL ); if (menu_isOpen(MENU_MAIN)) return; player.p->ptimer = PILOT_TAKEOFF_DELAY; pilot_setFlag( player.p, PILOT_TAKEOFF ); pilot_setThrust( player.p, 0. ); pilot_setTurn( player.p, 0. ); /* Reset speed */ player_autonavResetSpeed(); }
/** * @brief Opens the main menu (titlescreen). */ void menu_main (void) { int offset_logo, offset_wdw, freespace; unsigned int bwid, wid; glTexture *tex; /* Play load music. */ music_choose("load"); /* Load background and friends. */ tex = gl_newImage( "gfx/NAEV.png", 0 ); main_naevLogo = tex; nebu_prep( 300., 0. ); /* Needed for nebula to not spaz out */ /* Calculate Logo and window offset. */ freespace = SCREEN_H - tex->sh - MAIN_HEIGHT; if (freespace < 0) { /* Not enough freespace, this can get ugly. */ offset_logo = SCREEN_W - tex->sh; offset_wdw = 0; } else { /* We'll want a maximum seperation of 30 between logo and text. */ if (freespace/3 > 25) { freespace -= 25; offset_logo = -25; offset_wdw = -25 - tex->sh - 25; } /* Otherwise space evenly. */ else { offset_logo = -freespace/3; offset_wdw = freespace/3; } } /* create background image window */ bwid = window_create( "BG", -1, -1, SCREEN_W, SCREEN_H ); window_onClose( bwid, menu_main_cleanBG ); window_addRect( bwid, 0, 0, SCREEN_W, SCREEN_H, "rctBG", &cBlack, 0 ); window_addCust( bwid, 0, 0, SCREEN_W, SCREEN_H, "cstBG", 0, menu_main_nebu, NULL, &menu_main_lasttick ); window_addImage( bwid, (SCREEN_W-tex->sw)/2., offset_logo, "imgLogo", tex, 0 ); window_addText( bwid, 0., 10, SCREEN_W, 30., 1, "txtBG", NULL, &cWhite, naev_version(1) ); /* create menu window */ wid = window_create( "Main Menu", -1, offset_wdw, MAIN_WIDTH, MAIN_HEIGHT ); window_setCancel( wid, main_menu_promptClose ); /* Buttons. */ window_addButton( wid, 20, 20 + (BUTTON_HEIGHT+20)*4, BUTTON_WIDTH, BUTTON_HEIGHT, "btnLoad", "Load Game", menu_main_load ); window_addButton( wid, 20, 20 + (BUTTON_HEIGHT+20)*3, BUTTON_WIDTH, BUTTON_HEIGHT, "btnNew", "New Game", menu_main_new ); window_addButton( wid, 20, 20 + (BUTTON_HEIGHT+20)*2, BUTTON_WIDTH, BUTTON_HEIGHT, "btnOptions", "Options", menu_options_button ); window_addButton( wid, 20, 20 + (BUTTON_HEIGHT+20), BUTTON_WIDTH, BUTTON_HEIGHT, "btnCredits", "Credits", menu_main_credits ); window_addButton( wid, 20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnExit", "Exit", menu_exit ); /* Disable load button if there are no saves. */ if (!save_hasSave()) window_disableButton( wid, "btnLoad" ); /* Make the background window a parent of the menu. */ window_setParent( bwid, wid ); /* Reset timer. */ menu_main_lasttick = SDL_GetTicks(); menu_Open(MENU_MAIN); }
/** * @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 */ gl_fontInit( &gl_defFontMono, "dat/mono.ttf", conf.font_size_def ); /* 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 {
/** * @brief Displays the introduction sequence. * * @brief text Path of text file to use. * @brief mus Type of music to use (run through music.lua). * @return 0 on success. */ int intro_display( const char *text, const char *mus ) { double offset; /* distance from bottom of the top line. */ double line_height; /* # pixels per line. */ int lines_per_screen; /* max appearing lines on the screen. */ scroll_buf_t *sb_arr; /* array of lines to render. */ scroll_buf_t *sb_list; /* list " " " " */ double vel = 16.; /* velocity: speed of text. */ int stop = 0; /* stop the intro. */ unsigned int tcur, tlast; /* timers. */ double delta; /* time diff from last render to this one. */ int line_index = 0; /* index into the big list of intro lines. */ intro_img_t side_image; /* image to go along with the text. */ intro_img_t transition; /* image for transitioning. */ /* Load the introduction. */ if (intro_load(text) < 0) return -1; /* Change music to intro music. */ if (mus != NULL) music_choose(mus); /* We need to clear key repeat to avoid infinite loops. */ toolkit_clearKey(); /* Enable keyrepeat just for the intro. */ #if !SDL_VERSION_ATLEAST(2,0,0) SDL_EnableKeyRepeat( conf.repeat_delay, conf.repeat_freq ); #endif /* !SDL_VERSION_ATLEAST(2,0,0) */ /* Do a few calculations to figure out how many lines can be present on the screen at any given time. */ line_height = (double)intro_font.h * 1.3; lines_per_screen = (int)(SCREEN_H / line_height + 1.5); /* round up + 1 */ sb_arr = (scroll_buf_t*)malloc( sizeof(scroll_buf_t) * lines_per_screen ); /* Force the first line to be loaded immediately. */ offset = line_height; /* Create a cycle of lines. */ sb_list = arrange_scroll_buf( sb_arr, lines_per_screen ); /* Unset the side image. */ initialize_image( &side_image ); initialize_image( &transition ); tlast = SDL_GetTicks(); while (!stop) { tcur = SDL_GetTicks(); delta = (double)(tcur - tlast) / 1000.; tlast = tcur; /* Increment position. */ offset += vel * delta; while (! (offset < line_height)) { /* One line has scrolled off, and another one on. */ if (line_index < intro_nlines) { switch (intro_lines[line_index][0]) { case 't': /* plain ol' text. */ sb_list->text = &intro_lines[line_index][1]; offset -= line_height; sb_list = sb_list->next; break; case 'i': /* fade in image. */ intro_fade_image_in( &side_image, &transition, &intro_lines[line_index][1] ); break; case 'o': /* fade out image. */ if (NULL == side_image.tex) { WARN(_("Tried to fade out without an image.") ); break; } side_image.fade_rate = -0.1; side_image.c.a = 0.99; break; default: /* unknown. */ break; } ++line_index; } else { sb_list->text = NULL; offset -= line_height; sb_list = sb_list->next; } } /* while (offset > line_height) */ /* Fade the side image. */ if (side_image.tex != NULL && side_image.c.a < 1.0) { side_image.c.a += delta * vel * side_image.fade_rate; if (transition.tex != NULL && transition.fade_rate > 0.0) transition.c.a += delta * vel * transition.fade_rate; if (side_image.c.a > 1.0) { /* Faded in... */ side_image.c.a = 1.0; side_image.fade_rate = 0.0; } else if (side_image.c.a < 0.0) { /* Faded out... */ gl_freeTexture( side_image.tex ); if (transition.tex != NULL) { side_image.tex = transition.tex; side_image.c.a = transition.c.a; side_image.y = transition.y; side_image.fade_rate = 0.1; transition.tex = NULL; transition.c.a = 1.0; } else { side_image.c.a = 1.0; side_image.tex = NULL; side_image.fade_rate = 0.0; } } } /* Clear stuff. */ glClear(GL_COLOR_BUFFER_BIT); /* Only thing we actually care about updating is music. */ music_update( 0. ); /* Draw text. */ stop = intro_draw_text( sb_list, offset, line_height ); if (NULL != side_image.tex) /* Draw the image next to the text. */ gl_blitScale( side_image.tex, side_image.x, side_image.y, side_image.tex->w, side_image.tex->h, &side_image.c ); if (NULL != transition.tex && transition.c.a > 0.0) /* Draw the image in transition. */ gl_blitScale( transition.tex, transition.x, transition.y, transition.tex->w, transition.tex->h, &transition.c ); /* Display stuff. */ #if SDL_VERSION_ATLEAST(2,0,0) SDL_GL_SwapWindow( gl_screen.window ); #else /* SDL_VERSION_ATLEAST(2,0,0) */ SDL_GL_SwapBuffers(); #endif /* SDL_VERSION_ATLEAST(2,0,0) */ SDL_Delay(10); /* No need to burn CPU. */ /* Handle user events. */ intro_event_handler( &stop, &offset, &vel ); } /* while (!stop) */ /* free malloc'd memory. */ free( sb_arr ); if (NULL != side_image.tex) gl_freeTexture( side_image.tex ); if (NULL != transition.tex) gl_freeTexture( transition.tex ); /* Disable intro's key repeat. */ #if !SDL_VERSION_ATLEAST(2,0,0) SDL_EnableKeyRepeat( 0, 0 ); #endif /* !SDL_VERSION_ATLEAST(2,0,0) */ /* Stop music, normal music will start shortly after. */ music_stop(); /* Clean up after the introduction. */ intro_cleanup(); return 0; }