#ifndef lint
static char *RCSid = "$Header: /usr/brule/guest/empire/empire/emprcs/lib/commands/orde.c,v 2.5 1995/10/22 20:50:09 empire Exp $";
#endif

/*
 * orde.c
 *
 * turn on/off autonavigation
 *
 * from PSL Empire, 1985
 */

/* New Autonav Code added 4-1-94,
 * Chad Zabel
 */

#include <ctype.h>
#include "misc.h"
#include "player.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"
#include "item.h"

/*
**  Command syntax:
**
**  ORDER <ship>				  Show orders
**  ORDER <ship> c[ancel]			  Cancel orders
**  ORDER <ship> s[top]				  Suspend orders
**  ORDER <ship> r[esume]			  Resume orders
**  ORDER <ship> d[eclare] <dest1>		  Set destination
**		 d[eclare] <dest1> <dest2>
**  ORDER <ship> l[evel]   <field> <start/end> <comm> <level>
**
**
** New syntax:
**  qorder <ship>    display cargo levels     
**  sorder <ship>    display statistical info 
 */

orde()
{
	int	nships=0;
	int	diffeachship = 0;
	int	orders,sub,level;
	struct nstr_item nb;
	struct shpstr ship;
	struct ichrstr *i1;
	coord	p0x, p0y, p1x, p1y;
	int	i;
	s_char	*p,*p1, *dest; 
	s_char	buf1[128];
	s_char	buf[1024];
	s_char	prompt[128];

	if (!snxtitem(&nb, EF_SHIP, player->argp[1])) return RET_SYN;
	while (!player->aborted && nxtitem(&nb, (s_char *)(&ship))) {
		if (!player->owner || ship.shp_own == 0)
			continue;
		if (ship.shp_type < 0 || ship.shp_type > shp_maxno) {
			pr("bad ship type %d (#%d)\n",
				ship.shp_type, nb.cur);
			continue;
		}
#ifdef SAIL
		if (*ship.shp_path) {
			if (!diffeachship)
				pr("Ship #%d has a \"sail\" path!\n",
					ship.shp_uid);
			continue;
		}
#endif
		sprintf(prompt, "Ship #%d, declare, cancel, suspend, resume, level? ",
				ship.shp_uid);
		p = getstarg(player->argp[2], prompt, buf);
		if (player->aborted || !p)
			return RET_FAIL;
		if (!*p)
			if (!diffeachship) {
				return RET_FAIL;
			} else
				continue;

		switch (*p) {
		default:
			pr("Bad order type!\n");
			return RET_SYN;
		case 'c':    /* clear ship fields  */
			ship.shp_mission = 0;
			ship.shp_autonav &= ~(AN_AUTONAV+AN_STANDBY+AN_LOADING);
			for (i=0;i<TMAX;i++) { 
			ship.shp_tstart[i] = ' ';
			ship.shp_tend[i]   = ' ';
			ship.shp_lstart[i] = 0;
			ship.shp_lend[i]   = 0; 
			}
			break;
		case 's':   /* suspend ship movement  */
			ship.shp_mission = 0;
			ship.shp_autonav |= AN_STANDBY;
			break;
		case 'r':   /* resume ship movement   */
			ship.shp_mission = 0;
			ship.shp_autonav &= ~AN_STANDBY;
			break;
		case 'd':   /* declare path */
			orders = 0;
			/* Need location */
			if ((p=getstarg(player->argp[3],"Destination? ", buf))==0 || *p==0)
				return RET_SYN;
			if (!sarg_xy(p, &p0x, &p0y))
				return RET_SYN;
			p1x = p0x;
			p1y = p0y;


				
			if (!orders) {
			p = getstarg(player->argp[4],"Second dest? ", buf);
			if (!p || !*p || !strcmp (p, "-")) {	 	
				 orders = 1; 
				 pr("A one-way order has been accepted.\n\n");
			}

			 else { 
				if (!sarg_xy(p, &p1x, &p1y))
				return RET_SYN;  
				pr("A circular order has been accepted.\n\n");
			 }
			}

			/*
			 *  Set new destination and trade type fields.
			 */
			ship.shp_mission = 0;
			ship.shp_destx[1] = p1x;
			ship.shp_desty[1] = p1y;
			ship.shp_destx[0] = p0x;
			ship.shp_desty[0] = p0y;
	
 			ship.shp_autonav &= ~(AN_STANDBY+AN_SAILDIR+AN_LOADING);
			ship.shp_autonav |= AN_AUTONAV;
		  
		break; 	

		/* set cargo levels on the ship */
	
		case 'l' : 
                        /* convert player->argp[3] to an integer */
                        if (player->argp[3]) 
			  sub = atoi(player->argp[3]); 
			else { 
			  sprintf(buf1,"Field (1-%d) ",TMAX);
			  if (getstarg(player->argp[3],buf1, buf) == 0)
				return RET_SYN;
                          sub = atoi(buf);
                        }
                        /* check to make sure value in within range. */
			if (sub>TMAX || sub<1 ) {
			 pr("Value must range from 1 to %d\n",TMAX);
			    			    break;   }

			/* to keep sub in range of our arrays 
			   subtract 1 so the new range is 0-(TMAX-1)
			*/
			   sub = sub - 1; ; 

			   if (ship.shp_autonav & AN_AUTONAV ) {
				orders=1;
			        dest = getstarg(player->argp[4],"Start or End? ", buf);
        			if (orders) { /* before dest check */
				   if (!dest)
					break;
				switch (*dest) {
           			  default:
        		             pr("You must enter 'start' or 'end'\n");
				     return RET_SYN; 
				  case 'e' :
				  case 'E' :
				     i1 = whatitem(player->argp[5],"Commodity? ");
          			     if (!i1)
					break;
				     else {
					p1 = getstarg(player->argp[6],"Amount? ", buf);
					level = atoi(p1);
					}
				     if (level < 0) { 
					level = 0;  /* prevent negatives. */
					pr("You must use positive number! Level set to 0.\n");
				     } 
				     ship.shp_tstart[sub] = (s_char)i1->i_mnem;
				     ship.shp_lstart[sub] = level;
				     pr("Order Set \n"); 
				     break; 
				  case 's' :
				  case 'S' :
				     i1 = whatitem(player->argp[5],"Commodity? ");
          			     if (!i1)
					break;
				     else {
					p1 = getstarg(player->argp[6],"Amount? ", buf);
					level = atoi(p1);
					}
				     if (level < 0 ) { 
					level = 0;
 					pr("You must use positive number! Level set to 0.\n");
				     } 
				     ship.shp_tend[sub] = (s_char)i1->i_mnem;
				     ship.shp_lend[sub] = level;
				     pr("Order Set \n"); 
				     break;
				}
				}
			   }
			   else
			      pr("You need to 'declare' a ship path first, see 'info order'\n");

			   break;
		} /* end of switch (*p) */


	
                        /*
			 *  Set loading flag if ship is already in one
			 *  of the specified harbors and a cargo has been
			 *  specified.
			 */

			if ( ((ship.shp_x == ship.shp_destx[0])
				&& (ship.shp_y == ship.shp_desty[0])
				&& (ship.shp_lstart[0] != ' '))
			    || ((ship.shp_x == ship.shp_desty[1])
				&& (ship.shp_y == ship.shp_desty[1])
				&& (ship.shp_lstart[1] != ' ')) ) {

				coord tcord;
				s_char tcomm[TMAX];
				short  lev[TMAX];
				int i;

				ship.shp_autonav |= AN_LOADING;

			    /*  swap variables, this keeps 
			        the load_it() procedure happy. CZ
			     */
				tcord = ship.shp_destx[0];
				ship.shp_destx[0] = ship.shp_destx[1];
				ship.shp_destx[1] = tcord;
				tcord = ship.shp_desty[0];
				ship.shp_desty[0] = ship.shp_desty[1];
				ship.shp_desty[1] = tcord;

				for(i=0;i<TMAX;i++) {
				   lev[i]   = ship.shp_lstart[i];
				   ship.shp_lstart[i] = ship.shp_lend[i];
				   ship.shp_lend[i]   = lev[i];
				   tcomm[i] = ship.shp_tstart[i];
				   ship.shp_tstart[i] = ship.shp_tend[i];
				   ship.shp_tend[i]   = tcomm[i];
				}
			}
			/*
			**  Write ship back to database, then give it
			**  a kick down the autonav route if necessary.
			*/


		
		putship(ship.shp_uid, &ship);
		nships++;
	}
	return RET_OK;
}

