#include "empire.h"

extern BITMAP *sprite_buffer;
extern BITMAP *unittemp;
extern DATAFILE *graphics;
extern DATAFILE *units;
extern DATAFILE *darkunits;
extern DATAFILE *powered_overlay;
extern DATAFILE *p[4];

extern void draw_tile(int set, int pic, int x, int y);
extern void init_explode(int x, int y);
extern int get_set(int mapdat);
extern int get_tilenum(int mapdat);
extern int moves_needed(int mtype, int tx, int ty);
extern int unit_unloadable_here(int tx, int ty, int type);
extern int rounded_health(float h);
extern int any_unit_here(int tx, int ty);

int powered_overlay_num(int type);

_unit::_unit()
{
  moving_towards = -1;
  type = -1;
  color = -1;
  number = -1;
  ready = 0;
  price = -1;
  health = -1;
  exists = 0;
  basetype = -1;
  tilex = -1;
  tiley = -1;
  move = -1;
  movetype = -1;
  vision = -1;
  gas = -1;
  ammo = -1;
  submerged = 0;
  attacktype = -1;
  capturing = -1;
}

void _unit::create(int utype, int tx, int ty, int tcolor, int tnum)
{
  unitprops tmpr = get_properties(utype);
  move = tmpr.move;
  movetype = tmpr.movetype;
  vision = tmpr.vision;
  gas = tmpr.gas;
  ammo = tmpr.ammo;
  price = tmpr.price;
  attacktype = tmpr.attacktype;
  basetype = tmpr.basetype;
  capturing = -1;
  health = 10;
  x = tx * 40;
  y = ty * 40;
  destx = 0;
  desty = 0;
  tilex = tx;
  tiley = ty;
  unitmap[tilex][tiley] = (tcolor * 100) + tnum;
  type = utype;
  number = tnum;
  exists = 1;
  color = tcolor;
  direction = RIGHT;
  frame = 0;
  ready = 0;
  moving = 0;
  submerged = 0;
  otherunit = -1;
  moving_towards = -1;
  load[0].loaded = 0;
  load[0].type = -1;
  load[0].ammo = -1;
  load[0].gas = -1;
  load[0].subload.loaded = 0;
  load[0].health = -1;
  load[1].loaded = 0;
  load[1].type = -1;
  load[1].ammo = -1;
  load[1].gas = -1;
  load[1].health = -1;
  load[1].subload.loaded = 0;
  if ((type == APC) || (type == T_COPTER))
  {
    maxload = 1;
  }
  else if (type == LANDER)
  {
    maxload = 2;
  }
  else
  {
    maxload = 0;
  }
  clear_movelist();
}

void _unit::sort_movelist()
{
  int i = 0;
  while (i < 9)
  {
    if ((movelist[i] == -1))// && (movelist[i + 1] != 0))
    {
      movelist[i] = movelist[i + 1];
      movelist[i + 1] = -1;
    }
    i++;
  }
}

void _unit::clear_movelist()
{
  int i = 0;
  while (i < 10)
  {
    movelist[i] = -1;
    i++;
  }
}

void _unit::do_move()
{
  switch(direction)
  {
    case UP:
      y -= 4;
      break;
    case DOWN:
      y += 4;
      break;
    case LEFT:
      x -= 4;
      break;
    case RIGHT:
      x += 4;
      break;
  }
  tilex = x / 40;
  tiley = y / 40;
}

