#ifndef lint
static char *RCSid = "$Header: /usr/brule/guest/empire/empire/emprcs/lib/commands/load.c,v 2.15 1995/10/24 04:34:14 empire Exp $";
#endif /* not lint */

/*
 * load.c
 *
 * load (unload) goods from a sector onto a ship
 *
 * from PSL Empire, 1985
 *
 * hacked to allow planes/missiles to be loaded onto carriers/subs
 * by David Sharnoff 1987 
 * Rewritten by Ken Stevens, 1995
 */

#include "misc.h"
#include "player.h"
#include "xy.h"
#include "file.h"
#include "var.h"
#include "sect.h"
#include "ship.h"
#include "plane.h"	
#include "land.h"	
#include "item.h"
#include "nsc.h"
#include "nat.h"
#include "optlist.h"

/*
 * The values 1 and -1 are important below, don't change them.
 */
#define	LOAD	1
#define	UNLOAD	-1

void gift();
static int load_plane_ship();
static int load_land_ship();
static int load_comm_ship();
static int load_plane_land();
static int load_comm_land();

int
load()
{
	int	noisy;
	int     load_unload;
	int     ship_num;
	int     type;
	struct  nstr_item nbst;
	struct	ichrstr *ich;
	int	nships;
	struct	sctstr sect;
	struct	shpstr ship;
	int	retval;
	s_char	*p;
	s_char	buf[1024];

	if (!(p = getstarg(player->argp[1],
		"What commodity (or 'plane' or 'land')? ", buf)) || !*p)
		return RET_SYN;
	
	if (!strncmp(p, "plane", 5))
		type = EF_PLANE;
	else if (!strncmp(p, "land", 4))
		type = EF_LAND;
	else if (ich = whatitem(p, (s_char *)0))
		type = EF_SECTOR;
	else {
		pr("Bad commodity.\n");
		return RET_SYN;
	}

	if (!(p = getstarg(player->argp[2], "Ship(s): ", buf)) || !*p)
		return RET_SYN;

	noisy = isdigit(*p);

	if (!snxtitem(&nbst, EF_SHIP, p))
		return RET_SYN;

	nbst.flags &= ~(EFF_OWNER);

	load_unload = **player->argp == 'l' ? LOAD : UNLOAD;

	nships = 0;
	while (nxtitem(&nbst, (s_char *)&ship)) {
		if (!ship.shp_own)
			continue;
		if (!player->owner && (load_unload == UNLOAD)) {
			continue;
		}
		if (ship.shp_own != player->cnum) {
			if (!noisy)
				continue;
			if (getrel(getnatp(player->cnum),ship.shp_own) < FRIENDLY)
				continue;
		}
		ship_num = ship.shp_uid;
		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 (sect.sct_type != SCT_HARBR &&
		    (!opt_BIG_CITY || sect.sct_type != SCT_CAPIT)) {
			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":"");
			continue;
		}
		if (sect.sct_own != player->cnum && load_unload == UNLOAD && getrel(getnatp(sect.sct_own), player->cnum) < FRIENDLY) {
			if (noisy)
			pr("You can't unload into an unfriendly %s\n",
			   dchr[sect.sct_type].d_name);
			continue;
		}
		if (sect.sct_effic < 2) {
			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));
			continue;
		}
		switch (type) {
		case EF_PLANE:
			if (retval=load_plane_ship(&sect, &ship, noisy, load_unload, &nships))
				return retval;
			break;
		case EF_LAND:
			if (retval=load_land_ship(&sect, &ship, noisy, load_unload, &nships))
				return retval;
			break;
		case EF_SECTOR:
			if (retval=load_comm_ship(&sect, &ship, ich, load_unload, &nships))
				return retval;
		}
		/* load/unload plague */
		if (getvar(V_PSTAGE, (s_char *)&sect, EF_SECTOR) == PLG_INFECT &&
		    getvar(V_PSTAGE, (s_char *)&ship, EF_SHIP) == PLG_HEALTHY)
			putvar(V_PSTAGE, PLG_EXPOSED, (s_char *)&ship, EF_SHIP);
		if (getvar(V_PSTAGE, (s_char *)&ship, EF_SHIP) == PLG_INFECT &&
		    getvar(V_PSTAGE, (s_char *)&sect, EF_SECTOR) == PLG_HEALTHY)
			putvar(V_PSTAGE, PLG_EXPOSED, (s_char *)&sect, EF_SECTOR);
		putsect(&sect);
		putship(ship_num, &ship);
	}
	if (!nships)
		pr("No ships affected\n");
	else
		pr("%d ship%s %sloaded\n", nships, splur(nships),
			load_unload == UNLOAD ? "un" : "");
	return RET_OK;
}

