]> git.pond.sub.org Git - empserver/blobdiff - src/lib/subs/mission.c
Consistently use int for mission type parameters
[empserver] / src / lib / subs / mission.c
index 148fb5ff842bba343211da655db3eeac39a02980..cef5c47b854f0d118dfeb19f259032fe46985110 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *  Copyright (C) 1986-2009, Dave Pare, Jeff Bailey, Thomas Ruschak,
  *                           Ken Stevens, Steve McClure
  *
  *  This program is free software; you can redistribute it and/or modify
  *  ---
  *
  *  mission.c: Mission subroutines for planes/ships/units
- * 
+ *
  *  Known contributors to this file:
  *     Ken Stevens, 1995
  *     Steve McClure, 1996-2000
+ *     Markus Armbruster, 2003-2009
  */
 
 #include <config.h>
 
 #include <stdlib.h>
-#include "damage.h"
 #include "empobj.h"
 #include "file.h"
 #include "item.h"
@@ -70,8 +70,8 @@ static void build_mission_list_type(struct genlist *, coord, coord, int,
 static void divide(struct emp_qelem *, struct emp_qelem *, coord, coord);
 static int dosupport(struct genlist *, coord, coord, natid, natid);
 static int find_airport(struct emp_qelem *, coord, coord);
-static int mission_pln_arm(struct emp_qelem *, coord, coord, int,
-                          int, struct ichrstr *, int, int, int *);
+static void mission_pln_arm(struct emp_qelem *, coord, coord, 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);
@@ -109,13 +109,13 @@ ground_interdict(coord x, coord y, natid victim, char *s)
                cname(cn), newdam);
     }
     if (dam) {
-       collateral_damage(x, y, dam, 0);
+       collateral_damage(x, y, dam);
     }
     return dam;
 }
 
 int
-collateral_damage(coord x, coord y, int dam, struct emp_qelem *list)
+collateral_damage(coord x, coord y, int dam)
 {
     int coll;
     struct sctstr sect;
@@ -130,7 +130,7 @@ collateral_damage(coord x, coord y, int dam, struct emp_qelem *list)
            return 0;
        mpr(sect.sct_own, "%s takes %d%% collateral damage\n",
            xyas(x, y, sect.sct_own), coll);
-       sectdamage(&sect, coll, list);
+       sectdamage(&sect, coll);
        putsect(&sect);
        return coll;
     }
@@ -202,7 +202,7 @@ unit_interdict(coord x, coord y, natid victim, char *s, int hardtarget,
        }
     }
     if (dam) {
-       collateral_damage(x, y, dam, 0);
+       collateral_damage(x, y, dam);
     }
     return dam;
 }
