コード例 #1
0
ファイル: physics.c プロジェクト: Anatolis/naev
/**
 * @brief Updates the solid's position using an Euler integration.
 *
 * Simple method
 *
 *   d^2 x(t) / d t^2 = a, a = constant (acceleration)
 *   x'(0) = v, x(0) = p
 *
 *   d x(t) / d t = a*t + v, v = constant (initial velocity)
 *   x(t) = a/2*t + v*t + p, p = constant (initial position)
 *
 *   since dt isn't actually differential this gives us ERROR!
 *   so watch out with big values for dt
 *
 */
static void solid_update_euler (Solid *obj, const double dt)
{
   double px,py, vx,vy, ax,ay, th;
   double cdir, sdir;

   /* make sure angle doesn't flip */
   obj->dir += obj->dir_vel*dt;
   if (obj->dir >= 2*M_PI)
      obj->dir -= 2*M_PI;
   if (obj->dir < 0.)
      obj->dir += 2*M_PI;

   /* Initial positions. */
   px = obj->pos.x;
   py = obj->pos.y;
   vx = obj->vel.x;
   vy = obj->vel.y;
   th = obj->thrust;

   /* Save direction. */
   sdir = sin(obj->dir);
   cdir = cos(obj->dir);

   /* Get acceleration. */
   ax = th*cdir / obj->mass;
   ay = th*sdir / obj->mass;

   /* p = v*dt + 0.5*a*dt^2 */
   px += vx*dt + 0.5*ax * dt*dt;
   py += vy*dt + 0.5*ay * dt*dt;

   /* Update position and velocity. */
   vect_cset( &obj->vel, vx, vy );
   vect_cset( &obj->pos, px, py );
}
コード例 #2
0
ファイル: pilot_weapon.c プロジェクト: nenau/naev
/**
 * @brief Computes an estimation of ammo flying time
 *
 *    @param w the weapon that shoot
 *    @param parent Parent of the weapon
 *    @param target Target of the weapon
 */
double pilot_weapFlyTime( Outfit *o, Pilot *parent, Vector2d *pos, Vector2d *vel)
{
   Vector2d approach_vector, relative_location, orthoradial_vector;
   double speed, radial_speed, orthoradial_speed, dist, t;

   dist = vect_dist( &parent->solid->pos, pos );

   /* Beam weapons */
   if (outfit_isBeam(o))
      {
      if (dist > o->u.bem.range)
         return INFINITY;
      return 0.;
      }

   /* A bay doesn't have range issues */
   if (outfit_isFighterBay(o))
      return 0.;

   /* Rockets use absolute velocity while bolt use relative vel */
   if (outfit_isLauncher(o))
         vect_cset( &approach_vector, - vel->x, - vel->y );
   else
         vect_cset( &approach_vector, VX(parent->solid->vel) - vel->x,
               VY(parent->solid->vel) - vel->y );

   speed = outfit_speed(o);

   /* Get the vector : shooter -> target */
   vect_cset( &relative_location, pos->x - VX(parent->solid->pos),
         pos->y - VY(parent->solid->pos) );

   /* Get the orthogonal vector */
   vect_cset(&orthoradial_vector, VY(parent->solid->pos) - pos->y,
         pos->x -  VX(parent->solid->pos) );

   radial_speed = vect_dot( &approach_vector, &relative_location );
   radial_speed = radial_speed / VMOD(relative_location);

   orthoradial_speed = vect_dot(&approach_vector, &orthoradial_vector);
   orthoradial_speed = orthoradial_speed / VMOD(relative_location);

   if( ((speed*speed - VMOD(approach_vector)*VMOD(approach_vector)) != 0) && (speed*speed - orthoradial_speed*orthoradial_speed) > 0)
      t = dist * (sqrt( speed*speed - orthoradial_speed*orthoradial_speed ) - radial_speed) /
            (speed*speed - VMOD(approach_vector)*VMOD(approach_vector));
   else
      return INFINITY;

   /* if t < 0, try the other solution */
   if (t < 0)
      t = - dist * (sqrt( speed*speed - orthoradial_speed*orthoradial_speed ) + radial_speed) /
            (speed*speed - VMOD(approach_vector)*VMOD(approach_vector));

   /* if t still < 0, no solution */
   if (t < 0)
      return INFINITY;

   return t;
}
コード例 #3
0
ファイル: pilot_outfit.c プロジェクト: kyleLesack/naev
/**
 * @brief Gets the mount position of a pilot.
 *
 * Position is relative to the pilot.
 *
 *    @param p Pilot to get mount position of.
 *    @param id ID of the mount.
 *    @param[out] v Position of the mount.
 *    @return 0 on success.
 */