int
lload()
{
	int	noisy;
	int     load_unload;
	int     land_num;
	int	type;
	struct	nstr_item nbst;
	struct	ichrstr *ich;
	int	nunits;
	struct	sctstr sect;
	struct	lndstr land;
	int	retval;
	s_char	*p;
	s_char	buf[1024];

	if (!(p = getstarg(player->argp[1],
		   "What commodity (or 'plane')? ", buf)) || !*p)
		return RET_SYN;
	if (!strncmp(p, "plane", 5))
		type = EF_PLANE;
	else if (ich = whatitem(p, (s_char *)0))
		type = EF_SECTOR;
	else {
		pr("Bad commodity.\n");
		return RET_SYN;
	}

	if (!(p = getstarg(player->argp[2], "Unit(s): ", buf)) || !*p)
		return RET_SYN;

	noisy = isdigit(*p);

	if (!snxtitem(&nbst, EF_LAND, p))
		return RET_SYN;

	load_unload = *(*player->argp+1) == 'l' ? LOAD : UNLOAD;

	nunits = 0;
	while (nxtitem(&nbst, (s_char *)&land)) {
		if (!player->owner)
			continue;

		land_num = land.lnd_uid;

		if (!getsect(land.lnd_x, land.lnd_y, &sect)) /* XXX */
			continue;

		if (sect.sct_own != land.lnd_own) {
			pr("Sector %s is not yours.\n",
				xyas(land.lnd_x, land.lnd_y, player->cnum));
			continue;
		}
		switch (type) {
		case EF_PLANE:
			if (retval=load_plane_land(&sect, &land, noisy, load_unload, &nunits))
				return retval;
			break;
		case EF_SECTOR:
			if (retval=load_comm_land(&sect, &land, ich, load_unload, &nunits))
				return retval;
		}
		/* load/unload plague */
		if (getvar(V_PSTAGE, (s_char *)&sect, EF_SECTOR) == PLG_INFECT &&
		    getvar(V_PSTAGE, (s_char *)&land, EF_LAND) == PLG_HEALTHY)
			putvar(V_PSTAGE, PLG_EXPOSED, (s_char *)&land, EF_LAND);
		if (getvar(V_PSTAGE, (s_char *)&land, EF_LAND) == PLG_INFECT &&
		    getvar(V_PSTAGE, (s_char *)&sect, EF_SECTOR) == PLG_HEALTHY)
			putvar(V_PSTAGE, PLG_EXPOSED, (s_char *)&sect, EF_SECTOR);
		
		putsect(&sect);
		putland(land_num, &land);
	}
	if (nunits == 0)
		pr("No units affected\n");
	else
		pr("%d unit%s %sloaded\n", nunits, splur(nunits),
			load_unload == UNLOAD ? "un" : "");
	return RET_OK;
}

void
gift(givee, giver, ptr, type, mesg)
int   givee, giver;
s_char  *ptr;
int     type;
s_char  *mesg;
{
	s_char	*p, line[256];

	if (giver == givee)
		return;


	switch(type) {
		case EF_SHIP:	p = prship(ptr);
				break;
		case EF_PLANE:	p = prplane(ptr);
				break;
		case EF_LAND:	p = prland(ptr);
				break;
	}

	sprintf(line,"%s %s %s\n",cname(giver),p,mesg);
	wu(0,givee,line);
}

