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

/*
 * move.c
 *
 * Move something somewhere.  Has a weight,
 * returns move cost, and fills a result parameter
 * with the destination sector.
 *
 *
 */

#include "misc.h"
#include "player.h"
#include "var.h"
#include "sect.h"
#include "item.h"
#include "file.h"
#include "deity.h"
#include "xy.h"
#include "path.h"
#include "nat.h"
#include "map.h"
#include "nsc.h"
#include "damage.h"

extern int move_map();

int
move_ground(what, start, end, mobility, weight, path, map, exploring, dam)
	s_char	*what;
	struct	sctstr *start;
	struct	sctstr *end;	/* RESULT */
	double	mobility;
	double	weight;
	s_char	*path;
	int	(*map)();
	int	exploring, *dam;
{
	struct	sctstr sect, ending_sect;
	struct	sctstr next, dsect;
	int	vec[I_MAX+1];
	coord	curx, cury, oldx, oldy;
	coord	tmpx, tmpy;
	coord	dx, dy;
	s_char	*movstr, *BestLandPath();
	double	sect_mcost;
	double	total_mcost;
	double	mv_cost;
	int	dir;
	int	intcost;
	int	d, takedam = (*dam), out=0;
	s_char	bpath[512];
	s_char	buf2[512];
	s_char	prompt[128];
	s_char	buf[1024];

	*dam = 0;
        if (path && sarg_xy(path, &dx, &dy) && getsect(dx,dy,&ending_sect)){
		if ((ending_sect.sct_x == start->sct_x) &&
			(ending_sect.sct_y == start->sct_y)){
			pr("Start sector is ending sector!\n");
			return -1;
		}
		pr("Looking for best path to %s\n", path);
		path = BestLandPath(buf2, start, &ending_sect, &total_mcost);
		if (exploring && (path != (s_char *)0)) /* take off the 'h' */
			*(path+strlen(path)-1) = '\0';
		if (path == (s_char *)0)
			pr("No owned path exists!\n");
		else{
			pr("Using best path '%s', movement cost %1.3f\n",
				path,total_mcost);
       			bzero(bpath,512);
			bcopy(path,bpath,strlen(path));
			path = bpath;
		}
		if ((total_mcost*weight) > mobility){
			pr("Not enough mobility to go all the way. Nothing moved.\n");
			*end = *start;
			return -1;
		}
	}
	movstr = path;
	tmpx = start->sct_x;
	curx = tmpx;
	tmpy = start->sct_y;
	cury = tmpy;
	total_mcost = 0.0;
	if (getsect(curx, cury, &sect) < 0) {
		logerror("move_path: getsect %d,%d", curx, cury);
		return -1;
	}
	for (;;) {
		tmpx = curx;
		tmpy = cury;
		oldx = curx;
		oldy = cury;
		if (movstr == 0 || *movstr == 0) {
                        if (exploring) {
                                map(what, curx, cury, (s_char *)0); }
                        else {
                                move_map(what, curx, cury, (s_char *)0); }
			sprintf(prompt, "<%.1f: %c %s> ", mobility,
				dchr[sect.sct_type].d_mnem,
				xyas(sect.sct_x, sect.sct_y, player->cnum));
			movstr = getstring(prompt, buf);
		}
		if (movstr && sarg_xy(movstr, &dx, &dy)){
			if (getsect(dx,dy,&dsect)){
				movstr=BestLandPath(buf2,&sect,&dsect,&mv_cost);
			}else{
				pr("Invalid destination sector!\n");
				movstr=(s_char *)0;
			}

			if (movstr == (s_char *)0){
				pr("Can't get to %s from here!\n",
					xyas(dx,dy,player->cnum));
				movstr=(s_char *)0;
			}else{
				if ((mv_cost*weight) > mobility){
					pr("Not enough mobility to go all the way. Nothing moved.\n");
					movstr = (s_char *)0;
				}else{
					pr("Using best path '%s', movement cost %1.3f\n",
						movstr,mv_cost);
        				bzero(bpath,512);
					bcopy(movstr,bpath,strlen(movstr));
					movstr = bpath;
				}
			}
		}
		if (movstr == 0 || *movstr == 0)
			movstr = dirch;
		if ((dir = chkdir(*movstr, DIR_STOP, DIR_MAP)) < 0) {
			pr("\"%c\" is not legal...", *movstr);
			direrr("'%c' to stop ", "'%c' to view ",
				"& '%c' to map\n");
			*movstr = 0;
			continue;
		}
		movstr++;
		if (dir == DIR_MAP) {
			if (!exploring)
				map(what, curx, cury, movstr+1);
			*movstr = 0;
			continue;
		} else if (dir == DIR_STOP)
			break;
		else if (dir == DIR_VIEW) {
			pr("%d%% %s with %d civilians.\n", sect.sct_effic,
				dchr[sect.sct_type].d_name,
				getvar(V_CIVIL, (s_char *)&sect, EF_SECTOR));
			continue;
		}
		/*
		 * now see if we can move into the
		 * next sector.  Mobility, terrain,
		 * or ownership may prevent us.
		 */
		tmpx += diroff[dir][0];
		tmpy += diroff[dir][1];
		if (getsect(tmpx, tmpy, &next) < 0) {
			pr("You can't go there...\n");
			*movstr = 0;
			continue;
		}
		if (!player->god) {
			if ((next.sct_type == SCT_SANCT) &&
						       (next.sct_own != player->cnum)) {
				pr("Converts, huh?\n");
				*end = next;
				intcost = (int) total_mcost;
				if (chance(total_mcost - intcost))
					intcost++;
				return intcost;
			}
			getvec(VT_ITEM, vec, (s_char *)&next, EF_SECTOR);
			sect_mcost = sector_mcost(next.sct_type,next.sct_effic);
			if ((!player->owner && (!exploring || 
			    (vec[I_MILIT] || vec[I_CIVIL]))) ||
			    sect_mcost == -1.0) {
				/* already-owned, or prohibited terrain */
				pr("You can't go there...\n");
				*movstr = 0;
				continue;
			}
			sect_mcost *= weight;
			if (sect_mcost > mobility) {
				pr("Not enough mobility.  ");
				pr("You can't go there...\n");
				*movstr = 0;
				continue;
			}
			mobility -= sect_mcost;
			total_mcost += sect_mcost;
		}
		curx = tmpx;
		cury = tmpy;
		if (cury != start->sct_y)
			out=1;
		if (curx != start->sct_x)
			out=1;

		sect = next;

		if (takedam)
			*dam += check_lmines(sect.sct_x, sect.sct_y, weight);
		if (*dam >= 100)
			break;
		/*
		 * Check and see if anyone will interdict us
		 */
		if (takedam && chance(weight/100.0) &&
			((curx != oldx) || (cury != oldy)))
			(*dam) += ground_interdict(curx,cury,player->cnum,"commodities");
		if (*dam >= 100)
			break;
	}
	*end = sect;
	intcost = (int) total_mcost;
	if (intcost < 0)
		return -1;
	if ((start->sct_x == end->sct_x) && (start->sct_y == end->sct_y) && !out)
		return -1;

	if (chance(total_mcost - intcost))
		intcost++;
	return intcost;
}


