#ifndef lint
static char *RCSid = "$Header: /u/dhay/stan/kent/update/RCS/nav_ship.c,v 1.2 91/03/30 02:03:39 dhay Exp Locker: dhay $";
#endif

/*
 * nav_ship.c
 *
 * navigate ships and such.
 *
 */

#include "misc.h"
#ifdef	AUTONAV

#include <ctype.h>
#include "var.h"
#include "ship.h"
#include "sect.h"
#include "news.h"
#include "xy.h"
#include "nsc.h"
#include "nat.h"
#include "path.h"
#include "deity.h"
#include "file.h"


extern int check_nav();
 /* return codes from check_nav */
#define CN_LANDLOCKED	(1)
#define CN_CONSTRUCTION	(2)
#define CN_ERROR	(-1)
#define CN_NAVIGABLE	(0)

char *bestpath();

static int
nav_check_atdest(sp, mcp)
	register struct shpstr *sp;
	struct mchrstr *mcp;
{
	if ((sp->shp_x == sp->shp_destx[0])
			&& (sp->shp_y == sp->shp_desty[0])) {
		if ((sp->shp_destx[0] == sp->shp_destx[1]) &&
				(sp->shp_desty[0] == sp->shp_desty[1])) {
			/* End of road */
			sp->shp_autonav &= ~AN_AUTONAV;
			wu(0, sp->shp_own, fmt("%s arrived at %s, finished\n",
					nav_nameship(sp, mcp),
					xyas(sp->shp_x,sp->shp_y,sp->shp_own)));
		} else {
			coord tcord;
			u_char tcomm;
			wu(0, sp->shp_own, fmt("%s arrived at %s\n",
					nav_nameship(sp, mcp),
					xyas(sp->shp_x,sp->shp_y,sp->shp_own)));
			/* Swap */
			tcord = sp->shp_destx[0];
			sp->shp_destx[0] = sp->shp_destx[1];
			sp->shp_destx[1] = tcord;
			tcord = sp->shp_desty[0];
			sp->shp_desty[0] = sp->shp_desty[1];
			sp->shp_desty[1] = tcord;
			tcomm = sp->shp_trdtype[0];
			sp->shp_trdtype[0] = sp->shp_trdtype[1];
			sp->shp_trdtype[1] = tcomm;
			sp->shp_autonav |= AN_LOADING;
		}
	} else
		sp->shp_autonav &= ~AN_LOADING;
}

static int
nav_loadship(sp)
        register struct shpstr *sp;
{
	sp->shp_autonav &= ~AN_LOADING;
}

static int
nav_indir(sp, mcp, dirch, mobil)
        register struct shpstr *sp;
	struct mchrstr *mcp;
	int dirch;
	double  *mobil;
{
	int	m;
	int     dir;
	coord	newx;
	coord	newy;
	double  mobcost;
	int     mines;
	int	owner;
	struct sctstr *sectp;
	int	time_to_stop;

	time_to_stop = 0;
	dir = nav_chkdir(dirch, DIR_STOP, DIR_LAST);
	if (dir == -1) {
		/* somehow got a bad direction character, break */
		/* for example, destination reached */
		wu(0, sp->shp_own, fmt("%s bad dir char %d %d\n",
				nav_nameship(sp,mcp), dir, dirch));
		return(1);
	} else if (dir == DIR_STOP) {
		return(1);
	}
	newx = xnorm(sp->shp_x + diroff[dir][0]);
	newy = ynorm(sp->shp_y + diroff[dir][1]);

	mobcost = sp->shp_effic * 0.01 * mcp->m_speed;
	mobcost = 480.0 / (mobcost + techfact(sp->shp_tech, mobcost));

	sectp = getsectp(newx, newy);
	owner = (sectp->sct_own == sp->shp_own) ? 1 : 0;
	if (check_nav(sectp) != CN_NAVIGABLE ||
		    (sectp->sct_own && !owner && 
		    getrel(getnatp(sectp->sct_own), sp->shp_own) != ALLIED)) {
		wu(0, sp->shp_own, fmt("%s sector %s not navigable\n",
				nav_nameship(sp,mcp),
				xyas(newx, newy, sp->shp_own)));
		return(1);
	}
	sp->shp_x = newx;
	sp->shp_y = newy;
	*mobil -= mobcost;
	/* JNP  12/15/89
	   Stuff added for bigmap, generates automatic radar
	   while moving 
	 */
	nav_shiprad(sp, newx, newy);

	mines = getvar(V_MINE, (char *)sectp, EF_SECTOR);
	if (mines > 0 && (mcp->m_flags & M_SWEEP) && !owner) {
		int swept = 0;
		int	max, shells;

		max = vl_find(V_SHELL, mcp->m_vtype,
				mcp->m_vamt, (int) mcp->m_nv);
		shells = getvar(V_SHELL, (char *)sp, EF_SHIP);
		for (m=0; mines > 0 && m < 5; m++) {
			if (chance(0.66)) {
				mines--;
				swept++;
				shells = min(max, shells + 1);
			}
		}
		if (swept) {
			putvar(V_MINE, mines, (char *)sectp, EF_SECTOR);
			putvar(V_SHELL, shells, (char *)sp, EF_SHIP);
			wu(0,sp->shp_own,fmt("***%s swept %d mines from %s\n",
					nav_nameship(sp,mcp), swept,
					xyas(newx, newy, sp->shp_own)));
		}
	}
	if (mines > 0 && !owner && chance(0.05 * mines)) {
		/* send a telegram instead of pr'ing */
		nreport(sp->shp_own, N_HIT_MINE, 0, 1);
		if (mcp->m_glim)
			m = 15 + 1350 / mcp->m_armor;
		else
			m = 2100 / (mcp->m_vrnge*mcp->m_visib);
		m += random() % 21;
		shipdamage(sp, m);
		wu(0, sp->shp_own, fmt("***Kawhomp! %s hits mine at %s!\n",
				nav_nameship(sp,mcp),
				xyas(newx, newy, sp->shp_own)));
		if (sp->shp_effic < 20) {
			wu(0, sp->shp_own, fmt("%s sunk!\n",
				nav_nameship(sp, mcp)));
			sp->shp_own = 0;
		}
		mines--;
		putvar(V_MINE, mines, (char *)sectp, EF_SECTOR);
		sp->shp_autonav |= AN_STANDBY;
		time_to_stop = 1;
	}
	return(time_to_stop);
}