int pilot_getMount( const Pilot *p, const PilotOutfitSlot *w, Vector2d *v )
{
   double a, x, y;
   double cm, sm;
   const ShipMount *m;

   /* Calculate the sprite angle. */
   a  = (double)(p->tsy * p->ship->gfx_space->sx + p->tsx);
   a *= p->ship->mangle;

   /* 2d rotation matrix
    * [ x' ]   [  cos  sin  ]   [ x ]
    * [ y' ] = [ -sin  cos  ] * [ y ]
    *
    * dir is inverted so that rotation is counter-clockwise.
    */
   m = &w->sslot->mount;
   cm = cos(-a);
   sm = sin(-a);
   x = m->x * cm + m->y * sm;
   y = m->x *-sm + m->y * cm;

   /* Correction for ortho perspective. */
   y *= M_SQRT1_2;

   /* Don't forget to add height. */
   y += m->h;

   /* Get the mount and add the player.p offset. */
   vect_cset( v, x, y );

   return 0;
}
コード例 #4
0
ファイル: nlua_vec2.c プロジェクト: Elderman/naev
/**
 * @brief Subtracts two vectors or a vector and some cartesian coordinates.
 *
 * If x is a vector it subtracts both vectors, otherwise it subtracts cartesian
 * coordinates to the vector.
 *
 * @usage my_vec = my_vec - your_vec
 * @usage my_vec:sub( your_vec )
 * @usage my_vec:sub( 5, 3 )
 *
 *    @luaparam v Vector getting stuff subtracted from.
 *    @luaparam x X coordinate or vector to subtract.
 *    @luaparam y Y coordinate or nil to subtract.
 *    @luareturn The result of the vector operation.
 * @luafunc sub( v, x, y )
 */
static int vectorL_sub( lua_State *L )
{
    LuaVector vout, *v1, *v2;
    double x, y;

    /* Get self. */
    v1    = luaL_checkvector(L,1);

    /* Get rest of parameters. */
    v2 = NULL;
    if (lua_isvector(L,2)) {
        v2 = lua_tovector(L,2);
        x = v2->vec.x;
        y = v2->vec.y;
    }
    else if ((lua_gettop(L) > 2) && lua_isnumber(L,2) && lua_isnumber(L,3)) {
        x = lua_tonumber(L,2);
        y = lua_tonumber(L,3);
    }
    else NLUA_INVALID_PARAMETER(L);

    /* Actually add it */
    vect_cset( &vout.vec, v1->vec.x - x, v1->vec.y - y );
    lua_pushvector( L, vout );
    return 1;
}
コード例 #5
0
ファイル: nlua_vec2.c プロジェクト: VetHockey/naev
static int vectorL_sub__( lua_State *L )
{
   Vector2d *v1, *v2;
   double x, y;

   /* Get self. */
   v1    = luaL_checkvector(L,1);

   /* Get rest of parameters. */
   v2 = NULL;
   if (lua_isvector(L,2)) {
      v2 = lua_tovector(L,2);
      x = v2->x;
      y = v2->y;
   }
   else if ((lua_gettop(L) > 2) && lua_isnumber(L,2) && lua_isnumber(L,3)) {
      x = lua_tonumber(L,2);
      y = lua_tonumber(L,3);
   }
   else {
      NLUA_INVALID_PARAMETER(L);
      return 0;
   }

   /* Actually add it */
   vect_cset( v1, v1->x - x, v1->y - y );
   lua_pushvector( L, *v1 );
   return 1;
}
コード例 #6
0
ファイル: player_autonav.c プロジェクト: nenau/naev
/**
 * @brief Starts autonav with a local position destination.
 */
