]> git.pond.sub.org Git - empserver/blobdiff - src/lib/subs/mission.c
Update copyright notice
[empserver] / src / lib / subs / mission.c
index e3d78f8c7d0a75a1479d807f5dfefea327d65a09..04685dd0421b20d8b67793669e6b342e5387a58a 100644 (file)
@@ -1,11 +1,11 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2008, Dave Pare, Jeff Bailey, Thomas Ruschak,
- *                           Ken Stevens, Steve McClure
+ *  Copyright (C) 1986-2013, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *                Ken Stevens, Steve McClure, Markus Armbruster
  *
- *  This program is free software; you can redistribute it and/or modify
+ *  Empire is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
+ *  the Free Software Foundation, either version 3 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  *  ---
  *
@@ -30,6 +29,7 @@
  *  Known contributors to this file:
  *     Ken Stevens, 1995
  *     Steve McClure, 1996-2000
+ *     Markus Armbruster, 2003-2012
  */
 
 #include <config.h>
 #include "item.h"
 #include "misc.h"
 #include "mission.h"
+#include "news.h"
 #include "nsc.h"
 #include "optlist.h"
 #include "path.h"
-#include "player.h"
+#include "plague.h"
 #include "prototypes.h"
 #include "queue.h"
 #include "xy.h"
 
 struct genlist {
     struct emp_qelem queue;    /* list of units */
-    void *cp;                  /* pointer to desc of thing */
     struct empobj *thing;      /* thing's struct */
 };
 
@@ -63,17 +63,33 @@ struct airport {
 static void add_airport(struct emp_qelem *, coord, coord);
 static int air_damage(struct emp_qelem *, coord, coord, int, natid,
                      char *, int);
-static void build_mission_list(struct genlist *, coord, coord, int, natid);
-static void build_mission_list_type(struct genlist *, coord, coord, int,
-                                   int, natid);
+static void build_mission_list(struct genlist[],
+                              unsigned char[], unsigned char[],
+                              coord, coord, int);
+static void build_mission_list_type(struct genlist[], unsigned char[],
+                                   coord, coord, int, int);
 static void divide(struct emp_qelem *, struct emp_qelem *, coord, coord);
-static int dosupport(struct genlist *, coord, coord, natid, natid);
+static int dosupport(coord, coord, natid, natid, int);
 static int find_airport(struct emp_qelem *, coord, coord);
 static void mission_pln_arm(struct emp_qelem *, coord, coord, int,
-                           int, struct ichrstr *, int);
+                           int, struct ichrstr *);
 static void mission_pln_sel(struct emp_qelem *, int, int, int);
-static int perform_mission(coord, coord, natid, struct emp_qelem *, int,
-                          char *, int);
+static int perform_mission_land(int, struct lndstr *, coord, coord,
+                               natid, int, char *, int);
+static int perform_mission_ship(int, struct shpstr *, coord, coord,
+                               natid, int, char *, int);
+static int perform_mission_msl(int, struct emp_qelem *, coord, coord,
+                              natid, int);
+static int perform_mission_bomb(int, struct emp_qelem *, coord, coord,
+                               natid, int, char *, int, int);
+static int perform_mission(coord, coord, natid, struct emp_qelem *,
+                          int, char *, int);
+
+static int
+tally_dam(int dam, int newdam)
+{
+    return dam < 0 ? newdam : dam + newdam;
+}
 
 /*
  * Interdict commodities & transported planes
@@ -82,30 +98,30 @@ int
 ground_interdict(coord x, coord y, natid victim, char *s)
 {
     int cn;
-    int dam = 0, newdam, rel;
+    int dam = 0, newdam;
+    unsigned char act[MAXNOC];
     struct genlist mi[MAXNOC];
-    int z;
 
     memset(mi, 0, sizeof(mi));
-    for (z = 1; z < MAXNOC; z++)
-       emp_initque((struct emp_qelem *)&mi[z]);
+    act[0] = 0;
+    for (cn = 1; cn < MAXNOC; cn++) {
+       act[cn] = relations_with(cn, victim) <= HOSTILE;
+       emp_initque((struct emp_qelem *)&mi[cn]);
+    }
 
-    build_mission_list(mi, x, y, MI_INTERDICT, victim);
+    build_mission_list(mi, act, act, x, y, MI_INTERDICT);
 
     for (cn = 1; cn < MAXNOC; cn++) {
-       rel = getrel(getnatp(cn), victim);
-       if (rel > HOSTILE)
-           continue;
-
        if (QEMPTY(&mi[cn].queue))
            continue;
 
        newdam = perform_mission(x, y, victim, &mi[cn].queue,
                                 MI_INTERDICT, s, SECT_HARDTARGET);
-       dam += newdam;
-       if (newdam)
+       if (newdam > 0) {
+           dam += newdam;
            mpr(victim, "%s interdiction mission does %d damage!\n",
                cname(cn), newdam);
+       }
     }
     if (dam) {
        collateral_damage(x, y, dam);
@@ -141,15 +157,13 @@ only_subs(struct emp_qelem *list)
 {
     struct emp_qelem *qp;
     struct genlist *glp;
-    struct mchrstr *mcp;
 
     for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
        glp = (struct genlist *)qp;
 
        if (glp->thing->ef_type != EF_SHIP)
            return 0;
-       mcp = glp->cp;
-       if (!(mcp->m_flags & M_SUB))
+       if (!(mchr[glp->thing->type].m_flags & M_SUB))
            return 0;
        /* It's a sub! */
     }
