]> git.pond.sub.org Git - empserver/blobdiff - src/lib/subs/mission.c
Don't unlimber when guns unsuccessfully try to fire
[empserver] / src / lib / subs / mission.c
index 51835d418ea7b60a07948d4a5707bb28ee8083dc..2f147f471e2683317155a1735e1eabb75a09bd7a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2006, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *  Copyright (C) 1986-2008, Dave Pare, Jeff Bailey, Thomas Ruschak,
  *                           Ken Stevens, Steve McClure
  *
  *  This program is free software; you can redistribute it and/or modify
 
 #include <config.h>
 
+#include <stdlib.h>
+#include "empobj.h"
+#include "file.h"
+#include "item.h"
 #include "misc.h"
-#include "player.h"
-#include "xy.h"
-#include "sect.h"
-#include "ship.h"
-#include "land.h"
-#include "plane.h"
-#include "nat.h"
+#include "mission.h"
 #include "nsc.h"
-#include "file.h"
+#include "optlist.h"
 #include "path.h"
-#include "mission.h"
-#include "genitem.h"
-#include "news.h"
-#include "item.h"
-#include <fcntl.h>
-#include "damage.h"
-#include "queue.h"
+#include "player.h"
 #include "prototypes.h"
-#include "optlist.h"
+#include "queue.h"
+#include "xy.h"
 
 struct genlist {
     struct emp_qelem queue;    /* list of units */
-    int type;                  /* unit type: EF_SHIP, EF_PLANE, EF_LAND */
     void *cp;                  /* pointer to desc of thing */
-    void *thing;               /* thing's struct */
+    struct empobj *thing;      /* thing's struct */
 };
 
 struct airport {
@@ -68,15 +60,9 @@ struct airport {
     natid own;
 };
 
-union item_u {
-    struct shpstr ship;
-    struct plnstr plane;
-    struct lndstr land;
-};
-
 static void add_airport(struct emp_qelem *, coord, coord);
 static int air_damage(struct emp_qelem *, coord, coord, int, natid,
-                     s_char *, int);
+                     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);
@@ -84,16 +70,16 @@ 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 *);
+                          int, struct ichrstr *, int, int);
 static void mission_pln_sel(struct emp_qelem *, int, int, int);
 static int perform_mission(coord, coord, natid, struct emp_qelem *, int,
-                          s_char *, int);
+                          char *, int);
 
 /*
  * Interdict commodities & transported planes
  */
 int
