#include "empire.h"
#include "ranges.h"
#include "empai_path.h"

const int action_move    = 0;
const int action_attack  = 1;
const int action_capture = 2;
const int action_load    = 3;
const int action_unload1 = 4;
const int action_unload2 = 5;
const int action_standby = 6;
const int action_supply  = 7;
const int action_merge   = 8;

extern int mapmovable[20][20];
extern int tempmap[50][50];
extern int pathmap[50][50];

extern void animate_units(int forced);
extern void apply_player_bonuses(float& basic, _unit a, _unit d);
extern void draw_tiles(int scrollx, int scrolly, int editing, int keep_units);
extern void draw_tiles(int scrollx, int scrolly, int editing, int x1, int y1, int w, int h, int keep_units);
extern void play_moving_sound(int utype);
extern void do_explodes();
extern void transform_buildings(int plyr, int plyr2);
extern void supply_units(_unit u);
extern void draw_playerstats(int plyr);
extern void do_power();
extern void scroll_to_location(int x, int y);
extern void capture_building(_unit* u);
extern void merge_units(_unit* merger, int tx, int ty);
extern int basic_damage(int a, int d);
extern int defbonus(int tx, int ty);
extern int building_here(int tx, int ty);
extern int unit_here_thorough(int plyr, int tx, int ty, int ignore_n);
extern int can_attack(_unit a, _unit d);
extern int do_battle(_unit& a, _unit& d);
extern int rounded_health(float h);
extern int get_tilenum(int mapdat);
extern int rounded_health(float h);

extern string unit_name(int type);

typedef struct _action
{
  int type;
  _loc loc;
} _action;

typedef struct _actionset
{
  _action action[3];
} _actionset;

typedef struct _buildorder
{
  int unit;
  float ratio;
} _buildorder;

bool enemy_threat(int plyr);
bool enemy_within_radius(int plyr, int center_x, int center_y, int r);
void act(_unit& u, _action a);
void make_new_units(int plyr);
void set_best_path(_unit u, int tx, int ty);
void summon_empty_copter(int plyr, int tx, int ty);
void summon_lander(int plyr, int tx, int ty);
void unsummon_copter(int plyr, int tx, int ty);
int get_damage_cost(_unit a, _unit d);
int can_get_to_aitarget(_unit a, _aitarget d);
int any_unit_here(int tx, int ty);
int next_to_enemy(int plyr, int tx, int ty);
int needy(int unit_id);
int check_can_build(int plyr, int price[], int num[]);
int next_to_needy_friendly(int plyr, int tx, int ty);
int copter_summoned(int plyr, int tx, int ty);
int lander_summoned(int plyr, int tx, int ty);
int intmax(int a, int b);
int can_unload_from_here(int x, int y, int mountains);
int unit_heading_here(int plyr, int x, int y);
float get_ratio(int i, int weight, int limit, int num);
_actionset ponder_action(_unit& u);
_aitarget find_best_target(_unit u);
_aitarget aitarget_here(_unit u, int tx, int ty);

int in_battle, atk, def;
_aibuild build[4][18];
vector<_unit*> lander;
vector<_loc> base;
_loc capital;
extern vector<_connectedlocs> beaches;

