/** * @brief Opens the small ingame menu. */ void menu_small (void) { unsigned int wid; /* Check if menu should be openable. */ if ((player == NULL) || player_isFlag(PLAYER_DESTROYED) || pilot_isFlag(player,PILOT_DEAD) || comm_isOpen() || dialogue_isOpen() || /* Shouldn't open over dialogues. */ (menu_isOpen(MENU_MAIN) || menu_isOpen(MENU_SMALL) || menu_isOpen(MENU_DEATH) )) return; wid = window_create( "Menu", -1, -1, MENU_WIDTH, MENU_HEIGHT ); window_setCancel( wid, menu_small_close ); window_addButton( wid, 20, 20 + BUTTON_HEIGHT*2 + 20*2, BUTTON_WIDTH, BUTTON_HEIGHT, "btnResume", "Resume", menu_small_close ); window_addButton( wid, 20, 20 + BUTTON_HEIGHT + 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnOptions", "Options", menu_options_button ); window_addButton( wid, 20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnExit", "Exit", menu_small_exit ); menu_Open(MENU_SMALL); }
/** * @brief Handles input to the map overlay. */ int ovr_input( SDL_Event *event ) { int mx, my; double x, y; /* We only want mouse events. */ if (event->type != SDL_MOUSEBUTTONDOWN) return 0; /* Player must not be NULL. */ if (player_isFlag(PLAYER_DESTROYED) || (player.p == NULL)) return 0; /* Player must not be dead. */ if (pilot_isFlag(player.p, PILOT_DEAD)) return 0; /* Mouse targeting only uses left and right buttons. */ if (event->button.button != SDL_BUTTON_LEFT && event->button.button != SDL_BUTTON_RIGHT) return 0; /* Translate from window to screen. */ mx = event->button.x; my = event->button.y; gl_windowToScreenPos( &mx, &my, mx, my ); /* Translate to space coords. */ x = ((double)mx - SCREEN_W/2.) * ovr_res; y = ((double)my - SCREEN_H/2.) * ovr_res; return input_clickPos( event, x, y, 1., 10. * ovr_res, 15. * ovr_res ); }
/** * @brief Aborts autonav. * * @param reason Human-readable string describing abort condition. */ void player_autonavAbort( const char *reason ) { /* No point if player is beyond aborting. */ if ((player.p==NULL) || pilot_isFlag(player.p, PILOT_HYPERSPACE)) return; /* Cooldown (handled later) may be script-initiated and we don't * want to make it player-abortable while under manual control. */ if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL )) return; if (player_isFlag(PLAYER_AUTONAV)) { if (reason != NULL) player_message(_("\arAutonav aborted: %s!"), reason); else player_message(_("\arAutonav aborted!")); player_rmFlag(PLAYER_AUTONAV); /* Get rid of acceleration. */ player_accelOver(); /* Break possible hyperspacing. */ if (pilot_isFlag(player.p, PILOT_HYP_PREP)) { pilot_hyperspaceAbort(player.p); player_message(_("\apAborting hyperspace sequence.")); } /* Reset time compression. */ player_autonavEnd(); } }
/** * @brief Puts the game in cinematics mode or back to regular mode. * * Possible options are:<br/> * <ul> * <li>abort : (string) autonav abort message * <li>no2x : (boolean) whether to prevent the player from engaging double-speed, default false * <li>gui : (boolean) enables the player's gui, default disabled * </ul> * * @usage player.cinematics( true, { gui = true } ) -- Enables cinematics without hiding gui. * * @luaparam enable If true sets cinematics mode, if false disables. Defaults to disable. * @luaparam options Table of options. * @luafunc cinematics( enable, options ) */ static int playerL_cinematics( lua_State *L ) { int b; const char *abort_msg; int f_gui, f_2x; /* Defaults. */ abort_msg = NULL; f_gui = 0; f_2x = 0; /* Parse parameters. */ b = lua_toboolean( L, 1 ); if (lua_gettop(L) > 1) { if (!lua_istable(L,2)) { NLUA_ERROR( L, "Second parameter to cinematics should be a table of options or omitted!" ); return 0; } lua_getfield( L, 2, "abort" ); if (!lua_isnil( L, -1 )) abort_msg = luaL_checkstring( L, -1 ); lua_pop( L, 1 ); lua_getfield( L, 2, "gui" ); f_gui = lua_toboolean(L, -1); lua_pop( L, 1 ); lua_getfield( L, 2, "no2x" ); f_2x = lua_toboolean(L, -1); lua_pop( L, 1 ); } /* Remove doublespeed. */ if (player_isFlag( PLAYER_DOUBLESPEED )) { player_rmFlag( PLAYER_DOUBLESPEED ); pause_setSpeed(1.); } if (b) { /* Do stuff. */ player_autonavAbort( abort_msg ); player_rmFlag( PLAYER_DOUBLESPEED ); ovr_setOpen(0); pause_setSpeed(1.); if (!f_gui) player_setFlag( PLAYER_CINEMATICS_GUI ); if (f_2x) player_setFlag( PLAYER_CINEMATICS_2X ); } else { player_rmFlag( PLAYER_CINEMATICS_GUI ); player_rmFlag( PLAYER_CINEMATICS_2X ); } return 0; }
/** * @brief Resets the game speed. */ void player_autonavResetSpeed (void) { if (player_isFlag(PLAYER_DOUBLESPEED)) { tc_mod = 2.; pause_setSpeed( 2. ); } else { tc_mod = 1.; pause_setSpeed( 1. ); } tc_rampdown = 0; }
/** * @brief Prepares the player to enter autonav. * * @return 1 on success, 0 on failure (disabled, etc.) */ static int player_autonavSetup (void) { /* Not under manual control or disabled. */ if (pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ) || pilot_isDisabled(player.p)) return 0; /* Autonav is mutually-exclusive with other autopilot methods. */ player_restoreControl( PINPUT_AUTONAV, NULL ); player_message(_("\apAutonav initialized.")); if (!player_isFlag(PLAYER_AUTONAV)) { tc_base = player_isFlag(PLAYER_DOUBLESPEED) ? 2. : 1.; tc_mod = tc_base; if (conf.compression_mult >= 1.) player.tc_max = MIN( conf.compression_velocity / solid_maxspeed(player.p->solid, player.p->speed, player.p->thrust), conf.compression_mult ); else player.tc_max = conf.compression_velocity / solid_maxspeed(player.p->solid, player.p->speed, player.p->thrust); /* Safe cap. */ player.tc_max = MAX( 1., player.tc_max ); } /* Sane values. */ tc_rampdown = 0; tc_down = 0.; lasts = player.p->shield / player.p->shield_max; lasta = player.p->armour / player.p->armour_max; /* Set flag and tc_mod just in case. */ player_setFlag(PLAYER_AUTONAV); pause_setSpeed( tc_mod ); /* Make sure time acceleration starts immediately. */ player.autonav_timer = 0.; return 1; }
/** * @brief Aborts regular interstellar autonav, but not in-system autonav. * * @param reason Human-readable string describing abort condition. */ void player_autonavAbortJump( const char *reason ) { /* No point if player is beyond aborting. */ if ((player.p==NULL) || pilot_isFlag(player.p, PILOT_HYPERSPACE)) return; if (!player_isFlag(PLAYER_AUTONAV) || ((player.autonav != AUTONAV_JUMP_APPROACH) && (player.autonav != AUTONAV_JUMP_BRAKE))) return; /* It's definitely not in-system autonav. */ player_autonavAbort(reason); }
/** * @brief Checks whether the speed should be reset due to damage or missile locks. * * @return 1 if the speed should be reset. */ int player_autonavShouldResetSpeed (void) { double failpc, shield, armour; int i, n; Pilot **pstk; int hostiles, will_reset; if (!player_isFlag(PLAYER_AUTONAV)) return 0; hostiles = 0; will_reset = 0; failpc = conf.autonav_reset_speed; shield = player.p->shield / player.p->shield_max; armour = player.p->armour / player.p->armour_max; pstk = pilot_getAll( &n ); for (i=0; i<n; i++) { if ((pstk[i]->id != PLAYER_ID) && pilot_isHostile( pstk[i] ) && pilot_inRangePilot( player.p, pstk[i] ) && !pilot_isDisabled( pstk[i] ) && !pilot_isFlag( pstk[i], PILOT_BRIBED )) { hostiles = 1; break; } } if (hostiles) { if (failpc > .995) { will_reset = 1; player.autonav_timer = MAX( player.autonav_timer, 0. ); } else if ((shield < lasts && shield < failpc) || armour < lasta) { will_reset = 1; player.autonav_timer = MAX( player.autonav_timer, 2. ); } } lasts = shield; lasta = armour; if (will_reset || (player.autonav_timer > 0)) { player_autonavResetSpeed(); return 1; } return 0; }
/** * @brief Renders the starry background. * * @param dt Current delta tick. */ void background_renderStars( const double dt ) { (void) dt; unsigned int i; GLfloat hh, hw, h, w; GLfloat x, y, m, b; GLfloat brightness; double z; double sx, sy; int shade_mode; int j, n; /* * gprof claims it's the slowest thing in the game! */ /* Do some scaling for now. */ z = cam_getZoom(); z = 1. * (1. - conf.zoom_stars) + z * conf.zoom_stars; gl_matrixPush(); gl_matrixTranslate( SCREEN_W/2., SCREEN_H/2. ); gl_matrixScale( z, z ); if (!paused && (player.p != NULL) && !player_isFlag(PLAYER_DESTROYED) && !player_isFlag(PLAYER_CREATING)) { /* update position */ /* Calculate some dimensions. */ w = (SCREEN_W + 2.*STAR_BUF); w += conf.zoom_stars * (w / conf.zoom_far - 1.); h = (SCREEN_H + 2.*STAR_BUF); h += conf.zoom_stars * (h / conf.zoom_far - 1.); hw = w/2.; hh = h/2.; if ((star_x > SCREEN_W) || (star_y > SCREEN_H)) { sx = ceil( star_x / SCREEN_W ); sy = ceil( star_y / SCREEN_H ); n = MAX( sx, sy ); star_x /= (double)n; star_y /= (double)n; } else n = 1; /* Calculate new star positions. */ for (j=0; j < n; j++) { for (i=0; i < nstars; i++) { /* calculate new position */ b = 1./(9. - 10.*star_colour[8*i+3]); star_vertex[4*i+0] = star_vertex[4*i+0] + star_x*b; star_vertex[4*i+1] = star_vertex[4*i+1] + star_y*b; /* check boundaries */ if (star_vertex[4*i+0] > hw) star_vertex[4*i+0] -= w; else if (star_vertex[4*i+0] < -hw) star_vertex[4*i+0] += w; if (star_vertex[4*i+1] > hh) star_vertex[4*i+1] -= h; else if (star_vertex[4*i+1] < -hh) star_vertex[4*i+1] += h; } } /* Upload the data. */ gl_vboSubData( star_vertexVBO, 0, nstars * 4 * sizeof(GLfloat), star_vertex ); } /* Decide on shade mode. */ shade_mode = 0; if ((player.p != NULL) && !player_isFlag(PLAYER_DESTROYED) && !player_isFlag(PLAYER_CREATING)) { if (pilot_isFlag(player.p,PILOT_HYPERSPACE) && /* hyperspace fancy effects */ (player.p->ptimer < HYPERSPACE_STARS_BLUR)) { glShadeModel(GL_SMOOTH); shade_mode = 1; /* lines will be based on velocity */ m = HYPERSPACE_STARS_BLUR-player.p->ptimer; m /= HYPERSPACE_STARS_BLUR; m *= HYPERSPACE_STARS_LENGTH; x = m*cos(VANGLE(player.p->solid->vel)); y = m*sin(VANGLE(player.p->solid->vel)); } else if (dt_mod > 3.) { glShadeModel(GL_SMOOTH); shade_mode = 1; /* lines will be based on velocity */ m = (dt_mod-3.)*VMOD(player.p->solid->vel)/10.; x = m*cos(VANGLE(player.p->solid->vel)); y = m*sin(VANGLE(player.p->solid->vel)); } if (shade_mode) { /* Generate lines. */ for (i=0; i < nstars; i++) { brightness = star_colour[8*i+3]; star_vertex[4*i+2] = star_vertex[4*i+0] + x*brightness; star_vertex[4*i+3] = star_vertex[4*i+1] + y*brightness; } /* Upload new data. */ gl_vboSubData( star_vertexVBO, 0, nstars * 4 * sizeof(GLfloat), star_vertex ); } } /* Render. */ gl_vboActivate( star_vertexVBO, GL_VERTEX_ARRAY, 2, GL_FLOAT, 2 * sizeof(GLfloat) ); gl_vboActivate( star_colourVBO, GL_COLOR_ARRAY, 4, GL_FLOAT, 4 * sizeof(GLfloat) ); if (shade_mode) { glDrawArrays( GL_LINES, 0, nstars ); glDrawArrays( GL_POINTS, 0, nstars ); /* This second pass is when the lines are very short that they "lose" intensity. */ glShadeModel(GL_FLAT); } else { glDrawArrays( GL_POINTS, 0, nstars ); } /* Clear star movement. */ star_x = 0.; star_y = 0.; /* Disable vertex array. */ gl_vboDeactivate(); /* Pop matrix. */ gl_matrixPop(); /* Check for errors. */ gl_checkErr(); }
/** * @brief Runs the input command. * * @param keynum The index of the keybind. * @param value The value of the keypress (defined above). * @param kabs The absolute value. */ static void input_key( int keynum, double value, double kabs, int repeat ) { unsigned int t; HookParam hparam[3]; /* Repetition stuff. */ if (conf.repeat_delay != 0) { if ((value == KEY_PRESS) && !repeat) { repeat_key = keynum; repeat_keyTimer = SDL_GetTicks(); repeat_keyCounter = 0; } else if (value == KEY_RELEASE) { repeat_key = -1; repeat_keyTimer = 0; repeat_keyCounter = 0; } } /* * movement */ /* accelerating */ if (KEY("accel") && !repeat) { if (kabs >= 0.) { player_restoreControl( PINPUT_MOVEMENT, NULL ); player_accel(kabs); input_accelButton = 1; } else { /* prevent it from getting stuck */ if (value==KEY_PRESS) { player_restoreControl( PINPUT_MOVEMENT, NULL ); player_setFlag(PLAYER_ACCEL); player_accel(1.); input_accelButton = 1; } else if (value==KEY_RELEASE) { player_accelOver(); player_rmFlag(PLAYER_ACCEL); input_accelButton = 0; } /* double tap accel = afterburn! */ t = SDL_GetTicks(); if ((conf.afterburn_sens != 0) && (value==KEY_PRESS) && INGAME() && NOHYP() && NODEAD() && (t-input_accelLast <= conf.afterburn_sens)) pilot_afterburn( player.p ); else if (value==KEY_RELEASE) pilot_afterburnOver( player.p ); if (value==KEY_PRESS) input_accelLast = t; } /* turning left */ } else if (KEY("left") && !repeat) { if (kabs >= 0.) { player_restoreControl( PINPUT_MOVEMENT, NULL ); player_setFlag(PLAYER_TURN_LEFT); player_left = kabs; } else { /* set flags for facing correction */ if (value==KEY_PRESS) { player_restoreControl( PINPUT_MOVEMENT, NULL ); player_setFlag(PLAYER_TURN_LEFT); player_left = 1.; } else if (value==KEY_RELEASE) { player_rmFlag(PLAYER_TURN_LEFT); player_left = 0.; } } /* turning right */ } else if (KEY("right") && !repeat) { if (kabs >= 0.) { player_restoreControl( PINPUT_MOVEMENT, NULL ); player_setFlag(PLAYER_TURN_RIGHT); player_right = kabs; } else { /* set flags for facing correction */ if (value==KEY_PRESS) { player_restoreControl( PINPUT_MOVEMENT, NULL ); player_setFlag(PLAYER_TURN_RIGHT); player_right = 1.; } else if (value==KEY_RELEASE) { player_rmFlag(PLAYER_TURN_RIGHT); player_right = 0.; } } /* turn around to face vel */ } else if (KEY("reverse") && !repeat) { if (value==KEY_PRESS) { player_restoreControl( PINPUT_MOVEMENT, NULL ); player_setFlag(PLAYER_REVERSE); } else if ((value==KEY_RELEASE) && player_isFlag(PLAYER_REVERSE)) { player_rmFlag(PLAYER_REVERSE); if (!player_isFlag(PLAYER_ACCEL)) player_accelOver(); } /* * combat */ /* shooting primary weapon */ } else if (KEY("primary") && NODEAD() && !repeat) { if (value==KEY_PRESS) { player_setFlag(PLAYER_PRIMARY); } else if (value==KEY_RELEASE) player_rmFlag(PLAYER_PRIMARY); /* targeting */ } else if (INGAME() && NODEAD() && KEY("target_next")) { if (value==KEY_PRESS) player_targetNext(0); } else if (INGAME() && NODEAD() && KEY("target_prev")) { if (value==KEY_PRESS) player_targetPrev(0); } else if (INGAME() && NODEAD() && KEY("target_nearest")) { if (value==KEY_PRESS) player_targetNearest(); } else if (INGAME() && NODEAD() && KEY("target_nextHostile")) { if (value==KEY_PRESS) player_targetNext(1); } else if (INGAME() && NODEAD() && KEY("target_prevHostile")) { if (value==KEY_PRESS) player_targetPrev(1); } else if (INGAME() && NODEAD() && KEY("target_hostile")) { if (value==KEY_PRESS) player_targetHostile(); } else if (INGAME() && NODEAD() && KEY("target_clear")) { if (value==KEY_PRESS) player_targetClear(); /* face the target */ } else if (INGAME() && NODEAD() && KEY("face") && !repeat) { if (value==KEY_PRESS) { player_restoreControl( PINPUT_MOVEMENT, NULL ); player_setFlag(PLAYER_FACE); } else if ((value==KEY_RELEASE) && player_isFlag(PLAYER_FACE)) player_rmFlag(PLAYER_FACE); /* board them ships */ } else if (KEY("board") && INGAME() && NOHYP() && NODEAD() && !repeat) { if (value==KEY_PRESS) { player_restoreControl( 0, NULL ); player_board(); } /* * Escorts. */ } else if (INGAME() && NODEAD() && KEY("e_targetNext") && !repeat) { if (value==KEY_PRESS) player_targetEscort(0); } else if (INGAME() && NODEAD() && KEY("e_targetPrev") && !repeat) { if (value==KEY_PRESS) player_targetEscort(1); } else if (INGAME() && NODEAD() && KEY("e_attack") && !repeat) { if (value==KEY_PRESS) escorts_attack(player.p); } else if (INGAME() && NODEAD() && KEY("e_hold") && !repeat) { if (value==KEY_PRESS) escorts_hold(player.p); } else if (INGAME() && NODEAD() && KEY("e_return") && !repeat) { if (value==KEY_PRESS) escorts_return(player.p); } else if (INGAME() && NODEAD() && KEY("e_clear") && !repeat) { if (value==KEY_PRESS) escorts_clear(player.p); /* * secondary weapons */ /* shooting secondary weapon */ } else if (KEY("secondary") && NOHYP() && NODEAD() && !repeat) { if (value==KEY_PRESS) { player_setFlag(PLAYER_SECONDARY); } else if (value==KEY_RELEASE) player_rmFlag(PLAYER_SECONDARY); /* Weapon sets. */ } else if (KEY("weapset1")) { player_weapSetPress( 0, value, repeat ); } else if (KEY("weapset2")) { player_weapSetPress( 1, value, repeat ); } else if (KEY("weapset3")) { player_weapSetPress( 2, value, repeat ); } else if (KEY("weapset4")) { player_weapSetPress( 3, value, repeat ); } else if (KEY("weapset5")) { player_weapSetPress( 4, value, repeat ); } else if (KEY("weapset6")) { player_weapSetPress( 5, value, repeat ); } else if (KEY("weapset7")) { player_weapSetPress( 6, value, repeat ); } else if (KEY("weapset8")) { player_weapSetPress( 7, value, repeat ); } else if (KEY("weapset9")) { player_weapSetPress( 8, value, repeat ); } else if (KEY("weapset0")) { player_weapSetPress( 9, value, repeat ); /* * space */ } else if (KEY("autonav") && INGAME() && NOHYP() && NODEAD()) { if (value==KEY_PRESS) player_autonavStart(); /* target planet (cycles like target) */ } else if (KEY("target_planet") && INGAME() && NOHYP() && NOLAND() && NODEAD()) { if (value==KEY_PRESS) player_targetPlanet(); /* target nearest planet or attempt to land */ } else if (KEY("land") && INGAME() && NOHYP() && NOLAND() && NODEAD()) { if (value==KEY_PRESS) player_land(); } else if (KEY("thyperspace") && NOHYP() && NOLAND() && NODEAD()) { if (value==KEY_PRESS) player_targetHyperspace(); } else if (KEY("starmap") && NOHYP() && NODEAD() && !repeat) { if (value==KEY_PRESS) map_open(); } else if (KEY("jump") && INGAME() && !repeat) { if (value==KEY_PRESS) { player_restoreControl( 0, NULL ); player_jump(); } } else if (KEY("overlay") && NODEAD() && INGAME() && !repeat) { ovr_key( value ); } else if (KEY("mousefly") && NODEAD() && !repeat) { if (value==KEY_PRESS) player_toggleMouseFly(); } else if (KEY("autobrake") && NOHYP() && NOLAND() && NODEAD() && !repeat) { if (value==KEY_PRESS) { player_restoreControl( PINPUT_BRAKING, NULL ); player_brake(); } /* * Communication. */ } else if (KEY("log_up") && INGAME() && NODEAD()) { if (value==KEY_PRESS) { gui_messageScrollUp(5); } } else if (KEY("log_down") && INGAME() && NODEAD()) { if (value==KEY_PRESS) { gui_messageScrollDown(5); } } else if (KEY("hail") && INGAME() && NOHYP() && NODEAD() && !repeat) { if (value==KEY_PRESS) { player_hail(); } } else if (KEY("autohail") && INGAME() && NOHYP() && NODEAD() && !repeat) { if (value==KEY_PRESS) { player_autohail(); } /* * misc */ /* zooming in */ } else if (KEY("mapzoomin") && INGAME() && NODEAD()) { if (value==KEY_PRESS) gui_setRadarRel(-1); /* zooming out */ } else if (KEY("mapzoomout") && INGAME() && NODEAD()) { if (value==KEY_PRESS) gui_setRadarRel(1); /* take a screenshot */ } else if (KEY("screenshot")) { if (value==KEY_PRESS) player_screenshot(); #if SDL_VERSION_ATLEAST(2,0,0) /* toggle fullscreen */ } else if (KEY("togglefullscreen") && !repeat) { if (value==KEY_PRESS) naev_toggleFullscreen(); #endif /* SDL_VERSION_ATLEAST(2,0,0) */ /* pause the games */ } else if (KEY("pause") && !repeat) { if (value==KEY_PRESS) { if (!toolkit_isOpen()) { if (paused) unpause_game(); else pause_player(); } } /* toggle speed mode */ } else if (KEY("speed") && !repeat) { if ((value==KEY_PRESS) && (!player_isFlag( PLAYER_CINEMATICS_2X ))) { if (player_isFlag(PLAYER_DOUBLESPEED)) { if (!player_isFlag(PLAYER_AUTONAV)) pause_setSpeed(1.); player_rmFlag(PLAYER_DOUBLESPEED); } else { if (!player_isFlag(PLAYER_AUTONAV)) pause_setSpeed(2.); player_setFlag(PLAYER_DOUBLESPEED); } } /* opens a small menu */ } else if (KEY("menu") && NODEAD() && !repeat) { if (value==KEY_PRESS) menu_small(); /* shows pilot information */ } else if (KEY("info") && NOHYP() && NODEAD() && !repeat) { if (value==KEY_PRESS) menu_info( INFO_MAIN ); /* Opens the Lua console. */ } else if (KEY("console") && NODEAD() && !repeat) { if (value==KEY_PRESS) cli_open(); } /* Key press not used. */ else { return; } /* Run the hook. */ hparam[0].type = HOOK_PARAM_STRING; hparam[0].u.str = input_keybinds[keynum].name; hparam[1].type = HOOK_PARAM_BOOL; hparam[1].u.b = (value > 0.); hparam[2].type = HOOK_PARAM_SENTINEL; hooks_runParam( "input", hparam ); }
/** * @brief Handles a click event. */ static void input_clickevent( SDL_Event* event ) { unsigned int pid; int mx, my, mxr, myr, pntid, jpid; int rx, ry, rh, rw, res; int autonav; double x, y, zoom, px, py; double ang, angp, mouseang; HookParam hparam[2]; /* Generate hook. */ hparam[0].type = HOOK_PARAM_NUMBER; hparam[0].u.num = event->button.button; hparam[1].type = HOOK_PARAM_SENTINEL; hooks_runParam( "mouse", hparam ); #if !SDL_VERSION_ATLEAST(2,0,0) /* Handle zoom. */ if (event->button.button == SDL_BUTTON_WHEELUP) { input_clickZoom( 1.1 ); return; } else if (event->button.button == SDL_BUTTON_WHEELDOWN) { input_clickZoom( 0.9 ); return; } #endif /* !SDL_VERSION_ATLEAST(2,0,0) */ /* Player must not be NULL. */ if ((player.p == NULL) || player_isFlag(PLAYER_DESTROYED)) return; /* Player must not be dead. */ if (pilot_isFlag(player.p, PILOT_DEAD)) return; /* Middle mouse enables mouse flying. */ if (event->button.button == SDL_BUTTON_MIDDLE) { player_toggleMouseFly(); return; } /* Mouse targeting only uses left and right buttons. */ if (event->button.button != SDL_BUTTON_LEFT && event->button.button != SDL_BUTTON_RIGHT) return; autonav = (event->button.button == SDL_BUTTON_RIGHT) ? 1 : 0; px = player.p->solid->pos.x; py = player.p->solid->pos.y; gl_windowToScreenPos( &mx, &my, event->button.x, event->button.y ); if ((mx <= 15 || my <= 15 ) || (my >= gl_screen.h - 15 || mx >= gl_screen.w - 15)) { /* Border targeting is handled as a special case, as it uses angles, * not coordinates. */ x = (mx - (gl_screen.w / 2.)) + px; y = (my - (gl_screen.h / 2.)) + py; mouseang = atan2(py - y, px - x); angp = pilot_getNearestAng( player.p, &pid, mouseang, 1 ); ang = system_getClosestAng( cur_system, &pntid, &jpid, x, y, mouseang ); if ((ABS(angle_diff(mouseang, angp)) > M_PI / 64) || ABS(angle_diff(mouseang, ang)) < ABS(angle_diff(mouseang, angp))) pid = PLAYER_ID; /* Pilot angle is too great, or planet/jump is closer. */ if (ABS(angle_diff(mouseang, ang)) > M_PI / 64 ) jpid = pntid = -1; /* Asset angle difference is too great. */ if (!autonav && pid != PLAYER_ID) { if (input_clickedPilot(pid)) return; } else if (pntid >= 0) { /* Planet is closest. */ if (input_clickedPlanet(pntid, autonav)) return; } else if (jpid >= 0) { /* Jump point is closest. */ if (input_clickedJump(jpid, autonav)) return; } /* Fall-through and handle as a normal click. */ } /* Radar targeting requires raw coordinates. */ mxr = event->button.x; myr = gl_screen.rh - event->button.y; gui_radarGetPos( &rx, &ry ); gui_radarGetDim( &rw, &rh ); if ((mxr > rx && mxr <= rx + rw ) && (myr > ry && myr <= ry + rh )) { /* Radar */ zoom = 1.; gui_radarGetRes( &res ); x = (mxr - (rx + rw / 2.)) * res + px; y = (myr - (ry + rh / 2.)) * res + py; if (input_clickPos( event, x, y, zoom, 10. * res, 15. * res )) return; } /* Visual (on-screen) */ gl_screenToGameCoords( &x, &y, (double)mx, (double)my ); zoom = res = 1. / cam_getZoom(); input_clickPos( event, x, y, zoom, 10. * res, 15. * res ); return; }
/** * @brief Handles a click event. */ static void input_clickevent( SDL_Event* event ) { unsigned int pid; Pilot *p; int mx, my, mxr, myr, pntid, jpid; int rx, ry, rh, rw, res; double x, y, m, r, rp, d, dp, px, py; double ang, angp, mouseang; Planet *pnt; JumpPoint *jp; HookParam hparam[2]; /* Generate hook. */ hparam[0].type = HOOK_PARAM_NUMBER; hparam[0].u.num = event->button.button; hparam[1].type = HOOK_PARAM_SENTINAL; hooks_runParam( "mouse", hparam ); /* Handle zoom. */ if (event->button.button == SDL_BUTTON_WHEELUP) { input_clickZoom( 1.1 ); return; } else if (event->button.button == SDL_BUTTON_WHEELDOWN) { input_clickZoom( 0.9 ); return; } /* Middle mouse enables mouse flying. */ if (event->button.button == SDL_BUTTON_MIDDLE) { player_toggleMouseFly(); return; } /* Mouse targetting is left only. */ if (event->button.button != SDL_BUTTON_LEFT) return; /* Player must not be NULL. */ if (player_isFlag(PLAYER_DESTROYED) || (player.p == NULL)) return; px = player.p->solid->pos.x; py = player.p->solid->pos.y; gl_windowToScreenPos( &mx, &my, event->button.x, event->button.y ); gl_screenToGameCoords( &x, &y, (double)mx, (double)my ); if ((mx <= 15 || my <= 15 ) || (my >= gl_screen.h - 15 || mx >= gl_screen.w - 15)) { /* Border */ x = (mx - (gl_screen.w / 2.)) + px; y = (my - (gl_screen.h / 2.)) + py; mouseang = atan2(py - y, px - x); angp = pilot_getNearestAng( player.p, &pid, mouseang, 1 ); ang = system_getClosestAng( cur_system, &pntid, &jpid, x, y, mouseang ); if ((ABS(angle_diff(mouseang, angp)) > M_PI / 64) || ABS(angle_diff(mouseang, ang)) < ABS(angle_diff(mouseang, angp))) pid = PLAYER_ID; /* Pilot angle is too great, or planet/jump is closer. */ if (ABS(angle_diff(mouseang, ang)) > M_PI / 64 ) jpid = pntid = -1; /* Asset angle difference is too great. */ } else { /* Radar targeting requires raw coordinates. */ mxr = event->button.x; myr = gl_screen.rh - event->button.y; gui_radarGetPos( &rx, &ry ); gui_radarGetDim( &rw, &rh ); if ((mxr > rx && mxr <= rx + rw ) && (myr > ry && myr <= ry + rh )) { /* Radar */ m = 1; gui_radarGetRes( &res ); x = (mxr - (rx + rw / 2.)) * res + px; y = (myr - (ry + rh / 2.)) * res + py; } else /* Visual (on-screen) */ m = res = 1. / cam_getZoom(); dp = pilot_getNearestPos( player.p, &pid, x, y, 1 ); d = system_getClosest( cur_system, &pntid, &jpid, x, y ); rp = MAX( 1.5 * PILOT_SIZE_APROX * pilot_get(pid)->ship->gfx_space->sw / 2 * m, 10. * res); if (pntid >=0) { /* Planet is closer. */ pnt = cur_system->planets[ pntid ]; r = MAX( 1.5 * pnt->radius, 100. ); } else if (jpid >= 0) { jp = &cur_system->jumps[ jpid ]; r = MAX( 1.5 * jp->radius, 100. ); } else { r = 0.; } /* Reject pilot if it's too far or a valid asset is closer. */ if (dp > pow2(rp) || (d < pow2(r) && dp < pow2(rp) && dp > d)) pid = PLAYER_ID; if (d > pow2(r)) /* Planet or jump point is too far. */ jpid = pntid = -1; } if (pid != PLAYER_ID) { /* Apply an action if already selected. */ if (!pilot_isFlag(player.p, PILOT_DEAD) && (pid == player.p->target)) { p = pilot_get(pid); if (pilot_isDisabled(p) || pilot_isFlag(p, PILOT_BOARDABLE)) player_board(); else player_hail(); } else player_targetSet( pid ); } else if (pntid >= 0) { /* Planet is closest. */ if (pntid == player.p->nav_planet) { pnt = cur_system->planets[ pntid ]; if (planet_hasService(pnt, PLANET_SERVICE_LAND) && (!areEnemies( player.p->faction, pnt->faction ) || pnt->bribed )) player_land(); else player_hailPlanet(); } else player_targetPlanetSet( pntid ); } else if (jpid >= 0) { /* Jump point is closest. */ jp = &cur_system->jumps[ jpid ]; if (jpid == player.p->nav_hyperspace) { if (space_canHyperspace(player.p)) { if (!paused) player_autonavAbort(NULL); player_jump(); } else player_autonavStart(); } else player_targetHyperspaceSet( jpid ); } }
/** * @brief Saves the current game. * * @return 0 on success. */ int save_all (void) { char file[PATH_MAX]; xmlDocPtr doc; xmlTextWriterPtr writer; /* Do not save during tutorial. Or if saving is off. */ if (player_isTut() || player_isFlag(PLAYER_NOSAVE)) return 0; /* Create the writer. */ writer = xmlNewTextWriterDoc(&doc, conf.save_compress); if (writer == NULL) { ERR("testXmlwriterDoc: Error creating the xml writer"); return -1; } /* Set the writer parameters. */ xmlw_setParams( writer ); /* Start element. */ xmlw_start(writer); xmlw_startElem(writer,"naev_save"); /* Save the version and such. */ xmlw_startElem(writer,"version"); xmlw_elem( writer, "naev", "%d.%d.%d", VMAJOR, VMINOR, VREV ); xmlw_elem( writer, "data", "%s", ndata_name() ); xmlw_endElem(writer); /* "version" */ /* Save the data. */ if (save_data(writer) < 0) { ERR("Trying to save game data"); goto err_writer; } /* Finish element. */ xmlw_endElem(writer); /* "naev_save" */ xmlw_done(writer); /* Write to file. */ if ((nfile_dirMakeExist("%s", nfile_dataPath()) < 0) || (nfile_dirMakeExist("%ssaves", nfile_dataPath()) < 0)) { WARN("Failed to create save directory '%ssaves'.", nfile_dataPath()); goto err_writer; } nsnprintf(file, PATH_MAX, "%ssaves/%s.ns", nfile_dataPath(), player.name); /* Back up old savegame. */ if (!save_loaded) { if (nfile_backupIfExists(file) < 0) { WARN("Aborting save..."); goto err_writer; } } save_loaded = 0; /* Critical section, if crashes here player's game gets corrupted. * Luckily we have a copy just in case... */ xmlFreeTextWriter(writer); if (xmlSaveFileEnc(file, doc, "UTF-8") < 0) { WARN("Failed to write savegame! You'll most likely have to restore it by copying your backup savegame over your current savegame."); goto err; } xmlFreeDoc(doc); return 0; err_writer: xmlFreeTextWriter(writer); err: xmlFreeDoc(doc); return -1; }
/** * @brief Handles input to the map overlay. */ int ovr_input( SDL_Event *event ) { unsigned int pid; Pilot *p; int mx, my; double x, y, r, rp; double d, dp; Planet *pnt; JumpPoint *jp; int pntid, jpid; /* We only want mouse events. */ if (event->type != SDL_MOUSEBUTTONDOWN) return 0; /* Player must not be NULL. */ if (player_isFlag(PLAYER_DESTROYED) || (player.p == NULL)) return 0; /* Selection. */ if (event->button.button == SDL_BUTTON_LEFT) { /* Translate from window to screen. */ mx = event->button.x; my = event->button.y; gl_windowToScreenPos( &mx, &my, mx, my ); /* Translate to space coords. */ x = ((double)mx - SCREEN_W/2.) * ovr_res; y = ((double)my - SCREEN_H/2.) * ovr_res; /* Get nearest pilot and jump point/planet. */ dp = pilot_getNearestPos( player.p, &pid, x, y, 1 ); d = system_getClosest( cur_system, &pntid, &jpid, x, y ); p = pilot_get(pid); rp = MAX( 1.5 * PILOT_SIZE_APROX * p->ship->gfx_space->sw / 2, 20.*ovr_res ); if (pntid >=0) { /* Planet is closer. */ pnt = cur_system->planets[ pntid ]; r = MAX( 1.5 * pnt->radius, 20. * ovr_res ); } else if (jpid >= 0) { jp = &cur_system->jumps[ jpid ]; r = MAX( 1.5 * jp->radius, 20. * ovr_res ); } else r = 0.; /* Pilot is closest, or new jump point/planet is the same as the old. */ if ((dp < pow2(rp) && player.p->target != pid) && (dp < d || ((pntid >=0 && player.p->nav_planet == pntid) || (jpid >=0 && player.p->nav_planet == jpid)))) player_targetSet( pid ); else if ((pntid >= 0) && (d < pow2(r))) /* Planet is closest. */ player_targetPlanetSet( pntid ); else if ((jpid >= 0) && (d < pow2(r))) /* Jump point is closest. */ player_targetHyperspaceSet( jpid ); else return 0; return 1; } /* Autogo. */ else if (event->button.button == SDL_BUTTON_RIGHT) { if ((player.p == NULL) || pilot_isFlag( player.p, PILOT_MANUAL_CONTROL ) || pilot_isFlag( player.p, PILOT_HYP_PREP ) || pilot_isFlag( player.p, PILOT_HYP_BEGIN ) || pilot_isFlag( player.p, PILOT_HYPERSPACE )) return 1; /* Translate from window to screen. */ mx = event->button.x; my = event->button.y; gl_windowToScreenPos( &mx, &my, mx, my ); /* Translate to space coords. */ x = ((double)mx - SCREEN_W/2.) * ovr_res; y = ((double)my - SCREEN_H/2.) * ovr_res; /* Go to position. */ player_autonavPos( x, y ); return 1; } return 0; }
/** * @brief Updates the player's autonav. * * @param dt Current delta tick (should be real delta tick, not game delta tick). */ void player_updateAutonav( double dt ) { const double dis_dead = 5.0; const double dis_mod = 0.5; const double dis_max = 4.0; const double dis_ramp = 6.0; if (paused || (player.p==NULL) || pilot_isFlag(player.p, PILOT_DEAD)) return; /* We handle disabling here. */ if (pilot_isFlag(player.p, PILOT_DISABLED)) { /* It is somewhat like: * /------------\ 4x * / \ * -----/ \----- 1x * * <---><-><----------><-><---> * 5 6 X 6 5 Real time * 5 15 X 15 5 Game time * * For triangles we have to add the rectangle and triangle areas. */ /* 5 second deadtime. */ if (player.p->dtimer_accum < dis_dead) tc_mod = tc_base; else { /* Ramp down. */ if (player.p->dtimer - player.p->dtimer_accum < dis_dead + (dis_max-tc_base)*dis_ramp/2 + tc_base*dis_ramp) tc_mod = MAX( tc_base, tc_mod - dis_mod*dt ); /* Normal. */ else tc_mod = MIN( dis_max, tc_mod + dis_mod*dt ); } pause_setSpeed( tc_mod ); return; } /* Must be autonaving. */ if (!player_isFlag(PLAYER_AUTONAV)) return; /* Ramping down. */ if (tc_rampdown) { if (tc_mod != tc_base) { tc_mod = MAX( tc_base, tc_mod-tc_down*dt ); pause_setSpeed( tc_mod ); } return; } /* We'll update the time compression here. */ if (tc_mod == player.tc_max) return; else tc_mod += 0.2 * dt * (player.tc_max-tc_base); /* Avoid going over. */ if (tc_mod > player.tc_max) tc_mod = player.tc_max; pause_setSpeed( tc_mod ); }
/** * @brief Checks to see if the player has autonav enabled. * * @usage autonav = player.autonav() * @luareturn true if the player has autonav enabled. * @luafunc autonav() */ static int playerL_autonav( lua_State *L ) { lua_pushboolean( L, player_isFlag( PLAYER_AUTONAV ) ); return 1; }
/** * @brief Renders the overlay map. * * @param dt Current delta tick. */ void ovr_render( double dt ) { (void) dt; int i, j; Pilot **pstk; int n; double w, h, res; double x,y; glColour c = { .r=0., .g=0., .b=0., .a=0.5 }; /* Must be open. */ if (!ovr_open) return; /* Player must be alive. */ if (player_isFlag( PLAYER_DESTROYED ) || (player.p == NULL)) return; /* Default values. */ w = SCREEN_W; h = SCREEN_H; res = ovr_res; /* First render the background overlay. */ gl_renderRect( 0., 0., w, h, &c ); /* Render planets. */ for (i=0; i<cur_system->nplanets; i++) if ((cur_system->planets[ i ]->real == ASSET_REAL) && (i != player.p->nav_planet)) gui_renderPlanet( i, RADAR_RECT, w, h, res, 1 ); if (player.p->nav_planet > -1) gui_renderPlanet( player.p->nav_planet, RADAR_RECT, w, h, res, 1 ); /* Render jump points. */ for (i=0; i<cur_system->njumps; i++) if ((i != player.p->nav_hyperspace) && !jp_isFlag(&cur_system->jumps[i], JP_EXITONLY)) gui_renderJumpPoint( i, RADAR_RECT, w, h, res, 1 ); if (player.p->nav_hyperspace > -1) gui_renderJumpPoint( player.p->nav_hyperspace, RADAR_RECT, w, h, res, 1 ); /* Render pilots. */ pstk = pilot_getAll( &n ); j = 0; for (i=0; i<n; i++) { if (pstk[i]->id == PLAYER_ID) /* Skip player. */ continue; if (pstk[i]->id == player.p->target) j = i; else gui_renderPilot( pstk[i], RADAR_RECT, w, h, res, 1 ); } /* Render the targeted pilot */ if (j!=0) gui_renderPilot( pstk[j], RADAR_RECT, w, h, res, 1 ); /* Check if player has goto target. */ if (player_isFlag(PLAYER_AUTONAV) && (player.autonav == AUTONAV_POS_APPROACH)) { x = player.autonav_pos.x / res + w / 2.; y = player.autonav_pos.y / res + h / 2.; gl_renderCross( x, y, 5., &cRadar_hilight ); gl_printRaw( &gl_smallFont, x+10., y-gl_smallFont.h/2., &cRadar_hilight, "GOTO" ); } /* Render the player. */ gui_renderPlayer( res, 1 ); /* Render markers. */ ovr_mrkRenderAll( res ); } /** * @brief Renders all the markers. * * @param res Resolution to render at. */ static void ovr_mrkRenderAll( double res ) { int i; ovr_marker_t *mrk; double x, y; if (ovr_markers == NULL) return; for (i=0; i<array_size(ovr_markers); i++) { mrk = &ovr_markers[i]; x = mrk->u.pt.x / res + SCREEN_W / 2.; y = mrk->u.pt.y / res + SCREEN_H / 2.; gl_renderCross( x, y, 5., &cRadar_hilight ); if (mrk->text != NULL) gl_printRaw( &gl_smallFont, x+10., y-gl_smallFont.h/2., &cRadar_hilight, mrk->text ); } }