Example #1
0
/**
 * @brief Blits a sprite interpolating, position is relative to the player.
 *
 * Since position is in "game coordinates" it is subject to all
 * sorts of position transformations.
 *
 * Interpolation is:  sa*inter + sb*1.-inter)
 *
 *    @param sa Sprite A to blit.
 *    @param sb Sprite B to blit.
 *    @param inter Amount to interpolate.
 *    @param bx X position of the texture relative to the player.
 *    @param by Y position of the texture relative to the player.
 *    @param sx X position of the sprite to use.
 *    @param sy Y position of the sprite to use.
 *    @param c Colour to use (modifies texture colour).
 */
void gl_blitSpriteInterpolateScale( const glTexture* sa, const glTexture *sb,
      double inter, const double bx, const double by,
      double scalew, double scaleh,
      const int sx, const int sy, const glColour *c )
{
   double x,y, w,h, tx,ty, z;

   /* Translate coords. */
   gl_gameToScreenCoords( &x, &y, bx - scalew * sa->sw/2., by - scaleh * sa->sh/2. );

   /* Scaled sprite dimensions. */
   z = cam_getZoom();
   w = sa->sw*z*scalew;
   h = sa->sh*z*scaleh;

   /* check if inbounds */
   if ((x < -w) || (x > SCREEN_W+w) ||
         (y < -h) || (y > SCREEN_H+h))
      return;

   /* texture coords */
   tx = sa->sw*(double)(sx)/sa->rw;
   ty = sa->sh*(sa->sy-(double)sy-1)/sa->rh;

   gl_blitTextureInterpolate( sa, sb, inter, x, y, w, h,
         tx, ty, sa->srw, sa->srh, c );
}
Example #2
0
/**
 * @brief Blits a sprite, position is relative to the player.
 *
 * Since position is in "game coordinates" it is subject to all
 * sorts of position transformations.
 *
 *    @param sprite Sprite to blit.
 *    @param bx X position of the texture relative to the player.
 *    @param by Y position of the texture relative to the player.
 *    @param sx X position of the sprite to use.
 *    @param sy Y position of the sprite to use.
 *    @param c Colour to use (modifies texture colour).
 */
void gl_blitSprite( const glTexture* sprite, const double bx, const double by,
      const int sx, const int sy, const glColour* c )
{
   double x,y, w,h, tx,ty, z;

   /* Translate coords. */
   z = cam_getZoom();
   gl_gameToScreenCoords( &x, &y, bx - sprite->sw/2., by - sprite->sh/2. );

   /* Scaled sprite dimensions. */
   w = sprite->sw*z;
   h = sprite->sh*z;

   /* check if inbounds */
   if ((x < -w) || (x > SCREEN_W+w) ||
         (y < -h) || (y > SCREEN_H+h))
      return;

   /* texture coords */
   tx = sprite->sw*(double)(sx)/sprite->rw;
   ty = sprite->sh*(sprite->sy-(double)sy-1)/sprite->rh;

   gl_blitTexture( sprite, x, y, w, h,
         tx, ty, sprite->srw, sprite->srh, c );
}
Example #3
0
/**
 * @brief Updates the camera zoom.
 */
static void cam_updatePilotZoom( Pilot *follow, Pilot *target, double dt )
{
   double d, x,y, z,tz, dx, dy;
   double zfar, znear;
   double c;

   /* Must have auto zoom enabled. */
   if (conf.zoom_manual)
      return;

   /* Minimum depends on velocity normally.
    *
    * w*h = A, cte    area constant
    * w/h = K, cte    proportion constant
    * d^2 = A, cte    geometric longitud
    *
    * A_v = A*(1+v/d)   area of view is based on speed
    * A_v / A = (1 + v/d)
    *
    * z = A / A_v = 1. / (1 + v/d)
    */
   d     = sqrt(SCREEN_W*SCREEN_H);
   znear = MIN( conf.zoom_near, 1. / (0.8 + VMOD(follow->solid->vel)/d) );

   /* Maximum is limited by nebulae. */
   if (cur_system->nebu_density > 0.) {
      c     = MIN( SCREEN_W, SCREEN_H ) / 2;
      zfar  = CLAMP( conf.zoom_far, conf.zoom_near, c / nebu_getSightRadius() );
   }
   else
      zfar = conf.zoom_far;
   znear = MAX( znear, zfar );

   /*
    * Set Zoom to pilot target.
    */
   z = cam_getZoom();
   if (target != NULL) {
      /* Get current relative target position. */
      gui_getOffset( &x, &y );
      x += target->solid->pos.x - follow->solid->pos.x;
      y += target->solid->pos.y - follow->solid->pos.y;

      /* Get distance ratio. */
      dx = (SCREEN_W/2.) / (FABS(x) + 2*target->ship->gfx_space->sw);
      dy = (SCREEN_H/2.) / (FABS(y) + 2*target->ship->gfx_space->sh);

      /* Get zoom. */
      tz = MIN( dx, dy );
   }
   else
      tz = znear; /* Aim at in. */

   /* Gradually zoom in/out. */
   d  = CLAMP(-conf.zoom_speed, conf.zoom_speed, tz - z);
   d *= dt / dt_mod; /* Remove dt dependence. */
   if (d < 0) /** Speed up if needed. */
      d *= 2.;
   camera_Z =  CLAMP( zfar, znear, z + d);
}
Example #4
0
/**
 * @brief Converts screen coordinates to ingame coordinates.
 *
 *    @param[out] nx New ingame X coord.
 *    @param[out] ny New ingame Y coord.
 *    @param bx Screen X coord to translate.
 *    @param by Screen Y coord to translate.
 */