-ground_interdict(coord x, coord y, natid victim, s_char *s)
+ground_interdict(coord x, coord y, natid victim, char *s)
 {
     int cn;
     int dam = 0, newdam, rel;
@@ -122,13 +108,13 @@ ground_interdict(coord x, coord y, natid victim, s_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;
@@ -143,7 +129,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;
     }
@@ -160,7 +146,7 @@ only_subs(struct emp_qelem *list)
     for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
        glp = (struct genlist *)qp;
 
-       if (glp->type != EF_SHIP)
+       if (glp->thing->ef_type != EF_SHIP)
            return 0;
        mcp = glp->cp;
        if (!(mcp->m_flags & M_SUB))
@@ -174,10 +160,9 @@ only_subs(struct emp_qelem *list)
 
 /*
  *  Interdict ships & land units
- *
  */
 int
-unit_interdict(coord x, coord y, natid victim, s_char *s, int hardtarget,
+unit_interdict(coord x, coord y, natid victim, char *s, int hardtarget,
               int mission)
 {
     int cn;
@@ -216,7 +201,7 @@ unit_interdict(coord x, coord y, natid victim, s_char *s, int hardtarget,
        }
     }
     if (dam) {
-       collateral_damage(x, y, dam, 0);
+       collateral_damage(x, y, dam);
     }
     return dam;
 }
@@ -302,8 +287,8 @@ build_mission_list_type(struct genlist *mi, coord x, coord y, int mission,
 {
     struct nstr_item ni;
     struct genlist *glp;
-    struct genitem *gp;
-    union item_u item;
+    struct empobj *gp;
+    union empobj_storage item;
     int dist;
     int radius;
     int relat;
@@ -311,7 +296,7 @@ build_mission_list_type(struct genlist *mi, coord x, coord y, int mission,
 
     snxtitem_all(&ni, type);
     while (nxtitem(&ni, &item)) {
-       gp = (struct genitem *)&item;
+       gp = (struct empobj *)&item;
 
        if (gp->own == 0)
            continue;
@@ -339,7 +324,7 @@ build_mission_list_type(struct genlist *mi, coord x, coord y, int mission,
 
        radius = gp->radius;
        if (mission != MI_RESERVE)      /* XXX */
-           oprange(gp, type, &radius);
+           oprange(gp, &radius);
 
        if (dist > radius)
            continue;
@@ -348,7 +333,7 @@ build_mission_list_type(struct genlist *mi, coord x, coord y, int mission,
        /* Now check from where the object actually is */
        dist = mapdist(x, y, gp->x, gp->y);
        radius = 999;
-       oprange(gp, type, &radius);
+       oprange(gp, &radius);
        if (dist > radius)
            continue;
        /* Ok, the object can get to where the x,y is */
@@ -359,10 +344,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 &&
@@ -374,18 +359,7 @@ build_mission_list_type(struct genlist *mi, coord x, coord y, int mission,
 
        glp = malloc(sizeof(struct genlist));
        memset(glp, 0, sizeof(struct genlist));
-       glp->type = type;
-       switch (type) {
-       case EF_LAND:
-           glp->cp = &lchr[(int)gp->type];
-           break;
-       case EF_SHIP:
-           glp->cp = &mchr[(int)gp->type];
-           break;
-       case EF_PLANE:
-           glp->cp = &plchr[(int)gp->type];
-           break;
-       }
+       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);
@@ -409,8 +383,7 @@ find_escorts(coord x, coord y, natid cn, struct emp_qelem *escorts)
            continue;
 
        dist = mapdist(x, y, plane.pln_x, plane.pln_y);
-
-       if (dist > ((int)((float)plane.pln_range / 2.0)))
+       if (dist > plane.pln_range / 2)
            continue;
 
        plp = malloc(sizeof(struct plist));
@@ -423,22 +396,23 @@ find_escorts(coord x, coord y, natid cn, struct emp_qelem *escorts)
 
 static int
 perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
-               int mission, s_char *s, int hardtarget)
+               int mission, char *s, int hardtarget)
 {
     struct emp_qelem *qp, missiles, bombers, escorts, airp, b, e;
     struct emp_qelem *newqp;
     struct genlist *glp;
     struct plist *plp;
-    struct genitem *gp;
+    struct empobj *gp;
     struct lndstr *lp;
     struct shpstr *sp;
     struct sctstr sect;
     struct mchrstr *mcp;
     struct plchrstr *pcp;
-    int dam = 0, dam2, mission_flags, tech;
+    int dam = 0, dam2, mission_flags;
     natid plane_owner = 0;
-    int gun, shell, md, air_dam = 0;
-    double range2, prb, range, mobcost, hitchance;
+    int md, range, air_dam = 0;
+    double prb, hitchance, vrange;
+    int targeting_ships = *s == 's'; /* "subs" or "ships" FIXME gross! */
 
     getsect(x, y, &sect);
 
@@ -453,11 +427,8 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
 
        md = mapdist(x, y, gp->x, gp->y);
 
-       if (glp->type == EF_LAND) {
-           lp = glp->thing;
-
-           if (lp->lnd_effic < LAND_MINFIREEFF)
-               continue;
+       if (glp->thing->ef_type == EF_LAND) {
+           lp = (struct lndstr *)glp->thing;
 
            if (mission == MI_SINTERDICT)
                continue;
@@ -466,62 +437,42 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
                (md > land_max_interdiction_range))
                continue;
 
-           if (md > (lp->lnd_frg / 2))
-               continue;
-
-           if ((lp->lnd_ship != -1) || (lp->lnd_land != -1))
+           /* Too ponderous for interdiction fire */
+           if (lchr[(int)lp->lnd_type].l_flags & L_HEAVY)
                continue;
 
-           if (lnd_getmil(lp) < 1)
+           range = roundrange(lnd_fire_range(lp));
+           if (md > range)
                continue;
 
-           range = techfact((int)lp->lnd_tech, (double)lp->lnd_frg / 2.0);
-           range2 = (double)roundrange(range);
-
-           if (md > range2)
+           dam2 = lnd_fire(lp);
+           putland(lp->lnd_uid, lp);
+           if (dam2 < 0)
                continue;
 
-           shell = lp->lnd_item[I_SHELL];
-           gun = lp->lnd_item[I_GUN];
-           if (shell == 0 || gun == 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) {
-                   double dam3 = (double)dam2;
-                   if (chance(((double)lp->lnd_acc) / 100.0))
-                       dam2 = ldround((dam3 / 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);
            }
-       } else if (glp->type == EF_SHIP) {
-           sp = glp->thing;
+           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))
@@ -532,60 +483,38 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
                    continue;
                if (!(mcp->m_flags & M_DCH) && !(mcp->m_flags & M_SUBT))
                    continue;
-               range2 = techfact(sp->shp_tech, (double)mcp->m_vrnge);
-               range2 *= (double)sp->shp_effic / 200.0;
-               if (md > range2)
+               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 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;
-
-               range = sp->shp_effic * techfact(sp->shp_tech,
-                                                ((double)sp->shp_frnge)) /
-                   100.0;
-
-               range2 = (double)roundrange(range);
+               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;
-               mobcost = sp->shp_effic * 0.01 * sp->shp_speed;
-               mobcost = (480.0 / (mobcost +
-                                   techfact(sp->shp_tech, mobcost)));
-               sp->shp_mobil -= mobcost;
+               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",
                   prship(sp), cname(victim), s, xyas(x, y, sp->shp_own));
                wu(0, sp->shp_own,
-                  "\tEffective torpedo range is %.1f\n", range);
+                  "\tEffective torpedo range is %d.0\n", range);
                wu(0, sp->shp_own,
                   "\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",
@@ -593,8 +522,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,
@@ -605,32 +532,25 @@ 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 = techfact(sp->shp_tech, (double)mcp->m_frnge / 2.0);
-               range2 = (double)roundrange(range);
-               if (md > range2)
+               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)
+               if (mission == MI_SINTERDICT)
+                   dam2 = shp_dchrg(sp);
+               else
+                   dam2 = shp_fire(sp);
+               putship(sp->shp_uid, sp);
+               if (dam2 < 0)
                    continue;
-               gun = MAX(gun, 1);
-               dam2 = seagun(sp->shp_effic, gun);
-               if (range2 == 0.0)
+               if (range == 0.0)
                    prb = 1.0;
                else
-                   prb = ((double)md) / range2;
+                   prb = (double)md / range;
                prb *= prb;
                if (chance(prb))
-                   dam2 = (int)((float)dam2 / 2.0);
+                   dam2 /= 2;
                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);
@@ -640,11 +560,8 @@ 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->type == EF_PLANE) {
+       } else if (glp->thing->ef_type == EF_PLANE) {
            pcp = glp->cp;
            if (pcp->pl_flags & P_M)
                /* units have their own missile interdiction */
@@ -662,6 +579,9 @@ 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)) {
@@ -727,19 +647,18 @@ 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);
+                                       0, mission_flags);
 
        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);