void _unit::draw(int forced)
{
  DATAFILE *t = p[color];
  DATAFILE *q = (DATAFILE *)t[type].dat;
  int z = (direction - 1) * 2;
  int lx, ly;
  int s;
  int mx, my;
  int t1, t2;
  int framechange = int(frame);
  lx = x - (scroll_x * 40);
  ly = y - (scroll_y * 40);
  if (moving == 1)
  {
    create_dirty(BACK, lx, ly, 40, 40);
    rectfill(sprite_buffer, lx, ly, lx + 40, ly + 40, TRANS);
    unitmap[tilex][tiley] = otherunit;  //this keeps any units passed over
    do_move();
    otherunit = unitmap[tilex][tiley];  //from being erased from the unitmap
    unitmap[tilex][tiley] = (color * 100) + number;
    forced = 1;
    if ((x == destx * 40) && (y == desty * 40))
    {
      movelist[0] = -1;
      moving = 0;
      direction = RIGHT;
      sort_movelist();
      if (movelist[0] != -1)
      {
        direction = movelist[0];
        unitmap[tilex][tiley] = otherunit;
      }
    }
    if ((type == INFANTRY) || (type == MECH) || (type == B_COPTER) || (type == T_COPTER))
    {
      if (direction == RIGHT)
      {
        z = 8;
      }
      if (direction == LEFT)
      {
        z = 10;
      }
    }
    frame += .08;  //if moving, the frames change more quickly
  }
  if (moving == 0)
  {
    if (movelist[0] != -1)
    {
      switch(movelist[0])
      {
        case UP:
          destx = tilex;
          desty = tiley - 1;
          break;
        case DOWN:
          destx = tilex;
          desty = tiley + 1;
          break;
        case LEFT:
          destx = tilex - 1;
          desty = tiley;
          break;
        case RIGHT:
          destx = tilex + 1;
          desty = tiley;
          break;
      }
      gas -= moves_needed(movetype, tilex, tiley);
      direction = movelist[0];
      moving = 1;
    }
    if (moving == 0)
    {
      if (otherunit != -1)
      {  //if it stops moving when on top of another unit, it is merging
        otherunit = -1;  //which means the covered unit should be erased
      }
    }
  }
  frame += .04;
  if (frame >= 2)
  {
    frame = 0;
  }
  mx = mouse_x;
  my = mouse_y;
  if ((tilex >= scroll_x) && (tilex < scroll_x + 16))
  {  //if the sprite is on the screen
    if ((tiley >= scroll_y) && (tiley < scroll_y + 12))
    {      
      if ((int(frame) != framechange) || (forced == 1))
      {  //if the sprite has changed animation frames or is forced to be drawn
        clear_to_color(unittemp, TRANS);
        lx = x - (scroll_x * 40);
        ly = y - (scroll_y * 40);
        create_dirty(BACK, lx, ly, 41, 41);
        rectfill(sprite_buffer, lx - 1, ly - 1, lx + 42, ly + 42, TRANS);
        if (moving == 1)
        {
          if (otherunit != -1)
          {
            draw(&player[otherunit / 100].unit[otherunit % 100]);
          }
          t1 = any_unit_here(tilex - 1, tiley);
          if (t1 != -1)
          {
            draw(&player[t1 / 100].unit[t1 % 100]);
          }
          t1 = any_unit_here(tilex + 1, tiley);
          if (t1 != -1)
          {
            draw(&player[t1 / 100].unit[t1 % 100]);
          }
          t1 = any_unit_here(tilex, tiley - 1);
          if (t1 != -1)
          {
            draw(&player[t1 / 100].unit[t1 % 100]);
          }
          t1 = any_unit_here(tilex, tiley + 1);
          if (t1 != -1)
          {
            draw(&player[t1 / 100].unit[t1 % 100]);
          }
        }
        if (player[color].powered == 1)
        {
          if (ready == 1)
          {
            draw_sprite(unittemp, (BITMAP *)powered_overlay[z + powered_overlay_num(type) + int(frame)].dat, 0, 0);
          }
          else
          {
            draw_sprite(unittemp, (BITMAP *)powered_overlay[z + powered_overlay_num(type)].dat, 0, 0);
          }
        }
        if (ready == 1)
        {
          draw_sprite(unittemp, (BITMAP *)q[z + int(frame)].dat, 0, 0);
        }
        else
        {
          draw_sprite(unittemp, (BITMAP *)darkunits[color * 18 + type].dat, 0, 0);
        }
        if (capturing != -1)
        {  //draw a simple percentage bar and the capture amount left
          vline(unittemp, 1, 0, capturing * 2, BLACK);
          text_mode(-1);
          textprintf(unittemp, font, 0, 32, LGREY, "%-1d", capturing);
          text_mode(0);
        }
        draw_status_symbols(unittemp);
        draw_sprite(sprite_buffer, unittemp, lx, ly);
        create_dirty(SPRITE, lx, ly, 40, 40);
        if ((mx >= lx - 5) && (mx <= lx + 50))
        {  //if the mouse is in the area
          if ((my >= ly - 5) && (my <= ly + 50))
          {
            draw_mouse();
          }
        }
      }
    }
  }
}

