/*
	Intelligent Walk Engine - BETA TEST VERSION
	Made by Ismo Horppu on 1996-1997
*/

#include <stdio.h>
#include <process.h>
#include <dos.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#include <time.h>
#include "line.h"
#include "aihead.h"
#include <dpmi.h>
#include <go32.h>
#include "ct2egen.h"
#include "ct2egrx.h"

// suppose 0 is nonblocked pixel
char GetPixel (int x, int y)
{
	return Map[x][y][curz];
}

void PutPixel (int x, int y, char value)
{
	Map[x][y][curz] = value;
}

int RangeNorth (void)
{
	int blocked;
	int x, y;
	char val;
	int range = 0;

	// north
	y = WI.Current_Y;

	while (1){
		if (y < 1) break;
		y--;
		//val = GetPixel (WI.Current_X, y);
		val = CheckMove (WI.Current_X, y, curz);
		if (val != 1) break;
		range++;
	}

	if (range > abs (WI.Current_Y - WI.Target_Y) && !SecondaryFlag){
		range = abs (WI.Current_Y - WI.Target_Y);
	}

	return range;
}

int RangeEast (void)
{
	int blocked;
	int x, y;
	char val;
	int range = 0;

	// east
	x = WI.Current_X;

	while (1){
		if (x > 63) break;
		x++;
		val = CheckMove (WI.Current_X, y, curz);
//		val = GetPixel (x, WI.Current_Y);
		if (val != 1) break;
		range++;
	}

	if (range > abs (WI.Current_X - WI.Target_X) && !SecondaryFlag){
		range = abs (WI.Current_X - WI.Target_X);
	}

	return range;
}

int RangeSouth (void)
{
	int blocked;
	int x, y;
	char val;
	int range = 0;

	y = WI.Current_Y;

	while (1){
		if (y > 63) break;
		y++;
		//val = GetPixel (WI.Current_X, y);
		val = CheckMove (WI.Current_X, y, curz);
		if (val != 1) break;
		range++;
	}

	if (range > abs (WI.Current_Y - WI.Target_Y) && !SecondaryFlag){
		range = abs (WI.Current_Y - WI.Target_Y);
	}

	return range;
}

int RangeWest (void)
{
	int blocked;
	int x, y;
	char val;
	int range = 0;

	x = WI.Current_X;

	while (1){
		if (x < 1) break;
		x--;
		//val = GetPixel (x, WI.Current_Y);
		val = CheckMove (WI.Current_X, y, curz);
		if (val != 1) break;
		range++;
	}

	if (range > abs (WI.Current_X - WI.Target_X) && !SecondaryFlag){
		range = abs (WI.Current_X - WI.Target_X);
	}

	return range;
}

void SetNorth (void)
{
	WI.Cur_Y_Dir = -1;
}

void SetEast (void)
{
	WI.Cur_X_Dir = 1;
}

void SetSouth (void)
{
	WI.Cur_Y_Dir = 1;
}

void SetWest (void)
{
	WI.Cur_X_Dir = -1;
}

void SetBlocked (void)
{
	WI.Cur_X_Dir = WI.Cur_Y_Dir = 0;
	printf ("Error occured");
}

int SeekNorth (void)
{
	int range = 0;

	SecondaryFlag = 1;
	range = RangeNorth ();
	SecondaryFlag = 0;

	if (range != 0){
		SetNorth ();
	}

	return range;
}

int SeekSouth (void)
{
	int range = 0;

	SecondaryFlag = 1;
	range = RangeSouth ();
	SecondaryFlag = 0;

	if (range != 0){
		SetSouth ();
	}

	return range;
}

int SeekWest (void)
{
	int range = 0;

	SecondaryFlag = 1;
	range = RangeWest ();
	SecondaryFlag = 0;

	if (range != 0){
		SetWest ();
	}

       return range;
}

int SeekEast (void)
{
	int range = 0;

	SecondaryFlag = 1;
	range = RangeEast ();
	SecondaryFlag = 0;

	if (range != 0){
		SetEast ();
	}

	return range;
}

void nocmd (void)
{
}

