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

/*
 * move.c
 *
 * move commodities around
 *
 * from PSL Empire, 1985
 */

#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 "nat.h"
#include "nsc.h"
#include "land.h"
#include "optlist.h"


static	int move_map();

move()
{
	register int amount;
	struct	sctstr sect;
	struct	sctstr endsect;
	struct	sctstr start;
	int     packing;
	double	weight;
	int	left;
	int     mcost, dam;
	int     infected;
	int     stype;
	int     vtype;
	int     amt_src;
	int     amt_dst;
	struct	dchrstr *dp;
	struct	ichrstr *ip;
	int     work;
	int     loyal;
	int     own, mob;
	int	istest=0;
	coord	x, y;
	s_char	*p;
	s_char	prompt[1024];
	s_char	buf[1024];

	istest = *player->argp[0] == 't';
	if ((ip = whatitem(player->argp[1], "move what? ")) == 0)
		return RET_SYN;
	vtype = ip->i_vtype;
	if (!(p = getstarg(player->argp[2], "from sector : ", buf)))
		return RET_SYN;
	if (!sarg_xy(p, &x, &y))
		return RET_SYN;
	if (!getsect(x, y, &sect) || !player->owner) {
		pr("Not yours\n");
		return RET_FAIL;
	}
	/*
         * military control necessary to move
         * goodies in occupied territory.
         */
	if (!istest &&
	    sect.sct_oldown != player->cnum &&
	    vtype != V_MILIT) {
		int     tot_mil=0;
		struct  nstr_item ni;
		struct  lndstr land;
		snxtitem_xy(&ni, EF_LAND, sect.sct_x, sect.sct_y);
		while (nxtitem(&ni, (s_char *)&land)){
			if (land.lnd_own == player->cnum)
				tot_mil += total_mil(&land);
		}
		if ((getvar(V_MILIT, (s_char *)&sect, EF_SECTOR)+tot_mil) * 10
			< getvar(V_CIVIL, (s_char *)&sect, EF_SECTOR)) {
			pr("Military control required to move goods.\n");
			return RET_FAIL;
		}
	}
	stype = sect.sct_type;
	dp = &dchr[stype];
	infected = getvar(V_PTIME, (s_char *)&sect, EF_SECTOR) == PLG_INFECT;
	amt_src = getvar(vtype, (s_char *)&sect, EF_SECTOR);
	if (!istest && amt_src <= 0) {
		pr("No %s in %s\n", ip->i_name, 
		   xyas(sect.sct_x, sect.sct_y, player->cnum));
		return RET_FAIL;
	}
	own = sect.sct_own;
	mob = (int)sect.sct_mobil;
	if (!istest && vtype == V_CIVIL && sect.sct_oldown != own) {
		pr("You can't move conquered populace!\n");
		return RET_FAIL;
	}
	if (mob <= 0) {
		pr("No mobility in %s\n",
			xyas(sect.sct_x, sect.sct_y, player->cnum));
		return RET_SYN;
	}
	if (vtype == V_CIVIL) {
		work = sect.sct_work;
		if (work != 100)
			pr("Warning: civil unrest\n");
		loyal = sect.sct_loyal;
	} else if (vtype == V_MILIT) {
		work = 100;
		loyal = 0;
	}
	if (istest)
		sprintf(prompt, "Number of %s to test move? ", ip->i_name);
	else
		sprintf(prompt, "Number of %s to move? (max %d) ",
			ip->i_name,
			amt_src);
	if ((amount = onearg(player->argp[3], prompt)) < 0)
		return RET_FAIL;
	if (amount > amt_src) {
		if (istest) {
			pr("Note: there are actually only %d %s in %s,\nbut the test will be made for %d %s as you requested.\n",
			   amt_src, ip->i_name,
			   xyas(sect.sct_x, sect.sct_y, player->cnum),
			   amount, ip->i_name);
		} else {
			amount = amt_src;
			pr("Only moving %d.\n", amount);
		}
	}

	if (would_abandon(&sect,vtype,amount)){
		s_char	y_or_n[80], *ppp;

		ppp = (s_char *)0;
		while (!ppp || ((*ppp != 'y') && (*ppp != 'n'))){
			bzero(y_or_n,80);
			if (ppp && (*ppp != 'y') && (*ppp != 'n'))
				pr("Answer y or n!\n");

			sprintf(prompt,
				"Do you really want to abandon %s [yn]? ",
				xyas(sect.sct_x, sect.sct_y, player->cnum));
			ppp = getstarg(y_or_n, prompt, buf);
			if (player->aborted){
				pr("Move aborted.\n");
				return RET_OK;
			}
			if (ppp && isupper(*ppp))
				*ppp=tolower(*ppp);
		}
		if (*ppp != 'y'){
			pr("Move cancelled.\n");
			return RET_FAIL;
		}
	}

	if (amount <= 0)
		return RET_SYN;
	packing = ip->i_pkg[dp->d_pkg];
	if (packing > 1 && sect.sct_effic < 60)
		packing = 1;
	weight = (double)amount * ip->i_lbs / packing;
	/*
	 * First remove commodities from source sector
	 */
	if (!istest){
		getsect(x, y, &start);
		amt_src = getvar(vtype, (s_char *)&start, EF_SECTOR);
		if (amt_src < amount) {
			pr("Only %d %s left in %s!\n", amt_src,
				ip->i_name,xyas(start.sct_x,start.sct_y,player->cnum));
			amount = amt_src;
			amt_src = 0;
		}else
			amt_src -= amount;

		putvar(vtype, amt_src, (s_char *)&start, EF_SECTOR);
		putsect(&start);
	}

	/*
	 * Now parse the path and return ending sector.
	 */
	dam = (istest ? 0 : 1);
	if (dam && !chance(weight / 200.0))
		dam = 0;
	mcost = move_ground((s_char *)ip, &sect, &endsect,
		(double)sect.sct_mobil, weight, player->argp[4], move_map, 0, &dam);

	if (dam) {
		left = commdamage(amount, dam, ip->i_vtype);
		if (left < amount) {
			if (left) {
				pr("%d of the %s you were moving were destroyed!\nOnly %d %s made it to %s\n",
				   amount - left,
				   ip->i_name,
				   left,
				   ip->i_name,
				   xyas(endsect.sct_x, endsect.sct_y, player->cnum));			   
			} else {
				pr("All of the %s you were moving were destroyed!\n",ip->i_name);
			}
			amount = left;
		}
	}

	if (mcost > 0)
		pr("Total movement cost = %d\n",mcost);
	else
		pr("No mobility used\n");

	left=0;
	if (mcost < 0) {
		pr("Move aborted\n");
		getsect(x,y,&sect);
		sect.sct_mobil = (u_char)mob;
		left = mob;
	}else if (!istest){
		/*
	 	* decrement mobility appropriately.
	 	*/
		getsect(x, y, &start);
		if (mob < mcost)
			mob = 0;
		else
			mob -= mcost;
		start.sct_mobil = (u_char)mob;
		left = start.sct_mobil;
		putsect(&start);
		getsect(endsect.sct_x, endsect.sct_y, &sect);
	}

	/*
	 * Check for lotsa stuff
	 */
	if(sect.sct_own != player->cnum) {
		if (sect.sct_own != 0)
			pr("Somebody has captured that sector!\n");
		getsect(x,y,&sect);
		sect.sct_mobil = (u_char)mob;
		sect.sct_own = own;
		if (sect.sct_oldown == 0)
			sect.sct_oldown = own;
		left = mob;
	}
	if (vtype == V_CIVIL && getvar(V_CIVIL, (s_char *)&sect, EF_SECTOR) &&
	    sect.sct_oldown != player->cnum) {
		pr("Your civilians don't want to stay!\n");
		getsect(x,y,&sect);
		sect.sct_mobil = (u_char)mob;
		sect.sct_own = own;
		if (sect.sct_oldown == 0)
			sect.sct_oldown = own;
		left = mob;
	}

	if (!istest)
		pr("%d mob left in %s\n", left,
			xyas(start.sct_x,start.sct_y,player->cnum));

	amt_dst = getvar(vtype, (s_char *)&sect, EF_SECTOR);
	if (32767 - amt_dst < amount) {
		amount = 32767 - amt_dst;
		pr("Only %d can be left there.\n", amount);
	}
	if (istest)
		return RET_OK;
	if (putvar(vtype, amount + amt_dst, (s_char *)&sect, EF_SECTOR) < 0) {
		pr("No more room in %s.\n", 
			xyas(sect.sct_x, sect.sct_y, player->cnum));
		/* charge the player mobility anyway */
		amount = 0;
	}
	/*
	 * Now add commodities to destination sector,
	 * along with plague that came along for the ride.
	 * Takeover unowned sectors if not deity.
	 */
	if (infected && getvar(V_PTIME, (s_char *)&sect, EF_SECTOR) == 0)
		putvar(V_PTIME, PLG_EXPOSED, (s_char *)&sect, EF_SECTOR);
	if (vtype == V_CIVIL) {
		if (opt_NEW_WORK) {
			sect.sct_loyal =( (amt_dst * sect.sct_loyal) + 
					 (amount * loyal) ) / (amt_dst+amount);
			sect.sct_work =( (amt_dst * sect.sct_work) + 
					(amount * work) ) / (amt_dst+amount);
		} else {	/* ! NEW_WORK */

			/* It only takes one bad apple... */
			if (sect.sct_loyal < loyal)
				sect.sct_loyal = loyal;
			if (sect.sct_work > work)
				sect.sct_work = work;
		} /* end NEW_WORK */
	}
	putsect(&sect);
	return RET_OK;
}

