#ifndef lint
static char *RCSid = "$Header: paths.c,v 1.21 89/10/16 20:23:32 mr-frog Exp $";
#endif

/*
 * path.c
 *
 * routines associated with paths, directions, etc.
 *
 * from PSL Empire, 1985
 */

#include "misc.h"
#include "xy.h"
#include "path.h"
#include "nat.h"
#include "sect.h"
#include "file.h"

int
getdir(prompt, stop_msg, view_msg, bomb_msg)
	char   *prompt;
	char   *stop_msg;
	char   *view_msg;
	char   *bomb_msg;
{
	register int max_dir;
	register int min_dir;
	register int dir_num;
	register char *buf;

	if (stop_msg != 0)
		min_dir = DIR_STOP;
	else
		min_dir = DIR_FIRST;
	if (view_msg == 0)
		max_dir = DIR_LAST;
	else
		max_dir = DIR_VIEW;
	while (1) {
		if ((buf = getstring(prompt)) == 0 || *buf == 0)
			return -1;
		dir_num = chkdir(buf[0], min_dir, max_dir);
		if (dir_num >= min_dir)
			break;
		direrr(stop_msg, view_msg, bomb_msg);
	}
	return dir_num;
}

int
chkdir(dir_char, min_dir, max_dir)
	char    dir_char;
	int     min_dir;
	int     max_dir;
{
	register int i;

	for (i = min_dir; i <= max_dir; i++)
		if (dir_char == dirch[i])
			return i;
	return -1;
}

direrr(stop_msg, view_msg, map_msg)
	char   *stop_msg;
	char   *view_msg;
	char   *map_msg;
{
	pr("Legal directions are:\n");
	pr(fmt(" %c %c\n", dirch[DIR_UL], dirch[DIR_UR]));
	pr(fmt("%c   %c\n", dirch[DIR_L], dirch[DIR_R]));
	pr(fmt(" %c %c\n", dirch[DIR_DL], dirch[DIR_DR]));
	if (stop_msg != 0)
		pr(fmt(stop_msg, dirch[DIR_STOP]));
	if (view_msg != 0)
		pr(fmt(view_msg, dirch[DIR_VIEW]));
	if (map_msg != 0)
		pr(fmt(map_msg, dirch[DIR_MAP]));
}

/*
 * return pointer to path; prompt user until a stop char
 * or a bomb char have been entered.  A "bomb" char in
 * this context is actually "execute" for the partial
 * move commands, and isn't valid for those commands
 * which do not accept partial moves.
 */
char *
getpath(arg, x, y, onlyown, showdes, showxy)
	char	*arg;
	coord	x;
	coord	y;
	int	onlyown;
	int	showdes;
	int	showxy;
{
	static	char buf[256];
	char	*p;
	char	*prompt;
	char	*p1;
	coord	nx, ny;
	int	dir;
	int	len;
	char	*execute;
	struct	sctstr sect;

	*buf = 0;
	if (arg)
		strncpy(buf, arg, sizeof(buf)-2);
	buf[sizeof(buf)-1] = 0;
	p = buf;
	len = 0;
	if (showxy)
		execute = " & '%c' to execute\n";
	else
		execute = "\n";
more:
	while (*p) {
		dir = chkdir(*p, DIR_STOP, DIR_LAST);
		if (dir < 0) {
			pr(fmt("\"%c\" is not legal...", *p));
			direrr("'%c' to stop", (char *)0, execute);
			*p = 0;
			break;
		}
		nx = x + diroff[dir][0];
		ny = y + diroff[dir][1];
		getsect(nx, ny, &sect);
		if (onlyown && sect.sct_own != cnum) {
			*p = 0;
			pr(fmt("You don't own %s; you can't go there!\n",
				xyas(nx, ny, cnum)));
			break;
		}
		if (dir == DIR_STOP || dir == DIR_MAP) {
			p[1] = 0;
			return buf;
		}
		p++;
		len++;
		x = nx;
		y = ny;
	}
	if (showdes) {
		getsect(x, y, &sect);
		prompt = fmt("<%c: %s> ", dchr[sect.sct_type].d_mnem,
			xyas(x, y, cnum));
	} else
		prompt = fmt("<%d: %s> ", len, xyas(x, y, cnum));
	if ((p1 = getstring(prompt)) == 0 || *p1 == 0)
		return buf;
	(void) strcpy(p, p1);
	goto more;
}