int do_ai(int plyr)
{
  static int first = 1;
  static int i = 0;
  static int anum = 0;
  static int t = 0;
  static _actionset a;
  static int draw_stats, last_statpos;
  static int initial_delay, unit_delay;
  int t1, t2, t3, t4;
  int unit_moving;
  int powerflash = 0;
  _loc temploc;
  if (first == 1)
  {
    lander.clear();
    player[plyr].sort_units();    
    i = 0;
    while (i < 50)
    {
      if (player[plyr].unit[i].exists == 1)
      {
        if (player[plyr].unit[i].type == LANDER)
        {  //this creates a vector of pointers to landers, handy later on
          lander.push_back(&player[plyr].unit[i]);
        }
      }
      i++;
    }
    t2 = 0;
    while (t2 < h)
    {
      t1 = 0;
      while (t1 < l)
      {
        t3 = building_here(t1, t2);
        if (t3 > 3)
        {
          t3 -= 3;
          if ((t3 / 5 == plyr + 1) && (t3 % 5 > 0))
          {  //if it belongs to the player and produces units
            temploc.x = t1;
            temploc.y = t2;
            base.push_back(temploc);  //create a vector of base locations
          }
        }
        else if (t3 == plyr)
        {  //mark the location of the player's HQ
          capital.x = t1;
          capital.y = t2;
        }
        t1++;
      }
      t2++;
    }
    i = 0;
    t = 0;
    first = 0;
    anum = -2;
    in_battle = 0;
    atk = -1;
    def = -1;
    draw_stats = 0;
    last_statpos = -1;
    initial_delay = 0;
    set_mouse_range(639, 479, 639, 479);
    draw_mouse();
    if (player[plyr].power == 1000)
    {
      if (character[player[pturn].number].power != 4)
      {  //if the power is not the "refresh units" one
        player[plyr].powered = 1;
        player[plyr].power = 0;
        do_power();
        powerflash = 1;  //start the power animation
        play_sound(BLAST);
        draw_tiles(scroll_x, scroll_y, 0, 1);
      }
    }
    counter = 0;
  }
  if (initial_delay < 15)
  {  //have a little delay before the units start doing stuff
    initial_delay++;
  }
  else if (in_battle == 0)
  {
    do_explodes();
    animate_units(0);
    if (draw_stats != -1)
    {
      switch(last_statpos)
      {
        case 1:
          draw_tiles(scroll_x, scroll_y, 0, 0, 0, 4, 2, 1);
          break;
        case 2:
          draw_tiles(scroll_x, scroll_y, 0, 12, 0, 4, 2, 1);
          break;
      }
      draw_playerstats(plyr + (draw_stats * 10));  //see draw_playerstats for details on this
      last_statpos = draw_stats;
      draw_stats = -1;
    }
    if (i < 50)
    {
      _unit &z = player[plyr].unit[i];
      if (z.exists == 1)
      {
        if (z.ready == 1)
        {
          if (unit_delay < 15)
          {  //have a little delay between units as well
            unit_delay++;
          }
          else if (anum == -2)
          {
            scroll_to_location(z.tilex, z.tiley);  //focus on the unit
            clear_to_color(sprite_buffer, TRANS);
            draw_tiles(scroll_x, scroll_y, 0, 1);
            draw_range(plyr, i);  //this is for later calculations, as well as visuals
            animate_units(1);
            t1 = (z.tilex - scroll_x) * 40;
            t2 = (z.tiley - scroll_y) * 40;
            switch(z.color)
            {
              case 0:
                t3 = ORANGE;
                break;
              case 1:
                t3 = BLUE;
                break;
              case 2:
                t3 = GREEN;
                break;
              case 3:
                t3 = YELLOW;
                break;
            }  //draw a rectangle around the unit, colored the same as the unit's team
            rect(sprite_buffer, t1 + 1, t2 + 1, t1 + 39, t2 + 39, t3);
            anum = -1;
          }
          else if (anum == -1)
          {  //if it is the first action for the unit, find good actions to do
            a = ponder_action(z);
            anum = 0;
            t = 0;
            counter = 0;  //this may have taken a while, but nothing happened on
          }               //screen, so just set the counter like it took no time
          else if (t < 25)  //the unit's range is displayed for 25 logic loops (.5 seconds)
          {  //in other words, it shows the range while thinking, then pauses before acting
            t++;
            if (t == 25)
            {  //if it has finished with the pause, clear the range from the screen
              t1 = (z.tilex - scroll_x) - (z.move + 1);
              t2 = (z.tiley - scroll_y) - (z.move + 1);
              if (t1 < 0) t1 = 0;
              if (t2 < 0) t2 = 0;
              draw_tiles(scroll_x, scroll_y, 0, t1, t2, (z.move + 1) * 2, (z.move + 1) * 2, 1);
              if (z.tilex - scroll_x < 4)
              {
                draw_stats = 2;
              }
              else
              {
                draw_stats = 1;
              }
            }
          }
          else
          {
            unit_moving = z.movestatus(1);
            if (unit_moving != 1)
            {  //if the unit has is finished with an action or starting the first
              switch(anum)
              {
                case 0:
                case 1:
                case 2:
                  act(player[plyr].unit[i], a.action[anum]);
                  anum++;
                  if (z.exists == 0)
                  {  //if a battle or being loaded into a transport causes it to disappear
                    z.ready = 0;
                    anum = -2;
                    t = 0;
                  }
                  break;
                case 3:  //if the final action has just been done, this unit is finished
                  z.ready = 0;
                  anum = -2;
                  t = 0;
                  break;
              }
            }
          }
        }
        else  //if the unit is not ready, go to the next one
        {
          i++;
          unit_delay = 0;
        }
      }
      else  //if the unit does not exist, go to the next one
      {
        i++;
        unit_delay = 0;
      }
    }
    if ((i == 50))// && (z.ready != 1))  //if it has just finished with the 50th unit
    {
      if (player[plyr].power == 1000)
      {
        if (character[player[pturn].number].power == 4)
        {  //if the power is the "refresh units" one
          player[plyr].powered = 1;
          player[plyr].power = 0;
          do_power();
          powerflash = 1;  //start the power animation
          play_sound(BLAST);
          draw_tiles(scroll_x, scroll_y, 0, 1);
          i = 0;  //go back through all the units
        }
      }
      if (t == 0)
      {
        make_new_units(plyr);
        counter = 0;  //this also tends to take a while, but has no on-screen effect
        t++;
      }
      else if (t < 35)
      {  //pause for a little over half a second after the units are made
        t++;
      }
      else
      {
        first = 1;
        t = 0;
        set_mouse_range(0, 0, 639, 479);
        switch(last_statpos)
        {  //undraw the player stats
          case 1:
            draw_tiles(scroll_x, scroll_y, 0, 0, 0, 4, 2, 1);
            break;
          case 2:
            draw_tiles(scroll_x, scroll_y, 0, 12, 0, 4, 2, 1);
            break;
        }
        return 1;  //indicate that it is done
      }
    }
  }
  else  //if there is a battle animation going on
  {
    t1 = atk / 100;
    t2 = atk % 100;
    t3 = def / 100;
    t4 = def % 100;
    in_battle = do_battle(player[t1].unit[t2], player[t3].unit[t4]);
    return 0;
  }
  if (powerflash != 1)
  {
    return 0;  //indicate that it is not finished
  }
  else
  {
    return 10;
  }
}

