]> git.pond.sub.org Git - empserver/blobdiff - src/lib/commands/load.c
Update copyright notice
[empserver] / src / lib / commands / load.c
index 7c5fb81041ca7e80ef3c37ae056c083e1c77b23b..ae70cbff0ac7f0a3065a2bbef43252f83371e4b2 100644 (file)
@@ -1,11 +1,11 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2005, Dave Pare, Jeff Bailey, Thomas Ruschak,
- *                           Ken Stevens, Steve McClure
+ *  Copyright (C) 1986-2012, 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,
  *  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/>.
  *
  *  ---
  *
- *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
- *  related information and legal notices. It is expected that any future
- *  projects/authors will amend these files as needed.
+ *  See files README, COPYING and CREDITS in the root of the source
+ *  tree for related information and legal notices.  It is expected
+ *  that future projects/authors will amend these files as needed.
  *
  *  ---
  *
  *  load.c: load/unload goods from a sector onto a ship or land unit
- * 
+ *
  *  Known contributors to this file:
  *     David Sharnoff, 1987
  *     Ken Stevens, 1995 (rewritten)
  *     Steve McClure, 1998-2000
+ *     Markus Armbruster, 2004-2011
  */
 
-#include <string.h>
-#include "misc.h"
-#include "player.h"
-#include "xy.h"
-#include "file.h"
-#include "plague.h"
-#include "sect.h"
-#include "ship.h"
-#include "plane.h"
-#include "land.h"
+#include <config.h>
+
+#include <ctype.h>
+#include "commands.h"
 #include "item.h"
-#include "nsc.h"
-#include "nat.h"
+#include "land.h"
 #include "optlist.h"
-#include "commands.h"
+#include "plague.h"
+#include "plane.h"
+#include "ship.h"
+#include "unit.h"
 
 /*
  * The values 1 and -1 are important below, don't change them.
  */
-#define        LOAD    1
-#define        UNLOAD  -1
+#define LOAD   1
+#define UNLOAD -1
 
 static int load_plane_ship(struct sctstr *sectp, struct shpstr *sp,
                           int noisy, int load_unload, int *nshipsp);
@@ -82,12 +78,12 @@ load(void)
     struct sctstr sect;
     struct shpstr ship;
     int retval;
-    s_char *p;
-    s_char buf[1024];
+    char *p;
+    char buf[1024];
 
-    if (!(p = getstarg(player->argp[1],
-                      "What commodity (or 'plane' or 'land')? ", buf))
-       || !*p)
+    p = getstarg(player->argp[1],
+                "What commodity (or 'plane' or 'land')? ", buf);
+    if (!p || !*p)
        return RET_SYN;
 
     if (!strncmp(p, "plane", 5))
@@ -101,65 +97,53 @@ load(void)
        return RET_SYN;
     }
 
-    if (!(p = getstarg(player->argp[2], "Ship(s): ", buf)) || !*p)
+    p = getstarg(player->argp[2], "Ship(s): ", buf);
+    if (!p || !*p)
        return RET_SYN;
 
     noisy = isdigit(*p);
 
-    if (!snxtitem(&nbst, EF_SHIP, p))
+    if (!snxtitem(&nbst, EF_SHIP, p, NULL))
        return RET_SYN;
 
-    nbst.flags &= ~(EFF_OWNER);
-
     load_unload = **player->argp == 'l' ? LOAD : UNLOAD;
 
     nships = 0;