/*
 * Pretty tacky, but it works.
 * If more commands start doing this, then
 * rewrite map to do the right thing.
 */
/*ARGSUSED*/
static
move_map(what, curx, cury, arg)
	s_char	*what;
	int	curx, cury;
	s_char	*arg;
{
	player->argp[1] = arg;
	player->argp[2] = "";
	player->argp[3] = "";
	player->argp[4] = "";
	player->argp[5] = "";
	player->condarg = 0;
	map();
}

int
would_abandon(sp, vtype, amnt)
struct sctstr *sp;
int vtype;
int amnt;
{
	struct	sctstr sect;
	int	mil, civs, loyalcivs;

	if ((vtype != V_CIVIL) && (vtype != V_MILIT))
		return 0;

	bcopy(sp,&sect,sizeof(struct sctstr));

	mil = getvar(V_MILIT, (s_char *)sp, EF_SECTOR);
	civs = getvar(V_CIVIL, (s_char *)sp, EF_SECTOR);

	if (vtype == V_MILIT)
		mil -= amnt;

	if (vtype == V_CIVIL)
		civs -= amnt;

	if (sp->sct_own == sp->sct_oldown)
		loyalcivs = civs;
	else
		loyalcivs = 0;

	/* If they have a military unit there, they still own it */
	if (sp->sct_own != 0 && ((loyalcivs == 0) && (mil == 0) &&
		(has_units(sp->sct_x,sp->sct_y,sp->sct_own) == 0)))
		return 1;

	return 0;
}
