#include "gamesdef.h"
#include "misc.h"
#include "xy.h"
#include "var.h"
#include "sect.h"
#include "file.h"
#include "nat.h"

#define MAXROUTE	100	   /* return '?' if path longer than this */
#define WORLDSIZE	WORLD_X*WORLD_Y/2
#define valid(x,y)	(((x^y)&1)==0)

/* ________________________________________________________________
**
**  bestpath(x1,y1,x2,y2,(s_char *)terrain);
**
**  Calculate routing string to get from sector [x1,y1] to sector [x2,y2]
**  via a specified type of terrain.
**
**  Specify:
**
**	x1,y1	     starting coordinates
**
**	x2,y2	     destination coordinates
**
**	terrain	     ptr to string showing the types of sectors that
**		     we're allowed to pass through:
**
**		     A null string enables routing through any kind of
**		     sector (useful for airplanes).
**
**		     A string that begins with an 'R' ensures that
**		     the source and destination sectors also match
**		     the specified type of terrain.
**
**		     A string that begins with a '~' (after the 'R',
**		     if necessary) specifies that we can pass through
**		     any kind of sector EXCEPT those in the remainder
**                   of the string.
**
**		     Examples:
**
**			"R~.^"	all sectors along route must be
**				non-ocean, non-mountain
**
**			"+"	all sectors between start and end
**				must be highway
**
**			"h. "	all sectors along route must be
**				harbor, water, or unmapped
**
**  'bestpath' returns a pointer to a route string containing either:
**
**     yugjbn - string of normal routing characters if route possible
**     ?      - if route is longer than MAXROUTE characters
**     \0     - (null string) if no route possible
**     h      - if start and end points are the same sector
** ________________________________________________________________
*/

s_char *dirchar	= "juygbn";
int dx[6] 	= { 2, 1,-1,-2,-1, 1 };
int dy[6] 	= { 0,-1,-1, 0, 1, 1 };
int tmp;

s_char *bestpath(bpath, x, y, ex, ey, terrain)
	s_char	*bpath;
	int x,y,ex,ey;
	s_char *terrain;
{
  int i,j,tx,ty,markedsectors,routelen,restrict;
  int minx,maxx,miny,maxy,scanx,scany;
  unsigned int map[WORLD_X][WORLD_Y];

  *bpath = '\0';
  if (restrict = (*terrain == 'R')) terrain++;

  x  = xnorm(x);
  y  = ynorm(y);
  ex = xnorm(ex);
  ey = ynorm(ey);

  if (x==ex && y==ey) return("h");

  if ( !valid(x,y) || !valid(ex,ey) ) return((s_char *)0);

  if (restrict &&
      (!navigable( x, y,terrain) ||
      !navigable(ex,ey,terrain)) )  return((s_char *)0);

  for (i=0;i<WORLD_X;i++)
    for (j=0;j<WORLD_Y;j++)
      map[i][j] = 0xFFFF;	/* clear the workspace	*/

  routelen = 0;			/* path length is now 0	*/
  map[x][y] = 0;		/* mark starting spot	*/
  markedsectors = 1;		/* source sector marked */
  minx = x-2; maxx = x+2;	/* set X scan bounds	*/
  miny = y-1; maxy = y+1;	/* set Y scan bounds	*/

  do {
    if (++routelen == MAXROUTE) return("?");
    markedsectors = 0;
    for (scanx=minx;scanx<=maxx;scanx++) {
      x = xnorm(scanx);
      for (scany=miny;scany<=maxy;scany++) {
	y = ynorm(scany);
	if ( valid(x,y) ) {
	  if ((((map[x][y])&0x1FFF)==(routelen-1)) ) {
	    for (i=0;i<6;i++) {
	      tx = xnorm(x+dx[i]);
	      ty = ynorm(y+dy[i]);
	      if (map[tx][ty]==0xFFFF) {
		if ( navigable(tx,ty,terrain) || 
		    (tx==ex && ty==ey && !restrict) ) {
		  map[tx][ty] = ((i+1)<<13) + routelen;
		  markedsectors++;
		}
	      }
	      if (tx==ex && ty==ey) {
		bpath[routelen] = 0;
		while (routelen--) {
		  i = ((map[tx][ty])>>13) - 1;
		  bpath[routelen] = dirchar[i];
		  tx = xnorm(tx-dx[i]);
		  ty = ynorm(ty-dy[i]);
		}
		return((s_char *)bpath);
	      }
	    }
	  }
	}
      }
    }
    miny--;
    maxy++;
    minx-=2;
    maxx+=2;
  }
  while (markedsectors);
  return((s_char *)0); 		/* no route possible 	*/
}