@@ -165,44 +179,37 @@ int
 unit_interdict(coord x, coord y, natid victim, char *s, int hardtarget,
               int mission)
 {
-    int cn;
-    int dam = 0, newdam;
+    int cn, rel, newdam, osubs;
+    int dam = -1;
+    unsigned char plane_act[MAXNOC], other_act[MAXNOC];
     struct genlist mi[MAXNOC];
-    int z;
-    int osubs;
 
     memset(mi, 0, sizeof(mi));
-    for (z = 1; z < MAXNOC; z++)
-       emp_initque((struct emp_qelem *)&mi[z]);
+    other_act[0] = plane_act[0] = 0;
+    for (cn = 1; cn < MAXNOC; cn++) {
+       rel = relations_with(cn, victim);
+       other_act[cn] = rel <= HOSTILE;
+       plane_act[cn] = mission == MI_SINTERDICT
+           ? rel <= NEUTRAL : other_act[cn];
+       emp_initque((struct emp_qelem *)&mi[cn]);
+    }
 
-    build_mission_list(mi, x, y, mission, victim);
+    build_mission_list(mi, other_act, plane_act, x, y, mission);
 
     for (cn = 1; cn < MAXNOC; cn++) {
-       if (cn == victim)
-           continue;
-       if (mission == MI_SINTERDICT) {
-           if (getrel(getnatp(cn), victim) >= FRIENDLY)
-               continue;
-       } else if (getrel(getnatp(cn), victim) > HOSTILE)
-           continue;
-
        if (QEMPTY(&mi[cn].queue))
            continue;
 
        osubs = only_subs(&mi[cn].queue);
        newdam = perform_mission(x, y, victim, &mi[cn].queue,
                                 mission, s, hardtarget);
-       dam += newdam;
-       if (newdam) {
-           /* If only subs responded, then we don't know who's
-              subs they are */
+       dam = tally_dam(dam, newdam);
+       if (newdam > 0)
            mpr(victim, "%s interdiction mission does %d damage!\n",
                osubs ? "Enemy" : cname(cn), newdam);
-       }
     }
-    if (dam) {
+    if (dam > 0)
        collateral_damage(x, y, dam);
-    }
     return dam;
 }
 