void _unit::draw(_unit* u)
{
  DATAFILE *ttemp;
  DATAFILE *qtemp;
  int ztemp;
  ttemp = p[u->color];
  qtemp = (DATAFILE *)ttemp[u->type].dat;
  ztemp = (u->direction - 1) * 2;
  if (player[u->color].powered == 1)
  {
    draw_sprite(sprite_buffer, (BITMAP *)powered_overlay[ztemp + powered_overlay_num(u->type) + int(u->frame)].dat, (u->tilex - scroll_x) * 40, (u->tiley - scroll_y) * 40);
  }
  if (u->ready == 1)
  {
    draw_sprite(sprite_buffer, (BITMAP *)qtemp[ztemp + int(u->frame)].dat, (u->tilex - scroll_x) * 40, (u->tiley - scroll_y) * 40);
  }  
  else
  {
    draw_sprite(sprite_buffer, (BITMAP *)darkunits[u->color * 18 + u->type].dat, (u->tilex - scroll_x) * 40, (u->tiley - scroll_y) * 40);
  }
  create_dirty(SPRITE, ((u->tilex - scroll_x) * 40), ((u->tiley - scroll_y) * 40), 41, 41);
}

void _unit::draw_status_symbols(BITMAP *bmp)
{
  DATAFILE *glb = (DATAFILE *)graphics[2].dat;
  if (submerged == 1)
  {  //show a little 's' icon if it is submerged
    draw_sprite(bmp, (BITMAP *)glb[6].dat, 14, 0);
  }
  if (ammo < 3)
  {  //show an ammo warning if low and not a transport unit
    if ((type != APC) && (type != T_COPTER) && (type != LANDER))
    {
      draw_sprite(bmp, (BITMAP *)glb[5].dat, 7, 0);
    }
  }
  if (gas < 20)
  {  //show a gas warning if low
    draw_sprite(bmp, (BITMAP *)glb[4].dat, 0, 0);
  }
  if (rounded_health(health) < 10)
  {  //if less than maximum health, show it at the bottom-right
    text_mode(-1);
    textprintf(bmp, font, 33, 30, BLACK, "%-1d", rounded_health(health));
    text_mode(0);
  }
}

void _unit::set_move(int d)
{
  int i = 0;
  while (i < 10)
  {
    if (movelist[i] == -1)
    {
      movelist[i] = d;
      i = 10;
    }
    i++;
  }
}

void _unit::set_moves(int list[10])
{
  int i = 0;
  while (i < 10)
  {
    movelist[i] = list[i];
    i++;
  }
  sort_movelist();
}

