]> git.pond.sub.org Git - empserver/blobdiff - src/lib/subs/plnsub.c
Update copyright notice
[empserver] / src / lib / subs / plnsub.c
index 3567333cf41539a3f99b46f2dfec8e7e408f983b..deebbe3dd9673f89851664dc37b5ad940b5c71e2 100644 (file)
@@ -1,11 +1,11 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2010, Dave Pare, Jeff Bailey, Thomas Ruschak,
- *                           Ken Stevens, Steve McClure
+ *  Copyright (C) 1986-2016, 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/>.
  *
  *  ---
  *
  *     Dave Pare, 1986
  *     Ken Stevens, 1995
  *     Steve McClure, 1998-2000
- *     Markus Armbruster, 2004-2009
+ *     Markus Armbruster, 2004-2015
  */
 
 #include <config.h>
 
+#include "chance.h"
+#include "empobj.h"
 #include "file.h"
 #include "item.h"
 #include "land.h"
-#include "lost.h"
 #include "map.h"
 #include "misc.h"
 #include "nat.h"
 #include "nsc.h"
 #include "nuke.h"
 #include "optlist.h"
-#include "path.h"
+#include "plague.h"
 #include "plane.h"
 #include "player.h"
 #include "prototypes.h"
 #include "ship.h"
 #include "xy.h"
 