navigable(x,y,terrain)	/* return TRUE if sector is passable */
int x,y;
s_char *terrain;
{
	s_char c;
	int negate;
	struct sctstr sect;

	if (!*terrain)
		return(1);
	getsect(x,y,&sect);
	c = dchr[sect.sct_type].d_mnem;
	/* wu(0, 1, "checking %s as %c\n", xyas(x, y, 1), c); */
	if (negate = (*terrain=='~'))
		terrain++;
	while (*terrain && c!=*terrain)
		terrain++;
	return (negate ? (*terrain==0) : (*terrain!=0));
}

s_char *bestownedpath(bpath, bigmap, x,y,ex,ey,terrain,own,own_finish)
	s_char	*bpath;
	s_char	*bigmap;
	int	x,y,ex,ey;
	s_char	*terrain;
	int	own, own_finish;
{
  int i,j,tx,ty,markedsectors,routelen,restrict;
  int minx,maxx,miny,maxy,scanx,scany;
  unsigned int map[WORLD_X][WORLD_Y];

  if (restrict = (*terrain == 'R')) terrain++;

  x  = xnorm(x);
  y  = ynorm(y);
  ex = xnorm(ex);
  ey = ynorm(ey);

  if (x==ex && y==ey) return("h");

  if ( !valid(x,y) || !valid(ex,ey) ) return((s_char *)0);

  if (restrict && (!owned_and_navigable(bigmap, x, y,terrain,own)))
	return ((s_char *)0);

  if (restrict && own_finish && !owned_and_navigable(bigmap, ex,ey,terrain,own))
	return((s_char *)0);

  for (i=0;i<WORLD_X;i++)
    for (j=0;j<WORLD_Y;j++)
      map[i][j] = 0xFFFF;	/* clear the workspace	*/

  routelen = 0;			/* path length is now 0	*/
  map[x][y] = 0;		/* mark starting spot	*/
  markedsectors = 1;		/* source sector marked */
  minx = x-2; maxx = x+2;	/* set X scan bounds	*/
  miny = y-1; maxy = y+1;	/* set Y scan bounds	*/

  do {
    if (++routelen == MAXROUTE) return("?");
    markedsectors = 0;
    for (scanx=minx;scanx<=maxx;scanx++) {
      x = xnorm(scanx);
      for (scany=miny;scany<=maxy;scany++) {
	y = ynorm(scany);
	if ( valid(x,y) ) {
	  if ((((map[x][y])&0x1FFF)==(routelen-1)) ) {
	    for (i=0;i<6;i++) {
	      tx = xnorm(x+dx[i]);
	      ty = ynorm(y+dy[i]);
	      if (map[tx][ty]==0xFFFF) {
		if (owned_and_navigable(bigmap, tx,ty,terrain,own) || 
		    (tx==ex && ty==ey && !restrict) ) {
		  map[tx][ty] = ((i+1)<<13) + routelen;
		  markedsectors++;
		}
	      }
	      if (tx==ex && ty==ey) {
		bpath[routelen] = 0;
		while (routelen--) {
		  i = ((map[tx][ty])>>13) - 1;
		  bpath[routelen] = dirchar[i];
		  tx = xnorm(tx-dx[i]);
		  ty = ynorm(ty-dy[i]);
		}
		return((s_char *)bpath);
	      }
	    }
	  }
	}
      }
    }
    miny--;
    maxy++;
    minx-=2;
    maxx+=2;
  }
  while (markedsectors);
  return((s_char *)0); 		/* no route possible 	*/
}

/* return TRUE if sector is passable */
int
owned_and_navigable(map, x,y,terrain,own)
	s_char	*map;
	int	x,y;
	s_char	*terrain;
	int	own;
{
	s_char c, *t;
	s_char mineinfo;
	int negate;
	struct sctstr sect;
	int rel;

	getsect(x,y,&sect);
	c = dchr[sect.sct_type].d_mnem;
	mineinfo = map[sctoff(x, y)];
	if (sect.sct_own && sect.sct_own != own){
		rel = getrel(getnatp(sect.sct_own),own);
		if (rel < FRIENDLY)
			return 0;
	}
	/* check for bad harbors. */ 
	if ( c == 'h' && sect.sct_effic < 2)
		return (0);  
	/* check for bad bridges  */ 
	if ( c == '=' && sect.sct_effic < 60)
		return (0);
	/* check bmap for mines */   
	if (mineinfo == 'x' || mineinfo == 'X')
		return (0);    /* sector has mines in it. */ 
	if (!*terrain)
		return(1);
	t = terrain;
	/* wu(0, 1, "checking %s as %c\n", xyas(x, y, 1), c); */

	if (negate = (*t=='~'))
		t++;
	while (*t && c!=*t)
		t++;
	return (negate ? (*t==0) : (*t!=0));
}
