#include "empire.h"

extern void draw_tiles(int scrollx, int scrolly, int editing, int x1, int y1, int w, int h, int keep_units);
extern void draw_tiles(int scrollx, int scrolly, int editing, int keep_units);
extern void animate_units(int forced);
extern void clear_dirty_rects();
extern int can_attack(_unit a, _unit d);
extern int get_set(int mapdat);
extern int get_tilenum(int mapdat);
extern int rounded_health(float h);

void do_damage(_unit& a, _unit& d);
void do_battle_animation(_unit a, _unit d, int n);
void init_explosion(int x, int y);
void do_explosions();
void revise_health(float ah, float dh);
void play_attack_sound(int utype, int dtype);
void apply_player_bonuses(float& basic, _unit a, _unit d);
int do_battle(_unit& a, _unit& d);
int basic_damage(int a, int d);
int defbonus(int tx, int ty);

BITMAP *flashy;

typedef struct _anims
{
  int x;
  int y;
  float frame;
  int exists;
} _anims;

_anims explode[2];

int do_battle(_unit& a, _unit& d)
{
  static int first = 1;
  static int second = 0;
  static int animx = 655;
  static int oldmx, oldmy;
  static int timer, ca;
  static int attacked_twice = 0;
  int done = 0;
  int temp;
  if (first == 1)
  {
    flashy = create_bitmap(640, 200);
    explode[0].exists = 0;
    explode[1].exists = 0;
    animx = 655;
    first = 0;
    second = 1;
    oldmx = mouse_x;
    oldmy = mouse_y;
    position_mouse(640, 480);
    set_mouse_range(639, 479, 639, 479);
    attacked_twice = 0;
    draw_mouse();
  }
  else if (second == 1)
  {
    if (animx > 0)
    {
      animx -= 15;
      do_battle_animation(a, d, animx);
    }
    else
    {
      second = 0;
      timer = 25;
      ca = 0;
    }
  }
  else
  {
    do_explosions();
    if (ca == 0)
    {
      if (timer > 0)
      {
        timer--;
      }
      else
      {
        do_damage(a, d);
        play_attack_sound(a.type, d.type);
        init_explosion(305, 255);
        revise_health(a.health, d.health);
        timer = 25;
        ca = 1;
      }
    }
    else if (ca == 1)
    {
      if (timer > 0)
      {
        timer--;
      }
      else
      {
        ca = 2;
        if ((d.health > 0) && (d.attacktype != RANGED) && (a.attacktype != RANGED))
        {  //if neither unit is a ranged-attack unit
          if (can_attack(d, a) == 1)
          {  //if the defender can counterattack, do so
            do_damage(d, a);
            play_attack_sound(d.type, a.type);
            init_explosion(235, 255);
            revise_health(a.health, d.health);
            ca = 3;
          }
        }
        if (ca == 2)
        {
          timer = 25;
        }
        else
        {
          timer = 50;
        }
      }
    }
    else
    {
      if (timer > 0)
      {
        timer--;
      }
      else
      {
        done = 1;
      }
    }
    if (done == 1)
    {
      if ((player[a.color].powered == 1) && (attacked_twice == 0))
      {  //if the attacking player is powered up
        if (character[player[a.color].number].power == 6)
        {  //if it's the "ranged 75% attack again" power
          if (a.attacktype == RANGED)
          {  //if it's a ranged unit that just attacked
            if (d.exists == 1)
            {  //if the defender is still alive
              temp = rand()%100;
              if (temp < 75)  //75% chance of getting this
              {
                attacked_twice = 1;  //set things so that the attack happens again
                ca = 0;
                timer = 25;
                return 1;
              }
            }
          }
        }
      }
      draw_tiles(scroll_x, scroll_y, 0, 0, 3, 16, 8, 1);
      set_mouse_range(0, 0, 639, 479);
      position_mouse(oldmx, oldmy);
      first = 1;
      destroy_bitmap(flashy);
      return 0;  //returning 0 ends the battle phase
    }
  }
  return 1;
}

