#ifndef lint
static char *RCSid = "$Header: /usr/brule/guest/empire/empire/emprcs/lib/subs/plnsub.c,v 2.16 1995/10/24 04:46:24 empire Exp $";
#endif

/*
 * plnsub.c
 *
 * Plane subroutine stuff
 *
 * Dave Pare, 1986
 */

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

int
pln_onewaymission(target, shipno, flagp)
	struct	sctstr *target;
	int	*shipno;
	int	*flagp;
{
	int	nships;
	int	cno;
	int	flags;
	int	n;
	struct	shpstr ship;
	s_char	buf[1024];
	s_char	*p;

	flags = *flagp;
	if ((target->sct_own && target->sct_own != player->cnum &&
		(getrel(getnatp(target->sct_own),player->cnum) != ALLIED)) &&
		(target->sct_type != SCT_HARBR) &&
		(target->sct_type != SCT_BSPAN)) {
		pr("Nowhere to land at sector %s!\n",
			xyas(target->sct_x, target->sct_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));
		return -1;
	}
	cno = -1;
	if (target->sct_type != SCT_AIRPT || target->sct_effic < 60)
		flags |= P_V;
	if (target->sct_type == SCT_WATER || target->sct_type == SCT_HARBR
					|| target->sct_type == SCT_BSPAN) {
		nships = carriersatxy(target->sct_x, target->sct_y,
				M_FLY|M_CHOPPER, 0, player->cnum);
		if (nships <= 0) {
                        if (target->sct_type == SCT_WATER){
                                pr("Nowhere to land at sector %s!\n",
                                xyas(target->sct_x, target->sct_y, player->cnum));
    				return -1;
                        }else{
				if ((target->sct_own && 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));
					return -1;
				}
                                *shipno=cno;
                                *flagp=flags;
                                return 0;
                        }
		}
		cno = (-1);
		n = (-1);
		while (cno < 0) {
			if (!(p = getstarg(0, "Carrier #? ", buf)) || !*p)
				break;
			n = atoi(p);
			if (n < 0 || !getship(n, &ship) || (!player->owner &&
			    (getrel(getnatp(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", n,
				    xyas(target->sct_x, target->sct_y, player->cnum));
				continue;
			}
			if (!(mchr[ship.shp_type].m_flags & M_FLY)
				&& !(mchr[ship.shp_type].m_flags & M_XLIGHT)
				&& !(mchr[ship.shp_type].m_flags & M_CHOPPER)
			){
				pr("Can't land on %s.\n", prship(&ship));
				continue;
			}
			pr("landing on carrier %d\n",n);
			cno = n;
			flags &= ~P_V;
			if (mchr[ship.shp_type].m_flags & M_FLY)
				flags |= P_L;
			if (mchr[ship.shp_type].m_flags & M_CHOPPER)
				flags |= P_K;
			if (mchr[ship.shp_type].m_flags & M_XLIGHT)
				flags |= P_E;
		}
		if ((target->sct_own && target->sct_own != player->cnum) && 
			(getrel(getnatp(target->sct_own),player->cnum) != ALLIED) &&
			(cno== -1)){
			pr("You don't own %s!\n", xyas(target->sct_x,
				target->sct_y, player->cnum));
			return -1;
		}
	}

	if ((target->sct_own == 0) && (cno < 0)){
		pr("Can't land there!\n");
		return -1;
	}

	*shipno = cno;
	*flagp = flags;
	return 0;
}

pln_newlanding(list, tx, ty, cno)
	struct	qelem *list;
	coord	tx, ty;
	int	cno;
{
	struct	qelem *qp;
	struct	plist *plp;
	struct	shpstr ship;
	struct	sctstr sect;

	if (cno >= 0)
		getship(cno, &ship);
	for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
		plp = (struct plist *)qp;
		/* XXX - need to restrict # of planes per ship */
		if (cno >= 0){
                        count_planes(&ship);
			if (!can_be_on_ship(plp->plane.pln_uid,ship.shp_uid))
				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))
				pr("\tNo room on ship #%d! %s aborts!\n",cno,prplane(&plp->plane));
			else{
				if (plp->plane.pln_own != ship.shp_own){
					plp->plane.pln_own = ship.shp_own;
					wu(0,ship.shp_own,
					   "%s %s lands on your %s\n",
					   cname(player->cnum),
					   prplane(&plp->plane),
					   prship(&ship));
				}
			}
		}
		else{
			plp->plane.pln_x = tx;
			plp->plane.pln_y = ty;
			getsect(tx,ty,&sect);
			if (plp->plane.pln_own != sect.sct_own){
				plp->plane.pln_own = sect.sct_own;
				wu(0,sect.sct_own,
				   "%s %s lands at your sector %s\n",
				   cname(player->cnum),
				   prplane(&plp->plane),
				   xyas(tx,ty,sect.sct_own));
			}
			plp->plane.pln_ship = cno;
		}
	}
	if (cno >= 0)
		putship(cno, &ship);
}