_actionset ponder_action(_unit& u)
{
  _actionset aset;
  _action a[3];
  _loc d;
  _aitarget t;
  int temp1, temp2, temp3, temp4;
  a[0].type = action_standby;
  a[0].loc.x = -1;
  a[0].loc.y = -1;
  a[1].type = action_standby;
  a[1].loc.x = -1;
  a[1].loc.y = -1;
  a[2].type = action_standby;  //third action only used for unloading landers
  a[2].loc.x = -1;
  a[2].loc.y = -1;
  ofstream debug("time.txt", ios::app);
  debug << "Unit type: " << unit_name(u.type) << "\n";
  debug << "Start time: " << counter << "\n";
  if ((u.type == INFANTRY) || (u.type == MECH))
  {
    if (u.capturing != -1)  //if it is already capturing some building
    {
      a[0].type = action_capture;
      a[0].loc.x = u.tilex;
      a[0].loc.y = u.tiley;
    }
    else
    {
      d = capturable_building(u);
      if (d.x != -1)  //if there is a capturable building in range
      {
        if ((d.x == u.tilex) && (d.y == u.tiley))
        {  //if it is already on the capturable building
          a[0].type = action_capture;
          a[0].loc = d;
        }
        else
        {
          a[0].type = action_move;
          a[0].loc = d;
          a[1].type = action_capture;
          a[1].loc = d;
        }
      }
    }
  }
  if ((a[0].type == action_standby) && (u.attacktype != -1))
  {  //if the unit can attack and isn't going to capture a building
    if (u.attacktype == RANGED)
    {
      t = find_best_target(u);
      if (t.type != -1)  //if a target has been found, the unit will attack
      {
        a[0].type = action_attack;
        a[0].loc = t.loc;
      }
    }
    else  //a direct attacker
    {
      t = find_best_target(u);
      if (t.type != -1)
      {
        d = loc_to_attack(u, t);
        if ((u.tilex == d.x) && (u.tiley == d.y))
        {  //if the unit is already in the best position to attack
          a[0].type = action_attack;
          a[0].loc = t.loc;
        }
        else
        {
          a[0].type = action_move;
          a[0].loc = d;
          a[1].type = action_attack;
          a[1].loc = t.loc;
        }
      }
    }
  }
  if (a[0].type == action_standby)
  {  //if there were no units it could attack this turn
    if ((u.health < 7) || (u.gas < 15) || ((u.ammo < 3) && (u.attacktype != -1)))
    {  //if the unit has taken serious damage or is low on gas or ammo (and can attack)
      d = closest_free_building(u.color, u.number, u.movetype, u.move, u.basetype, u.tilex, u.tiley);
      if (d.x != -1)  //if there is a free friendly building, head for it
      {
        if ((d.x != u.tilex) || (d.y != u.tiley))
        {  //if it isn't already sitting on the best place
          a[0].type = action_move;
          a[0].loc = d;
        }
      }
      if (u.health < 5)
      {  //if the unit is very low on health, look for a merge instead
        d = unhealthy_unit_nearby(u.color, u.type, u.tilex, u.tiley);
        if (d.x != -1)
        {
          a[0].type = action_move;
          a[0].loc = d;
          a[1].type = action_merge;
          a[1].loc = d;
        }
      }
    }
  }
  if (a[0].type == action_standby)  
  {  //if it didn't need to get fixed or gassed up 
    if ((u.type == INFANTRY) || (u.type == MECH))
    {  //if it can capture things, head for the closest capturable building
      d = closest_move_to_enemy_building(u.color, u.number, u.movetype, u.move, u.tilex, u.tiley, 1);
      if (d.x != -1)
      {
        if ((d.x != u.tilex) || (d.y != u.tiley))
        { //if the closest move is not where it already is
          a[0].type = action_move;
          a[0].loc = d;
        }
      }
    }
    else if ((u.type != APC) && (u.type != T_COPTER) && (u.type != LANDER))
    {
      if (u.attacktype == DIRECT)
      {  //if it is a direct attacker, head for the nearest enemy unit
        d = closest_move_to_enemy_unit(u.color, u.number, u.movetype, u.move, u.tilex, u.tiley);
        if (d.x != -1)
        {
          if ((d.x != u.tilex) || (d.y != u.tiley))
          { //if the closest move is not where it already is
            a[0].type = action_move;
            a[0].loc = d;
          }
        }
        else  //no enemy units, head for nearest enemy base
        {
          d = closest_move_to_enemy_building(u.color, u.number, u.movetype, u.move, u.tilex, u.tiley, 0);
          if (d.x != -1)
          {
            if ((d.x != u.tilex) || (d.y != u.tiley))
            { //if the closest move is not where it already is
              a[0].type = action_move;
              a[0].loc = d;
            }
          }
        }
      }
      else
      {  //if it is a ranged attacker
        temp1 = u.move;
        if (u.gas < temp1)
        {
          temp1 = u.gas;
        }
        d = best_target_for_ranged_attack(u.color, u.number, u.tilex, u.tiley, get_rangemin(u.type), get_rangemax(u.type));
        if (d.x != -1)
        {
          temp2 = d.x;
          temp3 = d.y;
          d = closest_move_to_destination(u.color, u.number, u.movetype, temp1, u.tilex, u.tiley, temp2 * 100 + temp3, get_rangemax(u.type));
          if (d.x == -1)
          {
            d = closest_move_to_destination(u.color, u.number, u.movetype, temp1, u.tilex, u.tiley, temp2 * 100 + temp3, get_rangemin(u.type));
          }
        }
        if (d.x != -1)
        {  
          if ((d.x != u.tilex) || (d.y != u.tiley))
          { //if the closest move is not where it already is
            a[0].type = action_move;
            a[0].loc = d;
          }
        }
      }
    }
    else if (u.type == APC)
    {
      temp3 = u.move;
      if (temp3 > u.gas)
      {
        temp3 = u.gas;
      }
      if (u.load[0].loaded == 1)
      {  //if it's carrying a unit
        d = closest_move_to_enemy_building(u.color, u.number, u.movetype, temp3, u.tilex, u.tiley, 1);
        if (d.x != -1)
        {
          temp1 = d.x;
          temp2 = d.y;
          d = closest_move_to_destination(u.color, u.number, u.movetype, temp3, u.tilex, u.tiley, (d.x * 100) + d.y, 1);
          if (d.x != -1)
          {
            a[0].type = action_move;
            a[0].loc = d;
            if (tile_distance(d.x, d.y, temp1, temp2) == 1)
            {  //if the final move brings it one move away from the building
              a[1].type = action_unload1;
              a[1].loc.x = temp1;
              a[1].loc.y = temp2;
            }
          }
        }
        else
        {
          d = closest_move_to_enemy_unit(u.color, u.number, u.movetype, temp3, u.tilex, u.tiley);
          if (d.x != -1)
          {
            temp1 = d.x;
            temp2 = d.y;
            d = closest_move_to_destination(u.color, u.number, u.movetype, temp3, u.tilex, u.tiley, (d.x * 100) + d.y, 2);
            if (d.x != -1)
            {
              a[0].type = action_move;
              a[0].loc = d;
            }
          }
          else
          {  //if it can't get to an enemy or enemy location
            if (friendly_unit_maker_here(u.tilex, u.tiley, u.color) == true)
            {
              d = a_free_space(u.color, u.movetype, u.tilex, u.tiley);
              if (d.x != -1)
              {
                a[0].type = action_move;
                a[0].loc = d;
              }
            }
          } 
        }
        if (a[1].type == action_standby)
        {  //try to unload whenever it has something loaded
          if (a[0].type == action_move)
          {
            d = unloadable_point(a[0].loc.x, a[0].loc.y, 1);
          }
          else
          {
            d = unloadable_point(u.tilex, u.tiley, 1);
          }
          if (d.x != -1)
          {
            if (a[0].type == action_standby)
            {
              a[0].type = action_unload1;
              a[0].loc = d;
            }
            else
            {
              a[1].type = action_unload1;
              a[1].loc = d;
            }
          }
        }
      }
      else
      {  //if not loaded, resupply any units that need it
        d = closest_move_to_needy_friendly(u.color, u.number, u.movetype, temp3, u.tilex, u.tiley);
        if (d.x != -1)
        {
          if ((d.x != u.tilex) || (d.y != u.tiley))
          {
            a[0].type = action_move;
            a[0].loc = d;
            if (next_to_needy_friendly(u.color, d.x, d.y) == 1)
            {
              a[1].type = action_supply;
              a[1].loc = d;
            }
          }
          else
          {
            a[0].type = action_supply;
            a[0].loc = d;
          }
        }
      }
      if (a[1].type == action_standby)
      {  //if doing nothing, resupply whatever friendly units are around
        d.x = u.tilex;
        d.y = u.tiley;
        a[1].type = action_supply;
        a[1].loc = d;
      }
    }
    else if (u.type == T_COPTER)
    {
      if (u.moving_towards == -1)
      {
        if (u.load[0].loaded != 0)
        {  //if the copter has a passenger
          d = nearest_enemy_building(u.color, u.tilex, u.tiley);
          if (d.x != -1)
          {
            u.moving_towards = (d.x * 100) + d.y;
          }
        }   
      }
      temp4 = u.move;
      if (temp4 > u.gas)
      {
        temp4 = u.gas;
      }
      temp3 = 0;
      while ((u.moving_towards != -1) && (temp3 < 2))
      {
        temp3++;
        temp1 = u.moving_towards / 100;
        temp2 = u.moving_towards % 100;
        if (any_unit_here(temp1, temp2) == -1)
        {  //if the target space is empty
          d = closest_move_to_destination(u.color, u.number, u.movetype, temp4, u.tilex, u.tiley, u.moving_towards, 1);
          if (d.x != -1)
          {
            a[0].type = action_move;
            a[0].loc = d;
            if ((tile_distance(temp1, temp2, d.x, d.y) == 1) && (u.load[0].loaded == 1))
            {  //if the move takes it to one away from the carried unit's target
              a[1].type = action_unload1;
              a[1].loc.x = temp1;
              a[1].loc.y = temp2;
              u.moving_towards = -1;
            }
          }
          else
          {
            if ((tile_distance(temp1, temp2, u.tilex, u.tiley) == 1) && (u.load[0].loaded == 1))
            {  //if it is already one away from the carried unit's target
              a[0].type = action_unload1;
              a[0].loc.x = temp1;
              a[0].loc.y = temp2;
              u.moving_towards = -1;
            }
          }
        }
        else
        {  //if there is a unit on that space
          d = a_free_space(u.color, u.movetype, temp1, temp2);
          if (d.x != -1)
          {  //the new target is the closest empty space near the target
            u.moving_towards = (d.x * 100) + d.y;
          }
        }
      }
    }
    else
    {  //if the unit is a lander
      if (u.moving_towards == -1)
      {  //if it has no current destination
        if ((u.load[0].loaded == 1) || (u.load[1].loaded == 1))
        {  //if it has a passenger
          temp1 = 0;
          if ((u.load[0].loaded == 1) && (u.load[1].loaded == 1))
          {
            temp1 = 1;
          }
          else if (unit_heading_here(u.color, u.tilex, u.tiley) == -1)
          {
            temp1 = 1;
          }
          if (temp1 == 1)
          {  //leave shore if it is full or is not awaiting a second unit
            temp3 = 0;
            if (u.load[0].loaded == 1)
            {
              if ((u.load[0].type == INFANTRY) || (u.load[0].type == MECH))
              {
                temp3 = 1;
              }
            }
            if (u.load[1].loaded == 1)
            {
              if ((u.load[1].type == INFANTRY) || (u.load[1].type == MECH))
              {
                temp3 = 1;
              }
            }
            d = closest_enemy_beach(u.color, u.tilex, u.tiley, temp3);
            if (d.x != -1)
            {
              u.moving_towards = (d.x * 100) + d.y;
            }
          }
        }
      }
      if (u.moving_towards != -1)
      {
        temp1 = u.moving_towards / 100;
        temp2 = u.moving_towards % 100;
        d = closest_move_to_destination(u.color, u.number, M_SEA, u.move, u.tilex, u.tiley, u.moving_towards, 0);
        if (d.x != -1)
        {
          a[0].type = action_move;
          a[0].loc = d;
          if ((d.x == temp1) && (d.y == temp2))
          {  //if it reaches its destination at the end of the move
            u.moving_towards = -1;
            temp3 = 1;
            if (u.load[0].loaded == 1)
            {
              if ((u.load[0].type == INFANTRY) || (u.load[0].type == MECH))
              {
                d = unloadable_point(temp1, temp2, 1);
              }
              else
              {
                d = unloadable_point(temp1, temp2, 0);
              }
              if (d.x != -1)
              {
                a[temp3].type = action_unload1;
                a[temp3].loc = d;
                temp3++;
              }
            }
            if (u.load[1].loaded == 1)
            {
              if (temp3 == 1)
              {  //if there wasn't a unit in load[0]
                d.x = -1;
                d.y = -1;
              }
              if ((u.load[1].type == INFANTRY) || (u.load[1].type == MECH))
              {
                d = unloadable_point(temp1, temp2, 1, d);
              }
              else
              {
                d = unloadable_point(temp1, temp2, 0, d);
              }
              if (d.x != -1)
              {
                a[temp3].type = action_unload2;
                a[temp3].loc = d;
              }
            }
          }
        }
        else
        {  //if it can't get to the destination, give up
          u.moving_towards = -1;
        }
      }
    }
  }
  if (a[0].type == action_standby)
  {
    if (friendly_unit_maker_here(u.tilex, u.tiley, u.color) == true)
    {
      if (u.type != LANDER)
      {  //unless the unit's a lander, move off the unit-producing building
        d = a_free_space(u.color, u.movetype, u.tilex, u.tiley);
        if (d.x != -1)
        {
          a[0].type = action_move;
          a[0].loc = d;
        }
      }
      else
      {  //if it's a lander, move to a reachable friendly beach or stay at port
        d = reachable_friendly_beach(u.color, u.number, u.tilex, u.tiley, u.move);
        if (d.x != -1)
        {
          a[0].type = action_move;
          a[0].loc = d;
        }
      }
    }
  }
  if ((u.type == INFANTRY) || (u.type == MECH))
  {
    if ((a[0].type == action_move) && (u.moving_towards != -1))
    {  //if it's moving somewhere
      if (tile_distance(u.moving_towards % 100, u.moving_towards / 100, u.tilex, u.tiley) > 5)
      {  //if it's going to take more than one turn to get there
        d = closest_move_to_destination(u.color, u.number, M_TREAD, u.move, u.tilex, u.tiley, u.moving_towards, 1);
        if ((d.x != -1) && ((d.x != u.tilex) || (d.y != u.tiley)))
        {  //if an APC can get to the unit's target
          d = empty_APC_nearby(u.color, u.number, u.movetype, u.move, u.tilex, u.tiley);
          if (d.x != -1)
          {  //if there is an empty APC reachable this turn
            temp1 = any_unit_here(d.x, d.y);
            u.moving_towards = -1;
            a[0].type = action_move;
            a[0].loc = d;
            a[1].type = action_load;
            a[1].loc = d;
          }
        }  //the unit now moves to the APC
      }
    }
    else if (a[0].type == action_standby)
    {
      d = closest_move_to_available_lander(u.color, u.number, u.movetype, temp1, u.tilex, u.tiley);
      if (d.x == -1)
      {  //if there isn't a lander available, check for an APC
        d = closest_move_to_empty_APC(u.color, u.number, u.movetype, u.move, u.tilex, u.tiley);
        if (d.x != -1)
        {  //if there is an empty APC available
          a[0].type = action_move;
          a[0].loc = d;
          temp1 = unit_here_thorough(u.color, d.x, d.y, u.number);
          if (temp1 != -1)
          {  //if there is a unit at the final move point, it must be the APC
            a[1].type = action_load;
            a[1].loc = d;
          }
        }
      }
    }
  }
  if ((u.type == INFANTRY) || (u.type == MECH))
  {  //check for transportation
    if (a[0].type == action_standby)
    {  //if it has nothing to do on this land mass anymore
      d = closest_move_to_empty_copter(u.color, u.number, u.movetype, u.move, u.tilex, u.tiley);
      if (d.x != -1)
      {  //if there is an empty T-Copter available
        a[0].type = action_move;
        a[0].loc = d;
        temp1 = unit_here_thorough(u.color, d.x, d.y, u.number);
        if (temp1 != -1)
        {  //if there is a unit at the final move point, it must be the copter
          a[1].type = action_load;
          a[1].loc = d;
        }
        else
        {
          if (copter_summoned(u.color, u.tilex, u.tiley) == 1)
          {  //if a copter it summoned is now reachable
            unsummon_copter(u.color, u.tilex, u.tiley);
            d = a_free_space(u.color, u.movetype, d.x, d.y);
            if (d.x != -1)
            {
              summon_empty_copter(u.color, d.x, d.y);
            }
          }
        }
      }
      else
      {  //if there isn't a reachable copter, see if one's heading over
        if (copter_summoned(u.color, u.tilex, u.tiley) == 0)
        {  //if not, summon one
          d = empty_adjacent_space(u.tilex, u.tiley);
          if (d.x != -1)
          {
            summon_empty_copter(u.color, d.x, d.y);
          }
          else
          {  //if there is no free space next to the unit
            d = a_free_space(u.color, u.movetype, u.tilex, u.tiley);
            if (d.x != -1)
            {  //move to another free space and hope it's a better location for pickup
              a[0].type = action_move;
              a[0].loc = d;
            }
          }
        }
      }
    }
  }   
  if ((u.basetype == LAND) && (a[0].type == action_standby))
  {  //check for a lander if the unit can't do anything and could be moved in a lander
    temp3 = 1;
    if ((u.attacktype == DIRECT) || (u.attacktype == RANGED))
    {  //if it isn't an APC
      temp3 = 0;
      d = reachable_enemy_building(u.color, u.movetype, u.tilex, u.tiley, 0, 1);
      if (d.x != -1)
      {  //if there are enemy unit-producing buildings nearby
        d = closest_move_to_destination(u.color, u.number, u.movetype, u.move, u.tilex, u.tiley, (d.x * 100) + d.y, 0);
        if (d.x != -1)
        {
          a[0].type = action_move;
          a[0].loc = d;
        }
      }
      else
      {
        temp3 = 1;
      }
    }
    if (temp3 == 1)
    {  //if it wasn't an attacker or there was no unit-producing enemy building nearby
      if ((u.type != APC) || (a[0].type == action_unload1))
      {  //if it isn't an APC, or is an APC with a unit loaded into it
        temp1 = u.move;
        if (temp1 > u.gas)
        {
          temp1 = u.gas;
        }
        d = closest_move_to_available_lander(u.color, u.number, u.movetype, temp1, u.tilex, u.tiley);
        if (d.x != -1)
        {  //if there is an empty lander available
          a[0].type = action_move;
          a[0].loc = d;
          temp1 = unit_here_thorough(u.color, d.x, d.y, u.number);
          if (temp1 != -1)
          {  //if there is a unit at the final move point, it must be the lander
            a[1].type = action_load;
            a[1].loc = d;
            player[u.color].unit[temp1].moving_towards = -1;
          }
        }
        else
        {  //if there isn't a reachable lander, see if one's heading over
          if (lander_summoned(u.color, u.tilex, u.tiley) == 0)
          {  //if not, summon one
            summon_lander(u.color, u.tilex, u.tiley);
          }
        }
      }
    }
  }
  debug << "End time: " << counter << "\n\n";
  aset.action[0] = a[0];
  aset.action[1] = a[1];
  aset.action[2] = a[2];
  return aset;
}