/* ARGSUSED */
double
mcost(sp, own)
	struct	sctstr *sp;
	int	own;
{
	int	m_cost;

	if ((m_cost = dchr[sp->sct_type].d_mcst) == 0)
		return -1.0;
	return (m_cost * 100.0 - (double)sp->sct_effic) / 500.0;
}

/*
 * fly move cost
 */
/* ARGSUSED */
double
fcost(sp, own)
	struct	sctstr *sp;
	natid	own;
{
	return 1.0;
}

/*
 * nav move cost
 */
/* ARGSUSED */
double
ncost(sp, own)
	struct	sctstr *sp;
	natid	own;
{
	return 1.0;
}

/*
 * translate a 32 bit mask into a 10 element path
 */
char *
masktopath(mask)
	long	mask;
{
	static	char pathstr[32];
	int	i;
	int	val;
	char	*pp;

	pp = pathstr;
	for (i=0; i < sizeof(mask)*8; i += 3) {
		val = (mask & 0x7);
		if (val == 0)
			break;
		*pp++ = dirch[val];
		mask >>= 3;
	}
	*pp = '\0';
	return pathstr;
}

/*
 * translate a path into a bit mask...for now no longer
 * than 32 bits.
 */
long
pathtomask(path)
	char	*path;
{
	register char *pp;
	long	mask;
	int	i;
	int	val;

	mask = 0;
	for (i=0, pp=path; i < sizeof(mask)*8 && *pp; pp++, i += 3) {
		if ((val = chkdir(*pp, DIR_STOP, DIR_LAST)) == 0)
			break;
		mask |= val << i;
	}
	return mask;
}

/*
 * return end x,y of path, and the base
 * movement cost it takes to get there.
 */
double
pathtoxy(path, xp, yp, cost)
	char	*path;
	coord	*xp;
	coord	*yp;
	double	(*cost)();
{
	struct	sctstr s;
	char	*pp;
	coord	x;
	coord	y;
	int	val;
	double	m;
	int	c;

	x = *xp;
	y = *yp;
	m = 0.0;
	for (pp = path; *pp; pp++) {
		if ((val = chkdir(*pp, DIR_STOP, DIR_LAST)) == 0)
			break;
		x += diroff[val][0];
		y += diroff[val][1];
		c = dirch[val];
		if (c == DIR_STOP)
			break;
		if (!getsect(x, y, &s))
			return -1.0;
		m += cost(&s, s.sct_own);
	}
	*xp = xnorm(x);
	*yp = ynorm(y);
	return m;
}

/*
 * return true if "who" owns the path starting at x,y
 */
int
chkpath(who, path, x, y)
	natid	who;
	char	*path;
	coord	x;
	coord	y;
{
	char	*pp;
	int	val;
	struct	sctstr sect;

	for (pp = path; *pp; pp++) {
		if ((val = chkdir(*pp, DIR_STOP, DIR_LAST)) == 0)
			break;
		x += diroff[val][0];
		y += diroff[val][1];
		if (!getsect(x, y, &sect) || sect.sct_own != who)
			return 0;
	}
	return 1;
}

pathrange(cx, cy, pp, border, range)
	register coord	cx, cy;
	register char	*pp;
	int		border;
	struct	range	*range;
{
	int	dir;

	range->lx = cx;
	range->hx = cx;
	range->ly = cy;
	range->hy = cy;
	range->width = 0;
	range->height = 0;
	while ((dir = chkdir(*pp, DIR_FIRST, DIR_LAST)) >= 0) {
		pp++;
		cx += diroff[dir][0];
		cy += diroff[dir][1];
		if (cx < range->lx)
			range->lx = cx;
		if (cx > range->hx)
			range->hx = cx;
		if (cy < range->ly)
			range->ly = cy;
		if (cy > range->hy)
			range->hy = cy;
	}
	range->lx = xnorm(range->lx - border*2);
	range->ly = ynorm(range->ly - border);
	range->hx = xnorm(range->hx + border*2 + 1);
	range->hy = ynorm(range->hy + border + 1);
	xysize_range(range);
}