/*ARGSUSED*/
int
move_map(what, curx, cury, arg)
        s_char    *what;
        coord   curx, cury;
        s_char    *arg;
{
        struct  nstr_sect ns;
        struct  natstr *np;
        struct  sctstr sect;
        coord   rel_x, rel_y;
        s_char    range[128];
        s_char    view[7];
        int     i;
        int     vec[I_MAX+1];
	int	changed = 0;
 
        np = getnatp(player->cnum);
        rel_x = xrel(np, curx);
        rel_y = yrel(np, cury);
        sprintf(range, "%d:%d,%d:%d", rel_x-2, rel_x+2, rel_y-1, rel_y+1);
        player->condarg = 0;
	/* This is necessary, otherwise move_map would attempt to pay */
	/* attention to the conditional arguments left behind by such */
	/* a command as "tran p -1,-1 ?eff=100".. It'd then only see  */
	/* 100% efficienct sects, and get all screwed up         --ts */
        if (!snxtsct(&ns, range))
                return RET_FAIL;
        i = 0;
        while (i < 7 && nxtsct(&ns, &sect)) {
                view[i] = dchr[sect.sct_type].d_mnem;
                switch (sect.sct_type) {
                case SCT_WATER:
                case SCT_RURAL:
                case SCT_MOUNT:
                case SCT_WASTE:
                        break;
                default:
                        if (sect.sct_own != player->cnum && !player->god)
                                view[i] = '?';
                        break;
                }
		changed += map_set(player->cnum, ns.x, ns.y, view[i], 0);
                i++;
        }
	if (changed)
		writemap(player->cnum);
        if (!getsect(curx, cury, &sect))
                return RET_FAIL;
        getvec(VT_ITEM, vec, (s_char *)&sect, EF_SECTOR);
        pr("    %c %c      eff   mob   civ  mil   uw food  work  avail\n",
                view[0], view[1]);
        pr("   %c %c %c     %3d   %3d  %4d %4d %4d %4d   %3d   %3d\n",
                view[2], view[3], view[4],
                sect.sct_effic, sect.sct_mobil, vec[I_CIVIL],vec[I_MILIT],
        	vec[I_UW],vec[I_FOOD], sect.sct_work, sect.sct_avail);
        pr("    %c %c\n", view[5], view[6]);
        return RET_OK;
}

