Beispiel #1
0
/**
 * @brief Checks to see if can equip/remove an outfit from a slot.
 *
 *    @param p Pilot to check if can equip.
 *    @param s Slot being checked to see if it can equip/remove an outfit.
 *    @param o Outfit to check (NULL if being removed).
 *    @return NULL if can swap, or error message if can't.
 */
const char* pilot_canEquip( Pilot *p, PilotOutfitSlot *s, Outfit *o )
{
    Outfit *o_old;
    const char *err;
    double pa, ps, pe, pf;

    /* Just in case. */
    if ((p==NULL) || (s==NULL))
        return "Nothing selected.";

    if (o!=NULL) {
        /* Check slot type. */
        if (!outfit_fitsSlot( o, &s->sslot->slot ))
            return "Does not fit slot.";
        /* Check outfit limit. */
        if ((o->limit != NULL) && pilot_hasOutfitLimit( p, o->limit ))
            return "Already have an outfit of this type installed";
    }
    else {
        /* Check fighter bay. */
        if ((o==NULL) && (s!=NULL) && (s->u.ammo.deployed > 0))
            return "Recall the fighters first";
    }

    /* Store health. */
    pa = p->armour;
    ps = p->shield;
    pe = p->energy;
    pf = p->fuel;

    /* Swap outfit. */
    o_old       = s->outfit;
    s->outfit   = o;

    /* Check sanity. */
    pilot_calcStats( p );
    /* can now equip outfit even if ship won't be spaceworthy
     * err = pilot_checkSpaceworthy( p );*/
    /* actually, this is also redundant */
    if (!pilot_slotsCheckSanity(p))
        err = "Does not fit in slot";
    else
        err = NULL;

    /* Swap back. */
    s->outfit   = o_old;

    /* Recalc. */
    pilot_calcStats( p );

    /* Recover health. */
    p->armour = pa;
    p->shield = ps;
    p->energy = pe;
    p->fuel   = pf;

    return err;
}
Beispiel #2
0
/**
 * @brief Have pilot stop shooting their weapon.
 *
 * Only really deals with beam weapons.
 *
 *    @param p Pilot that was shooting.
 *    @param level Level of the shot.
 */
void pilot_shootStop( Pilot* p, int level )
{
   int i, recalc;
   PilotWeaponSet *ws;
   PilotOutfitSlot *slot;

   /* Get active set. */
   ws = pilot_weapSet( p, p->active_set );

   /* Case no outfits. */
   if (ws->slots == NULL)
      return;

   /* Stop all beams. */
   recalc = 0;
   for (i=0; i<array_size(ws->slots); i++) {
      slot = ws->slots[i].slot;

      /* Must have associated outfit. */
      if (ws->slots[i].slot->outfit == NULL)
         continue;

      /* Must match level. */
      if ((level != -1) && (ws->slots[i].level != level))
         continue;

      /* Only handle beams. */
      if (!outfit_isBeam(slot->outfit)) {
         /* Turn off the state. */
         if (outfit_isMod( slot->outfit )) {
            slot->state = PILOT_OUTFIT_OFF;
            recalc = 1;
         }
         continue;
      }

      /* Stop beam. */
      if (ws->slots[i].slot->u.beamid > 0) {
         /* Enforce minimum duration if set. */
         if (slot->outfit->u.bem.min_duration > 0.) {

            slot->stimer = slot->outfit->u.bem.min_duration -
                  (slot->outfit->u.bem.duration - slot->timer);

            if (slot->stimer > 0.)
               continue;
         }

         beam_end( p->id, slot->u.beamid );
         pilot_stopBeam(p, slot);
      }
   }

   /* Must recalculate. */
   if (recalc)
      pilot_calcStats( p );
}
Beispiel #3
0
/**
 * @brief Deactivates the afterburner.
 */
void pilot_afterburnOver (Pilot *p)
{
   if (p == NULL)
      return;
   if (p->afterburner == NULL)
      return;

   if (p->afterburner->state == PILOT_OUTFIT_ON) {
      p->afterburner->state  = PILOT_OUTFIT_OFF;
      pilot_rmFlag(p,PILOT_AFTERBURNER);
      pilot_calcStats( p );

      /* @todo Make this part of a more dynamic activated outfit sound system. */
      sound_play(p->afterburner->outfit->u.afb.sound_off);
   }
}
Beispiel #4
0
/**
 * @brief Adds an outfit to the pilot.
 *
 *    @param pilot Pilot to add the outfit to.
 *    @param outfit Outfit to add to the pilot.
 *    @param s Slot to add ammo to.
 *    @return 0 on success.
 */
int pilot_addOutfit( Pilot* pilot, Outfit* outfit, PilotOutfitSlot *s )
{
   int ret;

   /* Test to see if outfit can be added. */
   ret = pilot_addOutfitTest( pilot, outfit, s, 1 );
   if (ret != 0)
      return -1;

   /* Add outfit. */
   ret = pilot_addOutfitRaw( pilot, outfit, s );

   /* Recalculate the stats */
   pilot_calcStats(pilot);

   return ret;
}
Beispiel #5
0
/**
 * @brief Removes an outfit from the pilot.
 *
 *    @param pilot Pilot to remove the outfit from.
 *    @param s Slot to remove.
 *    @return 0 on success.
 */