+                                       P_F | P_ESC, mission_flags);
 
        pp = BestAirPath(buf, air->x, air->y, x, y);
        if (CANT_HAPPEN(!pp))
@@ -752,7 +671,7 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
               xyas(air->x, air->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, mission_flags, 0);
 
        if (!QEMPTY(&b))
            air_dam +=
@@ -764,7 +683,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);
@@ -832,22 +751,8 @@ cando(int mission, int type)
     return 0;
 }
 
-s_char *
-nameofitem(struct genitem *gp, int type)
-{
-    switch (type) {
-    case EF_SHIP:
-       return prship((struct shpstr *)gp);
-    case EF_PLANE:
-       return prplane((struct plnstr *)gp);
-    case EF_LAND:
-       return prland((struct lndstr *)gp);
-    }
-    return NULL;
-}
-
-s_char *
-mission_name(short int mission)
+char *
+mission_name(short mission)
 {
     switch (mission) {
     case MI_INTERDICT:
@@ -874,11 +779,11 @@ void
 show_mission(int type, struct nstr_item *np)
 {
     int first = 1, radius;
-    union item_u item;
-    struct genitem *gp;
+    union empobj_storage item;
+    struct empobj *gp;
 
     while (nxtitem(np, &item)) {
-       gp = (struct genitem *)&item;
+       gp = (struct empobj *)&item;
        if (!player->owner || gp->own == 0)
            continue;
 
@@ -886,13 +791,13 @@ show_mission(int type, struct nstr_item *np)
            pr("Thing                         x,y   op-sect rad mission\n");
            first = 0;
        }
-       pr("%-25s", nameofitem(gp, type));
+       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, type, &radius);
+           oprange(gp, &radius);
            prxy(" %3d,%-3d", gp->opx, gp->opy, player->cnum);
            if (radius < gp->radius)
                pr("  %4d", radius);
@@ -914,7 +819,7 @@ show_mission(int type, struct nstr_item *np)
            pr("  %4d", plus);
        } else if (gp->mission == MI_ESCORT) {
            pr("        ");
-           pr("  %4d", (int)(item.plane.pln_range / 2.0));
+           pr("  %4d", item.plane.pln_range / 2);
        } else
            pr("              ");
        if (gp->mission)
@@ -925,34 +830,26 @@ show_mission(int type, struct nstr_item *np)
 }
 
 int
