#include "main.h"

#define AI_left_angle_diff(a,b)  (b>a ? (b-a) : (b+(360-a)))
#define AI_right_angle_diff(a,b) (b>a ? (a+(360-b)) : (a-b))

#define FIRE_NORMAL             0

/*
Constructor for the ship class.
*/
BUGGY::BUGGY( int _x, int _y, int _type, int _ai, char _callsign[] ) {
  id = ID_BUGGY;
  x = _x;
  y = _y;
  type = _type;
  ai = _ai;
  strcpy(callsign, _callsign);
  fx = x;
  fy = y;
  xa = 0.0;
  ya = 0.0;
  va = 270;
  frame = 4;
  thrust = 0.0;
  nxa = 0.0;
  nya = 0.0;
  firetime = 10;
  kills = 0;
  dead = false;
  target = NULL;
  kl = kr = ku = kd = kf = false;
  spower = power = 201;
  scount = 0;
  dcount = 0;
  tbmp = create_bitmap(48,48);
  remove = false;
}

/*
Destructor for the ship class.
*/
BUGGY::~BUGGY() {
  destroy_bitmap(tbmp);
}

void ctextprintf(BITMAP *bmp, FONT *f, int x, int y, int color, char *format, ...)
{
   char buf[512];
   va_list ap;
   va_start(ap, format);
   uvsprintf(buf, format, ap);
   va_end(ap);
   textout(bmp, f, buf, x-1, y, 0);
   textout(bmp, f, buf, x+1, y, 0);
   textout(bmp, f, buf, x, y-1, 0);
   textout(bmp, f, buf, x, y+1, 0);
   textout(bmp, f, buf, x, y, color);
}

#define MISSION_NONE      0
#define MISSION_FACE      1
#define MISSION_FLEE      2
#define MISSION_THRUST    4
#define MISSION_FIRE      8     

/*
Decides what the ship's AI mission is.
*/
int BUGGY::AI_find_mission() {
  int flag = MISSION_NONE;
  int score[50];
  int t = -1;
  for (int j=0; j<50; j++) {
    score[j] = -9999;
  }
  
  for (int i=0; i<=numplayers; i++) {
    if (player[i] != NULL && player[i] != this &&
        !player[i]->dcount && !player[i]->dead) {
          int dx = player[i]->get_x() - x;
          int dy = player[i]->get_y() - y;
          int dist = (dx*dx) + (dy*dy);
          score[i] = 0;
          if (player[i]->power < 10)  score[i] += 20;
          if (player[i]->power < 50)  score[i] += 10;
          if (player[i]->power > 150) score[i] -= 10;
          if (player[i]->weapon == 0) score[i] += 5;      
          if (player[i]->power < power) score[i] += 5;
          if (player[i]->power > power) score[i] -= 5;    
          if (dist > 5000)          score[i] -= 5;
          if (dist < 2000)          score[i] += 5;
          if (dist < 100)           score[i] -= 30;

          if (t < 0) 
             t = i;
          else
          if (score[t] < score[i])
             t = i;
    } else {
          score[i] = -9999;
    }
  }

  if (t >= 0)
    target = player[t];
  else
    target = NULL;  

  return 1;
}


/*
Decides the best course of action to face the target if available.
*/
int BUGGY::AI_face_target() {
  if (!target) 
        return 0;
  int dx = target->get_x() - x;
  int dy = target->get_y() - y;
  int ta = (angle256(dx,dy)+360) % 360;
        
  int a_left  = abs(AI_left_angle_diff(va, ta));
  int a_right = abs(AI_right_angle_diff(va, ta));
  int a_diff  = MIN(a_left, a_right);

  //textprintf(buffer, _font(4), 0, 15+(type*10), -1, "%d %d %d", va, ta, a_diff);

  if (a_diff < 5)
          return 0;
  if (a_left < a_right)
          return 1;
  else
          return -1;
  return 0;
}