int pilot_rmOutfit( Pilot* pilot, PilotOutfitSlot *s )
{
   const char *str;
   int ret;

   str = pilot_canEquip( pilot, s, NULL );
   if (str != NULL) {
      WARN("Pilot '%s': Trying to remove outfit but %s",
            pilot->name, str );
      return -1;
   }

   ret = pilot_rmOutfitRaw( pilot, s );

   /* recalculate the stats */
   pilot_calcStats(pilot);

   return ret;
}
Beispiel #6
0
/**
 * @brief Activate the afterburner.
 */
void pilot_afterburn (Pilot *p)
{
   double afb_mod;

   if (p == NULL)
      return;

   if (pilot_isFlag(p, PILOT_HYP_PREP) || pilot_isFlag(p, PILOT_HYPERSPACE) ||
         pilot_isFlag(p, PILOT_LANDING) || pilot_isFlag(p, PILOT_TAKEOFF) ||
         pilot_isDisabled(p) || pilot_isFlag(p, PILOT_COOLDOWN))
      return;

   /* Not under manual control if is player. */
   if (pilot_isFlag( p, PILOT_MANUAL_CONTROL ) && pilot_isFlag( p, PILOT_PLAYER ))
      return;

   /** @todo fancy effect? */
   if (p->afterburner == NULL)
      return;

   /* The afterburner only works if its efficiency is high enough. */
   if (pilot_heatEfficiencyMod( p->afterburner->heat_T,
         p->afterburner->outfit->u.afb.heat_base,
         p->afterburner->outfit->u.afb.heat_cap ) < 0.3)
      return;

   if (p->afterburner->state == PILOT_OUTFIT_OFF) {
      p->afterburner->state  = PILOT_OUTFIT_ON;
      p->afterburner->stimer = outfit_duration( p->afterburner->outfit );
      pilot_setFlag(p,PILOT_AFTERBURNER);
      pilot_calcStats( p );

      /* @todo Make this part of a more dynamic activated outfit sound system. */
      sound_playPos(p->afterburner->outfit->u.afb.sound_on,
            p->solid->pos.x, p->solid->pos.y, p->solid->vel.x, p->solid->vel.y);
   }

   if (pilot_isPlayer(p)) {
      afb_mod = MIN( 1., player.p->afterburner->outfit->u.afb.mass_limit / player.p->solid->mass );
      spfx_shake( afb_mod * player.p->afterburner->outfit->u.afb.rumble * SHAKE_MAX );
   }
}
Beispiel #7
0
/**
 * @brief Handles a weapon set press.
 *
 *    @param p Pilot the weapon set belongs to.
 *    @param id ID of the weapon set.
 *    @param type Is +1 if it's a press or -1 if it's a release.
 */
void pilot_weapSetPress( Pilot* p, int id, int type )
{
   int i, l, on, n;
   PilotWeaponSet *ws;

   ws = pilot_weapSet(p,id);
   /* Case no outfits. */
   if (ws->slots == NULL)
      return;

   /* Handle fire groups. */
   switch (ws->type) {
      case WEAPSET_TYPE_CHANGE:
         /* On press just change active weapon set to whatever is available. */
         if (type > 0) {
            if (id != p->active_set)
               pilot_weapSetUpdateOutfits( p, ws );
            p->active_set = id;
         }
         break;

      case WEAPSET_TYPE_WEAPON:
         /* Activation philosophy here is to turn on while pressed and off
          * when it's not held anymore. */
         if (type > 0)
            ws->active = 1;
         else if (type < 0)
            ws->active = 0;
         break;

      case WEAPSET_TYPE_ACTIVE:
         /* The behaviour here is more complex. What we do is consider a group
          * to be entirely off if not all outfits are either on or cooling down.
          * In the case it's deemed to be off, all outfits that are off get turned
          * on, otherwise all outfits that are on are turrned to cooling down. */
         /* Only care about presses. */
         if (type < 0)
            break;

         /* Must not be disabled or cooling down. */
         if ((pilot_isDisabled(p)) || (pilot_isFlag(p, PILOT_COOLDOWN)))
            return;

         /* Decide what to do. */
         on = 1;
         l  = array_size(ws->slots);
         for (i=0; i<l; i++) {
            if (ws->slots[i].slot->state == PILOT_OUTFIT_OFF) {
               on = 0;
               break;
            }
         }

         /* Turn them off. */
         n = 0;
         if (on) {
            for (i=0; i<l; i++) {
               if (ws->slots[i].slot->state != PILOT_OUTFIT_ON)
                  continue;

               n += pilot_outfitOff( p, ws->slots[i].slot );
            }
         }
         /* Turn them on. */
         else {
            for (i=0; i<l; i++) {
               if (ws->slots[i].slot->state != PILOT_OUTFIT_OFF)
                  continue;
               if (outfit_isAfterburner(ws->slots[i].slot->outfit))
                  pilot_afterburn( p );
               else {
                  ws->slots[i].slot->state  = PILOT_OUTFIT_ON;
                  ws->slots[i].slot->stimer = outfit_duration( ws->slots[i].slot->outfit );
               }
               n++;
            }
         }
         /* Must recalculate stats. */
         if (n > 0)
            pilot_calcStats( p );

         break;
   }
}