/* 	DEMO.C - a demonstration PCRobots Robot in Turbo C		*/
/*		Written by P.D.Smith - July 1992			*/

#include <stdlib.h>
#include <time.h>

/* Include the PCROBOTS header file for the special function definitions*/
#include "pcrobots.h"

#define randomize() srand(time(NULL))
#define random(range) rand()%range

/* Function prototypes */
void	read_local_map(int x,int y);

/* Type definitions */
typedef unsigned char byte;

/* Define the robot's icon on the screen - this is a small smiley shape	*/
const char pattern[5]={27,4,4,17,14};

/*
 * Define possible angles of motion
 * x,y are x,y offsets on the map
 * angle is the angle of motion to specify
 */
struct 	{
	 int	x,
		y,
		angle;
	}
	angle[8]={{ 1, 0,0},
		  { 1, 1,45},
		  { 0, 1,90},
		  {-1, 1,135},
		  {-1, 0,180},
		  {-1,-1,225},
		  { 0,-1,270},
		  { 1,-1,315}};

/* Array to hold the map */
byte	map[100][100];

/* Current X and Y coordinates of the robot */
int	x_pos,
	y_pos;

/* Structure to hold information about the refueling points that
 * have been located.
 * x,y are coordinates (in map units)
 * last_visit is the time of the last visit (in game ticks)
 * 	to avoid revisiting refuelers too often
 */
struct  {
	 int 	x,
		y;
	 long	last_visit;
	} refueler[10];
int	num_refuelers=0;	/* number of refuelers that have
				   been found */

int	go_dir;			/* current direction (index to angle[]) */
int	last_battery;		/* last battery reading	*/
int	last_armour;		/* last armour status */

int	scan_angle=0;		/* Current scanning angle */
int	range;			/* values returned */
int	id;			/* from the scan routine */

void	main(void)
{
 int	i,
	j,
	try;
 int	x_square,
	y_square,
	next_x,
	next_y;
 int	new_armour,
	new_battery;
 int	invis_count=0;
 int	speed=0;
 long	now,
	last_shoot=-50;
 int	shot_counter=0;		/* this is used to detect shells hitting walls */

/* Configure robot - all normal, except with invisibility facility
 * This *MUST* be the first special function called by the robot   */
 configure(2,2,2,2,2,1);

 randomize();

 go_dir=random(8);		/* Select initial direction */

/* Set the robot's icon */
 set_pattern(pattern);

/* Clear the map to '255' so we know where we haven't been yet */
 for (i=0;i<100;i++)
 {
  for (j=0;j<100;j++)
   map[i][j]=255;
 }

 last_armour=damage();  	/* get initial armour and battery levels */
 last_battery=battery();

/* Note - this is an *INFINITE* loop - the PCROBOTS executive program
   kills the robot off */
 while(1)
 {
/* Get the current position */
  getxy(&x_pos,&y_pos);

  now=ticks();

/* Get the current map square */
  x_square = x_pos/10;
  y_square = y_pos/10;
/* Get the next square to be moved into */
  next_x   = x_square+angle[go_dir].x;
  next_y   = y_square+angle[go_dir].y;

/* If the current map square, or the next map_square to be moved into,
 * are unknown, read the local map */
  if ((map[y_square][x_square] == 255) ||
	(map[next_y][next_x]   == 255))
  {
   read_local_map (x_square,y_square);
  }

/* Ok, now we know where we are, look to see if the target square contains
 * a wall or trap - if so, choose a new direction which is clear */

/* Quick and easy way of dealing with the robot being near an outside wall */
  if (next_x<2)
   go_dir=(random(3)-1)%8;
  if (next_x>=98)
   go_dir=random(3)+3;
  if (next_y<2)
   go_dir=random(3)+1;
  if (next_y>=98)
   go_dir=random(3)+5;

  next_x   = x_square+angle[go_dir].x;
  next_y   = y_square+angle[go_dir].y;

  try=0;
  while ((map[next_y][next_x] == ARENA_WALL) ||
	 (map[next_y][next_x] == ARENA_DAMAGE) ||
	 ((next_x<0)||(next_x>=100)||(next_y<0)||(next_y>=100)))
  {
   debug_flag(0,1);
   srand((unsigned)now);
   go_dir=random(8);

   next_x   = x_square+angle[go_dir].x;
   next_y   = y_square+angle[go_dir].y;

/* Failsafe check to avoid the program getting trapped here */
   if (try++ > 50)
   {
    debug_flag(1,1);
    break;
   }
  }
  debug_flag(0,0);


  movement(speed,angle[go_dir].angle);

/* Come out of invisibility if necessary */
  if (invis_count>0)
   invis_count--;
  else
   invisibility(0);

/* See if we've been hit! */
  new_armour=damage();
  if (new_armour<last_armour)
  {
   invisibility(1);
   go_dir=random(8);
   invis_count=30;
  }
  last_armour=new_armour;

  new_battery=battery();

/* See if badly damaged- may be able to buy more armour */
  if ((last_armour<50)&&(new_battery>400))
  {
   buy_armour(2);
  }

/* If battery is depleted rest for a while */
  if ((new_battery<(600-(speed*8)))&&(invis_count==0))
   speed=0;
  else
   speed=50;


/* there's no point wasting time if my cannon hasn't reloaded yet */
  if ((now-last_shoot)>=50)
  {
   id=scan(scan_angle,10,&range);

// Check if no target, or target out of range - go to next angle if so */
   if ((id<0)||(range>700))
   {
    scan_angle=(scan_angle+10)%360;
    shot_counter=0;
   }
   else
   {
    shot_counter++;
    if (shot_counter==4)
    {
     if (get_shell_status()==SHELL_HIT_WALL)
     {
      scan_angle=(scan_angle+10)%360;
      id=-1;
     }
     shot_counter=0;
    }
    if (id>=0)
    {
     shoot(scan_angle,range);
     last_shoot=now;
    }
   }
  }

 }
}


/* Copy the local map into the main map
 * x,y are the current 'map' coordinates */
void	read_local_map(int x,int y)
{
 int 	i,
	j,
	val;
 byte	*ptr;

/* Buffer to hold the local map before copying it to the main map	*/
 byte	local_map[81];


/* Obtain the local map */
 get_local_map(local_map);

/* Copy the local map into the main map */
 ptr=local_map;

/* Get coordinates of top left of local map area */
 x-=4;
 y-=4;

 for (i=0;i<9;i++)
 {
  for (j=0;j<9;j++)
  {
/* only copy if within the actual arena */
   if ((x<0)||(x>=100)||(y<0)||(y>=100))
    ptr++;
   else
   {
    val=*(ptr++);
    map[y][x]=val;	/* store the map contents */

   }
   x++;			/* next column */
  }
  y++;			/* next row */
  x-=9;
 }
}