void act(_unit& u, _action a)
{
  _unit d;
  int i;
  int q;
  switch(a.type)
  {
    case action_move:
      if ((u.tilex != a.loc.x) || (u.tiley != a.loc.y))
      {  //a final crash safeguard: units don't move if they're already at the destination
        set_best_path(u, a.loc.x, a.loc.y);
        play_moving_sound(u.type);
      }
      break;
    case action_attack:
      in_battle = 1;
      def = any_unit_here(a.loc.x, a.loc.y);
      atk = (u.color * 100) + u.number;
      break;
    case action_capture:
      capture_building(&u);
      break;
    case action_load:
      q = unit_here_thorough(u.color, u.tilex, u.tiley, u.number);
      player[u.color].unit[q].load_unit(u);
      unitmap[u.tilex][u.tiley] = (u.color * 100) + q;  //makes sure unitmap is
      player[u.color].unit[u.number].exists = 0;        //correct for this spot
      break;
    case action_unload1:
      u.load[0].loaded = 0;
      i = player[u.color].create_unit(u.load[0].type, a.loc.x, a.loc.y, u.color);
      player[u.color].unit[i].gas = u.load[0].gas;
      player[u.color].unit[i].ammo = u.load[0].ammo;
      player[u.color].unit[i].health = u.load[0].health;
      if (u.load[0].subload.loaded == 1)
      {
        player[u.color].unit[i].load[0].loaded = 1;
        player[u.color].unit[i].load[0].type = u.load[0].subload.type;
        player[u.color].unit[i].load[0].gas = u.load[0].subload.gas;
        player[u.color].unit[i].load[0].ammo = u.load[0].subload.ammo;
        player[u.color].unit[i].load[0].health = u.load[0].subload.health;
        u.load[0].subload.loaded = 0;
      }
      player[u.color].unit[i].draw(1);
      break;
    case action_unload2:
      u.load[1].loaded = 0;
      i = player[u.color].create_unit(u.load[1].type, a.loc.x, a.loc.y, u.color);
      player[u.color].unit[i].gas = u.load[1].gas;
      player[u.color].unit[i].ammo = u.load[1].ammo;
      player[u.color].unit[i].health = u.load[1].health;
      if (u.load[1].subload.loaded == 1)
      {
        player[u.color].unit[i].load[0].loaded = 1;
        player[u.color].unit[i].load[0].type = u.load[1].subload.type;
        player[u.color].unit[i].load[0].gas = u.load[1].subload.gas;
        player[u.color].unit[i].load[0].ammo = u.load[1].subload.ammo;
        player[u.color].unit[i].load[0].health = u.load[1].subload.health;
        u.load[1].subload.loaded = 0;
      }      
      player[u.color].unit[i].draw(1);
      break;
    case action_standby:
      break;  //do nothing on standby
    case action_supply:
      supply_units(u);
      break;
    case action_merge:
      merge_units(&u, u.tilex, u.tiley);
      break;
  }
}