int SeekEastWest (void)
{
	int range = 0;

	if (WI.Current_X < WI.Target_X){
		range = SeekEast ();

		if (range == 0){
			range = SeekWest ();
		}
	}

	else if (WI.Current_X > WI.Target_X){
		range = SeekWest ();

		if (range == 0){
			range = SeekEast ();
		}

	}

	else if (WI.Current_X == WI.Target_X){
		range = SeekEast ();

		if (range == 0){
			range = SeekWest ();
		}
	}

	return range;
}

int SeekSouthNorth (void)
{
	int range = 0;

	if (WI.Current_Y < WI.Target_Y){
		range = SeekNorth ();

		if (range == 0){
			range = SeekSouth ();
		}
	}

	else if (WI.Current_Y > WI.Target_Y){
		range = SeekSouth ();

		if (range == 0){
			range = SeekNorth ();
		}

	}

	else if (WI.Current_Y == WI.Target_Y){
		range = SeekNorth ();

		if (range == 0){
			range = SeekSouth ();
		}
	}

	return range;
}

int Seek1 (void)
{
	int range = 0;

	if (WI.Base_Y_Dir == 1){
		range = SeekSouth ();

		if (range == 0){
			range = SeekEastWest ();

			if (range == 0){
				range = SeekNorth ();
			}
		}
	}

	return range;
}

int Seek2 (void)
{
	int range = 0;

	if (WI.Base_Y_Dir == -1){
		range = SeekNorth ();

		if (range == 0){
			range = SeekEastWest ();

			if (range == 0){
				range = SeekSouth ();
			}
		}
	}

	return range;
}

int Seek3 (void)
{
	int range = 0;

	if (WI.Base_X_Dir == 1){
		range = SeekEast ();

		if (range == 0){
			range = SeekSouthNorth ();

			if (range == 0){
				range = SeekWest ();
			}
		}
	}

	return range;
}

int Seek4 (void)
{
	int range = 0;

	if (WI.Base_X_Dir == -1){
		range = SeekWest ();

		if (range == 0){
			range = SeekSouthNorth ();

			if (range == 0){
				range = SeekEast ();
			}
		}
	}

	return range;
}

int SeekDir (void)
{
	int blocked;
	int x, y;
	char val;
	int range = 0;
	int c;

	WI.Cur_X_Dir = WI.Cur_Y_Dir = 0;
	if (WI.Base_X_Dir == 0 && WI.Base_Y_Dir == 0) return 1;

	// south
	if (WI.Base_Y_Dir == 1){
		range = SeekSouth ();

		if (range == 0){
			// north/ew check swapped
			range = SeekNorth ();

			if (range == 0){
				range = SeekEastWest ();
			}
		}
	}

	// north ?
	else if (WI.Base_Y_Dir == -1){
		range = SeekNorth ();

		if (range == 0){
			range = SeekEastWest ();

			if (range == 0){
				range = SeekSouth ();
			}
		}
	}


	// east ?
	else if (WI.Base_X_Dir == 1){
		range = SeekEast ();

		if (range == 0){
			range = SeekSouthNorth ();

			if (range == 0){
				range = SeekWest ();
			}
		}
	}

	// west ??? (notice old low priority add !)
	else if (WI.Base_X_Dir == -1){
		range = SeekWest ();

		if (range == 0){
			range = SeekSouthNorth ();

			if (range == 0){
				range = SeekEast ();
			}
		}
	}

	return range;
}