void player_autonavPos( double x, double y )
{
   if (!player_autonavSetup())
      return;

   player.autonav    = AUTONAV_POS_APPROACH;
   player.autonavmsg = "position";
   vect_cset( &player.autonav_pos, x, y );
}
コード例 #7
0
ファイル: player_autonav.c プロジェクト: nenau/naev
/**
 * @brief Starts autonav with a planet destination.
 */
void player_autonavPnt( char *name )
{
   Planet *p;

   p = planet_get( name );
   if (!player_autonavSetup())
      return;

   player.autonav    = AUTONAV_PNT_APPROACH;
   player.autonavmsg = p->name;
   vect_cset( &player.autonav_pos, p->pos.x, p->pos.y );
}
コード例 #8
0
ファイル: nlua_vec2.c プロジェクト: Elderman/naev
/**
 * @brief Sets the vector by cartesian coordinates.
 *
 * @usage my_vec:set(5, 3) -- my_vec is now (5,3)
 *
 *    @luaparam v Vector to set coordinates of.
 *    @luaparam x X coordinate to set.
 *    @luaparam y Y coordinate to set.
 * @luafunc set( v, x, y )
 */
static int vectorL_set( lua_State *L )
{
    LuaVector *v1;
    double x, y;

    /* Get parameters. */
    v1 = luaL_checkvector(L,1);
    x  = luaL_checknumber(L,2);
    y  = luaL_checknumber(L,3);

    vect_cset( &v1->vec, x, y );
    return 0;
}
コード例 #9
0
ファイル: nlua_vec2.c プロジェクト: Elderman/naev
/**
 * @brief Divides a vector by a number.
 *
 * @usage my_vec = my_vec / 3
 * @usage my_vec:div(3)
 *
 *    @luaparam v Vector to divide.
 *    @luaparam mod Amount to divide by.
 *    @luareturn The result of the vector operation.
 * @luafunc div( v, mod )
 */
static int vectorL_div( lua_State *L )
{
    LuaVector vout, *v1;
    double mod;

    /* Get parameters. */
    v1    = luaL_checkvector(L,1);
    mod   = luaL_checknumber(L,2);

    /* Actually add it */
    vect_cset( &vout.vec, v1->vec.x / mod, v1->vec.y / mod );
    lua_pushvector( L, vout );
    return 1;
}
コード例 #10
0
ファイル: nlua_vec2.c プロジェクト: VetHockey/naev
static int vectorL_div__( lua_State *L )
{
   Vector2d *v1;
   double mod;

   /* Get parameters. */
   v1    = luaL_checkvector(L,1);
   mod   = luaL_checknumber(L,2);

   /* Actually add it */
   vect_cset( v1, v1->x / mod, v1->y / mod );
   lua_pushvector( L, *v1 );
   return 1;
}
コード例 #11
0
ファイル: nlua_vec2.c プロジェクト: VetHockey/naev
/**
 * @brief Multiplies a vector by a number.
 *
 * @usage my_vec = my_vec * 3
 * @usage my_vec:mul( 3 )
 *
 *    @luaparam v Vector to multiply.
 *    @luaparam mod Amount to multiply by.
 *    @luareturn The result of the vector operation.
 * @luafunc mul( v, mod )
 */
static int vectorL_mul( lua_State *L )
{
   Vector2d vout, *v1;
   double mod;

   /* Get parameters. */
   v1    = luaL_checkvector(L,1);
   mod   = luaL_checknumber(L,2);

   /* Actually add it */
   vect_cset( &vout, v1->x * mod, v1->y * mod );
   lua_pushvector( L, vout );
   return 1;
}
コード例 #12
0
ファイル: nlua_vec2.c プロジェクト: Elderman/naev
/**
 * @brief Creates a new vector.
 *
 * @usage vec2.new( 5, 3 ) -- creates a vector at (5,3)
 * @usage vec2.new() -- creates a vector at (0,0)
 *
 *    @luaparam x If set, the X value for the new vector.
 *    @luaparam y If set, the Y value for the new vector.
 *    @luareturn The new vector.
 * @luafunc new( x, y )
 */