void gl_screenToGameCoords( double *nx, double *ny, int bx, int by )
{
   double cx,cy, gx,gy, z;

   /* Get parameters. */
   cam_getPos( &cx, &cy );
   z = cam_getZoom();
   gui_getOffset( &gx, &gy );

   /* calculate position - we'll use relative coords to player */
   *nx = (bx - SCREEN_W/2. - gx) / z + cx;
   *ny = (by - SCREEN_H/2. - gy) / z + cy;
}
Example #5
0
/**
 * @brief Converts ingame coordinates to screen coordinates.
 *
 *    @param[out] nx New screen X coord.
 *    @param[out] ny New screen Y coord.
 *    @param bx Game X coord to translate.
 *    @param by Game Y coord to translate.
 */
void gl_gameToScreenCoords( double *nx, double *ny, double bx, double by )
{
   double cx,cy, gx,gy, z;

   /* Get parameters. */
   cam_getPos( &cx, &cy );
   z = cam_getZoom();
   gui_getOffset( &gx, &gy );

   /* calculate position - we'll use relative coords to player */
   *nx = (bx - cx) * z + gx + SCREEN_W/2.;
   *ny = (by - cy) * z + gy + SCREEN_H/2.;
}
Example #6
0
/**
 * @brief Renders the background images.
 */
static void background_renderImages( background_image_t *bkg_arr )
{
   int i;
   background_image_t *bkg;
   double px,py, x,y, xs,ys, z;

   /* Must have an image array created. */
   if (bkg_arr == NULL)
      return;

   /* Render images in order. */
   for (i=0; i<array_size(bkg_arr); i++) {
      bkg = &bkg_arr[i];

      cam_getPos( &px, &py );
      x  = px + (bkg->x - px) * bkg->move - bkg->scale*bkg->image->sw/2.;
      y  = py + (bkg->y - py) * bkg->move - bkg->scale*bkg->image->sh/2.;
      gl_gameToScreenCoords( &xs, &ys, x, y );
      z = cam_getZoom();
      z *= bkg->scale;
      gl_blitScale( bkg->image, xs, ys,
            z*bkg->image->sw, z*bkg->image->sh, &bkg->col );
   }
}
Example #7
0
/**
 * @brief Renders the nebula overlay (hides what player can't see).
 *
 *    @param dt Current delta tick.
 */
void nebu_renderOverlay( const double dt )
{
   (void) dt;
   double gx, gy;
   double ox, oy;
   double z;
   double sx, sy;

   /* Get GUI offsets. */
   gui_getOffset( &gx, &gy );

   /* Get zoom. */
   z = cam_getZoom();

   /*
    * Renders the puffs
    */
   nebu_renderPuffs( 0 );

   /* Prepare the matrix */
   ox = gx;
   oy = gy;
   spfx_getShake( &sx, &sy );
   ox += sx;
   oy += sy;
   gl_matrixPush();
      gl_matrixTranslate( SCREEN_W/2.+ox, SCREEN_H/2.+oy );
      gl_matrixScale( z, z );

   /*
    * Mask for area player can still see (partially)
    */
   glShadeModel(GL_SMOOTH);
   gl_vboActivateOffset( nebu_vboOverlay, GL_VERTEX_ARRAY, 0, 2, GL_FLOAT, 0 );
   gl_vboActivateOffset( nebu_vboOverlay, GL_COLOR_ARRAY,
         sizeof(GLfloat)*2*18, 4, GL_FLOAT, 0 );
   glDrawArrays( GL_TRIANGLE_FAN, 0, 18 );


   /*
    * Solid nebula for areas the player can't see
    */
   glShadeModel(GL_FLAT);
   /* Colour is shared. */
   gl_vboActivateOffset( nebu_vboOverlay, GL_COLOR_ARRAY,
         sizeof(GLfloat)*((2+4)*18 + 2*28), 4, GL_FLOAT, 0 );
   /* Top left. */
   gl_vboActivateOffset( nebu_vboOverlay, GL_VERTEX_ARRAY,
         sizeof(GLfloat)*((2+4)*18 + 0*2*7), 2, GL_FLOAT, 0 );
   glDrawArrays( GL_TRIANGLE_FAN, 0, 7 );
   /* Top right. */
   gl_vboActivateOffset( nebu_vboOverlay, GL_VERTEX_ARRAY,
         sizeof(GLfloat)*((2+4)*18 + 1*2*7), 2, GL_FLOAT, 0 );
   glDrawArrays( GL_TRIANGLE_FAN, 0, 7 );
   /* Bottom right. */
   gl_vboActivateOffset( nebu_vboOverlay, GL_VERTEX_ARRAY,
         sizeof(GLfloat)*((2+4)*18 + 2*2*7), 2, GL_FLOAT, 0 );
   glDrawArrays( GL_TRIANGLE_FAN, 0, 7 );
   /* Bottom left. */
   gl_vboActivateOffset( nebu_vboOverlay, GL_VERTEX_ARRAY,
         sizeof(GLfloat)*((2+4)*18 + 3*2*7), 2, GL_FLOAT, 0 );
   glDrawArrays( GL_TRIANGLE_FAN, 0, 7 );

   gl_vboDeactivate();
   gl_matrixPop();

   /* Reset puff movement. */
   puff_x = 0.;
   puff_y = 0.;

   gl_checkErr();
}
Example #8
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();
}
Example #9
0
/**
 * @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;
}
Example #10
0
File: input.c Project: Ttech/naev
/**
 * @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 );
   }
}