int basic_damage(int a, int d)
{              //Anti-Air, APC, etc...
  int damage[324] = {45,  50,  50, 120,  0,  75,  0,  65, 105,  0, 10, 105,  55,  60,  55,  0, 120,  25,
      /*APC*/         0,   0,   0,   0,  0,   0,  0,   0,   0,  0,  0,   0,   0,   0,   0,  0,   0,   0,
      /*Artillery*/  75,  70,  75,   0, 40,   0, 65,   0,  90, 55, 45,  85,  80,  80,  80, 60,   0,  70,
      /*B-Copter*/   25,  60,  65,  65, 25,   0, 55,   0,  75, 25, 25,  75,  65,  55,  65, 25,  95,  55,
      /*B-Ship*/     85,  80,  80,   0, 50,   0, 95,   0,  95, 95, 55,  90,  90,  90,  85, 95,   0,  80,
      /*Bomber*/     95, 105, 105,   0, 75,   0, 85,   0, 110, 95, 95, 110, 105, 105, 105, 95,   0, 105,
      /*Cruiser*/     0,   0,   0, 115,  0,  65,  0,  55,   0,  0,  0,   0,   0,   0,   0, 90, 115,   0,
      /*Fighter*/     0,   0,   0, 100,  0, 100,  0,  55,   0,  0,  0,   0,   0,   0,   0,  0, 100,   0,
      /*Infantry*/    5,  14,  15,   7,  0,   0,  0,   0,  55,  0,  1,  45,  25,  12,  25,  0,  30,   5,
      /*Lander*/      0,   0,   0,   0,  0,   0,  0,   0,   0,  0,  0,   0,   0,   0,   0,  0,   0,   0,
      /*Md-Tank*/   105, 105, 105,  12, 10,   0, 55,   0, 105, 35, 55,  95, 105, 105, 105, 10,  45,  85,
      /*Mech*/       65,  75,  70,   9,  0,   0,  0,   0,  65,  0, 15,  55,  85,  85,  85,  0,  35,  55,
      /*Missiles*/    0,   0,   0, 120,  0, 100,  0, 100,   0,  0,  0,   0,   0,   0,   0,  0, 120,   0,
      /*Recon*/       4,  45,  45,  10,  0,   0,  0,   0,  70,  0,  1,  65,  28,  35,  55,  0,  35,   6,
      /*Rockets*/    85,  80,  80,   0, 55,   0, 85,   0,  95, 60, 55,  90,  90,  90,  85, 85,   0,  80,
      /*Sub*/         0,   0,   0,   0, 55,   0, 25,   0,   0, 95,  0,   0,   0,   0,   0, 55,   0,   0,
      /*T-Copter*/    0,   0,   0,   0,  0,   0,  0,   0,   0,  0,  0,   0,   0,   0,   0,  0,   0,   0,
      /*Tank*/       65,  75,  70,  10,  1,   0,  5,   0,  75, 10, 15,  70,  85,  85,  85,  1,  40,  55};
  return damage[(18 * a) + d];
}

int defbonus(int tx, int ty)
{
  int z = map[tx][ty];
  int s = get_set(z);
  int n = get_tilenum(z);
  switch(s)
  {
    case 0:  //Land
      switch(n)
      {
        case 2:
          return 2;
          break;
        case 3:
          return 1;
          break;
        case 4:
          return 4;
          break;
        default:
          return 0;
          break;
      }
      break;
    case 1:  //River
      return 0;
      break;
    case 2:  //Sea
      if (n == 1)  //Reef
      {
        return 1;
      }
      else
      {
        return 0;
      }
      break;
    case 3:  //Shoal
      return 0;
      break;
    case 4:  //Building
      return 3;
      break;
  }
}

void do_damage(_unit& a, _unit& d)
{
  float basic = float(basic_damage(a.type, d.type)) * a.health / 10;
  int def = defbonus(d.tilex, d.tiley);
  if (d.basetype == AIR)
  {  //air units have no terrain defense bonus
    def = 0;
  }
  apply_player_bonuses(basic, a, d);
  float total = basic - ((basic * float(def)) / 10);
  a.ammo--;
  if (player[d.color].powered == 0)
  {  //power does not increase on the turn the power is used
    player[d.color].power += (int(total) * d.price) / 10000;
  }
  if (player[d.color].power > 1000)
  {
    player[d.color].power = 1000;
  }
  if (player[a.color].powered == 0)
  {  //power does not increase on the turn the power is used
    player[a.color].power += (int(total) * d.price) / 20000;
  }
  if (player[a.color].power > 1000)
  {
    player[a.color].power = 1000;
  }
  d.health -= total / 10;
  if (d.health <= 0)
  {
    d.kill();
  }
}