static int vectorL_new( lua_State *L )
{
    LuaVector v;
    double x, y;

    if ((lua_gettop(L) > 1) && lua_isnumber(L,1) && lua_isnumber(L,2)) {
        x = lua_tonumber(L,1);
        y = lua_tonumber(L,2);
    }
    else {
        x = 0.;
        y = 0.;
    }

    vect_cset( &v.vec, x, y );
    lua_pushvector(L, v);
    return 1;
}
コード例 #13
0
ファイル: pilot_weapon.c プロジェクト: nenau/naev
/**
 * @brief Actually handles the shooting, how often the player.p can shoot and such.
 *
 *    @param p Pilot that is shooting.
 *    @param w Pilot's outfit to shoot.
 *    @param time Expected flight time.
 *    @return 0 if nothing was shot and 1 if something was shot.
 */
static int pilot_shootWeapon( Pilot* p, PilotOutfitSlot* w, double time )
{
   Vector2d vp, vv;
   double rate_mod, energy_mod;
   double energy;
   int j;

   /* Make sure weapon has outfit. */
   if (w->outfit == NULL)
      return 0;

   /* Reset beam shut-off if needed. */
   if (outfit_isBeam(w->outfit) && w->outfit->u.bem.min_duration)
      w->stimer = INFINITY;

   /* check to see if weapon is ready */
   if (w->timer > 0.)
      return 0;

   /* Calculate rate modifier. */
   pilot_getRateMod( &rate_mod, &energy_mod, p, w->outfit );

   /* Get weapon mount position. */
   pilot_getMount( p, w, &vp );
   vp.x += p->solid->pos.x;
   vp.y += p->solid->pos.y;

   /* Modify velocity to take into account the rotation. */
   vect_cset( &vv, p->solid->vel.x + vp.x*p->solid->dir_vel,
         p->solid->vel.y + vp.y*p->solid->dir_vel );

   /*
    * regular bolt weapons
    */
   if (outfit_isBolt(w->outfit)) {

      /* enough energy? */
      if (outfit_energy(w->outfit)*energy_mod > p->energy)
         return 0;

      energy      = outfit_energy(w->outfit)*energy_mod;
      p->energy  -= energy;
      pilot_heatAddSlot( p, w );
      weapon_add( w->outfit, w->heat_T, p->solid->dir,
            &vp, &p->solid->vel, p, p->target, time );
   }

   /*
    * Beam weapons.
    */
   else if (outfit_isBeam(w->outfit)) {
      /* Don't fire if the existing beam hasn't been destroyed yet. */
      if (w->u.beamid > 0)
         return 0;

      /* Check if enough energy to last a second. */
      if (outfit_energy(w->outfit)*energy_mod > p->energy)
         return 0;

      /** @todo Handle warmup stage. */
      w->state = PILOT_OUTFIT_ON;
      w->u.beamid = beam_start( w->outfit, p->solid->dir,
            &vp, &p->solid->vel, p, p->target, w );

      w->timer = w->outfit->u.bem.duration;

      return 1; /* Return early due to custom timer logic. */
   }

   /*
    * missile launchers
    *
    * must be a secondary weapon
    */
   else if (outfit_isLauncher(w->outfit)) {

      /* Shooter can't be the target - sanity check for the player.p */
      if ((w->outfit->u.lau.ammo->u.amm.ai != AMMO_AI_DUMB) && (p->id==p->target))
         return 0;

      /* Must have ammo left. */
      if ((w->u.ammo.outfit == NULL) || (w->u.ammo.quantity <= 0))
         return 0;

      /* enough energy? */
      if (outfit_energy(w->u.ammo.outfit)*energy_mod > p->energy)
         return 0;

      energy      = outfit_energy(w->u.ammo.outfit)*energy_mod;
      p->energy  -= energy;
      pilot_heatAddSlot( p, w );
      weapon_add( w->outfit, w->heat_T, p->solid->dir,
            &vp, &p->solid->vel, p, p->target, time );

      w->u.ammo.quantity -= 1; /* we just shot it */
      p->mass_outfit     -= w->u.ammo.outfit->mass;
      p->solid->mass     -= w->u.ammo.outfit->mass;

      pilot_updateMass( p );

      /* If last ammo was shot, update the range */
      if (w->u.ammo.quantity <= 0) {
         for (j=0; j<PILOT_WEAPON_SETS; j++)
            pilot_weapSetUpdateRange( &p->weapon_sets[j] );
      }
   }

   /*
    * Fighter bays.
    */
   else if (outfit_isFighterBay(w->outfit)) {

      /* Must have ammo left. */
      if ((w->u.ammo.outfit == NULL) || (w->u.ammo.quantity <= 0))
         return 0;

      /* Create the escort. */
      escort_create( p, w->u.ammo.outfit->u.fig.ship,
            &vp, &p->solid->vel, p->solid->dir, ESCORT_TYPE_BAY, 1 );

      w->u.ammo.quantity -= 1; /* we just shot it */
      p->mass_outfit     -= w->u.ammo.outfit->mass;
      w->u.ammo.deployed += 1; /* Mark as deployed. */
      pilot_updateMass( p );
   }
   else
      WARN(_("Shooting unknown weapon type: %s"), w->outfit->name);


   /* Reset timer. */
   w->timer += rate_mod * outfit_delay( w->outfit );

   return 1;
}
コード例 #14
0
ファイル: physics.c プロジェクト: Anatolis/naev
/**
 * @brief Runge-Kutta method of updating a solid based on its acceleration.
 *
 * Runge-Kutta 4 method
 *
 *   d^2 x(t) / d t^2 = a, a = constant (acceleration)
 *   x'(0) = v, x(0) = p
 *   x'' = f( t, x, x' ) = ( x' , a )
 *
 *   x_{n+1} = x_n + h/6 (k1 + 2*k2 + 3*k3 + k4)
 *    h = (b-a)/2
 *    k1 = f(t_n, X_n ), X_n = (x_n, x'_n)
 *    k2 = f(t_n + h/2, X_n + h/2*k1)
 *    k3 = f(t_n + h/2, X_n + h/2*k2)
 *    k4 = f(t_n + h, X_n + h*k3)
 *
 *   x_{n+1} = x_n + h/6*(6x'_n + 3*h*a, 4*a)
 *
 *
 * Main advantage comes thanks to the fact that Naev is on a 2d plane.
 *  Therefore RK chops it up in chunks and actually creates a tiny curve
 *  instead of approximating the curve for a tiny straight line.
 */