void set_best_path(_unit u, int tx, int ty)
{
  int i, q;
  int list[10];
  vector<_aipath> t = best_aipath(u.color, u.movetype, u.tilex, u.tiley, tx, ty);
  q = t.size();
  i = 0;
  while ((i < 10) && (i < q))
  {
    list[i] = t[i].dir;  //grab the first ten moves from the vector
    i++;
  }
  while (i < 10)
  {
    list[i] = -1;  //if the vector had less than 10 entries, fill the rest with -1
    i++;
  }
  player[u.color].unit[u.number].set_moves(list);
}

void make_new_units(int plyr)
{
  static int price[18];
  static int first = 1;
  int i, j, min, built_unit, z;
  int can_build;
  bool conserve_money = false;
  vector<_buildorder> order;
  _buildorder temp;
  _unit t;
  _loc l;
  int num[18];
  if (first == 1)
  {
    i = 0;
    while (i < 18)
    {
      t.create(i, -1, -1, -1, -1);
      price[i] = t.price;
      i++;
    }
    first = 0;
  }
  i = 0;
  while (i < 18)
  {
    num[i] = 0;
    i++;
  }
  order.resize(18);
  i = 0;
  while (i < 50)
  {  //this loop finds how many units of each type the player has on the field
    if (player[plyr].unit[i].exists == 1)
    {
      num[player[plyr].unit[i].type]++;
    }
    i++;
  }
  can_build = check_can_build(plyr, price, num);
  while (can_build == 1)
  {
    i = 0;
    while (i < 18)
    {
      order[i].unit = i;
      order[i].ratio = get_ratio(i, build[aiprofile][i].weight, build[aiprofile][i].limit, num[i]);
      i++;
    }
    i = 0;
    while (i < order.size() - 1)
    {  //arrange order in order of smallest ratio to largest
      min = i;
      j = i;
      while (j < order.size())
      {
        if (order[j].ratio < order[min].ratio)
        {
          min = j;
        }
        j++;
      }
      if (min != i)
      {
        temp = order[i];
        order[i] = order[min];
        order[min] = temp;
      }
      i++;
    }
    built_unit = -1;
    
    /*if (build[aiprofile][LANDER].weight > 0)
    {  //special case:  if landers can be built
      if (num[LANDER] == 0)
      {  //and there are no landers on the field at the moment
        l = open_build_loc(plyr, LANDER);
        if (l.x != -1)
        {  //and there is a place where a lander could be built
          if (price[LANDER] > player[plyr].cash)
          {  //but the player can't afford a lander
            i = 0;
            while (i < 18)
            {
              if (price[order[i].unit] > player[plyr].cash)
              {
                if (order[i].unit == LANDER)
                {  //if landers are higher priority than what could be built this turn
                  conserve_money = true;  //wait a turn and build it later
                  i = 18;
                }
                i++;
              }
              else
              {
                i = 18;
              }
            }
          }
        }
      }
    }*/
    i = 0;
    while ((built_unit == -1) && (conserve_money == false))
    {
      if (price[order[i].unit] <= player[plyr].cash)
      {  //if the player can afford the unit
        if (num[i] <= build[aiprofile][i].limit)
        {  //if there aren't already too many of that type
          l = open_build_loc(plyr, order[i].unit);
          if (l.x != -1)  //if there is a building that can make this unit
          {
            z = player[plyr].create_unit(order[i].unit, l.x, l.y, plyr);
            player[plyr].unit[z].draw(1);
            player[plyr].cash -= price[order[i].unit];
            built_unit = order[i].unit;
          }
        }
      }
      else
      {  //if the player can't afford the unit
        if (num[i] <= build[aiprofile][i].limit)
        {  //if it hasn't hit the limit for this unit type
          l = open_build_loc(plyr, order[i].unit);
          if (l.x != -1)
          {  //if there is an open build location for the unit
            if (enemy_threat(plyr) == false)
            {  //if the enemy is far away, build up cash for a better unit
              conserve_money = true;
              if ((num[INFANTRY] < 2) && (num[MECH] < 2))
              {  //unless there are no building cappers
                l = open_build_loc(plyr, INFANTRY);
                if (l.x != -1)
                {  //and if an infantry or mech could be built
                  if (player[plyr].cash >= price[MECH])
                  {  //build a mech
                    conserve_money = false;
                    z = player[plyr].create_unit(MECH, l.x, l.y, plyr);
                    player[plyr].unit[z].draw(1);
                    player[plyr].cash -= price[MECH];
                    built_unit = MECH;                    
                  }
                  else if (player[plyr].cash >= price[INFANTRY])
                  {  //or an infantry, depending on the financial situation
                    conserve_money = false;
                    z = player[plyr].create_unit(INFANTRY, l.x, l.y, plyr);
                    player[plyr].unit[z].draw(1);
                    player[plyr].cash -= price[INFANTRY];
                    built_unit = INFANTRY;
                  }
                }
              }
            }
          }
        }
      }
      i++;
    }
    if (conserve_money == false)
    {
      num[built_unit]++;  //increase unit counter to include new build
      can_build = check_can_build(plyr, price, num);
    }
    else
    {
      can_build = 0;
    }
  }
}