int
fly_map(curx, cury)
coord	curx, cury;
{
        struct  nstr_sect ns;
        struct  natstr *np;
        struct  sctstr sect;
        coord   rel_x, rel_y;
        s_char    view[7];
        int     i;
	s_char	range[128];
 
        np = getnatp(player->cnum);
        rel_x = xrel(np, curx);
        rel_y = yrel(np, cury);
        sprintf(range, "%d:%d,%d:%d", rel_x-2, rel_x+2, rel_y-1, rel_y+1);
        player->condarg = 0;
	/* This is necessary, otherwise move_map would attempt to pay */
	/* attention to the conditional arguments left behind by such */
	/* a command as "tran p -1,-1 ?eff=100".. It'd then only see  */
	/* 100% efficienct sects, and get all screwed up         --ts */

        if (!snxtsct(&ns, range))
                return RET_FAIL;
        i = 0;
        while (i < 7 && nxtsct(&ns, &sect)){
                if (!(view[i] = player->bmap[sctoff(ns.x, ns.y)]))
			view[i] = ' ';
                i++;
        }

        pr("    %c %c\n",view[0], view[1]);
        pr("   %c %c %c\n", view[2], view[3], view[4]);
        pr("    %c %c\n", view[5], view[6]);
        return RET_OK;
}

int
check_lmines(x, y, weight)
	coord	x,y;
	double	weight;
{
	struct	sctstr	sect;
	int	mines;
	int	dam = 0;

	getsect(x, y, &sect);
	mines = getvar(V_MINE, (s_char *)&sect, EF_SECTOR);
	if (mines > 0 &&
	    sect.sct_oldown != player->cnum &&
	    chance(DMINE_LHITCHANCE(mines)) &&
	    chance(weight/100.0)) {
		pr_beep();
		pr("Blammo! Landmines detected! in %s  ",
		   xyas(sect.sct_x,sect.sct_y,player->cnum));
		dam = roll(20);
		--mines;
		putvar(V_MINE, mines, (s_char *)&sect, EF_SECTOR);
		putsect(&sect);
		pr("%d damage sustained.\n", dam);
	}
	return dam;
}