@@ -290,8 +290,6 @@ build_mission_list_type(struct genlist *mi, coord x, coord y, int mission,
     struct genlist *glp;
     struct empobj *gp;
     union empobj_storage item;
-    int dist;
-    int radius;
     int relat;
     struct sctstr sect;
 
@@ -321,23 +319,8 @@ build_mission_list_type(struct genlist *mi, coord x, coord y, int mission,
        } else if (relat > HOSTILE)
            continue;
 
-       dist = mapdist(x, y, gp->opx, gp->opy);
-
-       radius = gp->radius;
-       if (mission != MI_RESERVE)      /* XXX */
-           oprange(gp, &radius);
-
-       if (dist > radius)
-           continue;
-
-       /* Ok, it is within the operations range. */
-       /* Now check from where the object actually is */
-       dist = mapdist(x, y, gp->x, gp->y);
-       radius = 999;
-       oprange(gp, &radius);
-       if (dist > radius)
+       if (!in_oparea(gp, x, y))
            continue;
-       /* Ok, the object can get to where the x,y is */
 
        if (opt_SLOW_WAR) {
            if (mission != MI_AIR_DEFENSE) {
@@ -345,10 +328,10 @@ build_mission_list_type(struct genlist *mi, coord x, coord y, int mission,
                if (getrel(getnatp(gp->own), sect.sct_own) > AT_WAR) {
 
                    /*
-                    * If the player->owner of the unit isn't 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 player->owner of that sect, bounce them.
+                    * old owner of that sect, bounce them.
                     */
                    if (sect.sct_type != SCT_WATER &&
                        sect.sct_own != gp->own &&
@@ -373,20 +356,15 @@ find_escorts(coord x, coord y, natid cn, struct emp_qelem *escorts)
     struct nstr_item ni;
     struct plist *plp;
     struct plnstr plane;
-    int dist;
 
     snxtitem_all(&ni, EF_PLANE);
     while (nxtitem(&ni, &plane)) {
        if (plane.pln_own != cn)
            continue;
-
        if (plane.pln_mission != MI_ESCORT)
            continue;
-
-       dist = mapdist(x, y, plane.pln_x, plane.pln_y);
-       if (dist > plane.pln_range / 2)
+       if (!in_oparea((struct empobj *)&plane, x, y))
            continue;
-
        plp = malloc(sizeof(struct plist));
        memset(plp, 0, sizeof(struct plist));
        plp->pcp = &plchr[(int)plane.pln_type];
@@ -409,10 +387,11 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
     struct sctstr sect;
     struct mchrstr *mcp;
     struct plchrstr *pcp;
-    int dam = 0, dam2, mission_flags, tech;
+    int dam = 0, dam2;
     natid plane_owner = 0;
-    int gun, shell, md, range, air_dam = 0;
-    double prb, hitchance, vrange;
+    int md, range, air_dam, sublaunch;
+    double hitchance, vrange;
+    int targeting_ships = *s == 's'; /* "subs" or "ships" FIXME gross! */
 
     getsect(x, y, &sect);
 
@@ -430,9 +409,6 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
        if (glp->thing->ef_type == EF_LAND) {
            lp = (struct lndstr *)glp->thing;
 
-           if (lp->lnd_effic < LAND_MINFIREEFF)
-               continue;
-
            if (mission == MI_SINTERDICT)
                continue;
 
@@ -440,61 +416,38 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
                (md > land_max_interdiction_range))
                continue;
 
-           if ((lp->lnd_ship != -1) || (lp->lnd_land != -1))
-               continue;
-
-           if (lp->lnd_item[I_MILIT] < 1)
-               continue;
-
-           range = roundrange(effrange(lp->lnd_frg, lp->lnd_tech));
+           range = roundrange(lnd_fire_range(lp));
            if (md > range)
                continue;
 
-           shell = lp->lnd_item[I_SHELL];
-           gun = lp->lnd_item[I_GUN];
-           if (shell == 0 || gun == 0)
+           dam2 = lnd_fire(lp);
+           putland(lp->lnd_uid, lp);
+           if (dam2 < 0)
                continue;
 
-           if (has_supply(lp)) {
-               use_supply(lp);
-               putland(lp->lnd_uid, lp);
-               dam2 = ldround(landunitgun(lp->lnd_effic, lp->lnd_dam, gun,
-                                          lp->lnd_ammo, shell), 1);
-               if (sect.sct_type == SCT_WATER) {
-                   if (chance(lp->lnd_acc / 100.0))
-                       dam2 = ldround(dam2 / 2.0, 1);
-               }
-               dam += dam2;
-               if (sect.sct_type == SCT_WATER)
-                   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(lp->lnd_own), prland(lp), xyas(x, y, victim));
+           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));
+
+           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;
 
-           if (sp->shp_effic < 60)
-               continue;
-           if (sp->shp_frnge == 0)
-               continue;
            if (((mission == MI_INTERDICT) ||
                 (mission == MI_SINTERDICT)) &&
                (md > ship_max_interdiction_range))
                continue;
-           if (sp->shp_item[I_MILIT] < 1)
-               continue;
-/*
-  if ((mcp->m_flags & M_SUB) &&
-  (sect.sct_type != SCT_WATER))
-  continue;
-*/
            if (mission == MI_SINTERDICT) {
                if (!(mcp->m_flags & M_SONAR))
                    continue;
@@ -509,33 +462,18 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
                    continue;
            }
            if (mcp->m_flags & M_SUB) {
-/* If we aren't shooting at "subs" or "ships" don't fire at all from
-   a sub. */
-               if (*s != 's')
-                   continue;
-               if (sp->shp_mobil < 0)
-                   continue;
-               gun = sp->shp_item[I_GUN];
-               if (gun < 1)
-                   continue;
-               shell = sp->shp_item[I_SHELL];
-               if (shell < SHP_TORP_SHELLS)
-                   shell += supply_commod(sp->shp_own,
-                                          sp->shp_x, sp->shp_y, I_SHELL,
-                                          SHP_TORP_SHELLS - shell);
-               if (shell < SHP_TORP_SHELLS)
-                   continue;
-
+               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;
-               sp->shp_item[I_SHELL] = shell - SHP_TORP_SHELLS;
-               sp->shp_mobil -= shp_mobcost(sp) / 2.0;
+               dam2 = shp_torp(sp, 1);
                putship(sp->shp_uid, sp);
-               hitchance = DTORP_HITCHANCE(md, sp->shp_visib);
+               if (dam2 < 0)
+                   continue;
+               hitchance = shp_torp_hitchance(sp, md);
 
                wu(0, sp->shp_own,
                   "%s locking on %s %s in %s\n",
@@ -546,7 +484,7 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
                   "\tWhooosh... Hitchance = %d%%\n",
                   (int)(hitchance * 100));
 
-               if (hitchance < 1.0 && !chance(hitchance)) {
+               if (!chance(hitchance)) {
                    wu(0, sp->shp_own, "\tMissed\n");
                    mpr(victim,
                        "Incoming torpedo sighted @ %s missed (whew)!\n",
@@ -554,8 +492,6 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
                    continue;
                }
                wu(0, sp->shp_own, "\tBOOM!...\n");
-               dam2 = TORP_DAMAGE();
-
                dam += dam2;
                nreport(victim, N_TORP_SHIP, 0, 1);
                wu(0, sp->shp_own,
@@ -566,31 +502,18 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
                    "Incoming torpedo sighted @ %s hits and does %d damage!\n",
                    xyas(x, y, victim), dam2);
            } else {
-               range = roundrange(effrange(sp->shp_frnge, sp->shp_tech));
+               range = roundrange(shp_fire_range(sp));
                if (md > range)
                    continue;
-               gun = sp->shp_item[I_GUN];
-               gun = MIN(gun, sp->shp_glim);
-               shell = sp->shp_item[I_SHELL];
-               if (shell < gun)
-                   shell += supply_commod(sp->shp_own,
-                                          sp->shp_x, sp->shp_y, I_SHELL,
-                                          gun - shell);
-               gun = MIN(gun, shell);
-               gun = MIN(gun, sp->shp_item[I_MILIT] / 2.0);
-               if (gun == 0)
-                   continue;
-               gun = MAX(gun, 1);
-               dam2 = seagun(sp->shp_effic, gun);
-               if (range == 0.0)
-                   prb = 1.0;
+               if (mission == MI_SINTERDICT)
+                   dam2 = shp_dchrg(sp);
                else
-                   prb = (double)md / range;
-               prb *= prb;
-               if (chance(prb))
-                   dam2 /= 2;
+                   dam2 = shp_fire(sp);
+               putship(sp->shp_uid, sp);
+               if (dam2 < 0)
+                   continue;
                dam += dam2;
-               if (sect.sct_type == SCT_WATER)
+               if (targeting_ships)
                    nreport(sp->shp_own, N_SHP_SHELL, victim, 1);
                else
                    nreport(sp->shp_own, N_SCT_SHELL, victim, 1);
@@ -600,9 +523,6 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
 
                mpr(victim, "%s %s fires at you at %s\n",
                    cname(sp->shp_own), prship(sp), xyas(x, y, victim));
-
-               sp->shp_item[I_SHELL] = shell - gun;
-               putship(sp->shp_uid, sp);
            }
        } else if (glp->thing->ef_type == EF_PLANE) {
            pcp = glp->cp;
@@ -622,21 +542,42 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
            else
                emp_insque(&plp->queue, &bombers);
            plane_owner = plp->plane.pln_own;
+       } else {
+           CANT_REACH();
+           break;
        }
     }
-    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;
+
+    /*
+     * Missiles, except for interdiction of ships or land units,
+     * because that happens elsewhere, in shp_missile_interdiction()
+     * and lnd_missile_interdiction().
+     */
+    air_dam = 0;
+    for (qp = missiles.q_back; qp != &missiles; qp = newqp) {
+       newqp = qp->q_back;
+       plp = (struct plist *)qp;
+
+       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;
+           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);
        }
+       emp_remque(qp);
+       free(qp);
     }
+    dam += air_dam;
 
     if (QEMPTY(&bombers)) {
        qp = list->q_forw;
@@ -670,6 +611,7 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
            add_airport(&airp, plp->plane.pln_x, plp->plane.pln_y);
     }
 
+    air_dam = 0;
     for (qp = airp.q_forw; qp != (&airp); qp = qp->q_forw) {
        struct airport *air;
        char buf[512];
@@ -687,32 +629,28 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
        /* Split off the escorts at this base into e */
        divide(&escorts, &e, air->x, air->y);
 
-       tech = 0;
-       mission_flags = 0;
-       mission_flags |= P_X;   /* stealth (shhh) */
-       mission_flags |= P_H;   /* gets turned off if not all choppers */
-
-       mission_flags = mission_pln_arm(&b, air->x, air->y, 2 * md, 'p', 0,
-                                       0, mission_flags, &tech);
+       mission_pln_arm(&b, air->x, air->y, 2 * md, 'p', NULL);
 
        if (QEMPTY(&b))
            continue;
 
-       mission_flags = mission_pln_arm(&e, air->x, air->y, 2 * md, 'p', 0,
-                                       P_F | P_ESC, mission_flags, &tech);
+       mission_pln_arm(&e, air->x, air->y, 2 * md, 'e', NULL);
 
        pp = BestAirPath(buf, air->x, air->y, x, y);
        if (CANT_HAPPEN(!pp))
            continue;
-       wu(0, plane_owner, "Flying %s mission from %s\n",
-          mission_name(mission), xyas(air->x, air->y, plane_owner));
+       wu(0, plane_owner, "Flying %s mission from %s to %s\n",
+          mission_name(mission),
+          xyas(air->x, air->y, plane_owner),
+          xyas(x, y, plane_owner));
        if (air->own && (air->own != plane_owner)) {
-           wu(0, air->own, "%s is flying %s mission from %s\n",
+           wu(0, air->own, "%s is flying %s mission from %s to %s\n",
               cname(plane_owner), mission_name(mission),
-              xyas(air->x, air->y, air->own));
+              xyas(air->x, air->y, air->own),
+              xyas(x, y, air->own));
        }
 
-       ac_encounter(&b, &e, air->x, air->y, pp, mission_flags, 0, 0, 0);
+       ac_encounter(&b, &e, air->x, air->y, pp, 0);
 
        if (!QEMPTY(&b))
            air_dam +=
@@ -724,7 +662,7 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
 
     if (air_dam > 0) {
        dam += air_dam;
-       if (sect.sct_type == SCT_WATER)
+       if (targeting_ships)
            nreport(plane_owner, N_SHP_BOMB, victim, 1);
        else
            nreport(plane_owner, N_SCT_BOMB, victim, 1);
@@ -793,7 +731,7 @@ cando(int mission, int type)
 }
 
 char *
-mission_name(short mission)
+mission_name(int mission)
 {
     switch (mission) {
     case MI_INTERDICT:
@@ -801,7 +739,7 @@ mission_name(short mission)
     case MI_SUPPORT:
        return "a support";
     case MI_OSUPPORT:
-       return "a offensive support";
+       return "an offensive support";
     case MI_DSUPPORT:
        return "a defensive support";
     case MI_RESERVE:
@@ -813,157 +751,44 @@ mission_name(short mission)
     case MI_AIR_DEFENSE:
        return "an air defense";
     }
+    CANT_REACH();
     return "a mysterious";
 }
 
-void
-show_mission(int type, struct nstr_item *np)
-{
-    int first = 1, radius;
-    union empobj_storage item;
-    struct empobj *gp;
-
-    while (nxtitem(np, &item)) {
-       gp = (struct empobj *)&item;
-       if (!player->owner || gp->own == 0)
-           continue;
-
-       if (first) {
-           pr("Thing                         x,y   op-sect rad mission\n");
-           first = 0;
-       }
-       pr("%-25s", obj_nameof(gp));
-       prxy(" %3d,%-3d", gp->x, gp->y, player->cnum);
-       if (gp->mission == MI_INTERDICT || gp->mission == MI_SUPPORT ||
-           gp->mission == MI_OSUPPORT ||
-           gp->mission == MI_DSUPPORT || gp->mission == MI_AIR_DEFENSE) {
-           radius = 999;
-           oprange(gp, &radius);
-           prxy(" %3d,%-3d", gp->opx, gp->opy, player->cnum);
-           if (radius < gp->radius)
-               pr("  %4d", radius);
-           else
-               pr("  %4d", gp->radius);
-       } else if (gp->mission == MI_RESERVE) {
-           struct sctstr sect;
-           int plus = 2;
-
-           getsect(gp->x, gp->y, &sect);
-           if ((sect.sct_type == SCT_HEADQ) && (sect.sct_effic >= 60))
-               plus++;
-
-           if (item.land.lnd_rad_max == 0)
-               plus = 0;
-           else
-               plus += item.land.lnd_rad_max;
-           prxy(" %3d,%-3d", gp->x, gp->y, player->cnum);
-           pr("  %4d", plus);
-       } else if (gp->mission == MI_ESCORT) {
-           pr("        ");
-           pr("  %4d", item.plane.pln_range / 2);
-       } else
-           pr("              ");
-       if (gp->mission)
-           pr(" is on %s mission\n", mission_name(gp->mission));
-       else
-           pr(" has no mission.\n");
-    }
-}
-
+/*
+ * Maximum distance GP can perform its mission.
+ * Note: this has nothing to do with the radius of the op-area.
+ * oprange() governs where the unit *can* strike, the op-area governs
+ * where the player wants it to strike.
+ */
 int
-oprange(struct empobj *gp, int *radius)
+oprange(struct empobj *gp)
 {
-    int range;
-
     switch (gp->ef_type) {
     case EF_SHIP:
-       range = ldround(effrange(((struct shpstr *)gp)->shp_frnge,
-                                ((struct shpstr *)gp)->shp_tech), 1);
-       break;
+       return ldround(shp_fire_range((struct shpstr *)gp), 1);
     case EF_LAND:
-       range = ldround(effrange(((struct lndstr *)gp)->lnd_frg,
-                                ((struct lndstr *)gp)->lnd_tech), 1);
-       break;
+       if (gp->mission == MI_RESERVE)
+           return lnd_reaction_range((struct lndstr *)gp);
+       return ldround(lnd_fire_range((struct lndstr *)gp), 1);
     case EF_PLANE:
        /* missiles go one way, so we can use all the range */
        if (plchr[(int)gp->type].pl_flags & P_M)
-           range = ((struct plnstr *)gp)->pln_range;
-       else
-           range = ((struct plnstr *)gp)->pln_range / 2;
-       break;
-    default:
-       CANT_HAPPEN("bad TYPE");
-       range = -1;
+           return ((struct plnstr *)gp)->pln_range;
+       return ((struct plnstr *)gp)->pln_range / 2;
     }
-
-    if (*radius > range)
-       *radius = range;
-
-    return range;
+    CANT_REACH();
+    return -1;
 }
 
-static int
-mission_pln_airbase_ok(struct plnstr *pp)
+/*
+ * Does GP's mission op area cover X,Y?
+ */
+int
+in_oparea(struct empobj *gp, coord x, coord y)
 {
-    struct shpstr ship;
-    struct lndstr land;
-    struct sctstr sect;
-    struct plchrstr *pcp = plchr + pp->pln_type;
-
-    if (pp->pln_ship >= 0) {
-       if (!getship(pp->pln_ship, &ship)) {
-           CANT_REACH();
-           return 0;
-       }
-       if (CANT_HAPPEN(ship.shp_effic < SHIP_MINEFF
-                       || !could_be_on_ship(pp, &ship)))
-           return 0;
-
-       if (ship.shp_own != pp->pln_own
-           && getrel(getnatp(ship.shp_own), pp->pln_own) != ALLIED) {
-           return 0;
-       }
-       if (ship.shp_effic < SHP_AIROPS_EFF)
-           return 0;
-
-    } else if (pp->pln_land >= 0) {
-       if (!getland(pp->pln_land, &land)) {
-           CANT_REACH();
-           return 0;
-       }
-       if (CANT_HAPPEN(land.lnd_effic < LAND_MINEFF
-                       || !(pcp->pl_flags & P_E)))
-           return 0;
-
-       if (land.lnd_own != pp->pln_own
-           && getrel(getnatp(land.lnd_own), pp->pln_own) != ALLIED)
-           return 0;
-       if (land.lnd_effic < LND_AIROPS_EFF)
-           return 0;
-       if (land.lnd_ship >= 0 || land.lnd_land >= 0) {
-           return 0;
-       }
-
-    } else {
-       if (!getsect(pp->pln_x, pp->pln_y, &sect)) {
-           CANT_REACH();
-           return 0;
-       }
-       /* First, check allied status */
-       /* Can't fly from non-owned sectors or non-allied sectors */
-       if ((sect.sct_own != pp->pln_own) &&
-           (getrel(getnatp(sect.sct_own), pp->pln_own) != ALLIED)) {
-           return 0;
-       }
-       /* non-vtol plane */
-       if ((pcp->pl_flags & P_V) == 0) {
-           if ((sect.sct_type != SCT_AIRPT) || (sect.sct_effic < 40)) {
-               return 0;
-           }
-       }
-    }
-
-    return 1;
+    return mapdist(x, y, gp->opx, gp->opy) <= gp->radius
+       && mapdist(x, y, gp->x, gp->y) <= oprange(gp);
 }
 
 /*
@@ -978,8 +803,6 @@ mission_pln_sel(struct emp_qelem *list, int wantflags, int nowantflags,
     struct plnstr *pp;
     struct plchrstr *pcp;
     struct plist *plp;
-    int y, bad, bad1;
-    unsigned x;
 
     for (qp = list->q_forw; qp != list; qp = next) {
        next = qp->q_forw;
@@ -1013,12 +836,12 @@ mission_pln_sel(struct emp_qelem *list, int wantflags, int nowantflags,
            continue;
        }
 
-       if (!mission_pln_airbase_ok(pp)) {
+       if (!pln_airbase_ok(pp, 0, 0)) {
            emp_remque(qp);
            free(qp);
            continue;
        }
-           
+
        if (pcp->pl_flags & P_A) {
            if (roll(100) > pln_identchance(pp, hardtarget, EF_SHIP)) {
                emp_remque(qp);
@@ -1034,77 +857,48 @@ mission_pln_sel(struct emp_qelem *list, int wantflags, int nowantflags,
 /*
  * Arm only the planes at x,y
  */
-static int
+static void
 mission_pln_arm(struct emp_qelem *list, coord x, coord y, int dist,
-               int mission, struct ichrstr *ip, int flags,
-               int mission_flags, int *tech)
+               int mission, struct ichrstr *ip)
 {
     struct emp_qelem *qp;
     struct emp_qelem *next;
     struct plist *plp;
+    struct plnstr *pp;
 
-    if (*tech == 0)
-       *tech = 9999;
     for (qp = list->q_forw; qp != list; qp = next) {
        next = qp->q_forw;
        plp = (struct plist *)qp;
+       pp = &plp->plane;
 
-       if (plp->plane.pln_x != x)
+       if (pp->pln_x != x)
            continue;
-       if (plp->plane.pln_y != y)
+       if (pp->pln_y != y)
            continue;
 
-       if (mission_pln_equip(plp, ip, flags, mission) < 0) {
+       if (CANT_HAPPEN(pp->pln_flags & PLN_LAUNCHED)
+           || mission_pln_equip(plp, ip, mission) < 0) {
            emp_remque(qp);
            free(qp);
            continue;
        }
-       if (flags & (P_S | P_I)) {
-           if (plp->pcp->pl_flags & P_S)
-               mission_flags |= P_S;
-           if (plp->pcp->pl_flags & P_I)
-               mission_flags |= P_I;
-       }
-       if (*tech > plp->plane.pln_tech)
-           *tech = plp->plane.pln_tech;
-       if (!(plp->pcp->pl_flags & P_H))
-           /* no stealth on this mission */
-           mission_flags &= ~P_H;
-       if (!(plp->pcp->pl_flags & P_X))
-           /* no stealth on this mission */
-           mission_flags &= ~P_X;
-       if (!(plp->pcp->pl_flags & P_A)) {
-           /* no asw on this mission */
-           mission_flags &= ~P_A;
-       }
-       if (!(plp->pcp->pl_flags & P_MINE)) {
-           /* no asw on this mission */
-           mission_flags &= ~P_MINE;
-       }
-
-       /*
-        *      Mob costs for missions are 1/2 normal
-        *       Not anymore. :)
-        */
-/*     plp->plane.pln_mobil -= pln_mobcost(dist,&plp->plane,flags)/2;*/
-       plp->plane.pln_mobil -= pln_mobcost(dist, &plp->plane, flags);
 
+       pp->pln_flags |= PLN_LAUNCHED;
+       pp->pln_mobil -= pln_mobcost(dist, pp, mission);
+       putplane(pp->pln_uid, pp);
     }
-    return mission_flags;
 }
 
 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;
-    int needed;
+    int load, needed;
     struct lndstr land;
     struct shpstr ship;
     struct sctstr sect;
     i_type itype;
-    int rval;
     short *item;
 
     pp = &plp->plane;
@@ -1123,74 +917,52 @@ mission_pln_equip(struct plist *plp, struct ichrstr *ip, int flags,
        return -1;
     }
     item[I_PETROL] -= pcp->pl_fuel;
-    rval = 0;
-    if (!(flags & P_F)) {
-       itype = I_NONE;
-       needed = 0;
-       switch (mission) {
-       case 's':
-       case 'p':
-           if (pp->pln_nuketype == -1) {
-               itype = I_SHELL;
-               needed = pp->pln_load;
-           }
-           break;
-       case 't':
-           if ((pcp->pl_flags & P_C) == 0 || ip == 0)
-               break;
-           itype = ip->i_uid;
-           needed = (pp->pln_load * 2) / ip->i_lbs;
-           break;
-       case 'd':
-           if ((pcp->pl_flags & P_C) == 0 || ip == 0)
-               break;
-           itype = ip->i_uid;
-           needed = (pp->pln_load * 2) / ip->i_lbs;
-           break;
-       case 'a':
-           if ((pcp->pl_flags & (P_V | P_C)) == 0)
-               break;
-           itype = I_MILIT;
-           needed = pp->pln_load / ip->i_lbs;
-           break;
-       case 'n':
-           if (pp->pln_nuketype == -1)
-               rval = -1;
-           break;
-       case 'i':               /* missile interception */
-           if (pp->pln_load) {
-               itype = I_SHELL;
-               needed = pp->pln_load;
-           }
-           break;
-       default:
-           break;
-       }
-       if (rval < 0 || (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_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_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 && (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)
        putland(land.lnd_uid, &land);
     else
        putsect(&sect);
-    return rval;
+    return 0;
 }
 
 /*
@@ -1261,7 +1033,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;
@@ -1270,7 +1041,7 @@ 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;
@@ -1296,28 +1067,18 @@ air_damage(struct emp_qelem *bombers, coord x, coord y, int mission,
               prplane(pp), cname(victim), s, xyas(x, y, pp->pln_own));
        }
        hitchance = pln_hitchance(pp, hardtarget, EF_SHIP);
-       if (plp->plane.pln_nuketype != -1)
+       if (nuk_on_plane(&plp->plane) >= 0)
            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,
@@ -1332,7 +1093,7 @@ air_damage(struct emp_qelem *bombers, coord x, coord y, int mission,
            }
            /* Now, even though we missed, the bombs
               land somewhere. */
-           collateral_damage(x, y, newdam, bombers);
+           collateral_damage(x, y, newdam);
        }
 
        /* use up missiles */
@@ -1342,215 +1103,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 mission_flags, tech, 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;
-
-           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);
-
-           tech = 0;
-           mission_flags = 0;
-           mission_flags |= P_X;       /* stealth (shhh) */
-           /* gets turned off if not all choppers */
-           mission_flags |= P_H;
-           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_flags =
-               mission_pln_arm(&i, air->x, air->y, 2 * dist, 'r', 0, P_F,
-                               mission_flags, &tech);
-
-           /* 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))
-               continue;
-           wu(0, cn, "Flying %s mission from %s\n",
-              mission_name(MI_AIR_DEFENSE), xyas(air->x, air->y, cn));
-           if (air->own && (air->own != cn)) {
-               wu(0, air->own, "%s is flying %s mission from %s\n",
-                  cname(cn), mission_name(MI_AIR_DEFENSE),
-                  xyas(air->x, air->y, air->own));
-           }
-
-           /* Now, fly the planes to the sector */
-           emp_initque(&empty);
-           ac_encounter(&i, &empty, air->x, air->y,
-                        path, mission_flags, 1, bomb_list, esc_list);
-
-           /* 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);
-       }
-    }
-
-    /* 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;
-}