int check_can_build(int plyr, int price[], int num[])
{
  int i = 0;
  _loc l;
  if (player[plyr].units_in_play() >= 50)
  {  //if the player has reached the unit limit
    return 0;
  }
  while (i < 18)
  {  //for every type of unit:
    if (num[i] < build[aiprofile][i].limit)
    {  //if the limit for this unit hasn't been reached
      if (price[i] <= player[plyr].cash)
      {  //if the player can afford the unit
        l = open_build_loc(plyr, i);
        if (l.x != -1)
        {  //if there is a building that can build the unit this turn
          return 1;  //then the player can build
        }
      }
    }
    i++;
  }
  return 0;
}


float get_ratio(int i, int weight, int limit, int num)
{
  float r = 100;
  if ((weight > 0) && (limit > num))
  {  //the lower the ratio, the higher the build priority
    r = float(num + 1) / float(weight);
  }  //if the weight is 0 or the limit is reached, the ratio stays at 100;
  return r;
}

_aitarget find_best_target(_unit u)
{
  _aitarget t;
  _aitarget best;
  int i, j, x, y, q, w, e;
  int damage_cost = 0;
  t.type = -1;
  t.health = -1;
  t.damage_cost = -1;
  t.loc.x = -1;
  t.loc.y = -1;
  best = t;
  i = 0;
  j = 0;
  if (u.attacktype == DIRECT)
  {
    while (i < 19)
    {
      j = 0;
      while (j < 19)
      {
        x = u.tilex - 9 + j;  //check out all tiles from tilex-9 to tilex+9
        y = u.tiley - 9 + i;  //and tiley-9 to tiley+9 (8 is max unit move)
        if ((x > -1) && (y > -1) && (x < l) && (y < h))
        {  //if the location is within the map
          t = aitarget_here(u, x, y);
          if (t.type != -1)
          {  //if there is a viable target here
            if (can_get_to_aitarget(u, t) == 1)
            {  //even if the unit is in range, it may not be attackable due to other units
              if (t.damage_cost > best.damage_cost)
              {
                best = t;
              }
            }
          }
        }
        j++;
      }
      i++;
    }
  }
  else if (u.attacktype == RANGED)
  {
    while (i < 11)
    {
      j = 0;
      while (j < 11)
      {
        x = u.tilex - 5 + j;  //check out all tiles from tilex-5 to tilex+5
        y = u.tiley - 5 + i;  //and tiley-5 to tiley+5 (5 is max range fire)
        if ((x > -1) && (y > -1) && (x < l) && (y < h))
        {  //if the location is within the map
          q = get_rangemin(u.type);
          w = get_rangemax(u.type);
          e = tile_distance(u.tilex, u.tiley, x, y);
          if ((e >= q) && (e <= w))
          {  //make sure the location to be checked is in firing range
            t = aitarget_here(u, x, y);
            if (t.type != -1)  //if there is a viable target here
            {
              if (t.damage_cost > best.damage_cost)
              {  //if damage to this unit is more costly to the enemy than the last target
                best = t;
              }
            }
          }
        }
        j++;
      }
      i++;
    }
  }
  return best;
}