void do_battle_animation(_unit a, _unit d, int n)
{
  static int first = 1;
  static int oldn;
  int def, i;
  DATAFILE *glb = (DATAFILE *)graphics[2].dat;
  if (first == 1)
  {
    DATAFILE *bigunits = (DATAFILE *)units[4].dat;
    clear_to_color(flashy, WHITE);
    def = defbonus(a.tilex, a.tiley);
    if (a.basetype == AIR)
    {  //no terrain defense boost for air units
      def = 0;
    }
    i = 0;
    while (i < def)
    {
      draw_sprite(flashy, (BITMAP *)glb[7].dat, 100 + (25 * i), 0);
      i++;
    }
    draw_sprite_h_flip(flashy, (BITMAP *)bigunits[(a.type * 4) + a.color].dat, 100, 25);
    text_mode(-1);
    textprintf_centre(flashy, (FONT *)glb[2].dat, 285, 150, BLACK, "%-1d", rounded_health(a.health));
    def = defbonus(d.tilex, d.tiley);
    if (d.basetype == AIR)
    {
      def = 0;
    }
    i = 0;
    while (i < def)
    {
      draw_sprite(flashy, (BITMAP *)glb[7].dat, 390 + (25 * i), 0);
      i++;
    }
    draw_sprite(flashy, (BITMAP *)bigunits[(d.type * 4) + d.color].dat, 390, 25);
    textprintf_centre(flashy, (FONT *)glb[2].dat, 355, 150, BLACK, "%-1d", rounded_health(d.health));
    text_mode(0);
    draw_sprite(back_buffer, flashy, 0, 140);
    rectfill(sprite_buffer, 0, 140, 640, 340, TRANS);
    clear_dirty_rects();  //make sure flashy isn't displayed immediately by getting
    oldn = n;             //rid of all dirty rectangles to be drawn to the screen
    first = 0;
  }
  create_dirty(BACK, 640 - oldn, 140, oldn - n, 200);
  oldn = n;
  if (n <= 0)
  {
    first = 1;
  }
}

void init_explosion(int x, int y)
{
  int i = 0;
  while (i < 2)
  {
    if (explode[i].exists == 0)
    {
      explode[i].exists = 1;
      explode[i].x = x;
      explode[i].y = y;
      explode[i].frame = 0;
      i = 2;
    }
    i++;
  }
}

void do_explosions()
{
  DATAFILE *exp1 = (DATAFILE *)explosions[0].dat;
  int i = 0;
  while (i < 2)
  {
    if (explode[i].exists == 1)
    {
      explode[i].frame += .75;
      blit(back_buffer, sprite_buffer, explode[i].x, explode[i].y, explode[i].x, explode[i].y, 100, 70);
      if (int(explode[i].frame) > 13)
      {
        explode[i].exists = 0;
        rectfill(sprite_buffer, explode[i].x, explode[i].y, explode[i].x + 100, explode[i].y + 70, TRANS);
        create_dirty(BACK, explode[i].x, explode[i].y, 100, 70);
      }
      else
      {
        draw_sprite(sprite_buffer, (BITMAP *)exp1[int(explode[i].frame)].dat, explode[i].x, explode[i].y);
      }
      create_dirty(SPRITE, explode[i].x, explode[i].y, 100, 70);
    }
    i++;
  }
}

void revise_health(float ah, float dh)
{
  DATAFILE *glb = (DATAFILE *)graphics[2].dat;
  rectfill(back_buffer, 330, 290, 380, 340, WHITE);
  rectfill(back_buffer, 260, 290, 310, 340, WHITE);
  text_mode(-1);
  textprintf_centre(back_buffer, (FONT *)glb[2].dat, 355, 290, BLACK, "%-1d", rounded_health(dh));
  create_dirty(BACK, 330, 290, 50, 50);
  textprintf_centre(back_buffer, (FONT *)glb[2].dat, 285, 290, BLACK, "%-1d", rounded_health(ah));
  create_dirty(BACK, 260, 290, 50, 50);
  text_mode(0);
}