void
pln_dropoff(list, ip, tx, ty, ptr, type)
	struct	qelem *list;
	struct	ichrstr *ip;
	coord	tx, ty;
	s_char	*ptr;
	int	type;
{
	struct	qelem *qp;
	struct	plist *plp;
	int	amt;
	struct	shpstr *ship;
	int	there;
	int	max;
	struct	mchrstr *mp;
	int	mines_there;

	if (ip == 0)
		return;
	amt = 0;
	for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
		plp = (struct plist *)qp;
		amt += plp->misc;
	}
	if (type == EF_SECTOR &&
		(((struct sctstr *)ptr)->sct_type == SCT_WATER) &&
		ip->i_vtype == V_SHELL){
                mines_there = getvar(V_MINE, ptr, EF_SECTOR);
                putvar(V_MINE, amt + mines_there, ptr, EF_SECTOR);
                pr("%d mines laid in %s.\n", amt,
                        xyas(((struct sctstr *)ptr)->sct_x,
			((struct sctstr *)ptr)->sct_y, player->cnum));
		if (amt > 0 &&
		    map_set(player->cnum, ((struct sctstr *)ptr)->sct_x,
			   ((struct sctstr *)ptr)->sct_y, 'X', 0))
			writemap(player->cnum);
		putsect((struct sctstr *) ptr);
	}else{
		there = getvar(ip->i_vtype, ptr, type) + amt;
		max = 32767;
		if (type == EF_SHIP) {
			ship = (struct shpstr *) ptr;
			mp = &mchr[ship->shp_type];
			max = vl_find(ip->i_vtype, mp->m_vtype,
				mp->m_vamt, (int)mp->m_nv);
		}
		if (there > max) {
			pr("%d excess %s discarded\n", max-there, ip->i_name);
			amt = max - there;
			there = max;
		}
		putvar(ip->i_vtype, there, ptr, type);
		pr("%d %s landed safely", amt, ip->i_name);
		if (type == EF_SECTOR) {
			struct	sctstr *sectp = (struct sctstr *)ptr;
			if (sectp->sct_own != player->cnum)
				wu(0, sectp->sct_own, "%s planes drop %d %s in %s\n",
					cname(player->cnum),amt,ip->i_name,
					xyas(sectp->sct_x,sectp->sct_y,
					sectp->sct_own));
			pr(" at %s\n", xyas(tx, ty, player->cnum));
			putsect((struct sctstr *) ptr);
		} else {
			struct	shpstr *sp = (struct shpstr *)ptr;
			if (sp->shp_own != player->cnum)
				wu(0, sp->shp_own, "%s planes land %d %s on carrier %d\n",
					cname(player->cnum),amt,ip->i_name,sp->shp_uid);
			pr(" on carrier #%d\n", ship->shp_uid);
			putship(ship->shp_uid, ship);
		}
	}
}