#define RK4_MIN_H 0.01 /**< Minimal pass we want. */
static void solid_update_rk4 (Solid *obj, const double dt)
{
   int i, N; /* for iteration, and pass calculation */
   double h, px,py, vx,vy; /* pass, and position/velocity values */
   double ix,iy, tx,ty, ax,ay, th; /* initial and temporary cartesian vector values */
   double vmod, vang;
   int vint;
   int limit; /* limit speed? */

   /* Initial positions and velocity. */
   px = obj->pos.x;
   py = obj->pos.y;
   vx = obj->vel.x;
   vy = obj->vel.y;
   limit = (obj->speed_max >= 0.);

   /* Initial RK parameters. */
   if (dt > RK4_MIN_H)
      N = (int)(dt / RK4_MIN_H);
   else
      N = 1;
   vmod = MOD( vx, vy );
   vint = (int) vmod/100.;
   if (N < vint)
      N = vint;
   h = dt / (double)N; /* step */

   /* Movement Quantity Theorem:  m*a = \sum f */
   th = obj->thrust  / obj->mass;

   for (i=0; i < N; i++) { /* iterations */

      /* Calculate acceleration for the frame. */
      ax = th*cos(obj->dir);
      ay = th*sin(obj->dir);

      /* Limit the speed. */
      if (limit) {
         vmod = MOD( vx, vy );
         if (vmod > obj->speed_max) {
            /* We limit by applying a force against it. */
            vang  = ANGLE( vx, vy ) + M_PI;
            vmod  = 3. * (vmod - obj->speed_max);

            /* Update accel. */
            ax += vmod * cos(vang);
            ay += vmod * sin(vang);
         }
      }

      /* x component */
      tx = ix = vx;
      tx += 2.*ix + h*tx;
      tx += 2.*ix + h*tx;
      tx += ix + h*tx;
      tx *= h/6.;

      px += tx;
      vx += ax * h;

      /* y component */
      ty = iy = vy;
      ty += 2.*(iy + h/2.*ty);
      ty += 2.*(iy + h/2.*ty);
      ty += iy + h*ty;
      ty *= h/6.;

      py += ty;
      vy += ay * h;

      /* rotation. */
      obj->dir += obj->dir_vel*h;
   }
   vect_cset( &obj->vel, vx, vy );
   vect_cset( &obj->pos, px, py );

   /* Sanity check. */
   if (obj->dir >= 2.*M_PI)
      obj->dir -= 2.*M_PI;
   else if (obj->dir < 0.)
      obj->dir += 2.*M_PI;
}
コード例 #15
0
ファイル: weapon.c プロジェクト: zid/naev
/**
 * @brief The AI of seeker missiles.
 *
 *    @param w Weapon to do the thinking.
 *    @param dt Current delta tick.
 */