unitprops _unit::get_properties(int type)
{
  unitprops u;
  switch(type)
  {
    case ANTI_AIR:
      u.move = 6;
      u.movetype = M_TREAD;
      u.vision = 2;
      u.gas = 60;
      u.ammo = 9;
      u.attacktype = DIRECT;
      u.price = 8000;
      u.basetype = LAND;
      break;
    case APC:
      u.move = 6;
      u.movetype = M_TREAD;
      u.vision = 1;
      u.gas = 70;
      u.ammo = 0;
      u.attacktype = -1;
      u.price = 5000;
      u.basetype = LAND;
      break;
    case ARTILLERY:
      u.move = 5;
      u.movetype = M_TREAD;
      u.vision = 1;
      u.gas = 50;
      u.ammo = 9;
      u.attacktype = RANGED;
      u.price = 6000;
      u.basetype = LAND;
      break;
    case B_COPTER:
      u.move = 6;
      u.movetype = M_AIR;
      u.vision = 3;
      u.gas = 99;
      u.ammo = 8;  //ammo is 6 in Advance Wars, but I don't use secondary weapons
      u.attacktype = DIRECT;
      u.price = 9000;
      u.basetype = AIR;
      break;
    case B_SHIP:
      u.move = 5;
      u.movetype = M_SEA;
      u.vision = 2;
      u.gas = 99;
      u.ammo = 9;
      u.attacktype = RANGED;
      u.price = 28000;
      u.basetype = SEA;
      break;
    case BOMBER:
      u.move = 7;
      u.movetype = M_AIR;
      u.vision = 2;
      u.gas = 99;
      u.ammo = 9;
      u.attacktype = DIRECT;
      u.price = 22000;
      u.basetype = AIR;
      break;
    case CRUISER:
      u.move = 6;
      u.movetype = M_SEA;
      u.vision = 3;
      u.gas = 99;
      u.ammo = 9;
      u.attacktype = DIRECT;
      u.price = 18000;
      u.basetype = SEA;
      break;
    case FIGHTER:
      u.move = 8;
      u.movetype = M_AIR;
      u.vision = 2;
      u.gas = 99;
      u.ammo = 9;
      u.attacktype = DIRECT;
      u.price = 20000;
      u.basetype = AIR;
      break;
    case INFANTRY:
      u.move = 3;
      u.movetype = M_INFANTRY;
      u.vision = 2;
      u.gas = 99;
      u.ammo = 99;
      u.attacktype = DIRECT;
      u.price = 1000;
      u.basetype = LAND;
      break;
    case LANDER:
      u.move = 6;
      u.movetype = M_SEA;
      u.vision = 1;
      u.gas = 99;
      u.ammo = 0;
      u.attacktype = -1;
      u.price = 12000;
      u.basetype = SEA;
      break;
    case MD_TANK:
      u.move = 5;
      u.movetype = M_TREAD;
      u.vision = 1;
      u.gas = 50;
      u.ammo = 8;
      u.attacktype = DIRECT;
      u.price = 16000;
      u.basetype = LAND;
      break;
    case MECH:
      u.move = 2;
      u.movetype = M_MECH;
      u.vision = 2;
      u.gas = 70;
      u.ammo = 8;  //ammo is 3 in Advance Wars, but I don't use secondary weapons
      u.attacktype = DIRECT;
      u.price = 3000;
      u.basetype = LAND;
      break;
    case MISSILES:
      u.move = 4;
      u.movetype = M_TIRES;
      u.vision = 5;
      u.gas = 50;
      u.ammo = 6;
      u.attacktype = RANGED;
      u.price = 12000;
      u.basetype = LAND;
      break;
    case RECON:
      u.move = 8;
      u.movetype = M_TIRES;
      u.vision = 5;
      u.gas = 80;
      u.ammo = 99;
      u.attacktype = DIRECT;
      u.price = 4000;
      u.basetype = LAND;
      break;
    case ROCKETS:
      u.move = 5;
      u.movetype = M_TIRES;
      u.vision = 1;
      u.gas = 50;
      u.ammo = 6;
      u.attacktype = RANGED;
      u.price = 15000;
      u.basetype = LAND;
      break;
    case SUB:
      u.move = 5;
      u.movetype = M_SEA;
      u.vision = 5;
      u.gas = 60;
      u.ammo = 6;
      u.attacktype = DIRECT;
      u.price = 20000;
      u.basetype = SEA;
      break;
    case T_COPTER:
      u.move = 6;
      u.movetype = M_AIR;
      u.vision = 2;
      u.gas = 99;
      u.ammo = 0;
      u.attacktype = -1;
      u.price = 5000;
      u.basetype = AIR;
      break;
    case TANK:
      u.move = 6;
      u.movetype = M_TREAD;
      u.vision = 3;
      u.gas = 70;
      u.ammo = 9;
      u.attacktype = DIRECT;
      u.price = 7000;
      u.basetype = LAND;
      break;
  }
  return u;
}