static int
eta_calc(sp, path, len, nupdates)
	struct shpstr *sp;
	s_char *path;
	int *len, *nupdates;
	
{
	extern int etu_per_update;
	extern float ship_mob_scale;
	struct mchrstr *mcp;
	double mobcost, mobil;
	int	i;

	i = strlen(path);
	*len = i;
	*nupdates = 1;

	mcp = &mchr[sp->shp_type];
	mobcost = sp->shp_effic * 0.01 * mcp->m_speed;
	mobcost = 480.0 / (mobcost + techfact(sp->shp_tech, mobcost));
	mobil = sp->shp_mobil;
	while (i) {
		if (mobil > 0) {
			mobil -= mobcost;
			i--;
		} else {
			mobil += (ship_mob_scale * (float)etu_per_update);
			(*nupdates)++;
		}
	}
}

qorde()
{
	extern	s_char *bestownedpath();
	int	nships=0;
	int	i;
	struct	nstr_item nb;
	struct	shpstr ship;

	if (!snxtitem(&nb, EF_SHIP, player->argp[1])) return RET_SYN;
	while (nxtitem(&nb, (s_char *)(&ship))) {
		if (!player->owner || ship.shp_own==0)
		    continue;
		if (ship.shp_type < 0 || ship.shp_type > shp_maxno) {
			pr("bad ship type %d (#%d)\n",
				ship.shp_type, nb.cur);
			continue;
		}
#ifdef SAIL
		if ((ship.shp_autonav & AN_AUTONAV) || (ship.shp_path[0])){
#else
		if (ship.shp_autonav & AN_AUTONAV){
#endif /* SAIL */
			if (!nships) { /* 1st ship, print banner */
				if (player->god) pr("own ");
				pr("shp#     ship type    ");
				pr("[Starting]       (Ending)    \n");
			}
		}

		/* Basic ship description */
#ifdef SAIL
		if ((ship.shp_autonav & AN_AUTONAV) || (ship.shp_path[0])){
#else
		if (ship.shp_autonav & AN_AUTONAV){
#endif /* SAIL */
			nships++;
			if (player->god) pr("%3d ", ship.shp_own);
			pr("%4d", nb.cur);
			pr(" %-16.16s", mchr[ship.shp_type].m_name);
		}
		if (ship.shp_autonav & AN_AUTONAV){

                        pr(" [");
			for (i=0;i<TMAX;i++) {
			  if(ship.shp_tend[i] != ' ' && 
				ship.shp_lend[i] != 0 ) {
			  pr("%d-",i+1);
		          pr("%c",ship.shp_tend[i]);
			  pr(":");
       		          pr("%d ",ship.shp_lend[i]);
			  }
			}
			pr("] , (");
                        for (i=0;i<TMAX;i++) {
			  if(ship.shp_tstart[i] != ' ' &&   
 			     ship.shp_lstart[i] != 0 ) { 
                          pr("%d-",i+1);
			  pr("%c",ship.shp_tstart[i]);
			  pr(":");
			  pr("%d ",ship.shp_lstart[i]);
		  	  }
			}
			pr(")\n");
		}

#ifdef	SHIPNAMES
#ifdef SAIL
		if ((ship.shp_autonav & AN_AUTONAV) || (ship.shp_path[0])){
#else
		if (ship.shp_autonav & AN_AUTONAV){
#endif /* SAIL */
			if (ship.shp_name[0] != 0) {
				if (player->god)
					pr("    ");
				pr("       %s\n",ship.shp_name);
			}
		}
#endif	/* SHIPNAMES */
	}
	if (!nships) {
		if (player->argp[1])
			pr("%s: No ship(s)\n", player->argp[1]);
		else
			pr("%s: No ship(s)\n", "");
		return RET_FAIL;
	} else
		pr("%d ship%s\n", nships, splur(nships));
	return RET_OK;
}
/*  Chad Zabel 1-15-94
 *  New command added to display autonav stats.
 */ 

sorde()
{
	extern	s_char *bestownedpath();
	int	nships=0;
	int	len, updates;
	s_char	*c;
	struct	nstr_item nb;
	struct	shpstr ship;
	s_char	buf[1024];

	if (!snxtitem(&nb, EF_SHIP, player->argp[1])) return RET_SYN;
	while (nxtitem(&nb, (s_char *)(&ship))) {
		if (!player->owner || ship.shp_own==0)
		    continue;
		if (ship.shp_type < 0 || ship.shp_type > shp_maxno) {
			pr("bad ship type %d (#%d)\n",
				ship.shp_type, nb.cur);
			continue;
		}
#ifdef SAIL
		if ((ship.shp_autonav & AN_AUTONAV) || (ship.shp_path[0])){
#else
		if (ship.shp_autonav & AN_AUTONAV){
#endif /* SAIL */
			if (!nships) { /* 1st ship, print banner */
				if (player->god) pr("own ");
				pr("shp#     ship type      x,y    ");
       				pr("start   end   ");
				pr("len  eta\n");
	
			}
		}

		/* Basic ship description */
#ifdef SAIL
		if ((ship.shp_autonav & AN_AUTONAV) || (ship.shp_path[0])){
#else
		if (ship.shp_autonav & AN_AUTONAV){
#endif /* SAIL */
			nships++;
			if (player->god) pr("%3d ", ship.shp_own);
			pr("%4d", nb.cur);
			pr(" %-16.16s", mchr[ship.shp_type].m_name);
			prxy(" %3d,%-3d", ship.shp_x, ship.shp_y, player->cnum);
		}
		if (ship.shp_autonav & AN_AUTONAV){
			/* Destination 1 */
			prxy(" %3d,%-3d", ship.shp_destx[1],
				       ship.shp_desty[1], player->cnum);

			/* Destination 2 */
			if (   (ship.shp_destx[1]!=ship.shp_destx[0])
			    || (ship.shp_desty[1]!=ship.shp_desty[0]) ) {
			       prxy(" %2d,%-2d",ship.shp_destx[0],
					ship.shp_desty[0], player->cnum);
			} else pr("      ");

			if (ship.shp_autonav & AN_STANDBY) 
				pr("  suspended\n");
		        else if (ship.shp_autonav & AN_LOADING) 
				pr("  loading\n");
		        else {
				/* ETA calculation */

				c = bestownedpath(buf, player->bmap, ship.shp_x,
					ship.shp_y, ship.shp_destx[0],
					ship.shp_desty[0], ".=h",
					ship.shp_own, 1);
				if (!c || !*c) 
					pr("no route possible\n");
			        else if (*c == 'h') 
					pr("has arrived\n");
			        else if (*c == '?') 
					pr("route too long\n");
			        else {
					/* distance to destination */
					eta_calc(&ship, c, &len, &updates);
					pr(" %3d %4d\n", len, updates);
				}
			}
		}
#ifdef	SHIPNAMES
#ifdef SAIL
		if ((ship.shp_autonav & AN_AUTONAV) || (ship.shp_path[0])){
			if (!(ship.shp_autonav & AN_AUTONAV))
				pr("\n");
#else
		if (ship.shp_autonav & AN_AUTONAV){
#endif /* SAIL */
			if (ship.shp_name[0] != 0) {
				if (player->god)
					pr("    ");
				pr("       %s\n",ship.shp_name);
			}
		}
#endif	/* SHIPNAMES */
	}
	if (!nships) {
		if (player->argp[1])
			pr("%s: No ship(s)\n", player->argp[1]);
		else
			pr("%s: No ship(s)\n", "");
		return RET_FAIL;
	} else
		pr("%d ship%s\n", nships, splur(nships));
	return RET_OK;
}