pln_sel(ni, list, ap, ap_to_target, rangemult, wantflags, nowantflags)
	struct	nstr_item *ni;
	struct	qelem *list;
	struct	sctstr *ap;
	int	ap_to_target;
	int	rangemult;
	int	wantflags;
	int	nowantflags;
{
	struct	plnstr plane;
	struct	shpstr ship;
	struct	lndstr land;
	struct	sctstr sect;
	int	range;
	struct	plchrstr *pcp;
	struct	plist *plp;
	register int	x,y;
	register int bad,bad1;

	initque(list);
	while (nxtitem(ni, (s_char *)&plane)) {
		if (!player->owner)
			continue;
		if (plane.pln_mobil <= (s_char)0)
			continue;
		range = mapdist(plane.pln_x, plane.pln_y, ap->sct_x, ap->sct_y);
		if (range > 4) {
			pr("%s too far from assembly point\n",
			   prplane(&plane));
			continue;
		}
		if (plane.pln_effic < 40) {
			pr("%s not efficient enough (must be 40%%)\n", prplane(&plane));
			continue;
		}
		range += ap_to_target;
		pcp = &plchr[plane.pln_type];
		bad=0;
		bad1=0;
		if (wantflags) {
			for(x=0;x<sizeof(wantflags)*8;x++){
				y=(1<<x);
				if ((wantflags & y) == y)
					if ((pcp->pl_flags & y) != y){
						switch(y){
							case P_F:
							case P_ESC: bad1=2;
								    break;
							case P_E:
							case P_L:
							case P_K: bad1=1;
								  break;
							default:  bad=1;
						}
					}
			}
			if (bad)
				continue;
			if (bad1 == 2){
				if ((pcp->pl_flags &  P_ESC) ||
					(pcp->pl_flags & P_F))
					bad1=0;
			}
			if (bad1 == 1){
				if ((wantflags & P_L) && (pcp->pl_flags &  P_L))
					bad1=0;
				if ((wantflags & P_K) && (pcp->pl_flags &  P_K))
					bad1=0;
				if ((wantflags & P_E) && (pcp->pl_flags &  P_E))
					bad1=0;
			}
			if (bad1)
				continue;
		}
		bad=0;
		bad1=0;
		if (nowantflags) {
			for(x=0;x<sizeof(nowantflags)*8;x++){
				y=(1<<x);
				if ((nowantflags & y) == y)
					if ((pcp->pl_flags & y) == y)
						bad=1;
			}
			if (bad)
				continue;
		}
		range *= rangemult;
		if (plane.pln_range < range) {
			pr("%s out of range (%d:%d)\n", prplane(&plane),
				plane.pln_range, range);
			continue;
		}
		if (plane.pln_ship >= 0) {
			if (!getship(plane.pln_ship, &ship) ||
			    plane.pln_own != player->cnum) {
	shipsunk:
				plane.pln_effic = 0;
				pr("(note) ship not valid for %s\n",
					prplane(&plane));
				putplane(ni->cur, &plane);
				continue;
			}
			if (!can_be_on_ship(plane.pln_uid,ship.shp_uid))
				goto shipsunk;
			if (ship.shp_effic < SHIP_MINEFF)
				goto shipsunk;
			if (ship.shp_effic < 50)
				continue;
		}
		if (plane.pln_land >= 0) {
			if (!getland(plane.pln_land, &land) ||
			    (plane.pln_own != player->cnum)){
	landdead:
				plane.pln_effic = 0;
				pr("(note) ship not valid for %s\n",
				   prplane(&plane));
				putplane(ni->cur, &plane);
				continue;
			}
			if (!(plchr[plane.pln_type].pl_flags & P_E))
				goto landdead;
			if (land.lnd_effic < LAND_MINEFF)
				goto landdead;
			if (land.lnd_effic < 50)
				continue;
			/* Can't fly off units in ships */
			if (land.lnd_ship >= 0)
				continue;
		}
		/*
		 * if not vtol and not at an airport, you lose!
		 */
		if ((pcp->pl_flags & P_V) == 0 && (plane.pln_ship < 0) &&
			(plane.pln_land < 0)) {
			if (!getsect(plane.pln_x, plane.pln_y, &sect) ||
			    sect.sct_type != SCT_AIRPT) {
				pr("%s not at airport\n", prplane(&plane));
				continue;
			}
			if (sect.sct_effic < 40) {
				pr("%s is not 40%% efficient, %s can't take off from there.\n",
				   xyas(sect.sct_x,sect.sct_y,plane.pln_own),
				   prplane(&plane));
				continue;
			}
			if (rangemult == 2 && sect.sct_effic < 60) {
				pr("%s is not 60%% efficient, %s can't land there.\n",
				   xyas(sect.sct_x,sect.sct_y,plane.pln_own),
				   prplane(&plane));
				continue;
			}
		}
		pr("%s standing by\n", prplane(&plane));
		plane.pln_mission = 0;
		putplane(plane.pln_uid, &plane);
		plp = (struct plist *) malloc(sizeof(struct plist));
		plp->state = P_OK;
		plp->misc = 0;
		plp->bombs = 0;
		plp->pcp = pcp;
		bcopy((s_char *)&plane, (s_char *)&plp->plane,
			sizeof(struct plnstr));
		insque(&plp->queue, list);
	}
}