static void think_seeker( Weapon* w, const double dt )
{
   double diff;
   double vel;
   Pilot *p;
   int effect;
   Vector2d v;
   double t;

   if (w->target == w->parent) return; /* no self shooting */

   p = pilot_get(w->target); /* no null pilot_nstack */
   if (p==NULL) {
      weapon_setThrust( w, 0. );
      weapon_setTurn( w, 0. );
      return;
   }

   /* Handle by status. */
   switch (w->status) {
      case WEAPON_STATUS_OK:
         if (w->lockon < 0.)
            w->status = WEAPON_STATUS_LOCKEDON;
         break;

      case WEAPON_STATUS_LOCKEDON: /* Check to see if can get jammed */
         if ((p->jam_range != 0.) &&  /* Target has jammer and weapon is in range */
               (vect_dist(&w->solid->pos,&p->solid->pos) < p->jam_range)) {

            /* Check to see if weapon gets jammed */
            if (RNGF() < p->jam_chance - w->outfit->u.amm.resist) {
               w->status = WEAPON_STATUS_JAMMED;
               /* Give it a nice random effect */
               effect = RNG(0,3);
               switch (effect) {
                  case 0: /* Stuck in left loop */
                     weapon_setTurn( w, w->outfit->u.amm.turn );
                     break;
                  case 1: /* Stuck in right loop */
                     weapon_setTurn( w, -w->outfit->u.amm.turn );
                     break;

                  default: /* Blow up. */
                     w->timer = -1.;
                     break;
               }
            }
            else /* Can't get jammed anymore */
               w->status = WEAPON_STATUS_UNJAMMED;
         }

      /* Purpose fallthrough */
      case WEAPON_STATUS_UNJAMMED: /* Work as expected */

         /* Smart seekers take into account ship velocity. */
         if (w->outfit->u.amm.ai == 2) {

            /* Calculate time to reach target. */
            vect_cset( &v, p->solid->pos.x - w->solid->pos.x,
                  p->solid->pos.y - w->solid->pos.y );
            t = vect_odist( &v ) / w->outfit->u.amm.speed;

            /* Calculate target's movement. */
            vect_cset( &v, v.x + t*(p->solid->vel.x - w->solid->vel.x),
                  v.y + t*(p->solid->vel.y - w->solid->vel.y) );

            /* Get the angle now. */
            diff = angle_diff(w->solid->dir, VANGLE(v) );
         }
         /* Other seekers are stupid. */
         else {
            diff = angle_diff(w->solid->dir, /* Get angle to target pos */
                  vect_angle(&w->solid->pos, &p->solid->pos));
         }

         /* Set turn. */
         weapon_setTurn( w, CLAMP( -w->outfit->u.amm.turn, w->outfit->u.amm.turn,
                  10 * diff * w->outfit->u.amm.turn ));
         break;

      case WEAPON_STATUS_JAMMED: /* Continue doing whatever */
         /* Do nothing, dir_vel should be set already if needed */
         break;

      default:
         WARN("Unknown weapon status for '%s'", w->outfit->name);
         break;
   }

   /* Limit speed here */
   vel = MIN(w->outfit->u.amm.speed, VMOD(w->solid->vel) + w->outfit->u.amm.thrust*dt);
   vect_pset( &w->solid->vel, vel, w->solid->dir );
   /*limit_speed( &w->solid->vel, w->outfit->u.amm.speed, dt );*/
}
コード例 #16
0
ファイル: pilot_weapon.c プロジェクト: Crockadavin/naev
/**
 * @brief Actually handles the shooting, how often the player.p can shoot and such.
 *
 *    @param p Pilot that is shooting.
 *    @param w Pilot's outfit to shoot.
 *    @return 0 if nothing was shot and 1 if something was shot.
 */