void play_attack_sound(int utype, int dtype)
{
  switch(utype)
  {
    case ANTI_AIR:
      play_sound(AAFIRE);
      break;
    case ARTILLERY:
      play_sound(MDTANKFIRE);
      break;
    case B_COPTER:
      play_sound(MISSILE);
      break;
    case B_SHIP:
      play_sound(MDTANKFIRE);
      break;
    case BOMBER:
      play_sound(BOMBS);
      break;
    case CRUISER:
      if ((dtype == FIGHTER) || (dtype == BOMBER) || (dtype == T_COPTER) || (dtype == B_COPTER))
      {
        play_sound(AUTOGUN);
      }
      else
      {
        play_sound(MDTANKFIRE);
      }
      break;
    case FIGHTER:
      play_sound(MISSILE);
      break;
    case INFANTRY:
      play_sound(AUTOGUN);
      break;
    case MD_TANK:
      play_sound(MDTANKFIRE);
      break;
    case MECH:
      if (dtype == INFANTRY)
      {
        play_sound(AUTOGUN);
      }
      else
      {
        play_sound(MISSILE);
      }
      break;
    case MISSILES:
      play_sound(MISSILE);
      break;
    case RECON:
      play_sound(AUTOGUN);
      break;
    case ROCKETS:
      play_sound(MISSILE);
      break;
    case SUB:
      play_sound(TORPEDO);
      break;
    case TANK:
      play_sound(TANKFIRE);
      break;
  }
}

void apply_player_bonuses(float& basic, _unit a, _unit d)
{
  switch(character[player[a.color].number].strength)
  {
    case 0:
      if (a.attacktype == DIRECT)
      {
        basic += 5;
      }
      break;
    case 1:
      if (a.attacktype == RANGED)
      {
        basic += 5;
      }
      break;
    case 2:
      if (a.movetype == LAND)
      {
        basic += 5;
      }
      break;
    case 3:
      if (a.movetype == AIR)
      {
        basic += 5;
      }
      break;
    case 4:
      if (a.movetype == SEA)
      {
        basic += 5;
      }
      break;
  }
  switch(character[player[a.color].number].weakness)
  {
    case 0:
      if (a.attacktype == DIRECT)
      {
        basic -= 5;
      }
      break;
    case 1:
      if (a.attacktype == RANGED)
      {
        basic -= 5;
      }
      break;
    case 2:
      if (a.movetype == LAND)
      {
        basic -= 5;
      }
      break;
    case 3:
      if (a.movetype == AIR)
      {
        basic -= 5;
      }
      break;
    case 4:
      if (a.movetype == SEA)
      {
        basic -= 5;
      }
      break;
  }
  switch(character[player[d.color].number].strength)
  {
    case 2:
      if (d.movetype == LAND)
      {
        basic -= 5;
      }
      break;
    case 3:
      if (d.movetype == AIR)
      {
        basic -= 5;
      }
      break;
    case 4:
      if (d.movetype == SEA)
      {
        basic -= 5;
      }
      break;
  }
  switch(character[player[d.color].number].weakness)
  {
    case 2:
      if (d.movetype == LAND)
      {
        basic += 5;
      }
      break;
    case 3:
      if (d.movetype == AIR)
      {
        basic += 5;
      }
      break;
    case 4:
      if (d.movetype == SEA)
      {
        basic += 5;
      }
      break;
  }  
  if (player[a.color].powered == 1)
  {
    switch(character[player[a.color].number].power)
    {  //if the attacker has...
      case 1:  //more powerful direct attacks
        if (a.attacktype == DIRECT)
        {
          basic += 15;
        }
        else
        {
          basic += 2;  //modest power gain for other unit types
        }
        break;
      case 2:  //more powerful ranged attacks
        if (a.attacktype == RANGED)
        {
          basic += 15;
        }
        else
        {
          basic += 2;
        }
        break;
      case 4:  //refreshed units
        basic -= 10;  //refreshed units deal less damage
        break;
      default:  //if it's powered in another way
        basic += 2;  //modest power gain for the units
        break;
    }
  }
  if (player[d.color].powered == 1)
  {
    switch(character[player[d.color].number].power)
    {  //if the defender has...
      case 4:  //refreshed units
        basic += 10;  //refreshed units take more damage
        break;
      default:
        basic -= 2;  //for other powers, powered units take less damage
        break;
    }
  }
  if (basic < 0)
  {
    basic = 0;
  }  
}