-oprange(struct genitem *gp, int type, int *radius)
+oprange(struct empobj *gp, int *radius)
 {
     int range;
-    struct shpstr ship;
-    struct lndstr land;
-    struct plnstr plane;
 
-    switch (type) {
+    switch (gp->ef_type) {
     case EF_SHIP:
-       getship(gp->uid, &ship);
-       range = ldround(techfact(gp->tech,
-                                (double)ship.shp_frnge / 2.0), 1);
+       range = ldround(shp_fire_range((struct shpstr *)gp), 1);
        break;
     case EF_LAND:
-       getland(gp->uid, &land);
-       range = ldround(techfact((int)land.lnd_tech,
-                                (double)land.lnd_frg / 2.0), 1);
+       range = ldround(lnd_fire_range((struct lndstr *)gp), 1);
        break;
     case EF_PLANE:
-       getplane(gp->uid, &plane);
        /* missiles go one way, so we can use all the range */
-       if (plchr[(int)plane.pln_type].pl_flags & P_M)
-           range = plane.pln_range;
+       if (plchr[(int)gp->type].pl_flags & P_M)
+           range = ((struct plnstr *)gp)->pln_range;
        else
-           range = ldround((double)plane.pln_range / 2.0, 1);;
+           range = ((struct plnstr *)gp)->pln_range / 2;
        break;
     default:
-       CANT_HAPPEN("bad TYPE");
+       CANT_REACH();
        range = -1;
     }
 
@@ -972,13 +869,8 @@ mission_pln_sel(struct emp_qelem *list, int wantflags, int nowantflags,
 {
     struct emp_qelem *qp, *next;
     struct plnstr *pp;
-    struct shpstr ship;
-    struct lndstr land;
-    struct sctstr sect;
     struct plchrstr *pcp;
     struct plist *plp;
-    int y, bad, bad1;
-    unsigned int x;
 
     for (qp = list->q_forw; qp != list; qp = next) {
        next = qp->q_forw;
@@ -1006,142 +898,18 @@ mission_pln_sel(struct emp_qelem *list, int wantflags, int nowantflags,
            }
        }
 
-       bad = 0;
-       bad1 = 0;
-       if (wantflags) {
-           for (x = 0; x < sizeof(wantflags) * 8; x++) {
-               y = (1 << x);
-               if ((wantflags & y) == y)
-                   if ((pcp->pl_flags & y) != y) {
-                       switch (y) {
-                       case P_F:
-                       case P_ESC:
-                           bad1 = 2;
-                           break;
-                       case P_E:
-                       case P_L:
-                       case P_K:
-                           bad1 = 1;
-                           break;
-                       default:
-                           bad = 1;
-                       }
-                   }
-           }
-           if (bad) {
-               emp_remque(qp);
-               free(qp);
-               continue;
-           }
-           if (bad1 == 2) {
-               if ((pcp->pl_flags & P_ESC) || (pcp->pl_flags & P_F))
-                   bad1 = 0;
-           }
-           if (bad1 == 1) {
-               if ((pcp->pl_flags & P_E) ||
-                   (pcp->pl_flags & P_K) || (pcp->pl_flags & P_L))
-                   bad1 = 0;
-           }
-           if (bad1) {
-               emp_remque(qp);
-               free(qp);
-               continue;
-           }
-       }
-       bad = 0;
-       bad1 = 0;
-       if (nowantflags) {
-           for (x = 0; x < sizeof(nowantflags) * 8; x++) {
-               y = (1 << x);
-               if ((nowantflags & y) == y)
-                   if ((pcp->pl_flags & y) == y)
-                       bad = 1;
-           }
-           if (bad) {
-               emp_remque(qp);
-               free(qp);
-               continue;
-           }
-       }
-       if (pp->pln_ship >= 0) {
-           if (!getship(pp->pln_ship, &ship)) {
-             shipsunk:
-               pp->pln_effic = 0;
-               putplane(pp->pln_uid, pp);
-               emp_remque(qp);
-               free(qp);
-               continue;
-           }
-           if (!can_be_on_ship(pp->pln_uid, ship.shp_uid)) {
-               goto shipsunk;
-           }
-           if (ship.shp_effic < SHIP_MINEFF) {
-               goto shipsunk;
-           }
-           /* Can't fly off of inefficient or non-owned, non-allied ships */
-           if ((ship.shp_effic < SHP_AIROPS_EFF) ||
-               ((ship.shp_own != pp->pln_own) &&
-                (getrel(getnatp(ship.shp_own), pp->pln_own) != ALLIED))) {
-               emp_remque(qp);
-               free(qp);
-               continue;
-           }
+       if (!pln_capable(pp, wantflags, nowantflags)) {
+           emp_remque(qp);
+           free(qp);
+           continue;
        }
-       if (pp->pln_land >= 0) {
-           if (!getland(pp->pln_land, &land)) {
-             landdead:
-               pp->pln_effic = 0;
-               putplane(pp->pln_uid, pp);
-               emp_remque(qp);
-               free(qp);
-               continue;
-           }
-           if (!(pcp->pl_flags & P_E))
-               goto landdead;
-           if (land.lnd_effic < LAND_MINEFF)
-               goto landdead;
-
-           /* Can't fly off of inefficient or non-owned, non-allied units */
-           if ((land.lnd_effic < LND_AIROPS_EFF) ||
-               ((land.lnd_own != pp->pln_own) &&
-                (getrel(getnatp(land.lnd_own), pp->pln_own) != ALLIED))) {
-               emp_remque(qp);
-               free(qp);
-               continue;
-           }
 
-           /* Can't fly off units in ships or other units */
-           if ((land.lnd_ship >= 0) || (land.lnd_land >= 0)) {
-               emp_remque(qp);
-               free(qp);
-               continue;
-           }
-       }
-       /* Now, check the sector status if not on a plane or unit */
-       if ((pp->pln_ship < 0) && (pp->pln_land < 0)) {
-           /* If we can't get the sector, we can't check it, and can't fly */
-           if (!getsect(pp->pln_x, pp->pln_y, &sect)) {
-               emp_remque(qp);
-               free(qp);
-               continue;
-           }
-           /* 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)) {
-               emp_remque(qp);
-               free(qp);
-               continue;
-           }
-           /* non-vtol plane */
-           if ((pcp->pl_flags & P_V) == 0) {
-               if ((sect.sct_type != SCT_AIRPT) || (sect.sct_effic < 40)) {
-                   emp_remque(qp);
-                   free(qp);
-                   continue;
-               }
-           }
+       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);
@@ -1156,29 +924,29 @@ mission_pln_sel(struct emp_qelem *list, int wantflags, int nowantflags,
 
 /*
  * Arm only the planes at x,y
- *
  */
 static int
 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_flags)
 {
     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, flags, mission) < 0) {
            emp_remque(qp);
            free(qp);
            continue;
@@ -1189,8 +957,6 @@ mission_pln_arm(struct emp_qelem *list, coord x, coord y, int dist,
            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;
@@ -1206,29 +972,24 @@ mission_pln_arm(struct emp_qelem *list, coord x, coord y, int dist,
            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, flags);
+       putplane(pp->pln_uid, pp);
     }
     return mission_flags;
 }
 
 int
 mission_pln_equip(struct plist *plp, struct ichrstr *ip, int flags,
-                 s_char mission)
+                 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;
@@ -1247,52 +1008,46 @@ 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)) {
+       load = pln_load(pp);
        itype = I_NONE;
        needed = 0;
        switch (mission) {
-       case 's':
-       case 'p':
+       case 's':               /* strategic bomb */
+       case 'p':               /* pinpoint bomb */
            if (pp->pln_nuketype == -1) {
                itype = I_SHELL;
-               needed = pp->pln_load;
+               needed = 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':
+       case 't':               /* transport */
+       case 'd':               /* drop */
            if ((pcp->pl_flags & P_C) == 0 || ip == 0)
                break;
            itype = ip->i_uid;
-           needed = (pp->pln_load * 2) / ip->i_lbs;
+           needed = (load * 2) / ip->i_lbs;
            break;
-       case 'a':
+       case 'a':               /* paradrop */
            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;
+           needed = load / ip->i_lbs;
            break;
        case 'i':               /* missile interception */
-           if (pp->pln_load) {
+           if (load) {
                itype = I_SHELL;
-               needed = pp->pln_load;
+               needed = load;
            }
            break;
+       case 'r':               /* reconnaissance */
+       case 0:                 /* plane interception */
+           break;
        default:
+           CANT_REACH();
            break;
        }
-       if (rval < 0 || (itype != I_NONE && needed <= 0)) {
+       if (itype != I_NONE && needed <= 0)
            return -1;
-       }
        if (itype != I_NONE) {
            if (itype == I_SHELL && item[itype] < needed)
                item[itype] += supply_commod(plp->plane.pln_own,
@@ -1314,7 +1069,7 @@ mission_pln_equip(struct plist *plp, struct ichrstr *ip, int flags,
        putland(land.lnd_uid, &land);
     else
        putsect(&sect);
-    return rval;
+    return 0;
 }
 
 /*
@@ -1378,7 +1133,7 @@ divide(struct emp_qelem *l1, struct emp_qelem *l2, coord x, coord y)
 
 static int
 air_damage(struct emp_qelem *bombers, coord x, coord y, int mission,
-          natid victim, s_char *s, int hardtarget)
+          natid victim, char *s, int hardtarget)
 {
     struct emp_qelem *qp;
     struct plist *plp;
@@ -1456,15 +1211,12 @@ 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 */
-       if (plp->pcp->pl_flags & P_M) {
-           makelost(EF_PLANE, pp->pln_own, pp->pln_uid, pp->pln_x,
-                    pp->pln_y);
-           pp->pln_own = 0;
-       }
+       if (plp->pcp->pl_flags & P_M)
+           pp->pln_effic = 0;
     }
 
     return dam;
@@ -1480,11 +1232,11 @@ 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;
+    int mission_flags, combat = 0, rel, dist, z;
     struct emp_qelem *qp, interceptors, airp, i, empty, *next;
     struct plist *plp;
     struct genlist *glp;
-    struct genitem *gp;
+    struct empobj *gp;
     struct genlist mi[MAXNOC];
     char buf[512];
     char *path;
@@ -1520,6 +1272,8 @@ air_defense(coord x, coord y, natid victim, struct emp_qelem *bomb_list,
            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);
 
@@ -1552,7 +1306,7 @@ air_defense(coord x, coord y, natid victim, struct emp_qelem *bomb_list,
        for (qp = interceptors.q_forw; qp != (&interceptors);
             qp = qp->q_forw)
            tcount++;
-       tcount -= (count * 2);
+       tcount -= count * 2;
        /* Just in case there are more incoming than we have */
        if (tcount < 0)
            tcount = 0;
@@ -1588,7 +1342,6 @@ air_defense(coord x, coord y, natid victim, struct emp_qelem *bomb_list,
            /* 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 */
@@ -1607,8 +1360,8 @@ air_defense(coord x, coord y, natid victim, struct emp_qelem *bomb_list,
                continue;
            }
            mission_flags =
-               mission_pln_arm(&i, air->x, air->y, 2 * dist, 'r', 0, P_F,
-                               mission_flags, &tech);
+               mission_pln_arm(&i, air->x, air->y, 2 * dist, 0, 0, P_F,
+                               mission_flags);
 
            /* Did we run out of interceptors? */
            if (QEMPTY(&i))
@@ -1622,8 +1375,10 @@ air_defense(coord x, coord y, natid victim, struct emp_qelem *bomb_list,
            }
 
            path = BestAirPath(buf, air->x, air->y, x, y);
-           if (CANT_HAPPEN(!path))
+           if (CANT_HAPPEN(!path)) {
+               pln_put(&i);
                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)) {
@@ -1635,7 +1390,7 @@ air_defense(coord x, coord y, natid victim, struct emp_qelem *bomb_list,
            /* 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);
+                        path, mission_flags, 1);
 
            /* If none made it, continue */
            if (QEMPTY(&i))
@@ -1665,6 +1420,8 @@ air_defense(coord x, coord y, natid victim, struct emp_qelem *bomb_list,
 
            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