nav_ship(sp, shipno, np)
        register struct shpstr *sp;
	int     shipno;
	struct  natstr *np;
{
	extern double techfact();
	extern char *argp[];
	struct sctstr *sectp;
	register n;
	char   *cp;
	int     nships;
	int     stopping;
	int     snum;
	double  mobil;
	struct nstr_item nb;
	struct mchrstr *mcp;
	int	vec[I_MAX+1];

	cnum = sp->shp_own;
	mcp = &mchr[sp->shp_type];

	/* just return if no autonaving to do for this ship */
	if (!(sp->shp_autonav & AN_AUTONAV) || (sp->shp_autonav & AN_STANDBY))
		return RET_OK;

	/* Try to load the ship */
	if (sp->shp_autonav & AN_LOADING)
		nav_loadship(sp);

	/* If ship still loading, leave it there. */
	if (sp->shp_autonav & AN_LOADING)
		return RET_OK;

	snum = sp->shp_uid;
	mobil = (double) sp->shp_mobil;
	if (mobil <= 0.0) {
		wu(0, cnum, fmt("%s has no mobility\n", nav_nameship(sp,mcp)));
		return RET_OK;
	}

	/* check crew - uws don't count */
	getvec(VT_ITEM, vec, (char *)sp, EF_SHIP);
	if (vec[I_MILIT] == 0 && vec[I_CIVIL] == 0) {
		wu(0, cnum, fmt("%s has no crew\n", nav_nameship(sp,mcp)));
		return RET_OK;
	}

	/* See if ship can move. */
	if (!(sectp=getsectp(sp->shp_x, sp->shp_y))) {
		wu(0, cnum, fmt("%s bad sector read\n", nav_nameship(sp,mcp)));
		return RET_SYN;
	}
	switch (check_nav(sectp)) {
	case CN_CONSTRUCTION:
		wu(0, cnum, fmt("%s sector %s under construction\n",
				nav_nameship(sp,mcp),
				xyas(sp->shp_x, sp->shp_y, sp->shp_own)));
		return RET_SYN;
	case CN_LANDLOCKED:
		wu(0, cnum, fmt("%s landlocked\n", nav_nameship(sp,mcp)));
		return RET_SYN;
	case CN_NAVIGABLE:
		break;
	case CN_ERROR:
	default:
		wu(0, cnum, fmt("%s bad navigable\n", nav_nameship(sp,mcp)));
		return RET_SYN;
		/*NOTREACHED*/
	}

	/* need to somehow make sector database available to bestpath */
	openbigmap(sp->shp_own);
	do {
		cp = bestpath(sp->shp_x, sp->shp_y, sp->shp_destx[0], 
				sp->shp_desty[0], ".= ");
		if (cp == 0 || (*cp == '\0') || (*cp == '?')) {
			wu(0, cnum, fmt("%s bad path, ship put on standby\n",
				nav_nameship(sp,mcp)));
			sp->shp_autonav |= AN_STANDBY;
			putship(sp->shp_uid, (char *)sp);
			return RET_SYN;
		}
		while (*cp && !stopping && sp->shp_own && mobil > 0.0) {
			if (nav_indir(sp, mcp, *cp++, &mobil)) {
				stopping = 1;
			}
		}
	} while (!stopping && sp->shp_own && mobil > 0.0);
	writebigmap();
	closebigmap();

	sp->shp_mobil = (int) mobil;

	/* Ship not sunk */
	if (sp->shp_own)
		nav_check_atdest(sp, mcp);
	putship(snum, sp);
	return RET_OK;
}
#endif	AUTONAV