int
pln_arm(list, dist, mission, ip, flags, mission_flags, tech)
	struct	qelem *list;
	int	mission;
	struct	ichrstr *ip;
	int	flags;
	int	mission_flags;
	int	*tech;
{
	struct	qelem *qp;
	struct	qelem *next;
	struct	plist *plp;

	if (*tech == 0)
		*tech = 9999;
	for (qp = list->q_forw; qp != list; qp = next) {
		next = qp->q_forw;
		plp = (struct plist *) qp;
		if (pln_equip(plp, ip, flags, mission) < 0) {
			remque(qp);
			free((s_char *)qp);
			continue;
		}
		if (flags & (P_S|P_I)) {
			if(plp->pcp->pl_flags & P_S)
				mission_flags |= P_S;
			if(plp->pcp->pl_flags & P_I)
				mission_flags |= P_I;
		}
		if (*tech > plp->plane.pln_tech)
			*tech = plp->plane.pln_tech;
		if (!(plp->pcp->pl_flags & P_H))
			/* no stealth on this mission */
			mission_flags &= ~P_H;
		if (!(plp->pcp->pl_flags & P_X))
			/* no stealth on this mission */
			mission_flags &= ~P_X;
		if (!(plp->pcp->pl_flags & P_A)) {
			/* no asw on this mission */
			mission_flags &= ~P_A;
		}
		if (!(plp->pcp->pl_flags & P_MINE)) {
			/* no asw on this mission */
			mission_flags &= ~P_MINE;
		}
		plp->plane.pln_mobil -= pln_mobcost(dist,&plp->plane,flags);
		pr("%s equipped\n", prplane(&plp->plane));
	}
	return mission_flags;
}

int
pln_equip(plp, ip, flags, mission)
	struct	plist *plp;
	struct	ichrstr *ip;
	int	flags;
	s_char	mission;
{
	register struct plchrstr *pcp;
	struct	plnstr *pp;
	int	needed;
	struct	lndstr land;
	struct	shpstr ship;
	struct	sctstr sect;
	int	type;
	s_char	*ptr;
	int	item;
	int	rval;
	int	vec[I_MAX+1];

	pp = &plp->plane;
	pcp = plp->pcp;
	if (pp->pln_ship >= 0) {
		getship(pp->pln_ship, &ship);
		type = EF_SHIP;
		ptr = (s_char *) &ship;
	} else
	if (pp->pln_land >= 0) {
		getland(pp->pln_land, &land);
		type = EF_LAND;
		ptr = (s_char *) &land;
	} else {
		getsect(pp->pln_x, pp->pln_y, &sect);
		type = EF_SECTOR;
		ptr = (s_char *) &sect;
	}
	getvec(VT_ITEM, vec, ptr, type);
	if (pcp->pl_fuel > vec[I_PETROL]) {
		pr("%s not enough petrol there!\n", prplane(pp));
		return -1;
	}
	vec[I_PETROL] -= pcp->pl_fuel;
	rval = 0;
	if ((flags & P_F) == 0) {
		item = 0;
		needed = 0;
		switch (mission) {
		case 's':
		case 'p':
                        if (pp->pln_nuketype == -1) {
				item = I_SHELL;
				needed = pcp->pl_load;
			}
			break;
		case 't':
			if ((pcp->pl_flags & P_C) == 0 || ip == 0)
				break;
			item = ip - ichr;
			needed = (pcp->pl_load * 2) / ip->i_lbs;
			break;
		case 'd':
			if ((pcp->pl_flags & P_C) == 0 || ip == 0)
				break;
			item = ip - ichr;
			needed = (pcp->pl_load * 2) / ip->i_lbs;
			break;
		case 'a':
			if ((pcp->pl_flags & (P_V|P_C)) == 0)
				break;
			item = I_MILIT;
			needed = pcp->pl_load / ip->i_lbs;
			break;
		case 'n':
			if (pp->pln_nuketype == (s_char)-1)
				rval = -1;
			break;
		default:
			break;
		}
		if (rval < 0 || (item && needed <= 0)) {
			pr("%s can't contribute to mission\n", prplane(pp));
			return -1;
		}
		if ((vec[item] < needed) && (item == I_SHELL))
			vec[item] += supply_commod(plp->plane.pln_own,
				plp->plane.pln_x,plp->plane.pln_y,I_SHELL,
				needed);
		if (vec[item] < needed) {
			pr("Not enough %s for %s\n",
				ichr[item].i_name, prplane(pp));
			return -1;
		} else {
			vec[item] -= needed;
		}
		if (item == I_SHELL && (mission == 's' || mission == 'p'))
			plp->bombs = needed;
		else
			plp->misc = needed;
	}
	putvec(VT_ITEM, vec, ptr, type);
	if (type == EF_SHIP)
		putship(ship.shp_uid,&ship);
	else if (type == EF_LAND)
		putland(land.lnd_uid,&land);
	else
		putsect(&sect);
	return rval;
}