-    while (nxtitem(&nbst, (s_char *)&ship)) {
+    while (nxtitem(&nbst, &ship)) {
        if (!ship.shp_own)
            continue;
-       if (!player->owner && (load_unload == UNLOAD)) {
-           continue;
-       }
-       if (opt_MARKET) {
-           if (ontradingblock(EF_SHIP, (int *)&ship)) {
-               pr("You cannot load/unload an item on the trading block!\n");
+       if (!player->owner) {
+           if (load_unload == UNLOAD || !noisy)
                continue;
-           }
-       }
-
-       if (ship.shp_own != player->cnum) {
-           if (!noisy)
-               continue;
-           if (getrel(getnatp(player->cnum), ship.shp_own) < FRIENDLY)
+           if (relations_with(ship.shp_own, player->cnum) < FRIENDLY)
                continue;
        }
+
        if (!getsect(ship.shp_x, ship.shp_y, &sect))    /* XXX */
            continue;
-       if ((sect.sct_own != player->cnum) &&
-           (ship.shp_own != player->cnum))
-           continue;
-       if (!player->owner &&
-           sect.sct_type != SCT_HARBR &&
-           (!opt_BIG_CITY || sect.sct_type != SCT_CAPIT))
-           continue;
        if (!sect.sct_own)
            continue;
-       if ((sect.sct_own != player->cnum) && (load_unload == LOAD)) {
-           if (noisy)
-               pr("You don't own %s \n",
-                  xyas(ship.shp_x, ship.shp_y, player->cnum));
-           continue;
+       if (!player->owner) {
+           if (ship.shp_own != player->cnum)
+               continue;
+           if (!sect_has_dock(&sect))
+               continue;
+           if (load_unload == LOAD) {
+               if (noisy)
+                   pr("You don't own %s \n",
+                      xyas(sect.sct_x, sect.sct_y, player->cnum));
+               continue;
+           }
        }
-       if (sect.sct_type != SCT_HARBR &&
-           (!opt_BIG_CITY || sect.sct_type != SCT_CAPIT)) {
+       if (!sect_has_dock(&sect)) {
            if (noisy)
-               pr("Sector %s is not a harbor%s.\n",
-                  xyas(ship.shp_x, ship.shp_y, player->cnum),
-                  opt_BIG_CITY ? " or a city" : "");
+               pr("Sector %s is not a harbor or canal.\n",
+                  xyas(sect.sct_x, sect.sct_y, player->cnum));
            continue;
        }
-       if (sect.sct_own != player->cnum && load_unload == UNLOAD
-           && getrel(getnatp(sect.sct_own), player->cnum) < FRIENDLY) {
+       if (load_unload == UNLOAD
+           && !player->owner
+           && relations_with(sect.sct_own, player->cnum) < FRIENDLY) {
            if (noisy)
                pr("You can't unload into an unfriendly %s\n",
                   dchr[sect.sct_type].d_name);
@@ -169,28 +153,34 @@ load(void)
            if (noisy)
                pr("The %s at %s is not 2%% efficient yet.\n",
                   dchr[sect.sct_type].d_name,
-                  xyas(ship.shp_x, ship.shp_y, player->cnum));
+                  xyas(sect.sct_x, sect.sct_y, player->cnum));
            continue;
        }
+
+       if (opt_MARKET) {
+           if (ontradingblock(EF_SHIP, &ship)) {
+               pr("You cannot load/unload an item on the trading block!\n");
+               continue;
+           }
+       }
+
        switch (type) {
        case EF_PLANE:
-           if (0 !=
-               (retval =
-                load_plane_ship(&sect, &ship, noisy, load_unload,
-                                &nships)))
+           retval = load_plane_ship(&sect, &ship, noisy, load_unload,
+                                    &nships);
+           if (retval != 0)
                return retval;
            break;
        case EF_LAND:
-           if (0 !=
-               (retval =
-                load_land_ship(&sect, &ship, noisy, load_unload,
-                               &nships)))
+           retval = load_land_ship(&sect, &ship, noisy, load_unload,
+                                   &nships);
+           if (retval != 0)
                return retval;
            break;
        case EF_SECTOR:
-           if (0 !=
-               (retval =
-                load_comm_ship(&sect, &ship, ich, load_unload, &nships)))
+           retval = load_comm_ship(&sect, &ship, ich, load_unload,
+                                   &nships);
+           if (retval != 0)
                return retval;
        }
        /* load/unload plague */
@@ -223,12 +213,12 @@ lload(void)
     struct sctstr sect;
     struct lndstr land;
     int retval;
-    s_char *p;
-    s_char buf[1024];
+    char *p;
+    char buf[1024];
 
-    if (!(p = getstarg(player->argp[1],
-                      "What commodity (or 'plane' or 'land')? ", buf))
-       || !*p)
+    p = getstarg(player->argp[1],
+                "What commodity (or 'plane' or 'land')? ", buf);
+    if (!p || !*p)
        return RET_SYN;
     if (!strncmp(p, "plane", 5))
        type = EF_PLANE;
@@ -241,64 +231,70 @@ lload(void)
        return RET_SYN;
     }
 
-    if (!(p = getstarg(player->argp[2], "Unit(s): ", buf)) || !*p)
+    p = getstarg(player->argp[2], "Unit(s): ", buf);
+    if (!p || !*p)
        return RET_SYN;
 
     noisy = isdigit(*p);
 
-    if (!snxtitem(&nbst, EF_LAND, p))
+    if (!snxtitem(&nbst, EF_LAND, p, NULL))
        return RET_SYN;
 
-    load_unload = *(*player->argp + 1) == 'l' ? LOAD : UNLOAD;
-
-    nbst.flags &= ~(EFF_OWNER);
+    load_unload = player->argp[0][1] == 'l' ? LOAD : UNLOAD;
 
     nunits = 0;
-    while (nxtitem(&nbst, (s_char *)&land)) {
+    while (nxtitem(&nbst, &land)) {
        if (land.lnd_own == 0)
            continue;
-
-       if (player->cnum != land.lnd_own &&
-           getrel(getnatp(player->cnum), land.lnd_own) != ALLIED)
-           continue;
+       if (!player->owner) {
+           if (load_unload == UNLOAD || !noisy)
+               continue;
+           if (relations_with(land.lnd_own, player->cnum) != ALLIED)
+               continue;
+       }
 
        if (!getsect(land.lnd_x, land.lnd_y, &sect))    /* XXX */
            continue;
+       if (!player->owner) {
+           if (land.lnd_own != player->cnum)
+               continue;
+           if (load_unload == LOAD) {
+               if (noisy)
+                   pr("Sector %s is not yours.\n",
+                      xyas(sect.sct_x, sect.sct_y, player->cnum));
+               continue;
+           }
+           if (relations_with(sect.sct_own, player->cnum) != ALLIED) {
+               pr("Sector %s is not yours.\n",
+                  xyas(sect.sct_x, sect.sct_y, player->cnum));
+               continue;
+           }
+       }
 
-       if (sect.sct_own != player->cnum && land.lnd_own != player->cnum)
-           continue;
        if (opt_MARKET) {
-           if (ontradingblock(EF_LAND, (int *)&land)) {
+           if (ontradingblock(EF_LAND, &land)) {
                pr("You cannot load/unload an item on the trading block!\n");
                continue;
            }
        }
 
-       if (sect.sct_own != player->cnum &&
-           getrel(getnatp(sect.sct_own), land.lnd_own) != ALLIED) {
-           pr("Sector %s is not yours.\n",
-              xyas(land.lnd_x, land.lnd_y, player->cnum));
-           continue;
-       }
        switch (type) {
        case EF_LAND:
-           if (0 !=
-               (retval =
-                load_land_land(&sect, &land, noisy, load_unload,
-                               &nunits)))
+           retval = load_land_land(&sect, &land, noisy, load_unload,
+                                   &nunits);
+           if (retval != 0)
                return retval;
            break;
        case EF_PLANE:
-           if (0 !=
-               (retval =
-                load_plane_land(&sect, &land, noisy, load_unload,
-                                &nunits)))
+           retval = load_plane_land(&sect, &land, noisy, load_unload,
+                                    &nunits);
+           if (retval != 0)
                return retval;
            break;
        case EF_SECTOR:
-           if (0 !=
-               (retval =
-                load_comm_land(&sect, &land, ich, load_unload, &nunits)))
+           retval = load_comm_land(&sect, &land, ich, load_unload,
+                                   &nunits);
+           if (retval != 0)
                return retval;
        }
        /* load/unload plague */
@@ -320,32 +316,54 @@ lload(void)
     return RET_OK;
 }
 
-void
-gift(int givee, int giver, s_char *ptr, int type, s_char *mesg)
+static int
+move_amount(int sect_amt, int unit_amt, int unit_max,
+          int load_unload, int amount)
+{
+    int move_amt;
+
+    if (amount < 0)
+       move_amt = -amount - unit_amt;
+    else
+       move_amt = load_unload == LOAD ? amount : -amount;
+    if (move_amt > unit_max - unit_amt)
+       move_amt = unit_max - unit_amt;
+    if (move_amt < -unit_amt)
+       move_amt = -unit_amt;
+    if (move_amt > sect_amt)
+       move_amt = sect_amt;
+    if (move_amt < sect_amt - ITEM_MAX)
+       move_amt = sect_amt - ITEM_MAX;
+    return move_amt;
+}
+
+static int
+load_comm_ok(struct sctstr *sectp, natid unit_own,
+            i_type item, int move_amt)
 {
-    s_char *p, line[256];
-
-    if (giver == givee)
-       return;
-
-
-    switch (type) {
-    case EF_SHIP:
-       p = prship((struct shpstr *)ptr);
-       break;
-    case EF_PLANE:
-       p = prplane((struct plnstr *)ptr);
-       break;
-    case EF_LAND:
-       p = prland((struct lndstr *)ptr);
-       break;
-    default:
-       CANT_HAPPEN("bad TYPE");
-       p = "a red herring";
+    if (!move_amt)
+       return 0;
+    if (move_amt < 0 && !player->god && unit_own != player->cnum)
+       return 0;
+    if (move_amt > 0 && !player->god && sectp->sct_own != player->cnum)
+       return 0;
+    if (sectp->sct_oldown != unit_own && item == I_CIVIL) {
+       pr("%s civilians refuse to %s at %s!\n",
+          (move_amt < 0 ? unit_own : sectp->sct_oldown) == player->cnum
+          ? "Your" : "Foreign",
+          move_amt < 0 ? "disembark" : "board",
+          xyas(sectp->sct_x, sectp->sct_y, player->cnum));
+       return 0;
     }
+    return 1;
+}
 
-    sprintf(line, "%s %s %s\n", cname(giver), p, mesg);
-    wu(0, givee, line);
+void
+gift(natid givee, natid giver, void *ptr, char *mesg)
+{
+    if (giver != givee)
+       wu(0, givee, "%s %s %s\n", cname(giver), unit_nameof(ptr), mesg);
+    unit_give_away(ptr, givee, 0);
 }
 
 static int
@@ -375,39 +393,39 @@ load_plane_ship(struct sctstr *sectp, struct shpstr *sp, int noisy,
     struct nstr_item ni;
     struct plnstr pln;
     int loaded = 0;
-    s_char buf[1024];
-    s_char *p;
-    s_char prompt[512];
+    char buf[1024];
+    char *p;
+    char prompt[512];
     struct mchrstr *mcp = mchr + sp->shp_type;
 
-    if (!(mcp->m_flags & (M_CHOPPER | M_XLIGHT | M_FLY | M_MSL))) {
+    if (mcp->m_nplanes + mcp->m_nchoppers + mcp->m_nxlight == 0) {
        if (noisy)
            pr("%s cannot carry planes\n", prship(sp));
        return 0;
     }
-    count_planes(sp);
     if (load_unload == LOAD &&
-       sp->shp_nchoppers >= mcp->m_nchoppers &&
-       sp->shp_nxlight >= mcp->m_nxlight &&
-       sp->shp_nplane >= mcp->m_nplanes) {
+       shp_nplane(sp, NULL, NULL, NULL)
+               >= mcp->m_nchoppers + mcp->m_nxlight + mcp->m_nplanes) {
        if (noisy)
            pr("%s doesn't have room for any more planes\n", prship(sp));
        return 0;
     }
     sprintf(prompt, "Plane(s) to %s %s? ",
            load_unload == LOAD ? "load onto" : "unload from", prship(sp));
-    if (!snxtitem(&ni, EF_PLANE,
-                 p = getstarg(player->argp[3], prompt, buf)))
+    p = getstarg(player->argp[3], prompt, buf);
+    if (!p)
+       return RET_SYN;
+    if (!snxtitem(&ni, EF_PLANE, p, NULL))
        return RET_SYN;
 
     if (!still_ok_ship(sectp, sp))
        return RET_SYN;
 
-    if (p && *p)
-       noisy &= isdigit(*p);
+    if (noisy && p && *p)
+       noisy = isdigit(*p);
 
-    while (nxtitem(&ni, (s_char *)&pln)) {
-       if (pln.pln_own != player->cnum)
+    while (nxtitem(&ni, &pln)) {
+       if (!player->owner)
            continue;
        if (!(plchr[(int)pln.pln_type].pl_flags & P_L)
            && !(plchr[(int)pln.pln_type].pl_flags & P_E)
@@ -430,28 +448,31 @@ load_plane_ship(struct sctstr *sectp, struct shpstr *sp, int noisy,
                   prplane(&pln), pln.pln_land);
            continue;
        }
+       if (pln.pln_harden != 0) {
+           if (noisy)
+               pr("%s has been hardened and can't be loaded\n",
+                  prplane(&pln));
+           continue;
+       }
 
-       /* Plane sanity done */
-       /* Find the right ship */
        if (load_unload == UNLOAD) {
            if (pln.pln_ship != sp->shp_uid)
                continue;
        } else if (sp->shp_x != pln.pln_x || sp->shp_y != pln.pln_y)
            continue;
 
-       /* ship to (plane or missle) sanity */
-       if (!can_be_on_ship(pln.pln_uid, sp->shp_uid)) {
-           if (plchr[(int)pln.pln_type].pl_flags & P_L) {
-               strcpy(buf, "planes");
-           } else if (plchr[(int)pln.pln_type].pl_flags & P_K) {
-               strcpy(buf, "choppers");
-           } else if (plchr[(int)pln.pln_type].pl_flags & P_M) {
-               strcpy(buf, "missiles");
-           } else if (plchr[(int)pln.pln_type].pl_flags & P_E) {
-               strcpy(buf, "extra light planes");
-           }                   /* else impossible */
-           if (noisy)
-               pr("%s cannot carry %s.\n", prship(sp), buf);
+       if (!could_be_on_ship(&pln, sp, 0, 0, 0, 0)) {
+           if (noisy) {
+               if (plchr[(int)pln.pln_type].pl_flags & P_K)
+                   p = "choppers";
+               else if (plchr[(int)pln.pln_type].pl_flags & P_E)
+                   p = "extra light planes";
+               else if (plchr[(int)pln.pln_type].pl_flags & P_M)
+                   p = "missiles";
+               else
+                   p = "planes";
+               pr("%s cannot carry %s.\n", prship(sp), p);
+           }
            continue;
        }
        /* Fit plane on ship */
@@ -463,31 +484,14 @@ load_plane_ship(struct sctstr *sectp, struct shpstr *sp, int noisy,
            }
            sprintf(buf, "loaded on your %s at %s",
                    prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
-           gift(sp->shp_own, player->cnum, (s_char *)&pln, EF_PLANE, buf);
-           makelost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
-                    pln.pln_y);
-           pln.pln_own = sp->shp_own;
-           makenotlost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
-                       pln.pln_y);
-           pln.pln_mission = 0;
+           gift(sp->shp_own, player->cnum, &pln, buf);
            putplane(pln.pln_uid, &pln);
        } else {
-           if (!take_plane_off_ship(&pln, sp)) {
-               pr("Unable to take plane off ship!\n");
-               logerror("load: plane %d could not be taken off ship %d\n",
-                        pln.pln_uid, sp->shp_uid);
-               continue;
-           }
+           pln.pln_ship = -1;
            sprintf(buf, "unloaded in your %s at %s",
                    dchr[sectp->sct_type].d_name,
                    xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
-           gift(sectp->sct_own, player->cnum, (s_char *)&pln,
-                EF_PLANE, buf);
-           makelost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
-                    pln.pln_y);
-           pln.pln_own = sectp->sct_own;
-           makenotlost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
-                       pln.pln_y);
+           gift(sectp->sct_own, player->cnum, &pln, buf);
            putplane(pln.pln_uid, &pln);
        }
        pr("%s %s %s at %s.\n",
@@ -505,30 +509,25 @@ static int
 load_land_ship(struct sctstr *sectp, struct shpstr *sp, int noisy,
               int load_unload, int *nshipsp)
 {
-    struct nstr_item pni, ni;
+    struct nstr_item ni;
     struct lndstr land;
-    struct plnstr plane;
     int loaded = 0;
-    s_char *p;
-    s_char prompt[512];
-    s_char buf[1024];
+    char *p;
+    char prompt[512];
+    char buf[1024];
     int load_spy = 0;
 
-    count_units(sp);
     if (load_unload == LOAD) {
-       if (opt_LANDSPIES) {
-           if ((mchr[(int)sp->shp_type].m_flags & M_SUB) &&
-               (mchr[(int)sp->shp_type].m_nland == 0)) {
-               if (sp->shp_nland >= 2) {
-                   pr("Non-land unit carrying subs can only carry up to two spy units.\n");
-                   return 0;
-               }
-               /* Eh, let 'em load a spy only */
-               load_spy = 1;
+       if ((mchr[(int)sp->shp_type].m_flags & M_SUB) &&
+           (mchr[(int)sp->shp_type].m_nland == 0)) {
+           if (shp_nland(sp) >= 2) {
+               pr("Non-land unit carrying subs can only carry up to two spy units.\n");
+               return 0;
            }
+           /* Eh, let 'em load a spy only */
+           load_spy = 1;
        }
-       if ((!load_spy) &&
-           (sp->shp_nland >= mchr[(int)sp->shp_type].m_nland)) {
+       if (!load_spy && shp_nland(sp) >= mchr[sp->shp_type].m_nland) {
            if (noisy) {
                if (mchr[(int)sp->shp_type].m_nland)
                    pr("%s doesn't have room for any more land units!\n",
@@ -541,18 +540,20 @@ load_land_ship(struct sctstr *sectp, struct shpstr *sp, int noisy,
     }
     sprintf(prompt, "Land unit(s) to %s %s? ",
            load_unload == LOAD ? "load onto" : "unload from", prship(sp));
-    if (!snxtitem(&ni, EF_LAND,
-                 p = getstarg(player->argp[3], prompt, buf)))
+    p = getstarg(player->argp[3], prompt, buf);
+    if (!p)
+       return RET_SYN;
+    if (!snxtitem(&ni, EF_LAND, p, NULL))
        return RET_SYN;
 
     if (!still_ok_ship(sectp, sp))
        return RET_SYN;
 
-    if (p && *p)
-       noisy &= isdigit(*p);
+    if (noisy && p && *p)
+       noisy = isdigit(*p);
 
-    while (nxtitem(&ni, (s_char *)&land)) {
-       if (land.lnd_own != player->cnum)
+    while (nxtitem(&ni, &land)) {
+       if (!player->owner)
            continue;
 
        if (load_unload == LOAD) {
@@ -568,8 +569,7 @@ load_land_ship(struct sctstr *sectp, struct shpstr *sp, int noisy,
                       prland(&land), land.lnd_land);
                continue;
            }
-           lnd_count_units(&land);
-           if (land.lnd_nland > 0) {
+           if (lnd_first_on_land(&land) >= 0) {
                if (noisy)
                    pr("%s cannot be loaded since it is carrying units\n",
                       prland(&land));
@@ -609,118 +609,54 @@ load_land_ship(struct sctstr *sectp, struct shpstr *sp, int noisy,
        }
        /* Fit unit on ship */
        if (load_unload == LOAD) {
-           count_units(sp);
            /* We have to check again, since it may have changed */
-           if (opt_LANDSPIES) {
-               if ((mchr[(int)sp->shp_type].m_flags & M_SUB) &&
-                   (mchr[(int)sp->shp_type].m_nland == 0)) {
-                   if (sp->shp_nland >= 2) {
-                       pr("Non-land unit carrying subs can only carry up to two spy units.\n");
-                       return 0;
-                   }
-                   /* Eh, let 'em load a spy only */
-                   load_spy = 1;
+           if ((mchr[(int)sp->shp_type].m_flags & M_SUB) &&
+               (mchr[(int)sp->shp_type].m_nland == 0)) {
+               if (shp_nland(sp) >= 2) {
+                   pr("Non-land unit carrying subs can only carry up to two spy units.\n");
+                   return 0;
                }
+               /* Eh, let 'em load a spy only */
+               load_spy = 1;
            }
-           if ((!load_spy) &&
-               (sp->shp_nland >= mchr[(int)sp->shp_type].m_nland)) {
+           if (!load_spy && shp_nland(sp) >= mchr[sp->shp_type].m_nland) {
                if (noisy) {
                    if (mchr[(int)sp->shp_type].m_nland)
-                       pr("%s doesn't have room for any more land units!\n", prship(sp));
+                       pr("%s doesn't have room for any more land units!\n",
+                          prship(sp));
                    else
                        pr("%s cannot carry land units!\n", prship(sp));
                }
                return 0;
            }
-#if 0
-           if (sp->shp_nland >= mchr[(int)sp->shp_type].m_nland) {
-               if (noisy)
-                   if (mchr[(int)sp->shp_type].m_nland)
-                       pr("%s doesn't have room for any more land units!\n", prship(sp));
-                   else
-                       pr("%s cannot carry land units!\n", prship(sp));
-               break;
-           }
-#endif
            sprintf(buf, "loaded on your %s at %s",
                    prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
-           gift(sp->shp_own, player->cnum, (s_char *)&land, EF_LAND, buf);
-           makelost(EF_LAND, land.lnd_own, land.lnd_uid, land.lnd_x,
-                    land.lnd_y);
-           land.lnd_own = sp->shp_own;
-           makenotlost(EF_LAND, land.lnd_own, land.lnd_uid, land.lnd_x,
-                       land.lnd_y);
+           gift(sp->shp_own, player->cnum, &land, buf);
            land.lnd_ship = sp->shp_uid;
            land.lnd_harden = 0;
-           land.lnd_mission = 0;
-           resupply_all(&land);
-           sp->shp_nland++;
            putland(land.lnd_uid, &land);
-           if (!has_supply(&land))
+#if 0
+          /*
+           * FIXME if this supplies from the sector, the putsect in
+           * load() / lload() duplicates those supplies, causing a
+           * seqno mismatch
+           */
+           if (!lnd_supply_all(&land))
                pr("WARNING: %s is out of supply!\n", prland(&land));
-           putship(sp->shp_uid, sp);
-           snxtitem_xy(&pni, EF_PLANE, land.lnd_x, land.lnd_y);
-           while (nxtitem(&pni, (s_char *)&plane)) {
-               if (plane.pln_flags & PLN_LAUNCHED)
-                   continue;
-               if (plane.pln_land != land.lnd_uid)
-                   continue;
-               sprintf(buf, "loaded on %s", prship(sp));
-               gift(sp->shp_own, player->cnum, (s_char *)&plane,
-                    EF_PLANE, buf);
-               makelost(EF_PLANE, plane.pln_own, plane.pln_uid,
-                        plane.pln_x, plane.pln_y);
-               plane.pln_own = sp->shp_own;
-               makenotlost(EF_PLANE, plane.pln_own, plane.pln_uid,
-                           plane.pln_x, plane.pln_y);
-               plane.pln_mission = 0;
-               putplane(plane.pln_uid, &plane);
-           }
+#else
+           if (!lnd_in_supply(&land))
+               pr("WARNING: %s is out of supply!\n", prland(&land));
+#endif
        } else {
            sprintf(buf, "unloaded in your %s at %s",
                    dchr[sectp->sct_type].d_name,
                    xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
 
            /* Spies are unloaded quietly, others aren't */
-           if (!(lchr[(int)land.lnd_type].l_flags & L_SPY)) {
-               gift(sectp->sct_own, player->cnum, (s_char *)&land,
-                    EF_LAND, buf);
-               makelost(EF_LAND, land.lnd_own, land.lnd_uid,
-                        land.lnd_x, land.lnd_y);
-               land.lnd_own = sectp->sct_own;
-               makenotlost(EF_LAND, land.lnd_own, land.lnd_uid,
-                           land.lnd_x, land.lnd_y);
-           }
-
-           land.lnd_ship = (-1);
-           sp->shp_nland--;
+           if (!(lchr[(int)land.lnd_type].l_flags & L_SPY))
+               gift(sectp->sct_own, player->cnum, &land, buf);
+           land.lnd_ship = -1;
            putland(land.lnd_uid, &land);
-           putship(sp->shp_uid, sp);
-
-           /* Spies are unloaded quietly, others aren't, and
-              in the off chance they can carry a plane (missile?)
-              they are quietly unloaded too. */
-           if (!(lchr[(int)land.lnd_type].l_flags & L_SPY)) {
-               snxtitem_xy(&pni, EF_PLANE, land.lnd_x, land.lnd_y);
-               while (nxtitem(&pni, (s_char *)&plane)) {
-                   if (plane.pln_flags & PLN_LAUNCHED)
-                       continue;
-                   if (plane.pln_land != land.lnd_uid)
-                       continue;
-                   sprintf(buf, "unloaded at %s",
-                           xyas(plane.pln_x, plane.pln_y,
-                                sectp->sct_own));
-                   gift(sectp->sct_own, player->cnum, (s_char *)&plane,
-                        EF_PLANE, buf);
-                   makelost(EF_PLANE, plane.pln_own, plane.pln_uid,
-                            plane.pln_x, plane.pln_y);
-                   plane.pln_own = sectp->sct_own;
-                   makenotlost(EF_PLANE, plane.pln_own, plane.pln_uid,
-                               plane.pln_x, plane.pln_y);
-                   plane.pln_mission = 0;
-                   putplane(plane.pln_uid, &plane);
-               }
-           }
        }
        pr("%s %s %s at %s.\n",
           prland(&land),
@@ -737,86 +673,58 @@ static int
 load_comm_ship(struct sctstr *sectp, struct shpstr *sp,
               struct ichrstr *ich, int load_unload, int *nshipsp)
 {
-    i_type item = ich->i_vtype;
+    i_type item = ich->i_uid;
     struct mchrstr *mcp = &mchr[(int)sp->shp_type];
-    int ship_amt, ship_max, sect_amt, move_amt;
-    int amount;
-    s_char prompt[512];
-    s_char *p;
-    s_char buf[1024];
+    int ship_amt, sect_amt, move_amt;
+    char prompt[512];
+    char *p;
+    char buf[1024];
 
     sprintf(prompt, "Number of %s to %s %s at %s? ",
            ich->i_name,
            (load_unload == UNLOAD) ?
            "unload from" : "load onto",
            prship(sp), xyas(sp->shp_x, sp->shp_y, player->cnum));
-    if (!(p = getstarg(player->argp[3], prompt, buf)) || !*p)
+    p = getstarg(player->argp[3], prompt, buf);
+    if (!p || !*p)
        return RET_SYN;
 
     if (!still_ok_ship(sectp, sp))
        return RET_SYN;
 
     ship_amt = sp->shp_item[item];
-    ship_max = mcp->m_item[item];
     sect_amt = sectp->sct_item[item];
-    amount = atoi(p);
-    if (amount < 0)
-       move_amt = -amount - ship_amt;
-    else
-       move_amt = load_unload == LOAD ? amount : -amount;
-    if (move_amt > ship_max - ship_amt)
-       move_amt = ship_max - ship_amt;
-    if (move_amt < -ship_amt)
-       move_amt = -ship_amt;
-    if (move_amt > sect_amt)
-       move_amt = sect_amt;
-    if (move_amt < sect_amt - ITEM_MAX)
-       move_amt = sect_amt - ITEM_MAX;
-    if (!move_amt)
+    move_amt = move_amount(sect_amt, ship_amt, mcp->m_item[item],
+                          load_unload, atoi(p));
+    if (!load_comm_ok(sectp, sp->shp_own, item, move_amt))
        return RET_OK;
-    if (sectp->sct_oldown != player->cnum && item == I_CIVIL) {
-       pr("%s civilians refuse to %s at %s!\n",
-          move_amt < 0 ? "Your" : "Foreign",
-          move_amt < 0 ? "disembark" : "board",
-          xyas(sectp->sct_x, sectp->sct_y, player->cnum));
-       return RET_FAIL;
-    }
-
-    if (!want_to_abandon(sectp, item, move_amt, 0))
+    if (!want_to_abandon(sectp, item, move_amt, NULL))
        return RET_FAIL;
     if (!still_ok_ship(sectp, sp))
        return RET_SYN;
     sectp->sct_item[item] = sect_amt - move_amt;
     sp->shp_item[item] = ship_amt + move_amt;
+
     if (move_amt >= 0) {
        pr("%d %s loaded onto %s at %s\n",
-          move_amt,
-          ich->i_name,
+          move_amt, ich->i_name,
           prship(sp), xyas(sp->shp_x, sp->shp_y, player->cnum));
        if (sp->shp_own != player->cnum) {
-           sprintf(buf, "%s loaded %d %s onto %s at %s\n",
-                   cname(player->cnum),
-                   move_amt,
-                   ich->i_name,
-                   prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
-           wu(0, sp->shp_own, buf);
+           wu(0, sp->shp_own, "%s loaded %d %s onto %s at %s\n",
+              cname(player->cnum), move_amt, ich->i_name,
+              prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
        }
     } else {
        pr("%d %s unloaded from %s at %s\n",
-          -move_amt,
-          ich->i_name,
+          -move_amt, ich->i_name,
           prship(sp), xyas(sp->shp_x, sp->shp_y, player->cnum));
        if (sectp->sct_own != player->cnum) {
-           sprintf(buf, "%s unloaded %d %s from %s at %s\n",
-                   cname(player->cnum),
-                   -move_amt,
-                   ich->i_name,
-                   prship(sp),
-                   xyas(sp->shp_x, sp->shp_y, sectp->sct_own));
-           wu(0, sectp->sct_own, buf);
+           wu(0, sectp->sct_own, "%s unloaded %d %s from %s at %s\n",
+              cname(player->cnum), -move_amt, ich->i_name,
+              prship(sp), xyas(sp->shp_x, sp->shp_y, sectp->sct_own));
        }
     }
-    ++(*nshipsp);
+    ++*nshipsp;
     return 0;
 }
 
@@ -827,17 +735,17 @@ load_plane_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
     struct nstr_item ni;
     struct plnstr pln;
     int loaded = 0;
-    s_char *p;
-    s_char prompt[512];
-    s_char buf[1024];
+    char *p;
+    char prompt[512];
+    char buf[1024];
+    struct lchrstr *lcp = lchr + lp->lnd_type;
 
-    if (!(lchr[(int)lp->lnd_type].l_flags & L_XLIGHT)) {
+    if (!lcp->l_nxlight) {
        if (noisy)
            pr("%s cannot carry extra-light planes.\n", prland(lp));
        return 0;
     }
-    count_land_planes(lp);
-    if (load_unload == LOAD && lp->lnd_nxlight >= lp->lnd_maxlight) {
+    if (load_unload == LOAD && lnd_nxlight(lp) >= lcp->l_nxlight) {
        if (noisy)
            pr("%s doesn't have room for any more extra-light planes\n",
               prland(lp));
@@ -845,24 +753,20 @@ load_plane_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
     }
     sprintf(prompt, "Plane(s) to %s %s? ",
            load_unload == LOAD ? "load onto" : "unload from", prland(lp));
-    if (!snxtitem(&ni, EF_PLANE,
-                 p = getstarg(player->argp[3], prompt, buf)))
+    p = getstarg(player->argp[3], prompt, buf);
+    if (!p)
+       return RET_SYN;
+    if (!snxtitem(&ni, EF_PLANE, p, NULL))
        return RET_SYN;
 
     if (!still_ok_land(sectp, lp))
        return RET_SYN;
 
-    if (p && *p)
-       noisy &= isdigit(*p);
-
-    if (sectp->sct_own != player->cnum && load_unload == LOAD) {
-       pr("Sector %s is not yours.\n",
-          xyas(lp->lnd_x, lp->lnd_y, player->cnum));
-       return 0;
-    }
+    if (noisy && p && *p)
+       noisy = isdigit(*p);
 
-    while (nxtitem(&ni, (s_char *)&pln)) {
-       if (pln.pln_own != player->cnum)
+    while (nxtitem(&ni, &pln)) {
+       if (!player->owner)
            continue;
 
        if (!(plchr[(int)pln.pln_type].pl_flags & P_E)) {
@@ -883,6 +787,13 @@ load_plane_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
                   prplane(&pln), pln.pln_land);
            continue;
        }
+       if (pln.pln_harden != 0) {
+           if (noisy)
+               pr("%s has been hardened and can't be loaded\n",
+                  prplane(&pln));
+           continue;
+       }
+
        /* Plane sanity done */
        /* Find the right unit */
        if (load_unload == UNLOAD) {
@@ -900,29 +811,13 @@ load_plane_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
            }
            sprintf(buf, "loaded on %s at %s",
                    prland(lp), xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
-           gift(lp->lnd_own, player->cnum, (s_char *)&pln, EF_PLANE, buf);
-           makelost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
-                    pln.pln_y);
-           pln.pln_own = lp->lnd_own;
-           makenotlost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
-                       pln.pln_y);
+           gift(lp->lnd_own, player->cnum, &pln, buf);
            putplane(pln.pln_uid, &pln);
        } else {
-           if (!take_plane_off_land(&pln, lp)) {
-               pr("Unable to take plane off unit!\n");
-               logerror("load: plane %d could not be taken off unit %d\n",
-                        pln.pln_uid, lp->lnd_uid);
-               continue;
-           }
+           pln.pln_land = -1;
            sprintf(buf, "unloaded at your sector at %s",
                    xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
-           gift(sectp->sct_own, player->cnum, (s_char *)&pln,
-                EF_PLANE, buf);
-           makelost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
-                    pln.pln_y);
-           pln.pln_own = sectp->sct_own;
-           makenotlost(EF_PLANE, pln.pln_own, pln.pln_uid, pln.pln_x,
-                       pln.pln_y);
+           gift(sectp->sct_own, player->cnum, &pln, buf);
            putplane(pln.pln_uid, &pln);
        }
        pr("%s %s %s at %s.\n",
@@ -940,90 +835,58 @@ static int
 load_comm_land(struct sctstr *sectp, struct lndstr *lp,
               struct ichrstr *ich, int load_unload, int *nunitsp)
 {
-    i_type item = ich->i_vtype;
+    i_type item = ich->i_uid;
     struct lchrstr *lcp = &lchr[(int)lp->lnd_type];
-    int land_amt, land_max, sect_amt, move_amt;
-    int amount;
-    s_char prompt[512];
-    s_char *p;
-    s_char buf[1024];
+    int land_amt, sect_amt, move_amt;
+    char prompt[512];
+    char *p;
+    char buf[1024];
 
     sprintf(prompt, "Number of %s to %s %s at %s? ",
            ich->i_name,
            (load_unload == UNLOAD) ?
            "unload from" : "load onto",
            prland(lp), xyas(lp->lnd_x, lp->lnd_y, player->cnum));
-    if (!(p = getstarg(player->argp[3], prompt, buf)) || !*p)
+    p = getstarg(player->argp[3], prompt, buf);
+    if (!p || !*p)
        return RET_SYN;
 
     if (!still_ok_land(sectp, lp))
        return RET_SYN;
 
     land_amt = lp->lnd_item[item];
-    land_max = lcp->l_item[item];
     sect_amt = sectp->sct_item[item];
-    amount = atoi(p);
-    if (amount < 0)
-       move_amt = -amount - land_amt;
-    else
-       move_amt = load_unload == LOAD ? amount : -amount;
-    if (move_amt > land_max - land_amt)
-       move_amt = land_max - land_amt;
-    if (move_amt < -land_amt)
-       move_amt = -land_amt;
-    if (move_amt > sect_amt)
-       move_amt = sect_amt;
-    if (move_amt < sect_amt - ITEM_MAX)
-       move_amt = sect_amt - ITEM_MAX;
-    if (!move_amt)
+    move_amt = move_amount(sect_amt, land_amt, lcp->l_item[item],
+                          load_unload, atoi(p));
+    if (!load_comm_ok(sectp, lp->lnd_own, item, move_amt))
        return RET_OK;
-    if (sectp->sct_own != player->cnum && move_amt > 0) {
-       pr("Sector %s is not yours.\n",
-          xyas(lp->lnd_x, lp->lnd_y, player->cnum));
-       return RET_FAIL;
-    }
-    if (sectp->sct_oldown != player->cnum && item == I_CIVIL) {
-       pr("%s civilians refuse to %s at %s!\n",
-          move_amt < 0 ? "Your" : "Foreign",
-          move_amt < 0 ? "disembark" : "board",
-          xyas(sectp->sct_x, sectp->sct_y, player->cnum));
-       return RET_FAIL;
-    }
     sectp->sct_item[item] = sect_amt - move_amt;
     lp->lnd_item[item] = land_amt + move_amt;
 
     /* Did we put mils onto this unit? If so, reset the fortification */
     if (item == I_MILIT && move_amt > 0)
        lp->lnd_harden = 0;
+
     if (move_amt >= 0) {
        pr("%d %s loaded onto %s at %s\n",
-          move_amt,
-          ich->i_name,
+          move_amt, ich->i_name,
           prland(lp), xyas(lp->lnd_x, lp->lnd_y, player->cnum));
        if (lp->lnd_own != player->cnum) {
-           sprintf(buf, "%s loaded %d %s onto %s at %s\n",
-                   cname(player->cnum),
-                   move_amt,
-                   ich->i_name,
-                   prland(lp), xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
-           wu(0, lp->lnd_own, buf);
+           wu(0, lp->lnd_own, "%s loaded %d %s onto %s at %s\n",
+              cname(player->cnum), move_amt, ich->i_name,
+              prland(lp), xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
        }
     } else {
        pr("%d %s unloaded from %s at %s\n",
-          -move_amt,
-          ich->i_name,
+          -move_amt, ich->i_name,
           prland(lp), xyas(lp->lnd_x, lp->lnd_y, player->cnum));
        if (sectp->sct_own != player->cnum) {
-           sprintf(buf, "%s unloaded %d %s from %s at %s\n",
-                   cname(player->cnum),
-                   -move_amt,
-                   ich->i_name,
-                   prland(lp),
-                   xyas(lp->lnd_x, lp->lnd_y, sectp->sct_own));
-           wu(0, sectp->sct_own, buf);
+           wu(0, sectp->sct_own, "%s unloaded %d %s from %s at %s\n",
+              cname(player->cnum), -move_amt, ich->i_name,
+              prland(lp), xyas(lp->lnd_x, lp->lnd_y, sectp->sct_own));
        }
     }
-    ++(*nunitsp);
+    ++*nunitsp;
     return 0;
 }
 
@@ -1031,19 +894,17 @@ static int
 load_land_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
               int load_unload, int *nunitsp)
 {
-    struct nstr_item pni, ni;
+    struct nstr_item ni;
     struct lndstr land;
-    struct plnstr plane;
     int loaded = 0;
-    s_char *p;
-    s_char prompt[512];
-    s_char buf[1024];
-
-    lnd_count_units(lp);
+    char *p;
+    char prompt[512];
+    char buf[1024];
 
-    if (load_unload == LOAD && lp->lnd_nland >= lp->lnd_maxland) {
+    if (load_unload == LOAD
+       && lnd_nland(lp) >= lchr[lp->lnd_type].l_nland) {
        if (noisy) {
-           if (lp->lnd_nland)
+           if (lchr[lp->lnd_type].l_nland)
                pr("%s doesn't have room for any more land units!\n",
                   prland(lp));
            else
@@ -1053,19 +914,20 @@ load_land_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
     }
     sprintf(prompt, "Land unit(s) to %s %s? ",
            load_unload == LOAD ? "load onto" : "unload from", prland(lp));
-    if (!snxtitem(&ni, EF_LAND,
-                 p = getstarg(player->argp[3], prompt, buf)))
+    p = getstarg(player->argp[3], prompt, buf);
+    if (!p)
+       return RET_SYN;
+    if (!snxtitem(&ni, EF_LAND, p, NULL))
        return RET_SYN;
 
     if (!still_ok_land(sectp, lp))
        return RET_SYN;
 
-    if (p && *p)
-       noisy &= isdigit(*p);
-
-    while (nxtitem(&ni, (s_char *)&land)) {
+    if (noisy && p && *p)
+       noisy = isdigit(*p);
 
-       if (land.lnd_own != player->cnum)
+    while (nxtitem(&ni, &land)) {
+       if (!player->owner)
            continue;
 
        if (load_unload == LOAD) {
@@ -1081,8 +943,7 @@ load_land_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
                       prland(&land), land.lnd_land);
                continue;
            }
-           lnd_count_units(&land);
-           if (land.lnd_nland > 0) {
+           if (lnd_first_on_land(&land) >= 0) {
                if (noisy)
                    pr("%s cannot be loaded since it is carrying units\n",
                       prland(&land));
@@ -1093,7 +954,7 @@ load_land_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
                    pr("%s can't be loaded onto itself!\n", prland(&land));
                continue;
            }
-           if (lchr[(int)land.lnd_type].l_flags & L_HEAVY) {
+           if (lchr[(int)land.lnd_type].l_flags & (L_HEAVY | L_TRAIN)) {
                if (noisy)
                    pr("%s is too heavy to load.\n", prland(&land));
                continue;
@@ -1112,11 +973,11 @@ load_land_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
 
        /* Fit unit on ship */
        if (load_unload == LOAD) {
-           lnd_count_units(lp);
-           if (lp->lnd_nland >= lp->lnd_maxland) {
+           if (lnd_nland(lp) >= lchr[lp->lnd_type].l_nland) {
                if (noisy) {
-                   if (lp->lnd_nland)
-                       pr("%s doesn't have room for any more land units!\n", prland(lp));
+                   if (lchr[lp->lnd_type].l_nland)
+                       pr("%s doesn't have room for any more land units!\n",
+                          prland(lp));
                    else
                        pr("%s cannot carry land units!\n", prland(lp));
                }
@@ -1124,71 +985,25 @@ load_land_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
            }
            sprintf(buf, "loaded on your %s at %s",
                    prland(lp), xyas(lp->lnd_x, lp->lnd_y, lp->lnd_own));
-           gift(lp->lnd_own, player->cnum, (s_char *)&land, EF_LAND, buf);
-           makelost(EF_LAND, land.lnd_own, land.lnd_uid, land.lnd_x,
-                    land.lnd_y);
-           land.lnd_own = lp->lnd_own;
-           makenotlost(EF_LAND, land.lnd_own, land.lnd_uid, land.lnd_x,
-                       land.lnd_y);
+           gift(lp->lnd_own, player->cnum, &land, buf);
            land.lnd_land = lp->lnd_uid;
            land.lnd_harden = 0;
-           land.lnd_mission = 0;
-           resupply_all(&land);
-           lp->lnd_nland++;
            putland(land.lnd_uid, &land);
-           if (!has_supply(&land))
+#if 0
+          /* FIXME same issue as in load_land_ship() */
+           if (!lnd_supply_all(&land))
                pr("WARNING: %s is out of supply!\n", prland(&land));
-           putland(lp->lnd_uid, lp);
-           snxtitem_xy(&pni, EF_PLANE, land.lnd_x, land.lnd_y);
-           while (nxtitem(&pni, (s_char *)&plane)) {
-               if (plane.pln_flags & PLN_LAUNCHED)
-                   continue;
-               if (plane.pln_land != land.lnd_uid)
-                   continue;
-               sprintf(buf, "loaded on %s", prland(lp));
-               gift(lp->lnd_own, player->cnum, (s_char *)&plane,
-                    EF_PLANE, buf);
-               makelost(EF_PLANE, plane.pln_own, plane.pln_uid,
-                        plane.pln_x, plane.pln_y);
-               plane.pln_own = lp->lnd_own;
-               makenotlost(EF_PLANE, plane.pln_own, plane.pln_uid,
-                           plane.pln_x, plane.pln_y);
-               plane.pln_mission = 0;
-               putplane(plane.pln_uid, &plane);
-           }
+#else
+           if (!lnd_in_supply(&land))
+               pr("WARNING: %s is out of supply!\n", prland(&land));
+#endif
        } else {
            sprintf(buf, "unloaded in your %s at %s",
                    dchr[sectp->sct_type].d_name,
                    xyas(sectp->sct_x, sectp->sct_y, sectp->sct_own));
-           gift(sectp->sct_own, player->cnum, (s_char *)&land,
-                EF_LAND, buf);
-           makelost(EF_LAND, land.lnd_own, land.lnd_uid, land.lnd_x,
-                    land.lnd_y);
-           land.lnd_own = sectp->sct_own;
-           makenotlost(EF_LAND, land.lnd_own, land.lnd_uid, land.lnd_x,
-                       land.lnd_y);
-           land.lnd_land = (-1);
-           lp->lnd_nland--;
+           gift(sectp->sct_own, player->cnum, &land, buf);
+           land.lnd_land = -1;
            putland(land.lnd_uid, &land);
-           putland(lp->lnd_uid, lp);
-           snxtitem_xy(&pni, EF_PLANE, land.lnd_x, land.lnd_y);
-           while (nxtitem(&pni, (s_char *)&plane)) {
-               if (plane.pln_flags & PLN_LAUNCHED)
-                   continue;
-               if (plane.pln_land != land.lnd_uid)
-                   continue;
-               sprintf(buf, "unloaded at %s",
-                       xyas(plane.pln_x, plane.pln_y, sectp->sct_own));
-               gift(sectp->sct_own, player->cnum, (s_char *)&plane,
-                    EF_PLANE, buf);
-               makelost(EF_PLANE, plane.pln_own, plane.pln_uid,
-                        plane.pln_x, plane.pln_y);
-               plane.pln_own = sectp->sct_own;
-               makenotlost(EF_PLANE, plane.pln_own, plane.pln_uid,
-                           plane.pln_x, plane.pln_y);
-               plane.pln_mission = 0;
-               putplane(plane.pln_uid, &plane);
-           }
        }
        pr("%s %s %s at %s.\n",
           prland(&land),