static int
load_plane_ship(sectp, sp, noisy, load_unload, nshipsp)
	struct	sctstr	*sectp;
	struct	shpstr	*sp;
	int	noisy;
	int	load_unload;
	int	*nshipsp;
{
	struct	nstr_item ni;
	struct	plnstr pln;
	int	loaded = 0;
	s_char	buf[1024];
	s_char	*p;
	s_char	prompt[512];
	struct	mchrstr	*mcp = mchr + sp->shp_type;

	if (!(mcp->m_flags & (M_CHOPPER|M_XLIGHT|M_FLY|M_MSL))) {
		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) {
		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)))
		return RET_SYN;

	if (p && *p)
		noisy &= isdigit(*p);

	while(nxtitem(&ni, (s_char *)&pln)) {			
		if (pln.pln_own != player->cnum)
			continue;
		if (!(plchr[pln.pln_type].pl_flags & P_L)
		    &&  !(plchr[pln.pln_type].pl_flags & P_E)
		    &&  !(plchr[pln.pln_type].pl_flags & P_K)
		    &&  !(plchr[pln.pln_type].pl_flags & P_M)
		    ) {
			if (noisy)
				pr("You can only load light planes, helos, xtra-light, or missiles onto ships.\n");
			continue;
		}
		if (load_unload == LOAD && pln.pln_ship > -1) {
			if (noisy)
				pr("%s is already on ship #%d!\n",
				   prplane(&pln), pln.pln_ship);
			continue;
		}
		if (load_unload == LOAD && pln.pln_land > -1) {
			if (noisy)
				pr("%s is already on land unit #%d!\n",
				   prplane(&pln), pln.pln_land);
			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[pln.pln_type].pl_flags & P_L) {
				strcpy(buf, "planes");
			} else if (plchr[pln.pln_type].pl_flags & P_K) {
				strcpy(buf, "choppers");
			} else if (plchr[pln.pln_type].pl_flags & P_M) {
				strcpy(buf, "missiles");
			} else if (plchr[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);
			continue;
		}
		/* Fit plane on ship */
		if (load_unload == LOAD){
			if (!put_plane_on_ship(&pln,sp)){
				if (noisy)
					pr("Can't put plane %d on this ship!\n",pln.pln_uid);
				continue;
			}
			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);
			pln.pln_own = sp->shp_own;
			pln.pln_mission = 0;
			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;
			}
			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);
			pln.pln_own = sectp->sct_own;
			putplane(pln.pln_uid,&pln);
		}
		pr("%s %s %s at %s.\n",
		   prplane(&pln),
		   (load_unload==UNLOAD)?
		   "unloaded from":"loaded onto",
		   prship(sp),
		   xyas(sp->shp_x, sp->shp_y, player->cnum));
		loaded = 1;
	}
	*nshipsp += loaded;
	return 0;
}

static int
load_land_ship(sectp, sp, noisy, load_unload, nshipsp)
	struct	sctstr	*sectp;
	struct	shpstr	*sp;
	int	noisy;
	int	load_unload;
	int	*nshipsp;
{
	struct	nstr_item pni, ni;
	struct	lndstr land;
	struct	plnstr plane;
	struct	sctstr sect;
	int	loaded = 0;
	s_char	*p;
	s_char	prompt[512];
	s_char	buf[1024];

	count_units(sp);
	if (load_unload==LOAD &&
	    sp->shp_nland >= mchr[sp->shp_type].m_nland) {
		if (noisy)
			if (mchr[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));
		return 0;
	}
	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)))
		return RET_SYN;
	if (p && *p)
		noisy &= isdigit(*p);

	while(nxtitem(&ni, (s_char *)&land)) {
			
		if (land.lnd_own != player->cnum)
			continue;
		
		if (load_unload == LOAD && land.lnd_ship > -1) {
			if (noisy)
				pr("%s is already on ship #%d!\n",
				   prland(&land), land.lnd_ship);
			continue;
		}

		/* Unit sanity done */
		/* Find the right ship */
		if (load_unload == UNLOAD) {
			if (land.lnd_ship != sp->shp_uid)
				continue;
		} else if (sp->shp_x != land.lnd_x
			   || sp->shp_y != land.lnd_y)
			continue;

		if ((!(lchr[land.lnd_type].l_flags & L_LIGHT)) &&
		    (!((mchr[sp->shp_type].m_flags & M_SUPPLY) &&
		       (!(mchr[sp->shp_type].m_flags & M_SUB))))) {
			if (noisy) {
				pr("You can only load light units onto ships,\n");
				pr("unless the ship is a non-sub supply ship\n");
				pr("%s not loaded\n", prland(&land));
			}
			continue;
		}
		/* Fit unit on ship */
		if (load_unload == LOAD) {
			count_units(sp);
			if (sp->shp_nland >= mchr[sp->shp_type].m_nland) {
				if (noisy)
					if (mchr[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;
			}
			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);
			land.lnd_own = sp->shp_own;
			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))
				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);
				plane.pln_own = sp->shp_own;
				plane.pln_mission = 0;
				putplane(plane.pln_uid,&plane);
			}
		} 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);
			land.lnd_own = sectp->sct_own;
			land.lnd_ship = (-1);
			sp->shp_nland--;
			putland(land.lnd_uid,&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, "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);
				plane.pln_own = sectp->sct_own;
				plane.pln_mission = 0;
				putplane(plane.pln_uid,&plane);
			}
		}
		pr("%s %s %s at %s.\n",
		   prland(&land),
		   (load_unload==UNLOAD)?
		   "unloaded from":"loaded onto",
		   prship(sp),
		   xyas(sp->shp_x, sp->shp_y, player->cnum));
		loaded = 1;
	}
	*nshipsp += loaded;
	return 0;
}