pln_put(list)
	struct	qelem *list;
{
	register struct qelem *qp;
	register struct qelem *newqp;
	struct	plist *plp;

	qp = list->q_forw;
	while (qp != list) { 
		plp = (struct plist *) qp;
		putplane(plp->plane.pln_uid, &plp->plane);
		newqp = qp->q_forw;
		remque(qp);
		free((s_char *)qp);
		qp = newqp;
	}
}

void
pln_removedupes(bomb_list, esc_list)
	struct	qelem *bomb_list;
	struct	qelem *esc_list;
{
	struct	qelem *bomb;
	struct	qelem *esc;
	struct	plist *bombp;
	struct	plist *escp;

	if (QEMPTY(bomb_list) || QEMPTY(esc_list))
		return;
	bomb = bomb_list->q_forw;
	while (bomb != bomb_list) {
		if (QEMPTY(esc_list)) {
			bomb = bomb_list;
			continue;
		}
		esc = esc_list->q_forw;
		bombp = (struct plist *) bomb;
		while (esc != esc_list) {
			escp = (struct plist *) esc;
			if (escp->plane.pln_uid == bombp->plane.pln_uid) {
				remque(esc);
				free((s_char *)esc);
				esc = esc_list;
			} else
				esc = esc->q_forw;
		}
		bomb = bomb->q_forw;
	}
}

put_plane_on_ship(plane,ship)
struct plnstr	*plane;
struct shpstr	*ship;
{
	struct	plchrstr *pcp;
	struct	mchrstr *mcp;

	pcp = &plchr[plane->pln_type];
	mcp = &mchr[ship->shp_type];

	if (((int)plane->pln_ship) == ((int)ship->shp_uid))
		return 1; /* Already on ship */

	/* Try to put on ship as a chopper plane */
	if ((pcp->pl_flags & P_K) &&
		(mcp->m_flags & M_CHOPPER) &&
		(ship->shp_nchoppers < mcp->m_nchoppers)){

		ship->shp_nchoppers++;
		plane->pln_x = ship->shp_x;
		plane->pln_y = ship->shp_y;
		plane->pln_ship = ship->shp_uid;
		putship(ship->shp_uid,ship);
		putplane(plane->pln_uid,plane);
		return 1;
	}

	/* Try to put on ship as an xlight plane */
	if ((pcp->pl_flags & P_E) &&
		(mcp->m_flags & M_XLIGHT) &&
		(ship->shp_nxlight < mcp->m_nxlight)){

		ship->shp_nxlight++;
		plane->pln_x = ship->shp_x;
		plane->pln_y = ship->shp_y;
		plane->pln_ship = ship->shp_uid;
		putship(ship->shp_uid,ship);
		putplane(plane->pln_uid,plane);
		return 1;
	}