/*
Draws the ship.
*/
void BUGGY::draw() {
  int cx = (int)(cos(grad360(va-90)) * 2);
  int cy = (int)(sin(grad360(va-90)) * 2);
  int barcol = makecol(255-((spower * 125) / 100), ((spower * 125) / 100), 0);

  int num = type ? 1 : 0;

  ctextprintf(topbar,_font(num),(type*40),2,-1,"%d",kills);

  if (!dead) {
    clear(tbmp);
    rotate_sprite(tbmp, _buggy(frame, num), 8+cx, 8+cy, itofix(to256(va)+64));
    draw_sprite(buffer, tbmp, x-24, y-24);
    rect(buffer,x-30,y+27,x+30,y+32,5);
    rectfill(buffer,x-29,y+28,(x-29)+(spower*58/200),y+31,barcol-4);
    rectfill(buffer,x-29,y+29,(x-29)+(spower*58/200),y+30,barcol);
  }
  if (scount<20) {
    draw_lightning(x-16+random()%32,y-16+random()%32,x-16+random()%32,y-16+random()%32);
    if (power == 201) {
      color_map = &light_table;
      draw_lit_sprite(buffer, tbmp, x-24, y-24, scount*12);
      color_map = &flare_table;
      draw_lightning(x,y,x-32+random()%64,y-32+random()%64);
      draw_lightning(x,y,x-32+random()%64,y-32+random()%64);
      draw_lightning(x,y,x-32+random()%64,y-32+random()%64);
      draw_lens_flare(buffer,x,y);
    }
  }
} 


/*
Gets input from the keyboard for local players or performs AI for cpu players.
*/
void BUGGY::get_action() {
  if (ai == AI_LOCAL) {
        int mx = 0, my = 0;
    get_mouse_mickeys(&mx, &my);        
    kl = kr = ku = kd = kf = false;     
        mframe += mx / 3;
        if (mframe > 0) mframe -= 1;
        if (mframe < 0) mframe += 1;
        if (mframe < -5) mframe = -5;
        if (mframe >  5) mframe =  5;
    kl = key[KEY_LEFT]  || (mframe < 0);
    kr = key[KEY_RIGHT] || (mframe > 0);
    ku = key[KEY_UP]    || (mouse_b & 2);
    kf = key[KEY_ENTER] || key[KEY_SPACE] || (mouse_b & 1);  
  }
  if (ai == AI_CPU) {
    kl = kr = ku = kd = kf = false;
    AI_find_mission();
        int turn = AI_face_target();
    if (turn != 0) {
      kl = turn < 0;
          kr = turn > 0;                                
    } else {
      kf = true;
      ku = true;
    }
  }
}

/*
Performs any needed calculations.
*/
void BUGGY::move() {
  get_action();
  if (!dead) {
    if (kl)  { // LEFT
      va-=8;
      frame--;
    } else
    if (kr) {  // RIGHT
      va+=8;
      frame++;
    } else {
      if (frame < 4) frame++;
      if (frame > 4) frame--;
    }
    if (ku) {
      if (ai == AI_LOCAL) {
        int tx1 = (int)(cos(grad360(va-7)) * 10);
        int ty1 = (int)(sin(grad360(va-7)) * 10);
        int tx2 = (int)(cos(grad360(va-7)) * 12);
        int ty2 = (int)(sin(grad360(va-7)) * 12);               
        //elist.add(new SMOKE(x-tx1, y-ty1));
        //elist.add(new SMOKE(x-tx2, y-ty2));
      }
      thrust = 0.4;
    } else {
      //if (thrust > 0) thrust -= 0.01;
      thrust = 0;
      if (xa > 0) xa -= 0.4;
      if (xa < 0) xa += 0.4;
      if (ya > 0) ya -= 0.4;
      if (ya < 0) ya += 0.4;
      if (fabs(xa) < 0.4) xa = 0.0;
      if (fabs(ya) < 0.4) ya = 0.0;
    }
    if (kf && !firetime) { // FIRE
      //printf("%c",7);
      elist.add(new BULLET(x,y,va,type));
      firetime = 10;
      if (ammo) {
        ammo--;
        if (!ammo) weapon = 0;
      }
    }
    if (firetime) firetime--;

    if (frame < 0) frame = 0;
    if (frame > 7) frame = 7;
    if (va < 0) va += 360;
    if (va > 360) va -= 360;

    if (nxa || nya) {
      xa = nxa;
      ya = nya;
      nxa = nya = 0;
    }

    float txa = cos(grad360(va)) * 7.1;
    float tya = sin(grad360(va)) * 7.1;

    if (xa < txa) xa += thrust;
    if (xa > txa) xa -= thrust;
    if (ya < tya) ya += thrust;
    if (ya > tya) ya -= thrust;

    if (fabs(txa-xa) < thrust) xa = txa;
    if (fabs(tya-ya) < thrust) ya = tya;
    if (fabs(xa) < thrust) xa = 0.0;
    if (fabs(ya) < thrust) ya = 0.0;

    fx += xa;
    fy += ya;

    if (fx > msx-16) { xa = -xa * 0.75; fx = msx-16; }
    if (fy > msy-16) { ya = -ya * 0.75; fy = msy-16; }
    if (fx < 16)     { xa = -xa * 0.75; fx = 16;     }
    if (fy < 16)     { ya = -ya * 0.75; fy = 16;     }

    if (power < 0) power = 0;
    if (spower > power) spower--;
    if (spower < power) spower += MAX(2,(int)((power - spower)*0.20));
    if (scount < 20) scount++;
    if (power <= 0) {
      dead = true;
      dcount = 75;
    }
    x = (int)fx;
    y = (int)fy;
  } /* if !dead */

  if (dead)  {
    if (dcount == 72) {
      elist.add(new EXPLO(x,y,64));
      elist.add(new EXPLO(x+random()%20,y+random()%20,64));
      elist.add(new EXPLO(x-random()%20,y-random()%20,64));
      elist.add(new EXPLO(x-random()%20,y+random()%20,64));
      elist.add(new EXPLO(x+random()%20,y-random()%20,64));
      elist.add(new PART(x-10,y-10,random()%360,0.04*(random()%30),type));
      elist.add(new PART(x-10,y+10,random()%360,0.04*(random()%30),type));
      elist.add(new PART(x+10,y-10,random()%360,0.04*(random()%30),type));
      elist.add(new PART(x+10,y+10,random()%360,0.04*(random()%30),type));
      elist.add(new T29(x, y));
      x = -9999;
      y = -9999;
    }
    if (dcount)
      dcount--;
    else {
      dead = false;
      if (ai != AI_NETWORK) {
        fx = random()%msx;
        fy = random()%msy;
        x = (int)fx;
        y = (int)fy;
      }
      spower = power = 201;
      xa = ya = ammo = icount = ccount = scount = pcount = weapon = 0;
    }
  } /* if dead */
}