@@ -212,19 +219,7 @@ unit_interdict(coord x, coord y, natid victim, char *s, int hardtarget,
 int
 off_support(coord x, coord y, natid victim, natid actee)
 {
-    int dam = 0;
-    struct genlist mi[MAXNOC];
-    int z;
-
-    memset(mi, 0, sizeof(mi));
-    for (z = 1; z < MAXNOC; z++)
-       emp_initque((struct emp_qelem *)&mi[z]);
-
-    build_mission_list(mi, x, y, MI_SUPPORT, victim);
-    build_mission_list(mi, x, y, MI_OSUPPORT, victim);
-
-    dam = dosupport(mi, x, y, victim, actee);
-    return dam;
+    return dosupport(x, y, victim, actee, MI_OSUPPORT);
 }
 
 /*
@@ -233,70 +228,69 @@ off_support(coord x, coord y, natid victim, natid actee)
 int
 def_support(coord x, coord y, natid victim, natid actee)
 {
-    int dam = 0;
-    struct genlist mi[MAXNOC];
-    int z;
-
-    memset(mi, 0, sizeof(mi));
-    for (z = 1; z < MAXNOC; z++)
-       emp_initque((struct emp_qelem *)&mi[z]);
-
-    build_mission_list(mi, x, y, MI_SUPPORT, victim);
-    build_mission_list(mi, x, y, MI_DSUPPORT, victim);
-
-    dam = dosupport(mi, x, y, victim, actee);
-    return dam;
+    return dosupport(x, y, victim, actee, MI_DSUPPORT);
 }
 
+/*
+ * Perform support missions in X,Y against VICTIM for ACTEE.
+ * MISSION is either MI_OSUPPORT or MI_DSUPPORT.
+ * Return total damage.
+ */
 static int
-dosupport(struct genlist *mi, coord x, coord y, natid victim, natid actee)
+dosupport(coord x, coord y, natid victim, natid actee, int mission)
 {
     int cn;
-    int rel;
+    unsigned char act[MAXNOC];
+    struct genlist mi[MAXNOC];
+    int newdam;
     int dam = 0;
 
+    memset(mi, 0, sizeof(mi));
+    act[0] = 0;
     for (cn = 1; cn < MAXNOC; cn++) {
-       rel = getrel(getnatp(cn), actee);
-       if ((cn != actee) && (rel != ALLIED))
-           continue;
-       rel = getrel(getnatp(cn), victim);
-       if ((cn != actee) && (rel != AT_WAR))
-           continue;
+       act[cn] = feels_like_helping(cn, actee, victim);
+       emp_initque((struct emp_qelem *)&mi[cn]);
+    }
+
+    build_mission_list(mi, act, act, x, y, MI_SUPPORT);
+    build_mission_list(mi, act, act, x, y, mission);
 
+    for (cn = 1; cn < MAXNOC; cn++) {
        if (QEMPTY(&mi[cn].queue))
            continue;
 
-       dam += perform_mission(x, y, victim, &mi[cn].queue, MI_SUPPORT,
-                              "", SECT_HARDTARGET);
+       newdam = perform_mission(x, y, victim, &mi[cn].queue, MI_SUPPORT,
+                                "", SECT_HARDTARGET);
+       if (newdam > 0)
+           dam += newdam;
     }
     return dam;
 }
 
 static void
-build_mission_list(struct genlist *mi, coord x, coord y, int mission,
-                  natid victim)
+build_mission_list(struct genlist mi[],
+                  unsigned char other_act[], unsigned char plane_act[],
+                  coord x, coord y, int mission)
 {
-    build_mission_list_type(mi, x, y, mission, EF_LAND, victim);
-    build_mission_list_type(mi, x, y, mission, EF_SHIP, victim);
-    build_mission_list_type(mi, x, y, mission, EF_PLANE, victim);
+    build_mission_list_type(mi, other_act, x, y, mission, EF_LAND);
+    build_mission_list_type(mi, other_act, x, y, mission, EF_SHIP);
+    build_mission_list_type(mi, plane_act, x, y, mission, EF_PLANE);
 }
 
 static void
-build_mission_list_type(struct genlist *mi, coord x, coord y, int mission,
-                       int type, natid victim)
+build_mission_list_type(struct genlist mi[], unsigned char act[],
+                       coord x, coord y, int mission, int type)
 {
     struct nstr_item ni;
     struct genlist *glp;
     struct empobj *gp;
     union empobj_storage item;
-    int relat;
-    struct sctstr sect;
 
     snxtitem_all(&ni, type);
     while (nxtitem(&ni, &item)) {
        gp = (struct empobj *)&item;
 
-       if (gp->own == 0)
+       if (!act[gp->own])
            continue;
 
        if (gp->mobil < 1)
@@ -309,40 +303,11 @@ build_mission_list_type(struct genlist *mi, coord x, coord y, int mission,
            (gp->mission != MI_INTERDICT))
            continue;
 
-       relat = getrel(getnatp(gp->own), victim);
-       if (mission == MI_SINTERDICT) {
-           if (relat >= FRIENDLY)
-               continue;
-           else if (type != EF_PLANE && relat > HOSTILE)
-               continue;
-       } else if (relat > HOSTILE)
-           continue;
-
        if (!in_oparea(gp, x, y))
            continue;
 
-       if (opt_SLOW_WAR) {
-           if (mission != MI_AIR_DEFENSE) {
-               getsect(x, y, &sect);
-               if (getrel(getnatp(gp->own), sect.sct_own) > AT_WAR) {
-
-                   /*
-                    * If the owner of the unit isn't at war
-                    * with the victim, and doesn't own the
-                    * sect being acted upon, and isn't the
-                    * old owner of that sect, bounce them.
-                    */
-                   if (sect.sct_type != SCT_WATER &&
-                       sect.sct_own != gp->own &&
-                       sect.sct_oldown != gp->own)
-                       continue;
-               }
-           }
-       }
-
        glp = malloc(sizeof(struct genlist));
        memset(glp, 0, sizeof(struct genlist));
-       glp->cp = get_empobj_chr(gp);
        glp->thing = malloc(sizeof(item));
        memcpy(glp->thing, &item, sizeof(item));
        emp_insque(&glp->queue, &mi[gp->own].queue);
@@ -365,7 +330,8 @@ find_escorts(coord x, coord y, natid cn, struct emp_qelem *escorts)
        if (!in_oparea((struct empobj *)&plane, x, y))
            continue;
        plp = malloc(sizeof(struct plist));
-       memset(plp, 0, sizeof(struct plist));
+       plp->load = 0;
+       plp->pstage = PLG_HEALTHY;
        plp->pcp = &plchr[(int)plane.pln_type];
        plp->plane = plane;
        emp_insque(&plp->queue, escorts);
@@ -376,201 +342,256 @@ static int
 perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
                int mission, char *s, int hardtarget)
 {
-    struct emp_qelem *qp, missiles, bombers, escorts, airp, b, e;
-    struct emp_qelem *newqp;
+    struct emp_qelem *qp, missiles, bombers;
     struct genlist *glp;
     struct plist *plp;
-    struct empobj *gp;
-    struct lndstr *lp;
-    struct shpstr *sp;
-    struct sctstr sect;
-    struct mchrstr *mcp;
     struct plchrstr *pcp;
-    int dam = 0, dam2;
-    natid plane_owner = 0;
-    int md, range, air_dam = 0;
-    double hitchance, vrange;
+    int dam = -1;
     int targeting_ships = *s == 's'; /* "subs" or "ships" FIXME gross! */
 
-    getsect(x, y, &sect);
-
     emp_initque(&missiles);
     emp_initque(&bombers);
-    emp_initque(&escorts);
-    emp_initque(&airp);
 
-    for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
+    for (qp = list->q_forw; qp != list; ) {
        glp = (struct genlist *)qp;
-       gp = glp->thing;
-
-       md = mapdist(x, y, gp->x, gp->y);
+       qp = qp->q_forw;
 
        if (glp->thing->ef_type == EF_LAND) {
-           lp = (struct lndstr *)glp->thing;
+           dam = perform_mission_land(dam, (struct lndstr *)glp->thing,
+                                      x, y, victim, mission, s,
+                                      targeting_ships);
+       } else if (glp->thing->ef_type == EF_SHIP) {
+           dam = perform_mission_ship(dam, (struct shpstr *)glp->thing,
+                                      x, y, victim, mission, s,
+                                      targeting_ships);
+       } else if (glp->thing->ef_type == EF_PLANE) {
+           pcp = &plchr[glp->thing->type];
+           if ((pcp->pl_flags & P_M)
+               && (hardtarget != SECT_HARDTARGET
+                   || (pcp->pl_flags & P_MAR)))
+               ;      /* units have their own missile interdiction */
+           else {
+               /* save planes for later */
+               plp = malloc(sizeof(struct plist));
+               plp->load = 0;
+               plp->pstage = PLG_HEALTHY;
+               plp->pcp = pcp;
+               memcpy(&plp->plane, glp->thing, sizeof(struct plnstr));
+               if (plp->pcp->pl_flags & P_M)
+                   emp_insque(&plp->queue, &missiles);
+               else
+                   emp_insque(&plp->queue, &bombers);
+           }
+       } else {
+           CANT_REACH();
+           break;
+       }
+       free(glp->thing);
+       free(glp);
+    }
 
-           if (mission == MI_SINTERDICT)
-               continue;
+    dam = perform_mission_msl(dam, &missiles, x, y, victim, hardtarget);
+    dam = perform_mission_bomb(dam, &bombers, x, y, victim, mission, s,
+                              hardtarget, targeting_ships);
+    return dam;
+}
 
-           if ((mission == MI_INTERDICT) &&
-               (md > land_max_interdiction_range))
-               continue;
+static int
+perform_mission_land(int dam, struct lndstr *lp, coord x, coord y,
+                    natid victim, int mission, char *s,
+                    int targeting_ships)
+{
+    int md, range, dam2;
 
-           range = roundrange(lnd_fire_range(lp));
-           if (md > range)
-               continue;
+    if (mission == MI_SINTERDICT)
+       return dam;
 
-           dam2 = lnd_fire(lp);
-           putland(lp->lnd_uid, lp);
-           if (dam2 < 0)
-               continue;
+    md = mapdist(x, y, lp->lnd_x, lp->lnd_y);
 
-           if (targeting_ships) {
-               if (chance(lnd_acc(lp) / 100.0))
-                   dam2 = ldround(dam2 / 2.0, 1);
-           }
-           dam += dam2;
-           if (targeting_ships)
-               nreport(lp->lnd_own, N_SHP_SHELL, victim, 1);
-           else
-               nreport(lp->lnd_own, N_SCT_SHELL, victim, 1);
-           wu(0, lp->lnd_own,
-              "%s fires at %s %s at %s\n",
-              prland(lp), cname(victim), s, xyas(x, y, lp->lnd_own));
+    if (mission == MI_INTERDICT && md > land_max_interdiction_range)
+       return dam;
 
-           mpr(victim, "%s %s fires at you at %s\n",
-               cname(lp->lnd_own), prland(lp), xyas(x, y, victim));
-       } else if (glp->thing->ef_type == EF_SHIP) {
-           sp = (struct shpstr *)glp->thing;
-           mcp = glp->cp;
+    range = roundrange(lnd_fire_range(lp));
+    if (md > range)
+       return dam;
 
-           if (((mission == MI_INTERDICT) ||
-                (mission == MI_SINTERDICT)) &&
-               (md > ship_max_interdiction_range))
-               continue;
-           if (mission == MI_SINTERDICT) {
-               if (!(mcp->m_flags & M_SONAR))
-                   continue;
-               if (!(mcp->m_flags & M_DCH) && !(mcp->m_flags & M_SUBT))
-                   continue;
-               vrange = techfact(sp->shp_tech, mcp->m_vrnge);
-               vrange *= sp->shp_effic / 200.0;
-               if (md > vrange)
-                   continue;
-               /* can't look all the time */
-               if (chance(0.5))
-                   continue;
-           }
-           if (mcp->m_flags & M_SUB) {
-               if (!targeting_ships)
-                   continue;   /* subs interdict only ships */
-               range = roundrange(torprange(sp));
-               if (md > range)
-                   continue;
-               if (!line_of_sight(NULL, x, y, gp->x, gp->y))
-                   continue;
-               dam2 = shp_torp(sp, 1);
-               putship(sp->shp_uid, sp);
-               if (dam2 < 0)
-                   continue;
-               hitchance = shp_torp_hitchance(sp, md);
-
-               wu(0, sp->shp_own,
-                  "%s locking on %s %s in %s\n",
-                  prship(sp), cname(victim), s, xyas(x, y, sp->shp_own));
-               wu(0, sp->shp_own,
-                  "\tEffective torpedo range is %d.0\n", range);
-               wu(0, sp->shp_own,
-                  "\tWhooosh... Hitchance = %d%%\n",
-                  (int)(hitchance * 100));
-
-               if (!chance(hitchance)) {
-                   wu(0, sp->shp_own, "\tMissed\n");
-                   mpr(victim,
-                       "Incoming torpedo sighted @ %s missed (whew)!\n",
-                       xyas(x, y, victim));
-                   continue;
-               }
-               wu(0, sp->shp_own, "\tBOOM!...\n");
-               dam += dam2;
-               nreport(victim, N_TORP_SHIP, 0, 1);
-               wu(0, sp->shp_own,
-                  "\tTorpedo hit %s %s for %d damage\n",
-                  cname(victim), s, dam2);
+    dam2 = lnd_fire(lp);
+    putland(lp->lnd_uid, lp);
+    if (dam2 < 0)
+       return dam;
 
-               mpr(victim,
-                   "Incoming torpedo sighted @ %s hits and does %d damage!\n",
-                   xyas(x, y, victim), dam2);
-           } else {
-               range = roundrange(shp_fire_range(sp));
-               if (md > range)
-                   continue;
-               if (mission == MI_SINTERDICT)
-                   dam2 = shp_dchrg(sp);
-               else
-                   dam2 = shp_fire(sp);
-               putship(sp->shp_uid, sp);
-               if (dam2 < 0)
-                   continue;
-               dam += dam2;
-               if (targeting_ships)
-                   nreport(sp->shp_own, N_SHP_SHELL, victim, 1);
-               else
-                   nreport(sp->shp_own, N_SCT_SHELL, victim, 1);
-               wu(0, sp->shp_own,
-                  "%s fires at %s %s at %s\n",
-                  prship(sp), cname(victim), s, xyas(x, y, sp->shp_own));
+    if (targeting_ships) {
+       if (chance(lnd_acc(lp) / 100.0))
+           dam2 = ldround(dam2 / 2.0, 1);
+    }
+    if (targeting_ships)
+       nreport(lp->lnd_own, N_SHP_SHELL, victim, 1);
+    else
+       nreport(lp->lnd_own, N_SCT_SHELL, victim, 1);
+    wu(0, lp->lnd_own,
+       "%s fires at %s %s at %s\n",
+       prland(lp), cname(victim), s, xyas(x, y, lp->lnd_own));
 
-               mpr(victim, "%s %s fires at you at %s\n",
-                   cname(sp->shp_own), prship(sp), xyas(x, y, victim));
-           }
-       } else if (glp->thing->ef_type == EF_PLANE) {
-           pcp = glp->cp;
-           if (pcp->pl_flags & P_M)
-               /* units have their own missile interdiction */
-               if (hardtarget != SECT_HARDTARGET || pcp->pl_flags & P_MAR)
-                   continue;
-
-           /* save planes for later */
-           plp = malloc(sizeof(struct plist));
-
-           memset(plp, 0, sizeof(struct plist));
-           plp->pcp = pcp;
-           memcpy(&plp->plane, glp->thing, sizeof(struct plnstr));
-           if (plp->pcp->pl_flags & P_M)
-               emp_insque(&plp->queue, &missiles);
-           else
-               emp_insque(&plp->queue, &bombers);
-           plane_owner = plp->plane.pln_own;
-       } else {
-           CANT_REACH();
-           break;
-       }
+    mpr(victim, "%s %s fires at you at %s\n",
+       cname(lp->lnd_own), prland(lp), xyas(x, y, victim));
+
+    return tally_dam(dam, dam2);
+}
+
+static int
+perform_mission_ship(int dam, struct shpstr *sp, coord x, coord y,
+                    natid victim, int mission, char *s,
+                    int targeting_ships)
+{
+    struct mchrstr *mcp = &mchr[sp->shp_type];
+    double vrange, hitchance;
+    int md, range, dam2;
+
+    md = mapdist(x, y, sp->shp_x, sp->shp_y);
+
+    if ((mission == MI_INTERDICT || mission == MI_SINTERDICT)
+       && md > ship_max_interdiction_range)
+       return dam;
+
+    if (mission == MI_SINTERDICT) {
+       if (!(mcp->m_flags & M_SONAR))
+           return dam;
+       if (!(mcp->m_flags & M_DCH) && !(mcp->m_flags & M_SUBT))
+           return dam;
+       vrange = techfact(sp->shp_tech, mcp->m_vrnge);
+       vrange *= sp->shp_effic / 200.0;
+       if (md > vrange)
+           return dam;
+       /* can't look all the time */
+       if (chance(0.5))
+           return dam;
     }
-    if (!QEMPTY(&missiles)) {
-       /* I arbitrarily chose 100 mindam -KHS */
-       dam +=
-           msl_launch_mindam(&missiles, x, y, hardtarget, EF_SECTOR, 100,
-                             "sector", victim, mission);
-       qp = missiles.q_forw;
-       while (qp != (&missiles)) {
-           newqp = qp->q_forw;
-           emp_remque(qp);
-           free(qp);
-           qp = newqp;
+    if (mcp->m_flags & M_SUB) {
+       if (!targeting_ships)
+           return dam;         /* subs interdict only ships */
+       range = roundrange(torprange(sp));
+       if (md > range)
+           return dam;
+       if (!line_of_sight(NULL, x, y, sp->shp_x, sp->shp_y))
+           return dam;
+       dam2 = shp_torp(sp, 1);
+       putship(sp->shp_uid, sp);
+       if (dam2 < 0)
+           return dam;
+       hitchance = shp_torp_hitchance(sp, md);
+
+       wu(0, sp->shp_own,
+          "%s locking on %s %s in %s\n",
+          prship(sp), cname(victim), s, xyas(x, y, sp->shp_own));
+       wu(0, sp->shp_own,
+          "\tEffective torpedo range is %d.0\n", range);
+       wu(0, sp->shp_own,
+          "\tWhooosh... Hitchance = %d%%\n",
+          (int)(hitchance * 100));
+
+       if (!chance(hitchance)) {
+           wu(0, sp->shp_own, "\tMissed\n");
+           mpr(victim,
+               "Incoming torpedo sighted @ %s missed (whew)!\n",
+               xyas(x, y, victim));
+           return tally_dam(dam, 0);
        }
+       wu(0, sp->shp_own, "\tBOOM!...\n");
+       nreport(victim, N_TORP_SHIP, 0, 1);
+       wu(0, sp->shp_own,
+          "\tTorpedo hit %s %s for %d damage\n",
+          cname(victim), s, dam2);
+
+       mpr(victim,
+           "Incoming torpedo sighted @ %s hits and does %d damage!\n",
+           xyas(x, y, victim), dam2);
+    } else {
+       range = roundrange(shp_fire_range(sp));
+       if (md > range)
+           return dam;
+       if (mission == MI_SINTERDICT)
+           dam2 = shp_dchrg(sp);
+       else
+           dam2 = shp_fire(sp);
+       putship(sp->shp_uid, sp);
+       if (dam2 < 0)
+           return dam;
+       if (targeting_ships)
+           nreport(sp->shp_own, N_SHP_SHELL, victim, 1);
+       else
+           nreport(sp->shp_own, N_SCT_SHELL, victim, 1);
+       wu(0, sp->shp_own,
+          "%s fires at %s %s at %s\n",
+          prship(sp), cname(victim), s, xyas(x, y, sp->shp_own));
+
+       mpr(victim, "%s %s fires at you at %s\n",
+           cname(sp->shp_own), prship(sp), xyas(x, y, victim));
     }
 
-    if (QEMPTY(&bombers)) {
-       qp = list->q_forw;
-       while (qp != list) {
-           glp = (struct genlist *)qp;
-           qp = qp->q_forw;
+    return tally_dam(dam, dam2);
+}
+
+static int
+perform_mission_msl(int dam, struct emp_qelem *missiles, coord x, coord y,
+                   natid victim, int hardtarget)
+{
+    int performed, air_dam, sublaunch, dam2;
+    struct emp_qelem *qp, *newqp;
+    struct plist *plp;
+
+    /*
+     * Missiles, except for interdiction of ships or land units,
+     * because that happens elsewhere, in shp_missile_interdiction()
+     * and lnd_missile_interdiction().
+     */
+    performed = air_dam = 0;
+    for (qp = missiles->q_back; qp != missiles; qp = newqp) {
+       newqp = qp->q_back;
+       plp = (struct plist *)qp;
 
-           free(glp->thing);
-           free(glp);
+       if (air_dam < 100
+           && !CANT_HAPPEN(hardtarget != SECT_HARDTARGET
+                           || (plp->pcp->pl_flags & P_MAR))
+           && mission_pln_equip(plp, NULL, 'p') >= 0) {
+           if (msl_launch(&plp->plane, EF_SECTOR, "sector", x, y, victim,
+                          &sublaunch) < 0)
+               goto use_up_msl;
+           performed = 1;
+           if (!msl_hit(&plp->plane, SECT_HARDTARGET, EF_SECTOR,
+                        N_SCT_MISS, N_SCT_SMISS, sublaunch, victim))
+               CANT_REACH();
+           dam2 = pln_damage(&plp->plane, 'p', 1);
+           air_dam += dam2;
+       use_up_msl:
+           plp->plane.pln_effic = 0;
+           putplane(plp->plane.pln_uid, &plp->plane);
        }
-       return dam;
+       emp_remque(qp);
+       free(qp);
     }
+
+    return performed ? tally_dam(dam, air_dam) : dam;
+}
+
+static int
+perform_mission_bomb(int dam, struct emp_qelem *bombers, coord x, coord y,
+                    natid victim, int mission, char *s, int hardtarget,
+                    int targeting_ships)
+{
+    struct emp_qelem *qp, *newqp, escorts, airp, b, e;
+    struct plist *plp;
+    int plane_owner, performed, air_dam;
+    size_t md;
+
+    emp_initque(&escorts);
+    emp_initque(&airp);
+
+    if (QEMPTY(bombers))
+       return dam;
+
+    plp = (struct plist *)bombers->q_forw;
+    plane_owner = plp->plane.pln_own;
+
     /*
      * If there are planes performing an
      * interdict or support mission, find
@@ -580,45 +601,46 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
     find_escorts(x, y, plane_owner, &escorts);
 
     if (mission == MI_SINTERDICT)
-       mission_pln_sel(&bombers, P_T | P_A, 0, hardtarget);
+       mission_pln_sel(bombers, P_T | P_A, 0, hardtarget);
     else
-       mission_pln_sel(&bombers, P_T, P_A, SECT_HARDTARGET);
+       mission_pln_sel(bombers, P_T, P_A, SECT_HARDTARGET);
 
     mission_pln_sel(&escorts, P_ESC | P_F, 0, SECT_HARDTARGET);
 
-    for (qp = bombers.q_forw; qp != (&bombers); qp = qp->q_forw) {
+    for (qp = bombers->q_forw; qp != bombers; qp = qp->q_forw) {
        plp = (struct plist *)qp;
        if (!find_airport(&airp, plp->plane.pln_x, plp->plane.pln_y))
            add_airport(&airp, plp->plane.pln_x, plp->plane.pln_y);
     }
 
+    performed = air_dam = 0;
     for (qp = airp.q_forw; qp != (&airp); qp = qp->q_forw) {
        struct airport *air;
-       char buf[512];
-       char *pp;
+       char buf[1024];
 
        air = (struct airport *)qp;
-       md = mapdist(x, y, air->x, air->y);
 
        emp_initque(&b);
        emp_initque(&e);
 
        /* Split off the bombers at this base into b */
-       divide(&bombers, &b, air->x, air->y);
+       divide(bombers, &b, air->x, air->y);
 
        /* Split off the escorts at this base into e */
        divide(&escorts, &e, air->x, air->y);
 
-       mission_pln_arm(&b, air->x, air->y, 2 * md, 'p', 0, 0);
+       if (path_find(air->x, air->y, x, y, plane_owner, MOB_FLY) < 0)
+           continue;
+       md = path_find_route(buf, sizeof(buf), air->x, air->y, x, y);
+       if (md >= sizeof(buf))
+           continue;
 
+       mission_pln_arm(&b, air->x, air->y, 2 * md, 'p', NULL);
        if (QEMPTY(&b))
            continue;
+       mission_pln_arm(&e, air->x, air->y, 2 * md, 'e', NULL);
 
-       mission_pln_arm(&e, air->x, air->y, 2 * md, 'p', 0, P_F | P_ESC);
-
-       pp = BestAirPath(buf, air->x, air->y, x, y);
-       if (CANT_HAPPEN(!pp))
-           continue;
+       performed = 1;
        wu(0, plane_owner, "Flying %s mission from %s to %s\n",
           mission_name(mission),
           xyas(air->x, air->y, plane_owner),
@@ -630,7 +652,7 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
               xyas(x, y, air->own));
        }
 
-       ac_encounter(&b, &e, air->x, air->y, pp, 0, 0);
+       ac_encounter(&b, &e, air->x, air->y, buf, 0);
 
        if (!QEMPTY(&b))
            air_dam +=
@@ -641,23 +663,12 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
     }
 
     if (air_dam > 0) {
-       dam += air_dam;
        if (targeting_ships)
            nreport(plane_owner, N_SHP_BOMB, victim, 1);
        else
            nreport(plane_owner, N_SCT_BOMB, victim, 1);
     }
 
-    /* free up all this memory */
-    qp = list->q_forw;
-    while (qp != list) {
-       glp = (struct genlist *)qp;
-       qp = qp->q_forw;
-
-       free(glp->thing);
-       free(glp);
-    }
-
     qp = escorts.q_forw;
     while (qp != (&escorts)) {
        newqp = qp->q_forw;
@@ -666,15 +677,15 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
        qp = newqp;
     }
 
-    qp = bombers.q_forw;
-    while (qp != (&bombers)) {
+    qp = bombers->q_forw;
+    while (qp != bombers) {
        newqp = qp->q_forw;
        emp_remque(qp);
        free(qp);
        qp = newqp;
     }
 
-    return dam;
+    return performed ? tally_dam(dam, air_dam) : dam;
 }
 
 int
@@ -711,7 +722,7 @@ cando(int mission, int type)
 }
 
 char *
-mission_name(short mission)
+mission_name(int mission)
 {
     switch (mission) {
     case MI_INTERDICT:
@@ -839,7 +850,7 @@ mission_pln_sel(struct emp_qelem *list, int wantflags, int nowantflags,
  */
 static void
 mission_pln_arm(struct emp_qelem *list, coord x, coord y, int dist,
-               int mission, struct ichrstr *ip, int flags)
+               int mission, struct ichrstr *ip)
 {
     struct emp_qelem *qp;
     struct emp_qelem *next;
@@ -857,21 +868,20 @@ mission_pln_arm(struct emp_qelem *list, coord x, coord y, int dist,
            continue;
 
        if (CANT_HAPPEN(pp->pln_flags & PLN_LAUNCHED)
-           || mission_pln_equip(plp, ip, flags, mission) < 0) {
+           || mission_pln_equip(plp, ip, mission) < 0) {
            emp_remque(qp);
            free(qp);
            continue;
        }
 
        pp->pln_flags |= PLN_LAUNCHED;
-       pp->pln_mobil -= pln_mobcost(dist, pp, flags);
+       pp->pln_mobil -= pln_mobcost(dist, pp, mission);
        putplane(pp->pln_uid, pp);
     }
 }
 
 int
-mission_pln_equip(struct plist *plp, struct ichrstr *ip, int flags,
-                 char mission)
+mission_pln_equip(struct plist *plp, struct ichrstr *ip, char mission)
 {
     struct plchrstr *pcp;
     struct plnstr *pp;
@@ -886,73 +896,60 @@ mission_pln_equip(struct plist *plp, struct ichrstr *ip, int flags,
     pcp = plp->pcp;
     if (pp->pln_ship >= 0) {
        getship(pp->pln_ship, &ship);
+       plp->pstage = ship.shp_pstage;
        item = ship.shp_item;
     } else if (pp->pln_land >= 0) {
        getland(pp->pln_land, &land);
+       plp->pstage = land.lnd_pstage;
        item = land.lnd_item;
     } else {
        getsect(pp->pln_x, pp->pln_y, &sect);
+       plp->pstage = sect.sct_pstage;
        item = sect.sct_item;
     }
     if (pcp->pl_fuel > item[I_PETROL]) {
        return -1;
     }
     item[I_PETROL] -= pcp->pl_fuel;
-    if (!(flags & P_F)) {
-       load = pln_load(pp);
-       itype = I_NONE;
-       needed = 0;
-       switch (mission) {
-       case 's':               /* strategic bomb */
-       case 'p':               /* pinpoint bomb */
-           if (nuk_on_plane(pp) < 0) {
-               itype = I_SHELL;
-               needed = load;
-           }
-           break;
-       case 't':               /* transport */
-       case 'd':               /* drop */
-           if ((pcp->pl_flags & P_C) == 0 || ip == 0)
-               break;
-           itype = ip->i_uid;
-           needed = (load * 2) / ip->i_lbs;
-           break;
-       case 'a':               /* paradrop */
-           if ((pcp->pl_flags & (P_V | P_C)) == 0)
-               break;
-           itype = I_MILIT;
-           needed = load / ip->i_lbs;
-           break;
-       case 'i':               /* missile interception */
-           if (load) {
-               itype = I_SHELL;
-               needed = load;
-           }
-           break;
-       case 'r':               /* reconnaissance */
-       case 0:                 /* plane interception */
-           break;
-       default:
-           CANT_REACH();
-           break;
-       }
-       if (itype != I_NONE && needed <= 0)
+    load = pln_load(pp);
+    itype = I_NONE;
+    switch (mission) {
+    case 'p':          /* pinpoint bomb */
+       itype = I_SHELL;
+       break;
+    case 'i':          /* missile interception */
+       if (load)
+           itype = I_SHELL;
+       break;
+    case 'e':          /* escort */
+    case 0:            /* plane interception */
+       load = 0;
+       break;
+    default:
+       CANT_REACH();
+       load = 0;
+    }
+
+    if (itype != I_NONE) {
+       needed = load / ichr[itype].i_lbs;
+       if (needed <= 0)
+           return -1;
+       if (CANT_HAPPEN(nuk_on_plane(pp) >= 0))
            return -1;
-       if (itype != I_NONE) {
-           if (itype == I_SHELL && item[itype] < needed)
-               item[itype] += supply_commod(plp->plane.pln_own,
-                                            plp->plane.pln_x,
-                                            plp->plane.pln_y,
-                                            I_SHELL, needed);
-           if (item[itype] < needed)
-               return -1;
-           item[itype] -= needed;
+       if (itype == I_SHELL && item[itype] < needed) {
+           if (pp->pln_ship >= 0)
+               shp_supply(&ship, I_SHELL, needed);
+           else if (pp->pln_land >= 0)
+               lnd_supply(&land, I_SHELL, needed);
+           else
+               sct_supply(&sect, I_SHELL, needed);
        }
-       if (itype == I_SHELL && (mission == 's' || mission == 'p'))
-           plp->bombs = needed;
-       else
-           plp->misc = needed;
+       if (item[itype] < needed)
+           return -1;
+       item[itype] -= needed;
+       plp->load = needed;
     }
+
     if (pp->pln_ship >= 0)
        putship(ship.shp_uid, &ship);
     else if (pp->pln_land >= 0)
@@ -1030,7 +1027,6 @@ air_damage(struct emp_qelem *bombers, coord x, coord y, int mission,
     struct plnstr *pp;
     int newdam, dam = 0;
     int hitchance;
-    int nukedam;
 
     for (qp = bombers->q_forw; qp != bombers; qp = qp->q_forw) {
        plp = (struct plist *)qp;
@@ -1039,10 +1035,9 @@ air_damage(struct emp_qelem *bombers, coord x, coord y, int mission,
        if ((mission == MI_SINTERDICT) && !(plp->pcp->pl_flags & P_A))
            continue;
 
-       if (!plp->bombs)
+       if (!plp->load)
            continue;
 
-       newdam = 0;
        if (plp->pcp->pl_flags & P_A) {
            if (roll(100) > pln_identchance(pp, hardtarget, EF_SHIP)) {
                wu(0, pp->pln_own,
@@ -1050,7 +1045,7 @@ air_damage(struct emp_qelem *bombers, coord x, coord y, int mission,
                   prplane(pp), xyas(x, y, pp->pln_own));
                continue;
            }
-           if (getrel(getnatp(pp->pln_own), victim) > HOSTILE) {
+           if (relations_with(pp->pln_own, victim) > HOSTILE) {
                wu(0, pp->pln_own,
                   "\t%s tracks %s %s at %s\n",
                   prplane(pp), cname(victim), s, xyas(x, y, pp->pln_own));
@@ -1069,24 +1064,14 @@ air_damage(struct emp_qelem *bombers, coord x, coord y, int mission,
            hitchance = 100;
        else if (hardtarget != SECT_HARDTARGET)
            wu(0, pp->pln_own, "\t\t%d%% hitchance...", hitchance);
-       /* Always calculate damage */
        if (roll(100) <= hitchance) {
-           newdam = pln_damage(&plp->plane, x, y, 'p', &nukedam, 1);
-           if (nukedam) {
-               if (mission == MI_INTERDICT) {
-                   wu(0, pp->pln_own,
-                      "\t\tnuclear warhead on plane %s does %d damage to %s %s\n",
-                      prplane(pp), nukedam, cname(victim), s);
-                   dam += nukedam;
-               }
-           } else {
-               wu(0, pp->pln_own,
-                  "\t\thit %s %s for %d damage\n",
-                  cname(victim), s, newdam);
-               dam += newdam;
-           }
+           newdam = pln_damage(&plp->plane, 'p', 1);
+           wu(0, pp->pln_own,
+              "\t\thit %s %s for %d damage\n",
+              cname(victim), s, newdam);
+           dam += newdam;
        } else {
-           newdam = pln_damage(&plp->plane, x, y, 'p', &nukedam, 0);
+           newdam = pln_damage(&plp->plane, 'p', 0);
            wu(0, pp->pln_own, "missed\n");
            if (mission == MI_SINTERDICT) {
                mpr(victim,
@@ -1111,216 +1096,3 @@ air_damage(struct emp_qelem *bombers, coord x, coord y, int mission,
 
     return dam;
 }
-
-/*
- * Check to see if anyone hostile to the victim
- * is running an air defense mission on this
- * sector. If so, do air combat
- */
-int
-air_defense(coord x, coord y, natid victim, struct emp_qelem *bomb_list,
-           struct emp_qelem *esc_list)
-{
-    int dam = 0, cn;
-    int combat = 0, rel, dist, z;
-    struct emp_qelem *qp, interceptors, airp, i, empty, *next;
-    struct plist *plp;
-    struct genlist *glp;
-    struct empobj *gp;
-    struct genlist mi[MAXNOC];
-    char buf[512];
-    char *path;
-    int count;
-    int tcount;
-
-    count = 0;
-    for (qp = bomb_list->q_forw; qp != bomb_list; qp = qp->q_forw)
-       count++;
-    for (qp = esc_list->q_forw; qp != esc_list; qp = qp->q_forw)
-       count++;
-
-    memset(mi, 0, sizeof(mi));
-    for (z = 1; z < MAXNOC; z++)
-       emp_initque((struct emp_qelem *)&mi[z]);
-
-    build_mission_list_type(mi, x, y, MI_AIR_DEFENSE, EF_PLANE, victim);
-
-    for (cn = 1; cn < MAXNOC; cn++) {
-       /* Check our relations */
-       rel = getrel(getnatp(cn), victim);
-
-       if (rel > HOSTILE)
-           continue;
-
-       if (QEMPTY(&mi[cn].queue))
-           continue;
-
-       /* Ok, make a list of all the interceptors.  Note that this *copies* the
-        * list from the mission creation.  This list must be deleted later. */
-       emp_initque(&interceptors);
-       for (qp = mi[cn].queue.q_forw; qp != (&mi[cn].queue); qp = next) {
-           next = qp->q_forw;
-           glp = (struct genlist *)qp;
-           gp = glp->thing;
-           if (CANT_HAPPEN(gp->ef_type != EF_PLANE))
-               break;
-
-           dist = mapdist(x, y, gp->x, gp->y);
-
-           plp = malloc(sizeof(struct plist));
-           memset(plp, 0, sizeof(struct plist));
-           plp->pcp = glp->cp;
-           memcpy(&plp->plane, glp->thing, sizeof(struct plnstr));
-
-           /* missiles go one way, so we can use all the range */
-           if (!(plp->pcp->pl_flags & P_M))
-               dist *= 2;
-           /* If it's out of range, free it and continue on */
-           if (dist > plp->plane.pln_range) {
-               free(plp);
-               continue;
-           }
-           emp_insque(&plp->queue, &interceptors);
-       }
-
-       /* Remove those who cannot go */
-       mission_pln_sel(&interceptors, P_F, 0, SECT_HARDTARGET);
-
-       if (QEMPTY(&interceptors))
-           continue;
-
-       /* Now, delete all the extras, but delete the first ones, not the last ones, so
-        * that the higher numbered planes go into battle (they should be the better ones
-        * at fighting, if all went well.) */
-       tcount = 0;
-       for (qp = interceptors.q_forw; qp != (&interceptors);
-            qp = qp->q_forw)
-           tcount++;
-       tcount -= count * 2;
-       /* Just in case there are more incoming than we have */
-       if (tcount < 0)
-           tcount = 0;
-       for (qp = interceptors.q_forw; qp != (&interceptors); qp = next) {
-           next = qp->q_forw;
-           if (tcount) {
-               tcount--;
-               /* Free it up and continue */
-               emp_remque(qp);
-               glp = (struct genlist *)qp;
-               free(glp);
-           }
-       }
-
-       /* Now, make a list of all the airports these planes are coming from */
-       emp_initque(&airp);
-       for (qp = interceptors.q_forw; qp != (&interceptors);
-            qp = qp->q_forw) {
-           plp = (struct plist *)qp;
-           if (!find_airport(&airp, plp->plane.pln_x, plp->plane.pln_y))
-               add_airport(&airp, plp->plane.pln_x, plp->plane.pln_y);
-       }
-
-       /* Now, fly them out one airport at a time */
-       for (qp = airp.q_forw; qp != (&airp); qp = qp->q_forw) {
-           struct airport *air;
-
-           air = (struct airport *)qp;
-           dist = mapdist(x, y, air->x, air->y);
-
-           emp_initque(&i);
-
-           /* Split off the interceptors at this base into i */
-           divide(&interceptors, &i, air->x, air->y);
-
-           sam_intercept(bomb_list, &i, cn, victim, x, y, 0);
-           sam_intercept(esc_list, &i, cn, victim, x, y, 1);
-
-           /* Did we run out of interceptors? */
-           if (QEMPTY(&i))
-               continue;
-           /* Did we run out of bombers? */
-           if (QEMPTY(bomb_list)) {
-               /* Yes, so we have to put the rest of the interceptors back, and
-                  then continue, or we leak memory */
-               pln_put(&i);
-               continue;
-           }
-           mission_pln_arm(&i, air->x, air->y, 2 * dist, 0, 0, P_F);
-
-           /* Did we run out of interceptors? */
-           if (QEMPTY(&i))
-               continue;
-           /* Did we run out of bombers? */
-           if (QEMPTY(bomb_list)) {
-               /* Yes, so we have to put the rest of the interceptors back, and
-                  then continue, or we leak memory */
-               pln_put(&i);
-               continue;
-           }
-
-           path = BestAirPath(buf, air->x, air->y, x, y);
-           if (CANT_HAPPEN(!path)) {
-               pln_put(&i);
-               continue;
-           }
-           wu(0, cn, "Flying %s mission from %s to %s\n",
-              mission_name(MI_AIR_DEFENSE),
-              xyas(air->x, air->y, cn),
-              xyas(x, y, cn));
-           if (air->own && (air->own != cn)) {
-               wu(0, air->own, "%s is flying %s mission from %s to %s\n",
-                  cname(cn), mission_name(MI_AIR_DEFENSE),
-                  xyas(air->x, air->y, air->own),
-                  xyas(x, y, air->own));
-           }
-
-           /* Now, fly the planes to the sector */
-           emp_initque(&empty);
-           ac_encounter(&i, &empty, air->x, air->y, path, 0, 1);
-
-           /* If none made it, continue */
-           if (QEMPTY(&i))
-               continue;
-
-           /* Some made it, so now they get to try to fight. */
-           /* Intercept the escorts first */
-           combat = 0;
-           if (!QEMPTY(esc_list)) {
-               mpr(victim, "%s air defense planes intercept!\n",
-                   cname(cn));
-               ac_combat_headers(victim, cn);
-               ac_airtoair(esc_list, &i);
-               combat = 1;
-           }
-           /* Now intercept the bombers */
-           if (!QEMPTY(bomb_list)) {
-               if (!combat) {
-                   mpr(victim, "%s air defense planes intercept!\n",
-                       cname(cn));
-                   ac_combat_headers(victim, cn);
-               }
-               ac_airtoair(bomb_list, &i);
-               PR(cn, "\n");
-               PR(victim, "\n");
-           }
-
-           pln_put(&i);
-       }
-       if (CANT_HAPPEN(!QEMPTY(&interceptors)))
-           pln_put(&interceptors);
-    }
-
-    /* We have to free all of these, if they are still there, otherwise they get
-       lost and we leak memory all over the place. */
-    for (cn = 1; cn < MAXNOC; cn++) {
-       /* free up all this memory if it's still there */
-       for (qp = mi[cn].queue.q_forw; qp != (&mi[cn].queue); qp = next) {
-           next = qp->q_forw;
-           glp = (struct genlist *)qp;
-           free(glp->thing);
-           free(glp);
-       }
-    }
-
-    return dam;
-}