	/* Try to put on ship as a normal plane */
	if ( ( ((pcp->pl_flags & P_L) && (mcp->m_flags & M_FLY)) ||
		((pcp->pl_flags & P_M) && (pcp->pl_flags & P_L) &&
		(mcp->m_flags & M_MSL)) ) &&
		(ship->shp_nplane < mcp->m_nplanes)){

		ship->shp_nplane++;
		plane->pln_x = ship->shp_x;
		plane->pln_y = ship->shp_y;
		plane->pln_ship = ship->shp_uid;
		putship(ship->shp_uid,ship);
		putplane(plane->pln_uid,plane);
		return 1;
	}

	/* We have failed */
	return 0;
}

take_plane_off_ship(plane,ship)
struct plnstr	*plane;
struct shpstr	*ship;
{
	struct plchrstr	*pcp;
	struct mchrstr	*mcp;

	pcp = &plchr[plane->pln_type];
	mcp = &mchr[ship->shp_type];

	/* Try to take off ship as a chopper plane */
	if ((pcp->pl_flags & P_K) &&
		(mcp->m_flags & M_CHOPPER) &&
		(ship->shp_nchoppers)){

		ship->shp_nchoppers--;
		plane->pln_ship = -1;
		putship(ship->shp_uid,ship);
		putplane(plane->pln_uid,plane);
		return 1;
	}

	/* Try to take off ship as an xlight plane */
	if ((pcp->pl_flags & P_E) &&
		(mcp->m_flags & M_XLIGHT) &&
		(ship->shp_nxlight)){

		ship->shp_nxlight--;
		plane->pln_ship = -1;
		putship(ship->shp_uid,ship);
		putplane(plane->pln_uid,plane);
		return 1;
	}

	/* Try to take off ship as a normal plane */
	if ( ( ((pcp->pl_flags & P_L) && (mcp->m_flags & M_FLY)) ||
		((pcp->pl_flags & P_M) && (pcp->pl_flags & P_L) &&
		(mcp->m_flags & M_MSL)) ) &&
		(ship->shp_nplane)){

		ship->shp_nplane--;
		plane->pln_ship = -1;
		putship(ship->shp_uid,ship);
		putplane(plane->pln_uid,plane);
		return 1;
	}

	/* We have failed */
	return 0;
}

take_plane_off_land(plane,land)
struct plnstr	*plane;
struct lndstr	*land;
{
	struct plchrstr	*pcp;
	struct lchrstr	*lcp;

	pcp = &plchr[plane->pln_type];
	lcp = &lchr[land->lnd_type];

	/* Try to take off ship as an xlight plane */
	if ((pcp->pl_flags & P_E) &&
		(lcp->l_flags & L_XLIGHT) &&
		(land->lnd_nxlight)){

		land->lnd_nxlight--;
		plane->pln_land = -1;
		putland(land->lnd_uid,land);
		putplane(plane->pln_uid,plane);
		return 1;
	}

	/* We have failed */
	return 0;
}

can_be_on_ship(p,s)
int    p,s;
{
	struct plnstr	plane;
	struct shpstr	ship;
	struct plchrstr	*pcp;
	struct mchrstr	*mcp;

	getplane(p,&plane);
	getship(s,&ship);

	pcp = &plchr[plane.pln_type];
	mcp = &mchr[ship.shp_type];

	if (pcp->pl_flags & P_L)
		if (mcp->m_flags & M_FLY)
			return 1;

	if (pcp->pl_flags & P_K)
		if (mcp->m_flags & M_CHOPPER)
			return 1;

	if (pcp->pl_flags & P_M)
		if (mcp->m_flags & M_MSL)
			return 1;

	if (pcp->pl_flags & P_E)
		if (mcp->m_flags & M_XLIGHT)
			return 1;

	return 0;
}