_aitarget aitarget_here(_unit u, int tx, int ty)
{
  _aitarget p;
  _unit t;
  int i, q;
  int found_p = -1;
  int found_n = -1;
  p.type = -1;
  i = 0;
  while (i < 4)
  {
    if ((player[i].playing == 1) && (i != u.color))
    {
      q = unit_here_thorough(i, tx, ty, -1);
      if (q != -1)
      {
        found_p = i;
        found_n = q;
        i = 4;
      }
    }
    i++;
  }
  if (found_p != -1)  //if an enemy unit has been found here
  {
    t = player[found_p].unit[found_n];
    if (can_attack(u, t) == 1)
    {
      p.type = t.type;
      p.loc.x = tx;
      p.loc.y = ty;
      p.health = t.health;
      p.damage_cost = get_damage_cost(u, t);
    }
  }
  return p;
}

int get_damage_cost(_unit a, _unit d)
{
  float basic = float(basic_damage(a.type, d.type)) * a.health / 10;
  int def = defbonus(d.tilex, d.tiley);  //most of this code lifted from battle.cpp
  if (d.basetype == AIR)
  {  //air units have no terrain defense bonus
    def = 0;
  }
  apply_player_bonuses(basic, a, d);
  float damage = basic - ((basic * float(def)) / 10);
  int cost = int(damage * d.price);
  return cost;
}

int can_get_to_aitarget(_unit a, _aitarget d)
{  //checks all 4 tiles adjacent to D to see if one is in range of A
  int x, y, z;
  x = d.loc.x + 1;
  y = d.loc.y;
  if (in_range(a, x, y) == 1)
  {
    z = any_unit_here(x, y);
    if ((z == -1) || (z == (a.color * 100) + a.number))
    {
      return 1;
    }
  }
  x = d.loc.x - 1;
  y = d.loc.y;
  if (in_range(a, x, y) == 1)
  {
    z = any_unit_here(x, y);
    if ((z == -1) || (z == (a.color * 100) + a.number))
    {
      return 1;
    }
  }
  x = d.loc.x;
  y = d.loc.y + 1;
  if (in_range(a, x, y) == 1)
  {
    z = any_unit_here(x, y);
    if ((z == -1) || (z == (a.color * 100) + a.number))
    {
      return 1;
    }
  }
  x = d.loc.x;
  y = d.loc.y - 1;
  if (in_range(a, x, y) == 1)
  {
    z = any_unit_here(x, y);
    if ((z == -1) || (z == (a.color * 100) + a.number))
    {
      return 1;
    }
  }
  return 0;
}

int any_unit_here(int tx, int ty)
{
  if ((tx > -1) && (ty > -1) && (tx < l) && (ty < h))
  {
    return unitmap[tx][ty];
  }
  return -1;
}

int next_to_enemy(int plyr, int tx, int ty)
{
  int z;
  z = any_unit_here(tx + 1, ty);
  if (z != -1)
  {
    if (z / 100 != plyr)
    {
      return 1;
    }
  }
  z = any_unit_here(tx - 1, ty);
  if (z != -1)
  {
    if (z / 100 != plyr)
    {
      return 1;
    }
  }
  z = any_unit_here(tx, ty + 1);
  if (z != -1)
  {
    if (z / 100 != plyr)
    {
      return 1;
    }
  }
  z = any_unit_here(tx, ty - 1);
  if (z != -1)
  {
    if (z / 100 != plyr)
    {
      return 1;
    }
  }
  return 0;   
}