static int pilot_shootWeapon( Pilot* p, PilotOutfitSlot* w )
{
   Vector2d vp, vv;
   double rate_mod, energy_mod;
   double energy;

   /* Make sure weapon has outfit. */
   if (w->outfit == NULL)
      return 0;

   /* check to see if weapon is ready */
   if (w->timer > 0.)
      return 0;

   /* Calculate rate modifier. */
   pilot_getRateMod( &rate_mod, &energy_mod, p, w->outfit );

   /* Get weapon mount position. */
   pilot_getMount( p, w, &vp );
   vp.x += p->solid->pos.x;
   vp.y += p->solid->pos.y;

   /* Modify velocity to take into account the rotation. */
   vect_cset( &vv, p->solid->vel.x + vp.x*p->solid->dir_vel,
         p->solid->vel.y + vp.y*p->solid->dir_vel );

   /*
    * regular bolt weapons
    */
   if (outfit_isBolt(w->outfit)) {

      /* enough energy? */
      if (outfit_energy(w->outfit)*energy_mod > p->energy)
         return 0;

      energy      = outfit_energy(w->outfit)*energy_mod;
      p->energy  -= energy;
      pilot_heatAddSlot( p, w );
      weapon_add( w->outfit, w->heat_T, p->solid->dir,
            &vp, &p->solid->vel, p, p->target );
   }

   /*
    * Beam weapons.
    */
   else if (outfit_isBeam(w->outfit)) {

      /* Check if enough energy to last a second. */
      if (outfit_energy(w->outfit)*energy_mod > p->energy)
         return 0;

      /** @todo Handle warmup stage. */
      w->state = PILOT_OUTFIT_ON;
      w->u.beamid = beam_start( w->outfit, p->solid->dir,
            &vp, &p->solid->vel, p, p->target, w );
   }

   /*
    * missile launchers
    *
    * must be a secondary weapon
    */
   else if (outfit_isLauncher(w->outfit)) {

      /* Shooter can't be the target - sanity check for the player.p */
      if ((w->outfit->u.lau.ammo->u.amm.ai > 0) && (p->id==p->target))
         return 0;

      /* Must have ammo left. */
      if ((w->u.ammo.outfit == NULL) || (w->u.ammo.quantity <= 0))
         return 0;

      /* enough energy? */
      if (outfit_energy(w->u.ammo.outfit)*energy_mod > p->energy)
         return 0;

      energy      = outfit_energy(w->u.ammo.outfit)*energy_mod;
      p->energy  -= energy;
      pilot_heatAddSlot( p, w );
      weapon_add( w->outfit, w->heat_T, p->solid->dir,
            &vp, &p->solid->vel, p, p->target );

      w->u.ammo.quantity -= 1; /* we just shot it */
      p->mass_outfit     -= w->u.ammo.outfit->mass;
      pilot_updateMass( p );
   }

   /*
    * Fighter bays.
    */
   else if (outfit_isFighterBay(w->outfit)) {

      /* Must have ammo left. */
      if ((w->u.ammo.outfit == NULL) || (w->u.ammo.quantity <= 0))
         return 0;

      /* Create the escort. */
      escort_create( p, w->u.ammo.outfit->u.fig.ship,
            &vp, &p->solid->vel, p->solid->dir, ESCORT_TYPE_BAY, 1 );

      w->u.ammo.quantity -= 1; /* we just shot it */
      p->mass_outfit     -= w->u.ammo.outfit->mass;
      w->u.ammo.deployed += 1; /* Mark as deployed. */
      pilot_updateMass( p );
   }
   else
      WARN("Shooting unknown weapon type: %s", w->outfit->name);


   /* Reset timer. */
   w->timer += rate_mod * outfit_delay( w->outfit );

   return 1;
}