/*
	this routine moves to pixel towards a target
*/
int RealWalk (void)
{
//	while (!kbhit()){
		if (WI.Current_X == WI.Target_X &&
		WI.Current_Y == WI.Target_Y) return 1;

		// seek line (try to find a target path)
		if (method == -1){
			UpdateBase ();
			targetx = WI.Target_X;
			targety = WI.Target_Y;

			trange = SeekLine2 (WI.Current_X, WI.Current_Y, WI.Target_X, WI.Target_Y);

			if (trange != -1){
				range = grange;
				WI.BaseCosine = gxs;
				WI.BaseSine = gys;
				method = 0;
				fx = WI.Current_X << 6;
				fy = WI.Current_Y << 6;
			}

			else{
				range = SeekLine (WI.Current_X, WI.Current_Y, WI.BaseCosine, WI.BaseSine);

				if (range == -1){
					return 2;
				}

				if (range != 0){
					method++;
					fx = WI.Current_X << 6;
					fy = WI.Current_Y << 6;
				}

				else{
					method = 1;
				}
			}
		}

		// cos/sine walk ?
		else if (method == 0){
			fx += WI.BaseCosine;
			fy += WI.BaseSine;
			WI.Current_X = fx >> 6;
			WI.Current_Y = fy >> 6;
			range--;
			if (range == 0) method = 1;
		}

		// N,S,E,W walk dir select (try to get to a target path)
		else if (method == 1){
			range = SeekDir ();

			if (range != 0){
				method = 2;
			}

			// failed... actually we should bail out...
			else method = -1;
		}

		// real walk ?
		else if (method == 2){
			trange = SeekLine3 (WI.Current_X, WI.Current_Y, WI.Target_X, WI.Target_Y);

			if (trange > 0){
				range = trange;
				WI.BaseCosine = gxs;
				WI.BaseSine = gys;
				method = 0;
				fx = WI.Current_X << 6;
				fy = WI.Current_Y << 6;
			}

			else{
				trange = SeekLine2 (WI.Current_X, WI.Current_Y, WI.Target_X, WI.Target_Y);

				if (trange != -1){
					range = grange;
					WI.BaseCosine = gxs;
					WI.BaseSine = gys;
					method = 0;
					fx = WI.Current_X << 6;
					fy = WI.Current_Y << 6;
				}

				else{
					WI.Current_X += WI.Cur_X_Dir;
					WI.Current_Y += WI.Cur_Y_Dir;
					range--;
					if (range == 0) method = -1;
				}
			}
		}

//		PutPixel (WI.Current_X, WI.Current_Y, 14);
//	delay (25);
//		PutPixel (WI.Current_X, WI.Current_Y, 0);

//	}

	GenX = WI.Current_X;
	GenY = WI.Current_Y;

	return 0;
}

int UpdateBase (void)
{
	if (WI.Current_X < WI.Target_X) WI.Base_X_Dir = 1;
	else if (WI.Current_X > WI.Target_X) WI.Base_X_Dir = -1;
	else if (WI.Current_X == WI.Target_X) WI.Base_X_Dir = 0;

	if (WI.Current_Y < WI.Target_Y) WI.Base_Y_Dir = 1;
	else if (WI.Current_Y > WI.Target_Y) WI.Base_Y_Dir = -1;
	else if (WI.Current_Y == WI.Target_Y) WI.Base_Y_Dir = 0;

	WI.BaseSine = GetYS (WI.Current_X, WI.Current_Y);
	WI.BaseCosine = GetXS (WI.Current_X, WI.Current_Y);
	return 0;
}

int StartWalk (signed int sx, signed int sy, signed int wx, signed int wy)
{
	int stat, range, trange;
	signed int bx, by;

	targetx = wx;
	targety = wy;

	// init coordinates (source&target)
	WI.Current_X = sx;
	WI.Current_Y = sy;

	WI.Target_X = wx;
	WI.Target_Y = wy;

	// set start xdir
	if (wx > sx) WI.Base_X_Dir = 1;
	else if (wx < sx) WI.Base_X_Dir = -1;
	else if (wx == sx) WI.Base_X_Dir = 0;

	// set start ydir
	if (wy > sy) WI.Base_Y_Dir = 1;
	else if (wy < sy) WI.Base_Y_Dir = -1;
	else if (wy == sy) WI.Base_Y_Dir = 0;

	// init rest variables
	WI.Cur_X_Dir = WI.Base_X_Dir;
	WI.Cur_Y_Dir = WI.Base_Y_Dir;

	// can we move straight to target point ?
	trange = SeekLine2 (WI.Current_X, WI.Current_Y, WI.Target_X, WI.Target_Y);

	if (trange != -1){
//		range = grange;
		WI.BaseCosine = gxs;
		WI.BaseSine = gys;
	}

	else{
		WI.BaseSine = GetYS (sx, sy);
		WI.BaseCosine = GetXS (sx, sy);
	}

	return 0;
}