void
plane_sweep(plane_list,x,y)
struct  qelem *plane_list;
coord	x,y;
{
	struct	plnstr	*pp;
	struct	plchrstr *pcp;
	struct  qelem   *qp;
	struct  qelem   *next;
	struct  plist   *ip;
	struct  sctstr  sect;
	int	mines_there;
	int	found = 0;

	getsect(x,y,&sect);
	mines_there = getvar(V_MINE, (s_char *)&sect, EF_SECTOR);

	if (mines_there == 0)
		return;

	if ((sect.sct_type != SCT_WATER) && (sect.sct_type != SCT_HARBR))
		return;

        for (qp=plane_list->q_forw;((qp!=plane_list)&&(mines_there));qp=next) {
                next = qp->q_forw;
                ip = (struct plist *) qp;
                pp = &ip->plane;
                pcp = ip->pcp;
		if (!(pcp->pl_flags & P_SWEEP)) /* if it isn't an sweep plane */
			continue;

		if (chance( ((double) (100-pcp->pl_acc))/100.0 )){
			pr("Sweep! in %s\n",
				xyas(sect.sct_x,sect.sct_y,pp->pln_own));
			mines_there--;
			found = 1;
		}
	}

	if (found && map_set(player->cnum, sect.sct_x, sect.sct_y, 'X', 0))
		writemap(player->cnum);
	putvar(V_MINE, mines_there, (s_char *)&sect, EF_SECTOR);
	putsect(&sect);
}

void
count_planes(sp)
struct shpstr *sp;
{
        struct  nstr_item ni;
        struct  plnstr plane;
        struct  plchrstr *pcp;
        struct  mchrstr *mcp;

        if (sp->shp_effic < SHIP_MINEFF)
                return;

        mcp = &mchr[sp->shp_type];
        sp->shp_nplane=0;
        sp->shp_nchoppers=0;
        sp->shp_nxlight=0;
        snxtitem_xy(&ni, EF_PLANE, sp->shp_x, sp->shp_y);
        while (nxtitem(&ni, (s_char *)&plane)){
                if (plane.pln_own == 0)
                	continue;
                if (plane.pln_ship == sp->shp_uid){
                        pcp = &plchr[plane.pln_type];
                        if ((pcp->pl_flags & P_K) &&
				(sp->shp_nchoppers < mcp->m_nchoppers))
                                sp->shp_nchoppers++;
			else
                        if ((pcp->pl_flags & P_E) &&
				(sp->shp_nxlight < mcp->m_nxlight))
                                sp->shp_nxlight++;
			else
                        if ((pcp->pl_flags & P_L) || (pcp->pl_flags & P_M))
                                sp->shp_nplane++;
                }
        }

        putship(sp->shp_uid,sp);
}

void
count_land_planes(lp)
struct lndstr *lp;
{
        struct  nstr_item ni;
        struct  plnstr plane;

        if (lp->lnd_effic < SHIP_MINEFF)
                return;

        lp->lnd_nxlight=0;
        snxtitem_all(&ni, EF_PLANE);
        while (nxtitem(&ni, (s_char *)&plane))
                if (plane.pln_land == lp->lnd_uid)
			lp->lnd_nxlight++;

        putland(lp->lnd_uid,lp);
}

count_sect_planes(sp)
struct sctstr *sp;
{
	int	count = 0;
        struct  nstr_item ni;
        struct  plnstr plane;

        snxtitem_all(&ni, EF_PLANE);
        while (nxtitem(&ni, (s_char *)&plane)) {
		if (!plane.pln_own)
			continue;
		if (plane.pln_flags & PLN_LAUNCHED)
			continue;
                if (plane.pln_x == sp->sct_x && plane.pln_y == sp->sct_y)
			++count;
	}

	return count;
}

put_plane_on_land(plane,land)
struct plnstr	*plane;
struct lndstr	*land;
{
	struct	plchrstr *pcp;
	struct	lchrstr *lcp;

	pcp = &plchr[plane->pln_type];
	lcp = &lchr[land->lnd_type];

	if (((int)plane->pln_land) == ((int)land->lnd_uid))
		return 1; /* Already on unit */