-static int fit_plane_on_ship(struct plnstr *, struct shpstr *);
+static int ship_can_carry(struct shpstr *, int, int, int, int);
+static int inc_shp_nplane(struct plnstr *, int *, int *, int *);
 
 /*
  * Get planes and escorts argument.
- * Read planes into *NI_BOMB, and (optional) escorts into *NI_ESC.
- * If INPUT_BOMB is not empty, use it, else prompt for more input.
- * Same for INPUT_ESC.
- * If we got a plane argument, initialize *NI_BOMB and *NI_ESC, and
+ * Read planes into *@ni_bomb, and (optional) escorts into *@ni_esc.
+ * If @input_bomb is not empty, use it, else prompt for more input.
+ * Same for @input_esc.
+ * If we got a plane argument, initialize *@ni_bomb and *@ni_esc, and
  * return 0.
- * Else return -1 (*NI_BOMB and *NI_ESC may be modified).
+ * Else return -1 (*@ni_bomb and *@ni_esc may be modified).
  */
 int
 get_planes(struct nstr_item *ni_bomb, struct nstr_item *ni_esc,
@@ -81,11 +82,12 @@ get_planes(struct nstr_item *ni_bomb, struct nstr_item *ni_esc,
 
 /*
  * Get assembly point argument.
- * If INPUT is not empty, use it, else prompt for more input using PROMPT.
- * If this yields a valid assembly point, read it into *AP_SECT and
- * return AP_SECT.
+ * If @input is not empty, use it.
+ * Else prompt for more input using @prompt.
+ * If this yields a valid assembly point, read it into *@ap_sect and
+ * return @ap_sect.
  * Else complain and return NULL.
- * *AP_SECT and BUF[1024] may be modified in either case.
+ * *@ap_sect and @buf[1024] may be modified in either case.
  */
 struct sctstr *
 get_assembly_point(char *input, struct sctstr *ap_sect, char *buf)
@@ -102,8 +104,7 @@ get_assembly_point(char *input, struct sctstr *ap_sect, char *buf)
        return NULL;
 
     /* over own or allied sector is fine */
-    if (ap_sect->sct_own == player->cnum
-       || getrel(getnatp(ap_sect->sct_own), player->cnum) == ALLIED)
+    if (relations_with(ap_sect->sct_own, player->cnum) == ALLIED)
        return ap_sect;
 
     /* over own or allied ship is fine */
@@ -111,8 +112,7 @@ get_assembly_point(char *input, struct sctstr *ap_sect, char *buf)
     while (nxtitem(&ni, &ship)) {
        if (ship.shp_effic < SHIP_MINEFF || ship.shp_own == 0)
            continue;
-       if (ship.shp_own == player->cnum
-           || getrel(getnatp(ship.shp_own), player->cnum) == ALLIED)
+       if (relations_with(ship.shp_own, player->cnum) == ALLIED)
            return ap_sect;
     }
 
@@ -120,20 +120,25 @@ get_assembly_point(char *input, struct sctstr *ap_sect, char *buf)
     return NULL;
 }
 
+/*
+ * Find out whether planes can fly one-way to @x,@y.
+ * Offer the player any carriers there.  If he chooses one, read it
+ * into @target->ship.  Else read the target sector into @target->sect.
+ * If planes can land there, set required plane flags in *@flagsp, and
+ * return 0.  Else return -1.
+ */
 int
-pln_onewaymission(struct sctstr *target, int *shipno, int *flagp)
+pln_where_to_land(coord x, coord y,
+                 union empobj_storage *target, int *flagsp)
 {
     int nships;
     int cno;
-    int flags, fl;
-    struct shpstr ship;
+    int fl;
     char buf[1024];
     char *p;
 
-    flags = *flagp;
-
     /* offer carriers */
-    nships = carriersatxy(target->sct_x, target->sct_y, player->cnum);
+    nships = carriersatxy(x, y, player->cnum);
     if (nships) {
        for (;;) {
            p = getstring("Carrier #? ", buf);
@@ -142,64 +147,56 @@ pln_onewaymission(struct sctstr *target, int *shipno, int *flagp)
            if (!*p)
                break;
            cno = atoi(p);
-           if (cno < 0
-               || !getship(cno, &ship)
+           if (!getship(cno, &target->ship)
                || (!player->owner
-                   && (getrel(getnatp(ship.shp_own), player->cnum)
+                   && (relations_with(target->ship.shp_own, player->cnum)
                        != ALLIED))) {
                pr("Not yours\n");
                continue;
            }
-           if (ship.shp_x != target->sct_x || ship.shp_y != target->sct_y) {
-               pr("Ship #%d not in %s\n", cno,
-                  xyas(target->sct_x, target->sct_y, player->cnum));
+           if (target->ship.shp_x != x || target->ship.shp_y != y) {
+               pr("Ship #%d not in %s\n", cno, xyas(x, y, player->cnum));
                continue;
            }
-           fl = carrier_planes(&ship, 0);
+           fl = carrier_planes(&target->ship, 0);
            if (fl == 0) {
-               pr("Can't land on %s.\n", prship(&ship));
+               pr("Can't land on %s.\n", prship(&target->ship));
                continue;
            }
            /* clear to land on ship#CNO */
            pr("landing on carrier %d\n", cno);
-           flags |= fl;
-           *shipno = cno;
-           *flagp = flags;
+           *flagsp |= fl;
            return 0;
        }
     }
 
     /* try to land at sector */
-    if (target->sct_own != player->cnum
-       && getrel(getnatp(target->sct_own), player->cnum) != ALLIED) {
-       pr("Nowhere to land at sector %s!\n",
-          xyas(target->sct_x, target->sct_y, player->cnum));
+    getsect(x, y, &target->sect);
+    if (relations_with(target->sect.sct_own, player->cnum) != ALLIED) {
+       pr("Nowhere to land at sector %s!\n", xyas(x, y, player->cnum));
        return -1;
     }
-    if (target->sct_type == SCT_MOUNT) {
-       pr("Nowhere to land at sector %s!\n",
-          xyas(target->sct_x, target->sct_y, player->cnum));
+    if (target->sect.sct_type == SCT_MOUNT) {
+       pr("Nowhere to land at sector %s!\n", xyas(x, y, player->cnum));
        return -1;
     }
-    if (target->sct_type != SCT_AIRPT || target->sct_effic < 60)
-       flags |= P_V;
-
     /* clear to land at sector */
-    *shipno = -1;
-    *flagp = flags;
+    if (target->sect.sct_type != SCT_AIRPT || target->sect.sct_effic < 60)
+       *flagsp |= P_V;
     return 0;
 }
 
 int
-pln_oneway_to_carrier_ok(struct emp_qelem *bomb_list,
-                        struct emp_qelem *esc_list, int cno)
+pln_can_land_on_carrier(struct emp_qelem *bomb_list,
+                       struct emp_qelem *esc_list,
+                       struct shpstr *sp)
+
 {
+    int n, nch, nxl, nmsl;
     struct emp_qelem *list, *qp;
     struct plist *plp;
-    struct shpstr ship;
 
-    if (cno < 0 || !getship(cno, &ship))
-       return 0;
+    n = shp_nplane(sp, &nch, &nxl, &nmsl);
 
     /* for both lists */
     for (list = bomb_list;
@@ -207,13 +204,14 @@ pln_oneway_to_carrier_ok(struct emp_qelem *bomb_list,
         list = list == bomb_list ? esc_list : NULL) {
        for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
            plp = (struct plist *)qp;
-           if (plp->plane.pln_ship == ship.shp_uid)
+           if (plp->plane.pln_ship == sp->shp_uid)
                continue;
-           if (!fit_plane_on_ship(&plp->plane, &ship))
+           n++;
+           if (!inc_shp_nplane(&plp->plane, &nch, &nxl, &nmsl))
                return 0;
        }
     }
-    return 1;
+    return ship_can_carry(sp, n, nch, nxl, nmsl);
 }
 
 void
@@ -229,7 +227,7 @@ pln_newlanding(struct emp_qelem *list, coord tx, coord ty, int cno)
     for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
        plp = (struct plist *)qp;
        if (cno >= 0) {
-           if (!could_be_on_ship(&plp->plane, &ship, 0, 0, 0, 0))
+           if (!could_be_on_ship(&plp->plane, &ship))
                pr("\t%s cannot land on ship #%d! %s aborts!\n",
                   prplane(&plp->plane), cno, prplane(&plp->plane));
            else if (!put_plane_on_ship(&plp->plane, &ship))
@@ -241,6 +239,9 @@ pln_newlanding(struct emp_qelem *list, coord tx, coord ty, int cno)
                       cname(player->cnum), prplane(&plp->plane),
                       prship(&ship));
                }
+               if (plp->pcp->pl_crew && plp->pstage == PLG_INFECT
+                   && ship.shp_pstage == PLG_HEALTHY)
+                   ship.shp_pstage = PLG_EXPOSED;
            }
        } else {
            plp->plane.pln_x = tx;
@@ -252,6 +253,9 @@ pln_newlanding(struct emp_qelem *list, coord tx, coord ty, int cno)
                   cname(player->cnum),
                   prplane(&plp->plane), xyas(tx, ty, sect.sct_own));
            }
+           if (plp->pcp->pl_crew && plp->pstage == PLG_INFECT
+               && sect.sct_pstage == PLG_HEALTHY)
+               sect.sct_pstage = PLG_EXPOSED;
            plp->plane.pln_ship = cno;
        }
     }