static int
load_comm_ship(sectp, sp, ich, load_unload, nshipsp)
	struct	sctstr *sectp;
	struct	shpstr *sp;
	struct	ichrstr *ich;
	int	load_unload;
	int	*nshipsp;
{
	register int item = ich->i_vtype;
	register int max_amt;
	register int move_amt;
	register int ship_amt;
	register int sect_amt;
	int     amount;
	int	upto=0, abs_max;
	s_char	prompt[512];
	s_char	*p;
	s_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)
		return 0;
	amount = atoi(p);
	if (amount < 0) {
		/* We want to load up to this amount */
		upto = -(amount);
		load_unload = LOAD;
	} else if (!amount)
		return 0;
	ship_amt = getvar(item, (s_char *)sp, EF_SHIP);
	sect_amt = getvar(item, (s_char *)sectp, EF_SECTOR);
	if (sectp->sct_oldown != player->cnum &&
	    item == V_CIVIL) {
		pr("%s civilians refuse to %s at %s!\n",
		   load_unload == UNLOAD ? "Your" : "Foreign",
		   load_unload == UNLOAD ?
		   "disembark" : "board",
		   xyas(sectp->sct_x, sectp->sct_y, player->cnum));
		return 0;
	}
	if (load_unload == UNLOAD) {
		abs_max = max_amt = min(9999 - sect_amt, ship_amt);
	} else {
		struct mchrstr *vbase;
		vbase = &mchr[sp->shp_type];
		abs_max = max_amt = vl_find(item, vbase->m_vtype,
					    vbase->m_vamt, (int) vbase->m_nv);
		max_amt = min(sect_amt, max_amt - ship_amt);
	}
	if (max_amt <= 0 && !upto)
		return 0;
	if (upto) {
		move_amt = upto - ship_amt;
		if (move_amt > sect_amt)
			move_amt = sect_amt;
		if (ship_amt+move_amt > abs_max)
			move_amt = abs_max - ship_amt;
	} else
		move_amt = load_unload * min(amount, max_amt);
	if (!move_amt)
		return 0;
	putvar(item, sect_amt - move_amt, (s_char *)sectp, EF_SECTOR);
	putvar(item, ship_amt + move_amt, (s_char *)sp, EF_SHIP);
	if (load_unload == LOAD) {
		pr("%d %s loaded onto %s at %s\n",
		   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);
		}
	} else {
		pr("%d %s unloaded from %s at %s\n",
		   -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",
				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);
		}
	}
	++(*nshipsp);
	return 0;
}