	/* Try to put on unit as an xlight plane */
	if ((pcp->pl_flags & P_E) &&
		(lcp->l_flags & L_XLIGHT) &&
		(land->lnd_nxlight < lcp->l_nxlight)){

		land->lnd_nxlight++;
		plane->pln_x = land->lnd_x;
		plane->pln_y = land->lnd_y;
		plane->pln_land = land->lnd_uid;
		putland(land->lnd_uid,land);
		putplane(plane->pln_uid,plane);
		return 1;
	}

	/* We have failed */
	return 0;
}

int
pln_hitchance(pp, hardtarget, type)
	struct	plnstr *pp;
	int	hardtarget;
	int	type;
{
	struct	plchrstr *pcp = plchr + pp->pln_type;
	float	tfact = (float)(pp->pln_tech - pcp->pl_tech) /
		            (pp->pln_tech - pcp->pl_tech / 2);
	int	acc = pcp->pl_acc;
	int	hitchance;

	if (type == EF_SHIP) {
		if (pcp->pl_flags & P_A)
			acc -= 20;
		if (!(pcp->pl_flags & P_T))
			acc += 35;
	}
	hitchance = (int)(pp->pln_effic * (1.0 - 0.1 * tfact) *
			 (1.0 - (float)acc / 100.0)) - hardtarget;

	/* smooth out the bottom of the graph with asymtote at 5 -KHS */
	if (hitchance < 20)
		hitchance = 5 + ldround(300.0 / (40.0 - hitchance), 1);
	if (hitchance > 100)
		hitchance = 100;
	return hitchance;
}

/* return 0 if there was a nuclear detonation */

int
pln_damage(pp, x, y, type, nukedamp)
	struct  plnstr *pp;
	coord	x,y;
	s_char	type;
	int	*nukedamp;
{
	struct plchrstr *pcp = plchr + pp->pln_type;
	int	i;
	int	hitroll;
	int	dam = 0;
	int	aim;
	int	effective = 1;
	int	pinbomber = 0;

	if (pp->pln_nuketype != (s_char)-1) {
		mpr(pp->pln_own, "Releasing RV's for %s detonation...\n",
		    pp->pln_flags & PLN_AIRBURST?"airburst":"groundburst");
		*nukedamp = detonate(pp, x, y);
		return 0;
	} else
		*nukedamp = 0;

	if (!pcp->pl_load) /* e.g. ab, blowing up on launch pad */
		return 0;

	i = roll(pcp->pl_load) + 1;
	if (i > pcp->pl_load)
		i = pcp->pl_load;

	if (pcp->pl_flags & P_M) {
		if (pcp->pl_flags & P_MAR)
			pinbomber = 1;
	} else if (pcp->pl_flags & P_T)
		pinbomber = 1;

	aim = 100 - pcp->pl_acc;
	if (type == 's') {
		if (pinbomber) {
			aim = pcp->pl_acc;
			effective = 0;
		}
		aim += 30;
	} else {
		if (!pinbomber) {
			effective = 0;
		}
	}
	while (i--) {
		dam += roll(6);
		hitroll = roll(100);
		if (hitroll >= 90) {
			dam += 8;
			mpr(pp->pln_own, "BLAM");
		} else if (hitroll < aim) {
			dam += 5;
			mpr(pp->pln_own, "Blam");
		} else {
			dam += 1;
			mpr(pp->pln_own, "blam");
		}
		if (i)
			mpr(pp->pln_own, "-");
	}
	mpr(pp->pln_own, "\n");
	if (effective)
		dam *= 2;
	return dam;
}

int
pln_identchance(pp, hardtarget, type)
	struct	plnstr *pp;
	int	hardtarget;
	int	type;
{
	double	misschance = (100.0-pln_hitchance(pp, hardtarget, type))/100.0;
	return (int)(100 - 100 * misschance * misschance);
}

int
pln_mobcost(dist, pp, flags)
	int	dist;
	struct	plnstr	*pp;
	int	flags;
{
	int cost;

	if ((flags & P_F) || (flags & P_ESC))
		cost = 10 * 100 / pp->pln_effic;
	else
		cost = 20 * 100 / pp->pln_effic;

	cost = ldround((double)cost * dist/pp->pln_range_max, 1);

	return min(32 + pp->pln_mobil, cost + 5);
}
