#include "gridhunt.h"

extern "C" int abs(int);

/* Now let's define a global Monster_pointer */
Monster *Mobptr;

/* General Functions */

int dice(int eyes)
{  return(random()%eyes+1); }

int int_sqr(int a) {return a*a;}


// --------------------------------------------------------------
/* Functions for the class Coor
 * Constructor I: just initialize
 */

Coor::Coor(int a,int b){x=a;y=b;}

Coor ERROR_COORD(-1,-1);

void Coor::print()
{  cout << "X: "<< x << " Y: " << y << "\n"; }

int Coor::operator==(Coor& arg2)
{ return (x==arg2.x && y==arg2.y); }


// ------------------------------------------------------------------
/* Functions for the class Mobile
 * Constructor I: just initialize
 * Constructor II: initialize with a name
 */

Mobile::Mobile(char* mob_name)
{
  cds.x=0;cds.y=0; // in the grid, if named !!
  strncpy(name,mob_name,40);
}

void Mobile::reset()
{
  if(cds==ERROR_COORD) return;
  cds.x=0; cds.y=0;
}

/* Private Functions
 */

int Mobile::do_move(int x,int y)
  {
    int test=cds.x+x;
    if(test<0 || test>=GRIDX) return FALSE;
    test=cds.y+y;
    if(test<0 || test>=GRIDY) return FALSE;
    cds.x+=x; cds.y+=y;
    return TRUE;
  }

/* Name the puppy, set puppy's position
 */
void Mobile::set_name(char *mob_name)
{
  if(mob_name) strncpy(name,mob_name,40);
}

char *Mobile::get_name()
{
  return name;
}

void Mobile::set_pos(int x, int y)
{
  /* This isn't very beautiful but it works. better: error */
  if(x>=GRIDX || x<0) return;
  if(y>=GRIDX || y<0) return;
  cds.x=x; cds.y=y;
}

/* Returns the position in COORDINATES !!!!!
 */
Coor Mobile::my_pos() {return cds;}

/* Movement: Directions....
 * 8 1 2
 *  \|/
 * 7-*-3
 *  /|\
 * 6 5 4
 */

int Mobile::move(int dir)
{
  int ret;
  switch(dir) // number between 1..8
    { 
    case 1: ret=do_move( 0, 1); break;
    case 2: ret=do_move( 1, 1); break;
    case 3: ret=do_move( 1, 0); break;
    case 4: ret=do_move( 1,-1); break;
    case 5: ret=do_move( 0,-1); break;
    case 6: ret=do_move(-1,-1); break;
    case 7: ret=do_move(-1, 0); break;
    case 8: ret=do_move(-1, 1); break;
    default: // no valid direction
      cerr << "invalid movement direction:" << dir << endl;
      return FALSE;
      break;
    }
  return ret /* True False */;
}  

/* Give the distance function to both Monster & Player
 * Returns the distance in Moves !!!!
 */

int Mobile::distance(const Mobile& mobile )
{
  int dx,dy;
  dx=abs(mobile.cds.x-cds.x); dy=abs(mobile.cds.y-cds.y);
  return (dx<=dy?dy:dx);
}

void Mobile::print_pos()
{
  cout << form("%-15s: x=%4d, y=%4d\n",
	    name,
	    cds.x,
	    cds.y);
}

/* Function for the Class MONSTER
 */
/* Monster::move overloads Mobile::move
 * Probabilities:
 * 1d12 : 1-4 (30%) Monsters stays, others: Monster moves
 * If monsters stays 10% Probability that monster teleports
 *                   30%(stay)*10%(teleport)==3% (for teleport)
 */

int Monster::move()
{
  /* returns TRUE if moved in a way, else FALSE */
  int move, teleport, ret, dir;
  
  move=((dice(12)>=4) ? TRUE : FALSE);       /* 60% */
  teleport=((dice(100)<=10) ? TRUE : FALSE); /* 10% */
  
  if(move==TRUE)
  {
    /* first move */
    do{
      ret=Mobile::move(dice(8));			
    }while(ret==FALSE);
    if(dice(5)==1)
      do{
	ret=Mobile::move(dice(8));			
      }while(ret==FALSE); 
  }
  else
  {
    /* chance for teleport */
    if(teleport==TRUE)
    {
      Mobile::teleport();
      ret=TRUE;
    }
  }
  return ret;
}

void Mobile::teleport()
{
  set_pos((random())%GRIDX,(random())%GRIDY);
}


/* Function for the Class PLAYER
 */


/* Player Move overloads the Mobile::move function
 *
 */

Player::Player(char *name):Mobile(name)
{turns=2; wins=a_pos=a_dis=a_mov=c_pos=c_dis=c_mov=0;}


void Player::tick(){turns=2;}

int Player::teleport()
{
	if (turns<2)
	{
		return FALSE;
	}
	else
	{
	Mobile::teleport();
	turns-=2;
	}
	return TRUE;
}

Coor Player::monster_pos()
{
  /* only if the player has 2 turns */
  if(turns < 2) return ERROR_COORD;

  turns-=2;
  c_pos++;
  return Mobptr->Mobile::my_pos();
}

int Player::monster_dist()
{
  /* only if the player has 2 turns */
  if(turns < 1) return -1;
  turns--;
  c_dis++;
  return Mobile::distance(*Mobptr);
}

Coor Player::player_pos(const Player& plr)
{
  return plr.Mobile::my_pos();
}

int Player::player_dist(const Player& plr)
{
  return Mobile::distance(plr);
}

int Player::move(int dir)
/* directions as in monster_move */
/* returns TRUE if Move was done correctly, otherwise false */
{
  int ret=FALSE;
  
  if(turns < 1)
    return ret;

  ret=Mobile::move(dir);
  if(ret==TRUE)
    {
      turns--;
      c_mov++;
    }
  return ret;
}

void Player::reset()
{
  a_pos=(a_pos+c_pos)/(1+1*(a_pos>0));
  a_dis=(a_dis+c_dis)/(1+1*(a_dis>0));
  a_mov=(a_mov+c_mov)/(1+1*(a_mov>0));

  c_mov=c_pos=c_dis=0;
  Mobile::reset();
}

/* prints the statistics of the calls !! flag== TRUE prints ava_stats
 * FALSE prints current_stats
 */
void Player::print_stats(int flag)
{
  int *mov=&c_mov,*dis=&c_dis,*pos=&c_pos;
  char text[20]="cur.";

  if(flag)
    {
      mov=&a_mov;
      dis=&a_dis;
      pos=&a_pos;
      strcpy(text,"avg.");
    }

  cout << form("%-15s %4s Stats: Mov: %4d  Dis: %4d  Pos: %4d  Wins: %4d\n",
	       Mobile::get_name(),
	       text,
	       *mov,
	       *dis,
	       *pos,
	       wins);
}