int needy(int unit_id)
{
  int p = unit_id / 100;
  int u = unit_id % 100;
  if ((player[p].unit[u].gas < 25) || ((player[p].unit[u].ammo < 4) && (player[p].unit[u].attacktype != -1)))
  {
    return 1;
  }
  else
  {
    return 0;
  }
}

int next_to_needy_friendly(int plyr, int tx, int ty)
{
  int z;
  z = needy(any_unit_here(tx + 1, ty));
  if (z == 1)
  {
    return 1;
  }
  z = needy(any_unit_here(tx - 1, ty));
  if (z == 1)
  {
    return 1;
  }
  z = needy(any_unit_here(tx, ty + 1));
  if (z == 1)
  {
    return 1;
  }
  z = needy(any_unit_here(tx, ty - 1));
  if (z == 1)
  {
    return 1;
  }
  return 0;
}

int copter_summoned(int plyr, int tx, int ty)
{
  int i = 0;
  while (i < 50)
  {
    if (player[plyr].unit[i].exists == 1)
    {
      if (player[plyr].unit[i].type == T_COPTER)
      {
        if (player[plyr].unit[i].moving_towards == (tx * 100) + ty)
        {
          return 1;
        }
      }
    }
    i++;
  }
  return 0;
}

void summon_empty_copter(int plyr, int tx, int ty)
{
  int i = 0;
  while (i < 50)
  {
    if (player[plyr].unit[i].exists == 1)
    {
      if (player[plyr].unit[i].type == T_COPTER)
      {
        if (player[plyr].unit[i].load[0].loaded == 0)
        {
          if (player[plyr].unit[i].moving_towards == -1)
          {
            player[plyr].unit[i].moving_towards = (tx * 100) + ty;
            i = 50;
          }
        }
      }
    }
    i++;
  }
}

void unsummon_copter(int plyr, int tx, int ty)
{
  int i = 0;
  while (i < 50)
  {
    if (player[plyr].unit[i].exists == 1)
    {
      if (player[plyr].unit[i].type == T_COPTER)
      {
        if (player[plyr].unit[i].load[0].loaded == 0)
        {
          if (player[plyr].unit[i].moving_towards == (tx * 100) + ty)
          {
            player[plyr].unit[i].moving_towards = -1;
            i = 50;
          }
        }
      }
    }
    i++;
  }
}


int lander_summoned(int plyr, int tx, int ty)
{
  int i;
  _loc d = closest_beach_for_lander(plyr, tx, ty);
  if (d.x != -1)
  {
    i = 0;
    while (i < lander.size())
    {
      if (lander[i]->moving_towards == (d.x * 100) + d.y)
      {
        if ((lander[i]->load[0].loaded == 0) || (lander[i]->load[1].loaded == 0))
        {
          return 1;
        }
      }
      i++;
    }       
  }
  return 0;
}

void summon_lander(int plyr, int tx, int ty)
{
  int i = 0;
  int min, j;
  int l = 999;
  int s = -1;
  int size = lander.size();
  _loc d = closest_beach_for_lander(plyr, tx, ty);
  _unit* temp;
  vector<_aipath> q;
  i = 0;
  while (i < size - 1)
  {  //sort lander[] in order of tile distance, shortest distance first
    min = i;  //the time the sort takes will, in most cases, be
    j = i;    //much better than if I had left it unsorted
    while (j < size)
    {
      if (tile_distance(lander[j]->tilex, lander[j]->tiley, d.x, d.y) < tile_distance(lander[min]->tilex, lander[min]->tiley, d.x, d.y))
      {
        min = j;
      }
      j++;
    }
    if (min != i)
    {
      temp = lander[i];
      lander[i] = lander[min];
      lander[min] = temp;
    }
    i++;
  }
  i = 0;
  if (d.x != -1)
  {
    tempmap = pathmap;  //store the contents of pathmap temporarily
    while (i < size)
    {
      if ((lander[i]->load[0].loaded == 0) && (lander[i]->load[1].loaded == 0))
      {  //if it has an empty load slot
        if (lander[i]->moving_towards == -1)
        {  //if it isn't already going somewhere
          //if (tile_distance(lander[i]->tilex, lander[i]->tiley, d.x, d.y) < l)
          fill_pathmap_for_unit(plyr, lander[i]->movetype, lander[i]->tilex, lander[i]->tiley);
          if (pathmap[d.x][d.y] < l)
          {  //if this lander can get to the beach in less moves
            l = pathmap[d.x][d.y];
            s = lander[i]->number;
          }
        }
      }
      i++;
    }
    pathmap = tempmap;  //restore pathmap to what it was originally
  }
  if (s != -1)
  {
    player[plyr].unit[s].moving_towards = (d.x * 100) + d.y;
  }
}

int intmax(int a, int b)
{
  if (a > b)
  {
    return a;
  }
  else
  {
    return b;
  }
}

int can_unload_from_here(int x, int y, int mountains)
{
  _loc d = unloadable_point(x, y, mountains);
  if (d.x != -1)
  {
    return 1;
  }
  return 0;
}

int unit_heading_here(int plyr, int x, int y)
{
  int i = 0;
  int t = (x * 100) + y;
  while (i < 50)
  {
    if (player[plyr].unit[i].exists == 1)
    {
      if (player[plyr].unit[i].moving_towards == t)
      {
        return i;
      }
    }
    i++;
  }
  return -1;
}

bool enemy_threat(int plyr)
{  //checks to see whether enemy units are near a base or the HQ
  int i = 0;
  int z = base.size();
  int x, y, r, t;
  _unit* u;
  while (i < z)
  {
    if (enemy_within_radius(plyr, base[i].x, base[i].y, 10) == true)
    {
      return true;
    }
    i++;
  }
  if (enemy_within_radius(plyr, capital.x, capital.y, 10) == true)
  {
    return true;
  }
  return false;
}

bool enemy_within_radius(int plyr, int center_x, int center_y, int r)
{
 int x, y, t;
  y = center_y - r;
  while (y <= center_y + r)
  {
    x = center_x - r;
    while (x <= center_x + r)
    {
      if ((x > 0) && (x < l) && (y > 0) && (y < h)
        && (tile_distance(x, y, center_x, center_y) <= r))
      {
        t = any_unit_here(x, y);
        if (t != -1)
        {
          if (t / 100 != plyr)
          {  //doesn't check whether the enemy unit can get to the base
            return true;  //only if it's within R tiles
          }  //yeah, I know it needs work
        }
      }
      x++;
    }
    y++;
  }
  return false;
}