static int
load_plane_land(sectp, lp, noisy, load_unload, nunitsp)
	struct	sctstr	*sectp;
	struct	lndstr	*lp;
	int	noisy;
	int	load_unload;
	int	*nunitsp;
{
	struct	nstr_item ni;
	struct	plnstr pln;
	int	loaded = 0;
	s_char	*p;
	s_char	prompt[512];
	s_char	buf[1024];

	if (!(lchr[lp->lnd_type].l_flags & L_XLIGHT)) {
		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 >= lchr[lp->lnd_type].l_nxlight) {
		if (noisy)
			pr("%s doesn't have room for any more extra-light planes\n",
			   prland(lp));
		return 0;
	}
	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)))
		return RET_SYN;
	if (p && *p)
		noisy &= isdigit(*p);

	while(nxtitem(&ni, (s_char *)&pln)) {			
		if (pln.pln_own != player->cnum)
			continue;
		
		if (!(plchr[pln.pln_type].pl_flags & P_E)) {
			if (noisy)
				pr("You can only load xlight planes onto units.\n");
			continue;
		}

		if (load_unload == LOAD && pln.pln_ship > -1) {
			if (noisy)
				pr("%s is already on ship #%d!\n",
				   prplane(&pln), pln.pln_ship);
			continue;
		}
		if (load_unload == LOAD && pln.pln_land > -1) {
			if (noisy)
				pr("%s is already on unit #%d!\n",
				   prplane(&pln), pln.pln_land);
			continue;
		}
		/* Plane sanity done */
		/* Find the right unit */
		if (load_unload == UNLOAD) {
			if (pln.pln_land != lp->lnd_uid)
				continue;
		} else if (lp->lnd_x != pln.pln_x
			   || lp->lnd_y != pln.pln_y)
			continue;

		/* Fit plane on unit */
		if (load_unload == LOAD){
			if (!put_plane_on_land(&pln,lp)){
				if (noisy)
					pr("Can't put plane %d on this unit!\n",pln.pln_uid);
				continue;
			}
			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);
			pln.pln_own = lp->lnd_own;
			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;
			}
			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);
			pln.pln_own = sectp->sct_own;
			putplane(pln.pln_uid,&pln);
		}
		pr("%s %s %s at %s.\n",
		   prplane(&pln),
		   (load_unload==UNLOAD)?
		   "unloaded from":"loaded onto",
		   prland(lp),
		   xyas(lp->lnd_x, lp->lnd_y, player->cnum));
		loaded = 1;
	}
	*nunitsp += loaded;
	return 0;
}

static int
load_comm_land(sectp, lp, ich, load_unload, nunitsp)
	struct	sctstr	*sectp;
	struct	lndstr	*lp;
	struct	ichrstr	*ich;
	int	load_unload;
	int	*nunitsp;
{
	register int item = ich->i_vtype;
	register int max_amt;
	register int move_amt;
	register int land_amt;
	register int sect_amt;
	int     amount;
	int	upto=0, abs_max;
	s_char	prompt[512];
	s_char	*p;
	s_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)
		return 0;
	amount = atoi(p);
	if (amount < 0) {
		/* We want to load up to this amount */
		upto = -(amount);
		load_unload = LOAD;
	} else if (!amount)
		return 0;

	land_amt = getvar(item, (s_char *)lp, EF_LAND);
	sect_amt = getvar(item, (s_char *)sectp, EF_SECTOR);
	if (sectp->sct_oldown != player->cnum && item == V_CIVIL) {
		pr("%s civilians refuse to %s at %s!\n",
		   load_unload == UNLOAD ? "Your" : "Foreign",
		   load_unload == UNLOAD ?
		   "disembark" : "board",
		   xyas(sectp->sct_x, sectp->sct_y, player->cnum));
		return 0;
	}
	if (load_unload == UNLOAD) {
		abs_max = max_amt = min(9999 - sect_amt, land_amt);
	} else {
		struct lchrstr *vbase;
		vbase = &lchr[lp->lnd_type];
		abs_max = max_amt = vl_find(item, vbase->l_vtype,
					    vbase->l_vamt, (int) vbase->l_nv);
		max_amt = min(sect_amt, max_amt - land_amt);
	}
	if ((max_amt <= 0) && (upto == 0))
		return 0;
	if (upto){
		move_amt = upto - land_amt;
		if (land_amt+move_amt > abs_max)
			move_amt = abs_max - land_amt;
		if (move_amt > sect_amt)
			move_amt = sect_amt;
	}else
		move_amt = load_unload * min(amount, max_amt);
	if (move_amt == 0)
		return 0;
	putvar(item, sect_amt - move_amt, (s_char *)sectp, EF_SECTOR);
	putvar(item, land_amt + move_amt, (s_char *)lp, EF_LAND);

	++(*nunitsp);
	return 0;
}