@@ -268,14 +272,10 @@ pln_dropoff(struct emp_qelem *list, struct ichrstr *ip, coord tx, coord ty,
     struct shpstr ship;
     int there;
     int max;
+    int pstage;
 
     if (!ip)
        return;
-    amt = 0;
-    for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
-       plp = (struct plist *)qp;
-       amt += plp->load;
-    }
     if (cno < 0) {
        getsect(tx, ty, &sect);
        if (!sect.sct_own) {
@@ -285,8 +285,7 @@ pln_dropoff(struct emp_qelem *list, struct ichrstr *ip, coord tx, coord ty,
                pr("Your %s vanish without a trace.\n", ip->i_name);
            return;
        }
-       if (sect.sct_own != player->cnum
-           && getrel(getnatp(sect.sct_own), player->cnum) != ALLIED) {
+       if (relations_with(sect.sct_own, player->cnum) != ALLIED) {
            pr("You don't own %s!  Cargo jettisoned...\n",
               xyas(tx, ty, player->cnum));
            return;
@@ -298,20 +297,33 @@ pln_dropoff(struct emp_qelem *list, struct ichrstr *ip, coord tx, coord ty,
        }
        there = sect.sct_item[ip->i_uid];
        max = ITEM_MAX;
+       pstage = sect.sct_pstage;
     } else {
        getship(cno, &ship);
        there = ship.shp_item[ip->i_uid];
        max = mchr[ship.shp_type].m_item[ip->i_uid];
+       pstage = ship.shp_pstage;
     }
+
+    amt = 0;
+    for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
+       plp = (struct plist *)qp;
+       amt += plp->load;
+       if (plp->load
+           && plp->pstage == PLG_INFECT && pstage == PLG_HEALTHY)
+           pstage = PLG_EXPOSED;
+    }
+
     there += amt;
     if (there > max) {
-       pr("%d excess %s discarded\n", max - there, ip->i_name);
-       amt = max - there;
+       pr("%d excess %s discarded\n", there - max, ip->i_name);
+       amt -= there - max;
        there = max;
     }
     pr("%d %s landed safely", amt, ip->i_name);
     if (cno < 0) {
        sect.sct_item[ip->i_uid] = there;
+       sect.sct_pstage = pstage;
        if (sect.sct_own != player->cnum)
            wu(0, sect.sct_own, "%s planes drop %d %s in %s\n",
               cname(player->cnum), amt, ip->i_name,
@@ -320,6 +332,7 @@ pln_dropoff(struct emp_qelem *list, struct ichrstr *ip, coord tx, coord ty,
        putsect(&sect);
     } else {
        ship.shp_item[ip->i_uid] = there;
+       ship.shp_pstage = pstage;
        if (ship.shp_own != player->cnum)
            wu(0, ship.shp_own, "%s planes land %d %s on carrier %d\n",
               cname(player->cnum), amt, ip->i_name, ship.shp_uid);
@@ -357,13 +370,13 @@ pln_mine(struct emp_qelem *list, coord tx, coord ty)
 }
 
 /*
- * Has PP's type capabilities satisfying WANTFLAGS and NOWANTFLAGS?
+ * Has @pp's type capabilities satisfying @wantflags and @nowantflags?
  * A plane type is capable unless
- * - it lacks all of the P_B, P_T in WANTFLAGS, or
- * - it lacks all of the P_F, P_ESC in WANTFLAGS, or
- * - it lacks all of the P_E, P_L, P_K in WANTFLAGS, or
- * - it lacks any of the other capabilities in WANTFLAGS, or
- * - it has any of the capabilities in NOWANTFLAGS.
+ * - it lacks all of the P_B, P_T in @wantflags, or
+ * - it lacks all of the P_F, P_ESC in @wantflags, or
+ * - it lacks all of the P_E, P_L, P_K in @wantflags, or
+ * - it lacks any of the other capabilities in @wantflags, or
+ * - it has any of the capabilities in @nowantflags.
  */
 int
 pln_capable(struct plnstr *pp, int wantflags, int nowantflags)
@@ -398,7 +411,7 @@ pln_capable(struct plnstr *pp, int wantflags, int nowantflags)
 }
 
 /*
- * Return union of capabilities of planes in LIST.
+ * Return union of capabilities of planes in @list.
  */
 int
 pln_caps(struct emp_qelem *list)
@@ -417,10 +430,10 @@ pln_caps(struct emp_qelem *list)
 }
 
 /*
- * Find plane types that can operate from carrier SP.
- * If MSL find missile types, else non-missile types.
+ * Find plane types that can operate from carrier @sp.
+ * If @msl find missile types, else non-missile types.
  * Return a combination of P_L, P_K, P_E.
- * It's zero if SP can't support air operations due to its type or
+ * It's zero if @sp can't support air operations due to its type or
  * state (low efficiency).
  */
 int
@@ -461,8 +474,7 @@ pln_airbase_ok(struct plnstr *pp, int oneway, int noisy)
            CANT_REACH();
            return 0;
        }
-       if (ship.shp_own != pp->pln_own
-           && getrel(getnatp(ship.shp_own), pp->pln_own) != ALLIED) {
+       if (relations_with(ship.shp_own, pp->pln_own) != ALLIED) {
            if (noisy)
                pr("(note) An ally does not own the ship %s is on\n",
                   prplane(pp));
@@ -477,8 +489,7 @@ pln_airbase_ok(struct plnstr *pp, int oneway, int noisy)
            CANT_REACH();
            return 0;
        }
-       if (land.lnd_own != pp->pln_own
-           && getrel(getnatp(land.lnd_own), pp->pln_own) != ALLIED) {
+       if (relations_with(land.lnd_own, pp->pln_own) != ALLIED) {
            if (noisy)
                pr("(note) An ally does not own the unit %s is on\n",
                   prplane(pp));
@@ -496,8 +507,7 @@ pln_airbase_ok(struct plnstr *pp, int oneway, int noisy)
            return 0;
        }
 
-       if (sect.sct_own != pp->pln_own
-           && getrel(getnatp(sect.sct_own), pp->pln_own) != ALLIED) {
+       if (relations_with(sect.sct_own, pp->pln_own) != ALLIED) {
            if (noisy)
                pr("(note) An ally does not own the sector %s is in\n",
                   prplane(pp));
@@ -513,14 +523,14 @@ pln_airbase_ok(struct plnstr *pp, int oneway, int noisy)
            if (sect.sct_effic < 40) {
                if (noisy)
                    pr("%s is not 40%% efficient, %s can't take off from there.\n",
-                      xyas(sect.sct_x, sect.sct_y, pp->pln_own),
+                      xyas(sect.sct_x, sect.sct_y, player->cnum),
                       prplane(pp));
                return 0;
            }
            if (!oneway && sect.sct_effic < 60) {
                if (noisy)
                    pr("%s is not 60%% efficient, %s can't land there.\n",
-                      xyas(sect.sct_x, sect.sct_y, pp->pln_own),
+                      xyas(sect.sct_x, sect.sct_y, player->cnum),
                       prplane(pp));
                return 0;
            }
@@ -541,7 +551,12 @@ pln_sel(struct nstr_item *ni, struct emp_qelem *list, struct sctstr *ap,
 
     emp_initque(list);
     while (nxtitem(ni, &plane)) {
-       if (!player->owner)
+       /*
+        * It would be nice to let deities fly foreign planes, but
+        * much of the code assumes that only the plane's owner can
+        * fly it.
+        */
+       if (!plane.pln_own || plane.pln_own != player->cnum)
            continue;
        if (plane.pln_mobil <= 0)
            continue;
@@ -580,6 +595,7 @@ pln_sel(struct nstr_item *ni, struct emp_qelem *list, struct sctstr *ap,
        putplane(plane.pln_uid, &plane);
        plp = malloc(sizeof(struct plist));
        plp->load = 0;
+       plp->pstage = PLG_HEALTHY;
        plp->pcp = pcp;
        plp->plane = plane;
        emp_insque(&plp->queue, list);
@@ -630,14 +646,17 @@ pln_equip(struct plist *plp, struct ichrstr *ip, char mission)
     pcp = plp->pcp;
     if (pp->pln_ship >= 0) {
        getship(pp->pln_ship, &ship);
+       plp->pstage = ship.shp_pstage;
        item = ship.shp_item;
        own = ship.shp_own;
     } else if (pp->pln_land >= 0) {
        getland(pp->pln_land, &land);
+       plp->pstage = land.lnd_pstage;
        item = land.lnd_item;
        own = land.lnd_own;
     } else {
        getsect(pp->pln_x, pp->pln_y, &sect);
+       plp->pstage = sect.sct_pstage;
        item = sect.sct_item;
        own = sect.sct_oldown;
     }
@@ -681,6 +700,8 @@ pln_equip(struct plist *plp, struct ichrstr *ip, char mission)
        break;
     case 'r':          /* reconnaissance */
     case 'e':          /* escort */
+       load = 0;
+       break;
     case 'i':          /* missile interception */
        if (CANT_HAPPEN(!(pcp->pl_flags & P_M)
                        || !(pcp->pl_flags & (P_N | P_O))))
@@ -721,7 +742,10 @@ pln_equip(struct plist *plp, struct ichrstr *ip, char mission)
                                         plp->plane.pln_y,
                                         I_SHELL, needed);
 #endif
-       abandon_needed = !!would_abandon(&sect, itype, needed, NULL);
+       if (pp->pln_ship >= 0 || pp->pln_land >= 0)
+           abandon_needed = 0;
+       else
+           abandon_needed = !!would_abandon(&sect, itype, needed, NULL);
        if (item[itype] < needed + abandon_needed) {
            pr("Not enough %s for %s\n", ichr[itype].i_name, prplane(pp));
            return -1;
@@ -814,59 +838,77 @@ pln_put1(struct plist *plp)
 }
 
 /*
- * Can PP be loaded on a ship of SP's type?
- * Assume that it already carries N planes, of which NCH are choppers,
- * NXL xlight, NMSL light missiles, and the rest are light fixed-wing
+ * Can a carrier of @sp's type carry this load of planes?
+ * The load consists of @n planes, of which @nch are choppers, @nxl
+ * xlight, @nmsl light missiles, and the rest are light fixed-wing
  * planes.
  */
-int
-could_be_on_ship(struct plnstr *pp, struct shpstr *sp,
-                int n, int nch, int nxl, int nmsl)
+static int
+ship_can_carry(struct shpstr *sp, int n, int nch, int nxl, int nmsl)
 {
-    struct plchrstr *pcp = &plchr[pp->pln_type];
     struct mchrstr *mcp = &mchr[sp->shp_type];
+    int nfw = n - nch - nxl - nmsl;
+
+    if (nch > mcp->m_nchoppers) /* overflow into fixed-wing slots */
+       nfw += nch - mcp->m_nchoppers;
+    if (nxl > mcp->m_nxlight)  /* overflow into missile slots */
+       nmsl += nxl - mcp->m_nxlight;
+    if (nmsl && !(mcp->m_flags & (M_MSL | M_FLY)))
+       return 0;               /* missile slots wanted */
+    if (nfw && !(mcp->m_flags & M_FLY))
+       return 0;               /* fixed-wing slots wanted */
+    return nfw + nmsl <= mcp->m_nplanes;
+}
+
+/*
+ * Increment carrier plane counters for @pp.
+ * If it's a chopper, increment *@nch.
+ * Else, if it's x-light, increment *@nxl.
+ * Else, if it's a light missile, increment *@msl.
+ * Return non-zero if it's a chopper, x-light or light.
+ */
+static int
+inc_shp_nplane(struct plnstr *pp, int *nch, int *nxl, int *nmsl)
+{
+    struct plchrstr *pcp = &plchr[pp->pln_type];
 
     if (pcp->pl_flags & P_K)
-       nch++;
+       (*nch)++;
     else if (pcp->pl_flags & P_E)
-       nxl++;
+       (*nxl)++;
     else if (!(pcp->pl_flags & P_L))
        return 0;
     else if (pcp->pl_flags & P_M)
-       nmsl++;
-    n++;
-
-    n -= MIN(nch, mcp->m_nchoppers);
-    n -= MIN(nxl, mcp->m_nxlight);
-    if (nmsl && !(mcp->m_flags & (M_MSL | M_FLY)))
-       return 0;               /* missile slots wanted */
-    if (nmsl < n && !(mcp->m_flags & M_FLY))
-       return 0;               /* fixed-wing slots wanted */
-    return n <= mcp->m_nplanes;
+       (*nmsl)++;
+    return 1;
 }
 
 /*
- * Fit a plane of PP's type on ship SP.
- * Updating the plane accordingly is the caller's job.
- * Return whether it fits.
+ * Can @pp be loaded on a ship of @sp's type?
  */
-static int
-fit_plane_on_ship(struct plnstr *pp, struct shpstr *sp)
+int
+could_be_on_ship(struct plnstr *pp, struct shpstr *sp)
 {
-    int n, nch, nxl, nmsl;
+    int nch = 0, nxl = 0, nmsl = 0;
 
-    n = shp_nplane(sp, &nch, &nxl, &nmsl);
-    return could_be_on_ship(pp, sp, n, nch, nxl, nmsl);
+    if (!inc_shp_nplane(pp, &nch, &nxl, &nmsl))
+       return 0;
+    return ship_can_carry(sp, 1, nch, nxl, nmsl);
 }
 
 int
 put_plane_on_ship(struct plnstr *plane, struct shpstr *ship)
 {
+    int n, nch, nxl, nmsl;
+
     if (plane->pln_ship == ship->shp_uid)
        return 1;               /* Already on ship */
 
-    if (!fit_plane_on_ship(plane, ship))
-       return 0;
+    n = shp_nplane(ship, &nch, &nxl, &nmsl);
+    if (!inc_shp_nplane(plane, &nch, &nxl, &nmsl))
+       return 0;               /* not a carrier plane */
+    if (!ship_can_carry(ship, n + 1, nch, nxl, nmsl))
+       return 0;               /* no space */
 
     plane->pln_x = ship->shp_x;
     plane->pln_y = ship->shp_y;
@@ -875,27 +917,14 @@ put_plane_on_ship(struct plnstr *plane, struct shpstr *ship)
     return 1;
 }
 
-/*
- * Fit a plane of PP's type on land unit LP.
- * Updating the plane accordingly is the caller's job.
- * Return whether it fits.
- */
-static int
-fit_plane_on_land(struct plnstr *pp, struct lndstr *lp)
-{
-    struct plchrstr *pcp = plchr + pp->pln_type;
-    struct lchrstr *lcp = lchr + lp->lnd_type;
-
-    return (pcp->pl_flags & P_E) && lnd_nxlight(lp) < lcp->l_nxlight;
-}
-
 int
 put_plane_on_land(struct plnstr *plane, struct lndstr *land)
 {
     if (plane->pln_land == land->lnd_uid)
        return 1;               /* Already on unit */
-
-    if (!fit_plane_on_land(plane, land))
+    if (!(plchr[plane->pln_type].pl_flags & P_E))
+       return 0;
+    if (lnd_nxlight(land) >= lchr[land->lnd_type].l_nxlight)
        return 0;
 
     plane->pln_x = land->lnd_x;
@@ -937,7 +966,7 @@ plane_sweep(struct emp_qelem *plane_list, coord x, coord y)
 
        if (chance((100.0 - pln_acc(pp)) / 100.0)) {
            pr("Sweep! in %s\n",
-              xyas(sect.sct_x, sect.sct_y, pp->pln_own));
+              xyas(sect.sct_x, sect.sct_y, player->cnum));
            mines_there--;
            found = 1;
        }
@@ -976,17 +1005,16 @@ pln_hitchance(struct plnstr *pp, int hardtarget, int type)
 }
 
 int
-pln_damage(struct plnstr *pp, char type, int noisy)
+pln_damage(struct plnstr *pp, char type, char *noisy)
 {
     struct plchrstr *pcp = plchr + pp->pln_type;
-    int load, i;
-    int hitroll;
+    int load, i, hitroll, aim, len;
     int dam = 0;
-    int aim;
     int effective = 1;
     int pinbomber = 0;
+    char buf[80];
 
-    if (CANT_HAPPEN(nuk_on_plane(pp) >= 0)) /* FIXME check uses! */
+    if (CANT_HAPPEN(nuk_on_plane(pp) >= 0))
        return 0;
 
     load = pln_load(pp);
@@ -1012,27 +1040,36 @@ pln_damage(struct plnstr *pp, char type, int noisy)
        aim = 100 - aim;
     }
 
+    len = snprintf(buf, sizeof(buf), "%s", noisy);
     while (i--) {
+       if (noisy) {
+           if (len > 75) {
+               mpr(pp->pln_own, "%s\n", buf);
+               len = 0;
+           }
+       }
        dam += roll(6);
        hitroll = roll(100);
        if (hitroll >= 90) {
            dam += 8;
            if (noisy)
-               mpr(pp->pln_own, "BLAM");
+               len += sprintf(buf + len, "BLAM");
        } else if (hitroll < aim) {
            dam += 5;
            if (noisy)
-               mpr(pp->pln_own, "Blam");
+               len += sprintf(buf + len, "Blam");
        } else {
            dam += 1;
            if (noisy)
-               mpr(pp->pln_own, "blam");
+               len += sprintf(buf + len, "blam");
+       }
+       if (noisy) {
+           if (i)
+               len += sprintf(buf + len, "-");
        }
-       if (i && noisy)
-           mpr(pp->pln_own, "-");
     }
-    if (noisy)
-       mpr(pp->pln_own, "\n");
+    if (noisy && len)
+       mpr(pp->pln_own, "%s\n", buf);
     if (effective)
        dam *= 2;
     return dam;
@@ -1066,7 +1103,7 @@ pln_is_in_orbit(struct plnstr *pp)
 }
 
 /*
- * Set PP's tech to TLEV along with everything else that depends on it.
+ * Set @pp's tech to @tlev along with everything else that depends on it.
  */
 void
 pln_set_tech(struct plnstr *pp, int tlev)