int _unit::movestatus(int origvalue)
{
  if (moving == 0)
  {
    return -1;
  }
  else
  {
    return origvalue;
  }
}

void _unit::supply()
{
  unitprops z = get_properties(type);
  gas = z.gas;
  ammo = z.ammo;
}

int _unit::load_unit(_unit u)
{
  int i = 0;
  int loadok = 0;
  loadok = can_load_unit(u);
  if (load[i].loaded == 1)
  {
    i++;
  }
  if (loadok == 1)
  {
    load[i].loaded = 1;
    load[i].type = u.type;
    load[i].gas = u.gas;
    load[i].ammo = u.ammo;
    load[i].health = u.health;
    if (u.load[0].loaded == 1)
    {  //if this is a lander and the loaded unit is an APC with a passenger
      load[i].subload.loaded = 1;
      load[i].subload.type = u.load[0].type;
      load[i].subload.gas = u.load[0].gas;
      load[i].subload.ammo = u.load[0].ammo;
      load[i].subload.health = u.load[0].health;
    }
    return 0;
  }
  return -1;  //return -1 if unable to load unit for whatever reason
}

int _unit::can_load_unit(_unit u)
{
  int can = 0;
  int i = 0;
  while (i < maxload)
  {
    if (load[i].loaded == 0)
    {
      if ((type == APC) || (type == T_COPTER))
      {
        if ((u.type == INFANTRY) || (u.type == MECH))
        {
          can = 1;
        }
      }
      else if (type == LANDER)
      {
        if (u.basetype == LAND)
        {
          can = 1;
        }
      }
    }
    i++;
  }
  return can;
}

int _unit::can_unload_unit(int n)
{
  int tx, ty, type;
  if ((load[n].loaded == 1) && (get_set(map[tilex][tiley]) != 2))
  {  //if the transport unit is over sea, it can't unload no matter what
    type = load[n].type;
    tx = tilex + 1;
    ty = tiley;
    if (unit_unloadable_here(tx, ty, type) == 1)
    {
      return 1;
    }
    tx = tilex - 1;
    if (unit_unloadable_here(tx, ty, type) == 1)
    {
      return 1;
    }
    tx = tilex;
    ty = tiley + 1;
    if (unit_unloadable_here(tx, ty, type) == 1)
    {
      return 1;
    }
    ty = tiley - 1;
    if (unit_unloadable_here(tx, ty, type) == 1)
    {
      return 1;
    }
  }
  return 0;
}

void _unit::kill()
{
  int lx, ly;
  lx = x - (scroll_x * 40);
  ly = y - (scroll_y * 40);
  health = 0;
  exists = 0;
  unitmap[tilex][tiley] = -1;
  rectfill(sprite_buffer, lx, ly, lx + 40, ly + 40, TRANS);
  init_explode(lx, ly);
}

void _unit::set_tiles(int tx, int ty)
{
  unitmap[tilex][tiley] = -1;
  rectfill(sprite_buffer, (tilex - scroll_x) * 40, (tiley - scroll_y) * 40, ((tilex - scroll_x) * 40) + 40, ((tiley - scroll_y) * 40) + 40, TRANS);
  tilex = tx;
  tiley = ty;
  x = tilex * 40;
  y = tiley * 40;
  unitmap[tilex][tiley] = (100 * color) + number;
}

int powered_overlay_num(int type)
{
  int a = 0;
  int num = 0;
  while (a < type)
  {
    switch(a)
    {
      case INFANTRY:
      case MECH:
      case B_COPTER:
      case T_COPTER:
        num += 12;
        break;
      default:
        num += 8;
        break;
    }
    a++;
  }
  return num;
}