/*
Adds a kill to the counter.
*/
void BUGGY::add_kill() {
  kills+=29;
}

/*
Get the amount of kills.
*/
int BUGGY::get_kills() {
  return kills;
}

/*
Get the callsign.
*/
char *BUGGY::get_callsign() {
  return callsign;
}

/*
Returns true if the entity can be removed from the list.
*/
bool BUGGY::done() {
  return remove;
}

/*
Collision detection method.
Handles any collision their might be between this entity and the given
entity.
*/
void BUGGY::collide(ENTITY *other) {
  if (other != this && !dead) {
    if ( abs(other->get_x() - x) < 15 &&
         abs(other->get_y() - y) < 15)
    {
      if (other->get_id() == ID_BULLET) {
        if (type != other->get_owner()) {
          if (((BULLET*)other)->get_pressure()) {
            nxa = xa + (other->get_xa() / 10);
            nya = ya + (other->get_ya() / 10);
          }
          spower = power;
          if (ai != AI_NETWORK)
            if (power) power -= ((BULLET*)other)->get_damage() + 20;
          scount = 0;
          if (power<0) {
            player[other->get_owner()]->add_kill();
            int num = other->get_owner();
            power = 0;
          }
        }
      }
      if (other->get_id() == ID_BUGGY) {
        float txa = other->get_xa();
        float tya = other->get_ya();
        if (other->get_x() - x < 0)
          if (txa < 0) nxa = -txa;
            else nxa = txa;
        else
          if (txa > 0) nxa = -txa;
            else nxa = txa;
        if (other->get_y() - y < 0)
          if (tya < 0) nya = -tya;
            else nya = tya;
        else
          if (tya > 0) nya = -tya;
            else nya = tya;
      }

    }
  }
}

/*
Get functions to allow access to private data inside the class.
*/
int BUGGY::get_x() {
  return x;
}

int BUGGY::get_y() {
  return y;
}

int BUGGY::get_id() {
  return id;
}

int BUGGY::get_va() {
  if (xa + ya == 0) return 0;
  return angle360(xa,ya);
}

float BUGGY::get_xa() {
  return xa;
}

float BUGGY::get_ya() {
  return ya;
}

int BUGGY::get_owner() {
  return type;
}

/* END */
