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

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

vector<_unitexplosion> boom;  //changed boom to a vector, now there can be any number at once

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 show_minimap();
extern void hide_minimap();
extern void text_box(int x, int y, int w, int h, char *ret, int leng, int spaces);
extern int get_set(int mapdat);
extern int get_tilenum(int mapdat);
extern int do_battle(_unit& a, _unit& d);
extern int HQ_exists(int playernum);
extern int base_exists(int playernum);
extern int do_ai(int plyr);
extern int any_unit_here(int tx, int ty);

extern int pathmap[50][50];

int unitmap[50][50];
int pturn;

int very_first_turn;

int mapmovable[20][20];
int mlist[10];

void animate_units(int forced);
void check_minimap(int &m);
void set_moves(int plyr, int unitnum, int tx, int ty);
void clear_moveselect();
void draw_path(_unit u);
void undraw_path(_unit u);
void supply_units(_unit u);
void draw_unitstats(_unit u);
void draw_attackables(_unit u);
void draw_playerstats(int plyr);
void draw_unloadables(int tx, int ty, int type);
void transform_buildings(int plyr, int plyr2);
void repair_units(int plyr);
void scroll_to_hq(int plyr);
void scroll_to_location(int x, int y);
void play_moving_sound(int utype);
void decrease_gas(int plyr);
void init_explode(int x, int y);
void do_explodes();
void do_power();
void capture_building(_unit* u);
void merge_units(_unit* merger, int tx, int ty);
int check_scrolling();
int check_scrolling(int forcex, int forcey);
int unit_here(int plyr, int mx, int my, int loctype);
int unit_here_thorough(int plyr, int tx, int ty, int ignore_n);
int moves_needed(int mtype, int tx, int ty);
int get_ltype(int tx, int ty);
int do_moveselect(int plyr, int u, int tx, int ty);
int list_distance(_unit u);
int move_overlap(int tx, int ty, int listend, _unit u);
int building_here(int tx, int ty);
int do_unitmenu(int menutype, int tx, int ty, int pturn, int moved);
int unit_type(string name);
int buildings_owned(int plyr);
int can_attack(_unit a, _unit d);
int unit_unloadable_here(int tx, int ty, int type);
int unit_unloadable_here(int ox, int oy, int tx, int ty, int type);
int do_unloadmenu(_unit u, int moved);
int rounded_health(float h);
int unit_exists(int plyr);
int do_savemenu(int moved);
int player_defeated(int plyr);
int do_powerflash(int cnum);
int do_cancelattack_menu(int moved);
int do_cancelunload_menu(int moved);
int secure_base(int plyr);
string do_generalmenu(int moved);
string do_actionmenu(_unit u, int num, int movedthisturn, int moved);
string unit_name(int type);
_target attackable(_unit attacker, int tx, int ty);
_target any_unit_here(int tx, int ty, int ignore_p);

int logic()
{
  static int drawfirst = 1;
  static int unitselected = -1;
  static int unitmoving = -1;
  static int actionmenu = -1;
  static int unitmenu = -1;
  static int generalmenu = -1;
  static int powerflash = -1;
  static int battle = 0;
  static int unitx, unity;
  static int movedthisturn;
  static int drew_attackrange;
  static int drew_unitstats;
  static int drew_playerstats = 320;
  static int oldmx, oldmy, oldcapstatus, unloadstatus;
  static int attackselect;
  static int drew_attackables;
  static int unloadselect;
  static int unloadnum;
  static int drew_unloadables;
  static int attacker, defender;
  static int oldux, olduy;
  static int saving_game;
  static int cancel_attack;
  static int cancel_unload;
  static int windelay = -1;
  int moved = mouse_moved();
  int mx = mouse_x;
  int my = mouse_y;
  int temp1, temp2, temp3, temp4;
  int z;
  string s;
  _unit qw;
  _target target;
  if (drawfirst == 1)
  {
    player[pturn].powered = 0;  //if the player was powered last turn, dispel it now
    if (!((player[pturn].controller == AI) && (player[pturn].units_in_play() > 0)))
    {  //if the player is human or an AI with no units, scroll to the HQ
      scroll_to_hq(pturn);
      clear_to_color(sprite_buffer, TRANS);
      draw_tiles(scroll_x, scroll_y, 0, 1);
    }
    check_scrolling(scroll_x, scroll_y);  //if I don't do this, the static floats
    drawfirst = 0;                        //in check_scrolling aren't the right
    z = 0;                                //ones and bad things happen
    while (z < 4)
    {
      if (player[z].playing == 1)
      {
        if (loaded_game == 0)  //if the game has just been loaded from
        {                      //a file, the units are not refreshed
          player[z].ready_units();
        }
      }
      z++;
    }
    boom.resize(0);  //remove all explosions from existence
    if (loaded_game == 0)  //likewise, the player does not receive more cash
    {                      //and units are not repaired when the game is loaded
      player[pturn].cash += buildings_owned(pturn) * 1000;
      if (player[pturn].cash > 1000000) player[pturn].cash = 1000000;
      repair_units(pturn);
      decrease_gas(pturn);
    }
    if (loaded_game == 1)  //next turn, it won't matter whether the game
    {                      //was originally loaded from a file or not
      loaded_game = 0;
    }
    animate_units(1);  //force the units to be drawn
    draw_mouse();
    actionmenu = -1;
    unitmenu = -1;
    generalmenu = -1;
    powerflash = -1;
    unloadstatus = 0;
    drew_attackrange = -1;
    drew_playerstats = -1;
    drew_unitstats = -1;
    attackselect = -1;
    drew_attackables = 0;
    unloadselect = -1;
    unloadnum = 0;
    drew_unloadables = 0;
    cancel_attack = 0;
    cancel_unload = 0;
    battle = 0;
    saving_game = 0;
    position_mouse(320, 240);
  }
  temp1 = 0;
  temp2 = 0;
  while (temp1 < 4)
  {  //this loop finds how many players are still in the game
    if (player[temp1].playing == 1)
    {
      temp2++;
    }
    temp1++;
  }
  if ((temp2 == 1) && (battle == 0))
  {  //if only one player is left in the game and no battle is happening
    if (windelay == -1)
    {
      windelay = 20;
    }
    else if (windelay == 0)
    {
      drawfirst = 1;
      animate_units(1);
      windelay = -1;
      return GAMEOVER;
    }
    else
    {
      windelay--;
    }
  }
  temp1 = 0;
  while ((temp1 < 4) && (battle == 0))
  {  //this loop checks whether a player has been defeated
    if (player[temp1].playing == 1)
    {
      temp2 = 0;
      if ((unit_exists(temp1) == 0) && (base_exists(temp1) == 0))
      {
        temp2 = 1;
      }
      else if (unit_exists(temp1) == 0)
      {  //if the player controls bases, but no units
        if (secure_base(temp1) == 0)
        {  //if there is no base without an enemy on it
          temp2 = 1;
        }
      }
      if (temp2 == 1)
      {
        player[temp1].playing = 0;
        transform_buildings(temp1, -1);
        draw_tiles(scroll_x, scroll_y, 0, 1);
        if (temp1 == pturn)
        {
          pturn++;
          while (player[pturn].playing != 1)
          {
            pturn++;
            if (pturn >= 4) pturn = 0;
          }
        }
      }
    }
    temp1++;
  }
  if ((very_first_turn == 1) && (player[pturn].controller == AI))
  {
    draw_tiles(scroll_x, scroll_y, 0, 1);
    very_first_turn = 0;
    return LOGIC;
  }
  if (very_first_turn == 1)
  {
    very_first_turn = 0;
  }
  if ((battle == 0) && (powerflash == -1))
  {  //unit explosions shouldn't happen at battle or power screens
    if (player[pturn].controller != AI)  //and empai.cpp handles the explosions on AI turns
    {
      do_explodes();
    }
  }
  if ((unloadselect == -1) && (actionmenu == -1) && (unitmenu == -1) && (generalmenu == -1) && (battle == 0) && (saving_game == 0) && (powerflash == -1) && (player[pturn].controller != AI))
  {  //animating units when a menu is up, or during battle, or when it's the AI's turn, can mess things up
    animate_units(0);
    if (unitselected == -1)
    {  //don't draw playerstats if a unit is selected (stats get in the way)
      if (drew_playerstats != -1)
      {
        if (drew_playerstats == 320)  //drawn on right side
        {
          rectfill(sprite_buffer, 510, 0, 640, 80, TRANS);
          create_dirty(BACK, 510, 0, 130, 80);
        }
        else  //drawn on left side
        {
          rectfill(sprite_buffer, 0, 0, 130, 80, TRANS);
          create_dirty(BACK, 0, 0, 130, 80);
        }
      }
    }
    if (drew_unitstats != -1)  //if the unitstats are up
    {  //make sure a unit hasn't been drawn over the stats
      qw = player[pturn].unit[drew_unitstats];
      if (qw.tilex - scroll_x > 5)
      {
        create_dirty(BACK, 0, 445, 100, 35);
      }
      else
      {
        create_dirty(BACK, 540, 445, 100, 35);
      }
    }
  }
  if (powerflash != -1)  //if the player has decided to use his special power
  {  //this does a little animation for it
    powerflash = do_powerflash(player[pturn].number);
    if (powerflash == -1)  //if the animation has just ended
    {
      draw_tiles(scroll_x, scroll_y, 0, 1);  //put everything back on the screen, since
    }                                        //the animation cleared then when it ran
  }
  else if (player[pturn].controller == AI)  //if the player is controlled by the AI
  {
    temp1 = do_ai(pturn);
    powerflash = temp1 / 10;  //if the AI uses its power, it indicates that in temp1's tens column
    if (powerflash == 0) powerflash = -1;
    temp1 %= 10;  //ignore the powerflash information and just get a 1 or 0
    if (temp1 == 1)  //if do_ai() has indicated that it is finished
    {
      pturn++;
      while (player[pturn].playing != 1)
      {
        pturn++;
        if (pturn >= 4) pturn = 0;
      }
      drawfirst = 1;
    }
  }  //if not an AI player, the rest of this deals with human controls
  else if (saving_game == 1)
  {
    saving_game = do_savemenu(moved);
    if (saving_game == 0)
    {  //get rid of the menu if it's done by drawing over it
      draw_tiles(scroll_x, scroll_y, 0, 1);
    }
  }
  else if (attackselect != -1)
  {
    if (drew_attackables == 0)
    {
      draw_attackables(player[pturn].unit[attackselect]);
      mouse_bitmap = (BITMAP *)mouse[1].dat;  //change the mouse to a crosshair
      drew_attackables = 1;
    }
    if (cancel_attack == 0)
    {
      if (mouse_rclicked() == 1)
      {
        cancel_attack = 1;
      }
      if (mouse_clicked() == 1)
      {  //the (mx + 7) and (my + 7) are because the crosshair's center is 7 pixels away
        target = attackable(player[pturn].unit[attackselect], (mx + 7) / 40 + scroll_x, (my + 7) / 40 + scroll_y);
        if (target.player != -1)  //if there is an attackable unit where the mouse is
        {
          battle = 1;
          attacker = (pturn * 100) + attackselect;
          defender = (target.player * 100) + target.unit;
          draw_tiles(scroll_x, scroll_y, 0, 1);
          attackselect = -1;
          mouse_bitmap = (BITMAP *)mouse[0].dat;  //change the mouse back to normal
          drew_attackables = 0;
        }
      }
    }
    else if (cancel_attack == 1)
    {
      mouse_bitmap = (BITMAP *)mouse[0].dat;
      cancel_attack = do_cancelattack_menu(moved);
      if (cancel_attack == 0)
      {
        mouse_bitmap = (BITMAP *)mouse[1].dat;
        temp1 = (player[pturn].unit[attackselect].tilex - scroll_x) * 40;
        temp2 = (player[pturn].unit[attackselect].tiley - scroll_y) * 40;
        position_mouse(temp1 + 20, temp2 + 20);
      }
      if (cancel_attack == 2)
      {
        temp1 = (player[pturn].unit[attackselect].tilex - scroll_x) * 40;
        temp2 = (player[pturn].unit[attackselect].tiley - scroll_y) * 40;      
        draw_tiles(scroll_x, scroll_y, 0, 1);
        player[pturn].unit[attackselect].ready = 1;
        player[pturn].unit[attackselect].set_tiles(oldux, olduy);
        player[pturn].unit[attackselect].draw(1);
        position_mouse(temp1 + 20, temp2 + 20);
        drew_attackables = 0;
        cancel_attack = 0;
        attackselect = -1;
      }
    }
  }
  else if (unloadselect != -1)
  {
    qw = player[pturn].unit[unloadselect];
    if (drew_unloadables == 0)
    {
      if ((qw.load[0].loaded == 1) && (qw.load[1].loaded == 1))
      {  //the lander is the only unit which can load two other units
        player[pturn].unit[unloadselect].ready = 1;
      }
      else
      {
        player[pturn].unit[unloadselect].ready = 0;
      }
      unloadnum = do_unloadmenu(qw, moved);
      if ((unloadnum != -1) && (unloadnum != 2))
      {
        draw_unloadables(qw.tilex, qw.tiley, qw.load[unloadnum].type);
        drew_unloadables = 1;
        position_mouse(oldmx, oldmy);
      }
      else if (unloadnum == 2)
      {  //if unloadnum == 2 then the cancel button has been pressed
        if (unloadstatus == 0)
        {  //if it hasn't unloaded anything, it can return to its original state
          player[pturn].unit[unloadselect].set_tiles(oldux, olduy);
          player[pturn].unit[unloadselect].ready = 1;
        }
        draw_tiles(scroll_x, scroll_y, 0, 1);
        unloadselect = -1;
      }
    }
    else if (cancel_unload == 0)
    {
      if (mouse_rclicked() == 1)
      {
        cancel_unload = 1;
      }
      if (mouse_clicked() == 1)
      {
        if (unit_unloadable_here(qw.tilex, qw.tiley, (mx / 40) + scroll_x, (my / 40) + scroll_y, qw.load[unloadnum].type) == 1)
        {
          player[pturn].unit[unloadselect].load[unloadnum].loaded = 0;
          temp1 = player[pturn].create_unit(qw.load[unloadnum].type, (mx / 40) + scroll_x, (my / 40) + scroll_y, pturn);
          player[pturn].unit[temp1].gas = player[pturn].unit[unloadselect].load[unloadnum].gas;
          player[pturn].unit[temp1].ammo = player[pturn].unit[unloadselect].load[unloadnum].ammo;
          player[pturn].unit[temp1].health = player[pturn].unit[unloadselect].load[unloadnum].health;
          if (player[pturn].unit[unloadselect].load[unloadnum].subload.loaded == 1)
          {
            player[pturn].unit[temp1].load[0].loaded = 1;
            player[pturn].unit[temp1].load[0].type = player[pturn].unit[unloadselect].load[unloadnum].subload.type;
            player[pturn].unit[temp1].load[0].gas = player[pturn].unit[unloadselect].load[unloadnum].subload.gas;
            player[pturn].unit[temp1].load[0].ammo = player[pturn].unit[unloadselect].load[unloadnum].subload.ammo;
            player[pturn].unit[temp1].load[0].health = player[pturn].unit[unloadselect].load[unloadnum].subload.health;
            player[pturn].unit[unloadselect].load[unloadnum].subload.loaded = 0;
          }
          draw_tiles(scroll_x, scroll_y, 0, 12, 0, 4, 3, 0);  //draw over the menu
          draw_tiles(scroll_x, scroll_y, 0, (qw.tilex - scroll_x) - 1, (qw.tiley - scroll_y) - 1, 3, 3, 0);
          drew_unloadables = 0;
          animate_units(1);
          unloadnum = 0;
          unloadstatus = 1;
          if (player[pturn].unit[unloadselect].ready == 0)
          {  //if it is a lander, it can unload both units in one turn
            unloadselect = -1;
          }
        }
      }
    }
    else if (cancel_unload == 1)
    {
      cancel_unload = do_cancelunload_menu(moved);
      if (cancel_unload == 0)
      {
        temp1 = (player[pturn].unit[unloadselect].tilex - scroll_x) * 40;
        temp2 = (player[pturn].unit[unloadselect].tiley - scroll_y) * 40;
        position_mouse(temp1 + 20, temp2 + 20);
        draw_unloadables(qw.tilex, qw.tiley, qw.load[unloadnum].type);
      }
      if (cancel_unload == 2)
      {
        temp1 = (player[pturn].unit[unloadselect].tilex - scroll_x) * 40;
        temp2 = (player[pturn].unit[unloadselect].tiley - scroll_y) * 40;
        position_mouse(temp1 + 20, temp2 + 20);
        if (unloadstatus == 0)
        {  //if it hasn't unloaded anything yet, it can return to its original position
          player[pturn].unit[unloadselect].set_tiles(oldux, olduy);
          player[pturn].unit[unloadselect].draw(1);
        }
        draw_tiles(scroll_x, scroll_y, 0, 1);
        drew_unloadables = 0;
        cancel_unload = 0;
        unloadselect = -1;
      }
    }
  }
  else if (battle == 0)
  {
    check_minimap(moved);
    if (unitselected == -1)
    {  //don't scroll the map if a unit is selected or the menu is up
      if ((actionmenu == -1) && (unitmenu == -1) && (generalmenu == -1))
      {
        if (check_scrolling() == 1)
        {  //if the map has scrolled, get the playerstats to redraw
          drew_playerstats = -1;
        }
      }
    }
    if (generalmenu != -1)
    {
      s = do_generalmenu(moved);
      if (s != "-")
      {
        if (s == "End Turn")
        {
          pturn++;
          while (player[pturn].playing != 1)
          {
            pturn++;
            if (pturn >= 4) pturn = 0;
          }
          drawfirst = 1;
        }
        else if (s == "Power")
        {
          player[pturn].powered = 1;
          player[pturn].power = 0;
          do_power();
          powerflash = 1;  //start the power animation
          play_sound(BLAST);
          draw_tiles(scroll_x, scroll_y, 0, 1);
        }
        else if (s == "Quit to Menu")
        {
          pturn = 0;
          generalmenu = -1;
          position_mouse(oldmx, oldmy);
          clear_to_color(sprite_buffer, TRANS);
          drawfirst = 1;
          return MENU;
        }
        else if (s == "Save Game")
        {
          saving_game = 1;
          draw_tiles(scroll_x, scroll_y, 0, 1);
        }
        else if (s == "Cancel")
        {
          draw_tiles(scroll_x, scroll_y, 0, 1);
        }
        position_mouse(oldmx, oldmy);
        generalmenu = -1;
        drew_playerstats = -1;  //put the playerstats back on the screen
      }
    }
    else if (unitmenu != -1)
    {
      temp1 = do_unitmenu(unitmenu, unitx, unity, pturn, moved);
      if (temp1 == 1)  //do_unitmenu should return 1 when a unit has been
      {                //created or if the player cancels the unitmenu
        drew_playerstats = -1;
        unitmenu = -1;
      }
    }
    else if (actionmenu > -1)  //a unit has finished moving and has a menu up
    {
      s = do_actionmenu(player[pturn].unit[actionmenu], actionmenu, movedthisturn, moved);
      if (s != "-")
      {
        player[pturn].unit[actionmenu].ready = 0;
        qw = player[pturn].unit[actionmenu];
        if (s == "Attack")
        {
          attackselect = actionmenu;
        }
        else if (s == "Supply")
        {
          supply_units(player[pturn].unit[actionmenu]);
        }
        else if (s == "Capture")
        {
          capture_building(&player[pturn].unit[actionmenu]);
        }
        else if (s == "Load")
        {
          temp1 = unit_here_thorough(pturn, qw.tilex, qw.tiley, actionmenu);
          player[pturn].unit[temp1].load_unit(qw);
          unitmap[qw.tilex][qw.tiley] = (pturn * 100) + temp1;  //makes sure unitmap is
          player[pturn].unit[actionmenu].exists = 0;            //correct for this spot
        }
        else if (s == "Unload")
        {
          unloadselect = actionmenu;
        }
        else if (s == "Merge")
        {
          merge_units(&player[pturn].unit[actionmenu], qw.tilex, qw.tiley);
        }
        else if (s == "Dive")
        {
          player[pturn].unit[actionmenu].submerged = 1;
        }
        else if (s == "Surface")
        {
          player[pturn].unit[actionmenu].submerged = 0;
        }
        else if (s == "Cancel")
        {
          player[pturn].unit[actionmenu].ready = 1;
          player[pturn].unit[actionmenu].set_tiles(oldux, olduy);
          temp1 = unit_here_thorough(pturn, qw.tilex, qw.tiley, qw.number);
          if (temp1 != -1)
          {
            unitmap[qw.tilex][qw.tiley] = temp1;  //if merge was canceled, restore unitmap value
          }
          player[pturn].unit[actionmenu].capturing = oldcapstatus;
        }
        temp1 = building_here(qw.tilex, qw.tiley);
        if (temp1 > 9)  //if the unit is standing on a unit-producing building
        {
          temp2 = ((temp1 - 4) % 5) - 1;
          if (temp2 != pturn)  //and if it is an enemy building
          {  //check to see whether the owner of the building is now screwed
            if (player_defeated(temp2) == 1)
            {
              transform_buildings(temp2, -1);        //if so, that player's buildings
              draw_tiles(scroll_x, scroll_y, 0, 1);  //become neutral
              player[temp2].clear_units();
              player[temp2].playing = 0;
            }
          }
        }
        drew_playerstats = -1;
        actionmenu = -1;
        draw_tiles(scroll_x, scroll_y, 0, 1);  //get rid of the actionmenu by drawing
        position_mouse(oldmx, oldmy);          //over it and put the mouse back where
      }                                        //it was before the actionmenu appeared
    }
    else if (unitselected == -1)
    {
      if (unitmoving == -1)  //no unit is selected or moving
      {
        if (drew_playerstats == -1)
        {
          draw_playerstats(pturn);
          drew_playerstats = mx;
          if (drew_playerstats > 320)
          {
            drew_playerstats = 321;
          }
          else
          {
            drew_playerstats = 320;
          }
        }
        else
        {
          switch(drew_playerstats)
          {
            case 320:
              if (mx > 320)
              {
                drew_playerstats = -1;
                draw_tiles(scroll_x, scroll_y, 0, 12, 0, 4, 2, 1);
              }
              break;
            case 321:
              if (mx < 321)
              {
                drew_playerstats = -1;
                draw_tiles(scroll_x, scroll_y, 0, 0, 0, 4, 2, 1);
              }
              break;
          }
        }
        if (drew_unitstats == -1)
        {
          temp1 = unit_here(pturn, mx, my, LMOUSE);
          if (temp1 > -1)
          {
            draw_unitstats(player[pturn].unit[temp1]);
            drew_unitstats = temp1;
          }
        }
        if ((key[KEY_LSHIFT]) || (key[KEY_RSHIFT]))
        {  //draws a ranged-attack unit's range
          if (drew_attackrange == -1)
          {
            z = any_unit_here((mx / 40) + scroll_x, (my / 40) + scroll_y);//unit_here(pturn, mx, my, LMOUSE);
            if (z != -1)
            {
              if (player[z / 100/*pturn*/].unit[z % 100/*z*/].attacktype == RANGED)
              {
                draw_attackrange(player[z / 100/*pturn*/].unit[z % 100/*z*/]);
                drew_attackrange = z;
              }
            }
          }
        }
        else if (mouse_clicked() == 1)
        {
          z = unit_here(pturn, mx, my, LMOUSE);
          if ((z != -1) && (player[pturn].unit[z].ready == 1))
          {  //if a unit is here and ready, select it
            unitselected = z;
            oldux = player[pturn].unit[z].tilex;
            olduy = player[pturn].unit[z].tiley;
            oldcapstatus = player[pturn].unit[z].capturing;
            unloadstatus = 0;
            clear_moveselect();
            switch(drew_playerstats)  //erase the playerstats from the screen
            {
              case 320:
                draw_tiles(scroll_x, scroll_y, 0, 12, 0, 4, 2, 1);
                break;
              case 321:
                draw_tiles(scroll_x, scroll_y, 0, 0, 0, 4, 2, 1);
                break;
            }
            drew_playerstats = -1;
            draw_range(pturn, z);
            BITMAP *temp = create_bitmap(40, 40);
            clear_to_color(temp, YELLOW);
            draw_trans_sprite(back_buffer, temp, mx - (mx % 40), my - (my % 40));
            create_dirty(BACK, mx - (mx % 40), my - (my % 40), 40, 40);
            destroy_bitmap(temp);
            animate_units(1);
          }
          else if (z == -1)
          {  //if there is no unit here, but there is a building that can make units
            temp1 = 1;
            temp2 = 0;
            while (temp2 < 4)
            {
              if (player[temp2].playing == 1)
              {
                if (unit_here(temp2, mx, my, LMOUSE) != -1)
                {
                  temp1 = 0;
                }
              }
              temp2++;
            }  //makes sure no units of any team are on here
            if (temp1 == 1)
            {
              temp1 = building_here(mx / 40 + scroll_x, my / 40 + scroll_y);
              if (temp1 > 8)  //if < 8, they are either capitals or cities
              {               //and therefore cannot produce units
                if (((temp1 - 9) % 5) - 1 == pturn)  //if the current player controls it
                {
                  unitmenu = (temp1 - 9) / 5;  //-9 to get rid of the capitals and cities
                  unitx = mx / 40 + scroll_x; // /5 to separate them into building types
                  unity = my / 40 + scroll_y;
                }
              }
            }
          }
        }
        else if (mouse_rclicked() == 1)
        {  //if the mouse is right-clicked, bring up the general menu
          oldmx = mx;  //save the mouse location to be put back after the menu closes
          oldmy = my;
          generalmenu = 1;
        }
        else
        {
          if (unit_here(pturn, mx, my, LMOUSE) != drew_unitstats)
          {
            draw_tiles(scroll_x, scroll_y, 0, 0, 10, 16, 2, 1);  //draw over the stats
            drew_unitstats = -1;
          }
          if (drew_attackrange > -1)
          {
            undraw_attackrange(player[drew_attackrange / 100/*pturn*/].unit[drew_attackrange % 100]);
            drew_attackrange = -1;
            drew_unitstats = -1;
            drew_playerstats = -1;
          }
        }
      }
      else  //a unit is in the process of moving somewhere
      {
        temp1 = unitmoving;
        qw = player[pturn].unit[unitmoving];
        unitmoving = qw.movestatus(unitmoving);
        if (unitmoving == -1)  //if the unit has just stopped moving
        {
          actionmenu = temp1;
          oldmx = mx;
          oldmy = my;
        }
      }
    }
    else  //a unit is currently selected
    {
      if (moved == 1)
      {
        if (in_range(pturn, unitselected, (mx / 40) + scroll_x, (my / 40) + scroll_y) == 1)
        {
          unitselected = do_moveselect(pturn, unitselected, (mx / 40) + scroll_x, (my / 40) + scroll_y);
        }
      }
      if (mouse_clicked() == 1)
      {
        qw = player[pturn].unit[unitselected];
        temp1 = unit_here(pturn, mx, my, LMOUSE);
        temp2 = 0;
        if (temp1 != -1)
        {  //this checks to see if another of the player's units is here
          if (player[pturn].unit[temp1].can_load_unit(qw) == 1)
          {  //if a unit is here but can load the selected unit, everything's OK
            temp2 = 1;
          }
          else if ((player[pturn].unit[temp1].type == qw.type) && (temp1 != unitselected))
          {  //if it is the same type and has less than full health, they can merge
            if (player[pturn].unit[temp1].health < 10)
            {
              temp2 = 1;
            }
          }
          else if (mlist[0] == -1)  //the unit hasn't moved at all and therefore
          {                         //unit_here is just detecting the selected unit
            temp2 = 1;
          }
        }
        else
        {  //if there is no unit here then everything's fine
          temp3 = (mx / 40) + scroll_x;
          temp4 = (my / 40) + scroll_y;
          if (in_range(qw, temp3, temp4) == 1)
          {  //only have movement if the mouse is on a movable tile
            temp2 = 1;
          }
        }
        if (temp2 == 1)
        {
          temp1 = qw.tilex - scroll_x;
          temp2 = qw.tiley - scroll_y;
          draw_tiles(scroll_x, scroll_y, 0, temp1 - qw.move, temp2 - qw.move, 1 + (2 * qw.move), 1 + (2 * qw.move), 0);
          if (mlist[0] == -1)  //so do_actionmenu can tell if a unit has been ordered
          {                    //to move, which is important for ranged-attack units
            movedthisturn = 0;
          }
          else
          {
            movedthisturn = 1;
            player[pturn].unit[unitselected].capturing = -1;  //stops any capture process
            play_moving_sound(qw.type);
          }
          player[pturn].unit[unitselected].set_moves(mlist);
          unitmoving = unitselected;
          player[pturn].unit[unitselected].draw(1);
          unitselected = -1;
          do_moveselect(-1, -1, -1, -1);  //this resets do_moveselect's static ints
        }
      }
    }
  }
  else
  {
    temp1 = attacker / 100;
    temp2 = attacker % 100;
    temp3 = defender / 100;
    temp4 = defender % 100;
    battle = do_battle(player[temp1].unit[temp2], player[temp3].unit[temp4]);
    if (battle == 0)  //if the battle just ended
    {
      draw_tiles(scroll_x, scroll_y, 0, 1);  //redraw the screen and units
      if (player_defeated(temp1) == 1)
      {  //if the attacker's last unit is defeated
        transform_buildings(temp1, -1);        //defeated player's buildings
        draw_tiles(scroll_x, scroll_y, 0, 1);  //become neutral
        player[temp1].clear_units();
        player[temp1].playing = 0;
      }
      if (player_defeated(temp3) == 1)
      {  //if the defender's last unit is defeated
        transform_buildings(temp3, -1);        //defeated player's buildings
        draw_tiles(scroll_x, scroll_y, 0, 1);  //become neutral
        player[temp3].clear_units();
        player[temp3].playing = 0;
      }      
    }
  }
  if ((moved == 1) && (player[pturn].controller != AI))
  {  //if it is the AI's turn, don't draw the mouse
    draw_mouse();
  }
  return LOGIC;
}





void animate_units(int forced)
{
  int i = 0;
  int j;
  while (i < 4)
  {
    if (player[i].playing == 1)
    {
      j = 0;
      while (j < 50)
      {
        if (player[i].unit[j].exists == 1)
        {
          player[i].unit[j].draw(forced);
        }
        j++;
      }
    }
    i++;
  }
}





void check_minimap(int &m)
{
  static int minimap = 0;
  static int minimapmx;
  static int minimapmy;
  if (key[KEY_SPACE])
  {
    m = 0;  //force the mouse to not draw if the minimap is up
    if (minimap == 0)
    {
      minimap = 1;
      minimapmx = mouse_x;
      minimapmy = mouse_y;
      create_dirty(BACK, minimapmx, minimapmy, 16, 16);  //remove the mouse from view
      show_minimap();
    }
    position_mouse(minimapmx, minimapmy);  //mouse doesn't move if the minimap is up
  }
  else if ((!(key[KEY_SPACE])) && (minimap == 1))
  {
    hide_minimap();
    minimap = 0;
    m = 1;  //put the mouse back on the screen
  }
}





int check_scrolling()
{
  return check_scrolling(-1, -1);
}

int check_scrolling(int forcex, int forcey)
{
  static float scrx = 0;
  static float scry = 0;
  int scrolled = 0;
  int mickeyx;
  int mickeyy;
  int mx = mouse_x;
  int my = mouse_y;
  int tscrolled = 0;
  get_mouse_mickeys(&mickeyx, &mickeyy);
  scroll_x = int(scrx);
  scroll_y = int(scry);
  if (!(mouse_b & 1))
  {  //the screen can't scroll while the mouse button is down
    if (((mx == 0) && (mickeyx < 0)) || (key[KEY_LEFT]))
    {
      if (scrx > 0)
      {
        scrx -= .25;
        scrolled = 1;
      }
    }
    if (((mx == 639) && (mickeyx > 0)) || (key[KEY_RIGHT]))
    {
      if (scrx + 16 < l)
      {
        scrx += .25;
        scrolled = 1;
      }
    }
    if (((my == 479) && (mickeyy > 0)) || (key[KEY_DOWN]))
    {
      if (scry + 12 < h)
      {
        scry += .25;
        scrolled = 1;
      }
    }
    if (((my == 0) && (mickeyy < 0)) || (key[KEY_UP]))
    {
      if (scry > 0)
      {
        scry -= .25;
        scrolled = 1;
      }
    }
  }
  if ((forcex != -1) && (forcey != -1))
  {
    scrx = float(forcex);
    scry = float(forcey);
  }  
  if ((scroll_x != int(scrx)) || (scroll_y != int(scry)))
  {  //if the map has scrolled, redraw the tiles
    scroll_x = int(scrx);
    scroll_y = int(scry);
    draw_tiles(scroll_x, scroll_y, 0, 0);
    clear_to_color(sprite_buffer, TRANS);
    animate_units(1);
    tscrolled = 1;
  }
  if (scrolled == 0)
  {
    scrx = int(scrx);
    scry = int(scry);
  }
  return tscrolled;
}





int unit_here(int plyr, int x, int y, int loctype)
{
  int mtx, mty;
  if (loctype == LMOUSE)
  {
    mtx = (x / 40) + scroll_x;
    if (mtx > l) mtx = l;
    mty = (y / 40) + scroll_y;
    if (mty > h) mty = h;
  }
  else
  {
    mtx = x;
    mty = y;
  }
  int z = unitmap[mtx][mty];
  if (plyr == z / 100)
  {
    return z % 100;
  }
  return -1;
}

int moves_needed(int mtype, int tx, int ty)
{        //Infantry, Tires, Tread, Air, Mech, Sea
  int movegrid[48] = {1, 1, 1, 1, 1,99,  //Buildings        0
                      1, 2, 1, 1, 1,99,  //Plains           1
                      1, 1, 1, 1, 1, 1,  //Shoal            2
                      1, 3, 2, 1, 1,99,  //Forest           3
                      2,99,99, 1, 1,99,  //Mountain         4
                      2,99,99, 1, 1,99,  //River            5
                      1, 1, 1, 1, 1,99,  //Road             6
                     99,99,99, 1,99, 1}; //Sea              7
  int ltype = get_ltype(tx, ty);
  if ((ltype == 0) && (mtype == 5))  //sea units can go to ports
  {
    int z = get_tilenum(map[tx][ty]);
    z -= 4;  //get rid of capitals
    if (z / 5 == 3)  //if it's a port
    {
      return 1;
    }
  }
  return movegrid[mtype + (ltype * 6)];
}

int get_ltype(int tx, int ty)
{
  int s;
  int z;
  s = get_set(map[tx][ty]);
  z = get_tilenum(map[tx][ty]);
  if (s == 4)  //buildings
  {
    return 0;
  }
  else if (s == 0)  //land
  {
    if (z == 2)  //forest
    {
      return 3;
    }
    else if (z == 4)  //mountain
    {
      return 4;
    }
    else if (z == 3)  //plains
    {
      return 1;
    }
    else  //road
    {
      return 6;
    }
  }
  else if (s == 3)  //shoal
  {
    return 2;
  }
  else if (s == 1)  //river
  {
    return 5;
  }
  else //sea
  {
    return 7;
  }
}





void clear_moveselect()
{
  int i = 0;
  while (i < 10)
  {
    mlist[i] = -1;
    i++;
  }
}

int do_moveselect(int plyr, int u, int tx, int ty)
{
  static int first = 1;
  static int lastx;
  static int lasty;
  int i;
  int dir;
  int findpath;
  int temp;
  int w, q;
  _unit theunit = player[plyr].unit[u];
  if (first == 1)
  {
    lastx = player[plyr].unit[u].tilex;
    lasty = player[plyr].unit[u].tiley;
    findpath = 1;
    first = 0;
  }
  if ((tx == -1) && (ty == -1))  //if -1 for tx and ty, reset the static ints
  {
    clear_moveselect();
    u = -1;
    draw_tiles(scroll_x, scroll_y, 0, 1);
    first = 1;
  }
  else if ((tx != lastx) || (ty != lasty))
  {
    if (theunit.move > theunit.gas)
    {
      theunit.move = theunit.gas;
    }
    findpath = 0;
    if (tile_distance(lastx, lasty, tx, ty) == 1)
    {  //if the mouse hasn't skipped a tile or anything like that
      if (list_distance(theunit) <= theunit.move - moves_needed(theunit.movetype, tx, ty))
      {  //if the movement is still within the unit's range
        BITMAP *temp = create_bitmap(40, 40);
        clear_to_color(temp, YELLOW);
        draw_trans_sprite(back_buffer, temp, (tx - scroll_x) * 40, (ty - scroll_y) * 40);
        create_dirty(BACK, (tx - scroll_x) * 40, (ty - scroll_y) * 40, 40, 40);
        animate_units(1);  //so the units aren't drawn over
        destroy_bitmap(temp);
        i = 0;
        while (i < 10)
        {
          if (mlist[i] == -1)
          {
            if (ty == lasty + 1)
            {
              dir = DOWN;
            }
            if (ty == lasty - 1)
            {
              dir = UP;
            }
            if (tx == lastx + 1)
            {
              dir = RIGHT;
            }
            if (tx == lastx - 1)
            {
              dir = LEFT;
            }
            mlist[i] = dir;
            if (move_overlap(tx, ty, i, theunit) == 1)
            {
              findpath = 1;
            }
            i = 10;
          }
          i++;
        }
      }
      else
      {
        findpath = 1;
      }
    }
    else
    {  //if the path is not connected
      findpath = 1;
    }
    if ((tx == player[plyr].unit[u].tilex) && (ty == player[plyr].unit[u].tiley))
    {  //if the mouse is over the unit's original position, reset the movelist
      findpath = 0;  //also, don't bother getting a best path
      undraw_path(theunit);
      clear_moveselect();
      draw_path(theunit);
    }
    if ((findpath == 1) && (pathmap[tx][ty] <= theunit.move))
    {  //find the best path from (tx, ty) to the unit's location
      undraw_path(theunit);
      vector<_aipath> t = best_aipath(plyr, theunit.movetype, theunit.tilex, theunit.tiley, tx, ty);
      q = t.size();
      i = 0;
      while ((i < 10) && (i < q))
      {
        mlist[i] = t[i].dir;  //grab the first ten moves from the vector
        i++;
      }
      while (i < 10)
      {
        mlist[i] = -1;  //if the vector had less than 10 entries, fill the rest with -1
        i++;
      }
      draw_path(theunit);
    }
    lastx = tx;
    lasty = ty;
  }
  return u;
}

void draw_path(_unit u)
{
  BITMAP *temp = create_bitmap(40, 40);
  clear_to_color(temp, YELLOW);
  int i = 0;
  int tx = u.tilex;
  int ty = u.tiley;
  int draw = 0;
  draw_trans_sprite(back_buffer, temp, (tx - scroll_x) * 40, (ty - scroll_y) * 40);
  create_dirty(BACK, (tx - scroll_x) * 40, (ty - scroll_y) * 40, 40, 40);
  while (i < 10)
  {
    switch(mlist[i])
    {
      case -1:
        draw = 0;
        break;
      case LEFT:
        tx -= 1;
        draw = 1;
        break;
      case RIGHT:
        tx += 1;
        draw = 1;
        break;
      case UP:
        ty -= 1;
        draw = 1;
        break;
      case DOWN:
        ty += 1;
        draw = 1;
        break;
    }
    if (draw == 1)
    {
      draw_trans_sprite(back_buffer, temp, (tx - scroll_x) * 40, (ty - scroll_y) * 40);
      create_dirty(BACK, (tx - scroll_x) * 40, (ty - scroll_y) * 40, 40, 40);
      draw = 0;
    }
    i++;
  }
  animate_units(1);  //so the units aren't drawn over
  destroy_bitmap(temp);
}

void undraw_path(_unit u)
{
  DATAFILE *glb = (DATAFILE *)graphics[2].dat;
  int tx = u.tilex;
  int ty = u.tiley;
  int i = 0;
  int draw = 0;
  draw_tiles(scroll_x, scroll_y, 0, tx - scroll_x, ty - scroll_y, 1, 1, 0);
  draw_trans_sprite(back_buffer, (BITMAP *)glb[3].dat, (tx - scroll_x) * 40, (ty - scroll_y) * 40);
  create_dirty(BACK, (tx - scroll_x) * 40, (ty - scroll_y) * 40, 40, 40);
  while (i < 10)
  {
    switch(mlist[i])
    {
      case -1:
        draw = 0;
        break;
      case LEFT:
        tx -= 1;
        draw = 1;
        break;
      case RIGHT:
        tx += 1;
        draw = 1;
        break;
      case UP:
        ty -= 1;
        draw = 1;
        break;
      case DOWN:
        ty += 1;
        draw = 1;
        break;
    }
    if (draw == 1)
    {
      draw_tiles(scroll_x, scroll_y, 0, tx - scroll_x, ty - scroll_y, 1, 1, 0);
      draw_trans_sprite(back_buffer, (BITMAP *)glb[3].dat, (tx - scroll_x) * 40, (ty - scroll_y) * 40);
      create_dirty(BACK, (tx - scroll_x) * 40, (ty - scroll_y) * 40, 40, 40);
      draw = 0;
    }
    i++;
  }  
}

int list_distance(_unit u)
{
  int i = 0;
  int moves = 0;
  int x = u.tilex;
  int y = u.tiley;
  int getmoves;
  while (i < 10)
  {
    getmoves = 1;
    switch(mlist[i])
    {
      case -1:
        getmoves = 0;
        break;
      case UP:
        y -= 1;
        break;
      case DOWN:
        y += 1;
        break;
      case LEFT:
        x -= 1;
        break;
      case RIGHT:
        x += 1;
        break;
    }
    if (getmoves == 1)
    {
      moves += moves_needed(u.movetype, x, y);
    }
    else  //if a -1 has been encountered, stop the loop short
    {
      i = 10;
    }
    i++;
  }
  return moves + 1;
}

int move_overlap(int tx, int ty, int listend, _unit u)
{
  int i = 0;
  int x = u.tilex;
  int y = u.tiley;
  while (i <= listend)
  {
    if ((tx == x) && (ty == y))
    {
      return 1;
    }
    switch(mlist[i])
    {
      case UP:
        y -= 1;
        break;
      case DOWN:
        y += 1;
        break;
      case LEFT:
        x -= 1;
        break;
      case RIGHT:
        x += 1;
        break;
    }
    i++;
  }
  return 0;
}

string do_actionmenu(_unit u, int num, int movedthisturn, int moved)
{
  int i;
  int q;
  static int bnum;
  int attack;
  int supply;
  int load;
  int merge;
  static _button items[5];
  static int first = 1;
  static int x1, y1, x2, y2;
  string item[4];
  _target t;
  if (first == 1)
  {
    i = 0;
    while (i < 4)
    {
      item[i] = "-";
      i++;
    }
    if ((u.tilex - scroll_x) * 40 < 350)
    {
      x1 = 500;
      x2 = 639;
    }
    else
    {
      x1 = 0;
      x2 = 139;
    }
    y1 = 0;
    i = 0;
    load = 0;
    q = unit_here_thorough(u.color, u.tilex, u.tiley, u.number);
    if (q != -1)
    {  //if another unit is here, check if it can load the selected unit
      if (player[u.color].unit[q].can_load_unit(u) == 1)
      {  
        load = 1;
      }
    }
    if (load == 1)
    {
      item[i] = "Load";
      i++;
    }
    merge = 0;
    q = unit_here_thorough(u.color, u.tilex, u.tiley, u.number);
    if (q != -1)
    {
      if (load != 1)
      {  //there is another unit here, and it cannot be load, so it must be a merge
        merge = 1;
        item[i] = "Merge";
        i++;
      }
    }
    attack = 0;
    if (u.ammo > 0)
    {
      if (u.attacktype == DIRECT)
      {
        t = enemy_nearby(u.color, u.tilex, u.tiley);
        while (t.unit != -1)
        {  //loops until it finds an attackable unit or runs out of possible targets
          if (can_attack(u, player[t.player].unit[t.unit]) == 1)
          {
            attack = 1;
            t.unit = -1;
          }
          else
          {
            t = enemy_nearby(u.color, u.tilex, u.tiley, t.player, t.unit + 1);
          }
        }
      }
      else  //if not direct, must either be ranged or -1 and I don't
      {     //have to worry about -1 attacktypes, since their ammo is 0
        t = enemy_in_range(u.color, u.tilex, u.tiley, u.type);
        if (movedthisturn == 0)
        {  //ranged units cannot attack on turns where they have moved
          while (t.unit != -1)
          {  //loops until it finds an attackable unit or runs out of possible targets
            if (can_attack(u, player[t.player].unit[t.unit]) == 1)
            {
              attack = 1;
              t.unit = -1;
            }
            else
            {
              t = enemy_in_range(u.color, u.tilex, u.tiley, u.type, t.player, t.unit + 1);
            }
          }
        }
      }
    }
    if ((attack == 1) && (load == 0) && (merge == 0))  
    {  //unit can't attack when it can be loaded or merged
      item[i] = "Attack";
      i++;
    }
    supply = 0;
    if (u.type == APC)
    {
      if (unit_nearby(u.color, u.tilex, u.tiley) != -1)
      {
        supply = 1;
      }
    }
    if ((supply == 1) && (load == 0) && (merge == 0))  
    {  //can't supply either when it can be loaded or merged
      item[i] = "Supply";
      i++;
    }
    if (((u.type == INFANTRY) || (u.type == MECH)) && (merge == 0))
    {
      q = building_here(u.tilex, u.tiley);
      if (q != -1)
      {
        if (q < 4)
        {
          q %= 4;  //t < 4 are the capitals, so there is no 5th 'neutral' type
        }
        else
        {
          q = (q - 4) % 5;  //all other t are buildings, which have a neutral 5th type
          q--;  //because neutral buldings are before the controlled ones, I have to
        }       //subtract 1 from q for it to match correctly with u.color (player num)
        if (q != u.color)
        {
          item[i] = "Capture";
          i++;
        }
      }
    }
    if ((load == 0) && (merge == 0))
    {
      q = 0;
      while (q < 2)
      {
        if (u.can_unload_unit(q) == 1)
        {
          item[i] = "Unload";
          i++;
          q = 2;
        }
        q++;
      }
    }
    if (merge == 0)
    {
      if (u.type == SUB)
      {
        if (u.submerged == 1)
        {
          item[i] = "Surface";
        }
        else
        {
          item[i] = "Dive";
        }
        i++;
      }
    }
    if ((load == 0) && (merge == 0))
    {
      item[i] = "Standby";
      i++;
    }
    item[i] = "Cancel";
    i++;
    i = 0;
    bnum = 0;
    y2 = 1;
    while (i < 4)
    {
      if (item[i] != "-")
      {
        items[i].init(x1 + 1, y2, x2 - (x1 + 2), 30, item[i].c_str());
        y2 += 31;
        bnum++;
      }
      else
      {
        i = 5;
      }
      i++;
    }
    position_mouse(x1 + 70, y1 + 15);  //mouse positioned on middle of Standby button
    set_mouse_range(x1, y1, x2, y2);
    rectfill(back_buffer, x1, y1, x2, y2, LGREY);
    rect(back_buffer, x1, y1, x2, y2, ORANGE);
    i = 0;
    while (i < bnum)
    {
      items[i].draw(back_buffer);
      i++;
    }
    rectfill(sprite_buffer, x1, y1, x2, y2, TRANS);  //get rid of any unit sprites
    create_dirty(BACK, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
    first = 0;
  }
  i = 0;
  while (i < bnum)
  {
    items[i].check(back_buffer, moved);
    if (items[i].clicked() == 1)
    {
      first = 1;
      set_mouse_range(0, 0, 639, 479);  //return the mouse boundries to normal
      return items[i].text;
    }
    i++;
  }
  return "-";
}

int building_here(int tx, int ty)
{
  int s = get_set(map[tx][ty]);
  int t = get_tilenum(map[tx][ty]);
  if (s == 4)  //set 4 is the buildings tileset
  {
    return t;
  }
  return -1;
}

int do_unitmenu(int type, int tx, int ty, int pturn, int moved)
{
  DATAFILE *bigunits = (DATAFILE *)units[4].dat;
  static int first = 1;
  static int ok[18];  //each ok[] corresponds to a unit type
  static _button items[11];  //maximum number of buttons possible at once is 11
  static int lastitem;
  static int oldmx, oldmy;
  static int m_over;
  static int limit;
  int i;
  int j;
  _unit u;
  if (first == 1)
  {
    limit = 0;
    oldmx = mouse_x;
    oldmy = mouse_y;
    i = 0;
    while (i < 18)
    {
      ok[i] = 0;
      i++;
    }
    switch(type)
    {
      case 0:  //bases
        ok[0] = 1;   //Anti-Air
        ok[1] = 1;   //APC
        ok[2] = 1;   //Artillery
        ok[8] = 1;   //Infantry
        ok[10] = 1;  //Md Tank
        ok[11] = 1;  //Mech
        ok[12] = 1;  //Missiles
        ok[13] = 1;  //Recon
        ok[14] = 1;  //Rockets
        ok[17] = 1;  //Tank
        break;
      case 1:  //airport
        ok[3] = 1;   //B Copter
        ok[5] = 1;   //Bomber
        ok[7] = 1;   //Fighter
        ok[16] = 1;  //T Copter
        break;
      case 2:  //port
        ok[4] = 1;   //B Ship
        ok[6] = 1;   //Cruiser
        ok[9] = 1;   //Lander
        ok[15] = 1;  //Sub
        break;
    }
    rect(back_buffer, 40, 40, 400, 350, ORANGE);
    rectfill(back_buffer, 41, 41, 399, 349, LGREY);
    rectfill(sprite_buffer, 40, 40, 400, 350, TRANS);  //make sure no units are drawn
    create_dirty(BACK, 40, 40, 361, 311);
    if (player[pturn].units_in_play() >= 50)  //if the player cannot make more units
    {
      i = 0;
      while (i < 18)
      {
        ok[i] = 0;
        i++;
      }
      text_mode(-1);
      textout(back_buffer, font, "Unit Limit Reached", 50, 290, BLACK);
      create_dirty(BACK, 50, 290, 100, 10);
      text_mode(0);
      limit = 1;
    }
    i = 0;
    j = 0;
    while (i < 18)
    {
      if (ok[i] == 1)
      {
        items[j].init(50, 50 + (25 * j), 100, 20, unit_name(i));
        items[j].draw(back_buffer);
        j++;
      }
      i++;
    }
    items[j].init(50, 310, 100, 20, "Cancel");
    items[j].draw(back_buffer);
    lastitem = j;
    m_over = -1;
    set_mouse_range(40, 40, 400, 350);
    position_mouse(220, 195);
    first = 0;
  }
  j = 0;
  i = 0;
  while ((i < lastitem) && (limit == 0))
  {
    items[i].check(back_buffer, moved);
    if (items[i].mouseover() == 1)
    {
      j = 1;
      if (m_over != i)
      {
        u.create(unit_type(items[i].text), -1, -1, -1, -1);
        rectfill(back_buffer, 250, 50, 350, 60, LGREY);
        text_mode(-1);
        if (u.price <= player[pturn].cash)
        {
          textprintf(back_buffer, font, 250, 50, BLACK, "Price: %-1d", u.price);
        }
        else
        {
          textprintf(back_buffer, font, 250, 50, RED, "Price: %-1d", u.price);
        }
        text_mode(0);
        create_dirty(BACK, 250, 50, 100, 10);
        rectfill(back_buffer, 210, 130, 360, 280, LGREY);
        draw_sprite_h_flip(back_buffer, (BITMAP *)bigunits[(u.type * 4) + pturn].dat, 210, 130);
        create_dirty(BACK, 210, 130, 150, 150);
        m_over = i;
      }
    }
    if (items[i].clicked() == 1)
    {
      u.create(unit_type(items[i].text), -1, -1, -1, -1);
      if (player[pturn].cash >= u.price)
      {
        player[pturn].cash -= u.price;
        player[pturn].create_unit(u.type, tx, ty, pturn);
        draw_tiles(scroll_x, scroll_y, 0, 1);
        set_mouse_range(0, 0, 639, 479);
        position_mouse(oldmx, oldmy);
        m_over = -1;
        first = 1;
        return 1;
      }
    }
    i++;
  }
  if (j == 0)  //if the mouse isn't over any button
  {
    m_over = -1;
  }
  items[lastitem].check(back_buffer, moved);
  if (items[lastitem].clicked() == 1)  //cancel button
  {
    draw_tiles(scroll_x, scroll_y, 0, 1);
    set_mouse_range(0, 0, 639, 479);
    position_mouse(oldmx, oldmy);
    m_over = -1;
    first = 1;
    return 1;
  }
  return 0;
}

void supply_units(_unit u)
{
  int q;
  int x, y;
  x = u.tilex - 1;
  y = u.tiley;
  q = unit_here(u.color, x, y, LTILE);
  if (q != -1)
  {
    player[u.color].unit[q].supply();
  }
  x = u.tilex + 1;
  y = u.tiley;
  q = unit_here(u.color, x, y, LTILE);
  if (q != -1)
  {
    player[u.color].unit[q].supply();
  }
  x = u.tilex;
  y = u.tiley - 1;
  q = unit_here(u.color, x, y, LTILE);
  if (q != -1)
  {
    player[u.color].unit[q].supply();
  }
  x = u.tilex;
  y = u.tiley + 1;
  q = unit_here(u.color, x, y, LTILE);
  if (q != -1)
  {
    player[u.color].unit[q].supply();
  }
}

_target any_unit_here(int tx, int ty, int ignore_p)
{
  _target t;
  int z = unitmap[tx][ty];
  int p = z / 100;
  if (z != -1)
  {
    if (p != ignore_p)
    {
      z %= 100;  //this gets rid of the player ID and leaves only the unit number
      t.player = p;
      t.unit = z;
      return t;
    }
  }
  t.player = -1;
  t.unit = -1;
  return t;
}

void draw_unitstats(_unit u)
{
  BITMAP *statbuf;
  int i = 0;
  int bigbuf = 0;
  while (i < 2)
  {
    if (u.load[i].loaded != 0)
    {
      bigbuf = 1;
    }
    i++;
  }
  if (bigbuf == 0)
  {
    statbuf = create_bitmap(100, 35);
  }
  else
  {
    statbuf = create_bitmap(100, 80);
  }
  clear_to_color(statbuf, DGREY);
  text_mode(-1);
  textprintf(statbuf, font, 5, 5, WHITE, "Health: %-1d", rounded_health(u.health));
  textprintf(statbuf, font, 5, 15, WHITE, "Ammo: %-1d", u.ammo);
  textprintf(statbuf, font, 5, 25, WHITE, "Gas: %-1d", u.gas);
  text_mode(0);
  if (u.load[0].loaded == 1)
  {
    textprintf(statbuf, font, 5, 40, WHITE, "%-1s %-1d", unit_name(u.load[0].type).c_str(), rounded_health(u.load[0].health));
  }
  if (u.load[1].loaded == 1)
  {
    textprintf(statbuf, font, 5, 50, WHITE, "%-1s %-1d", unit_name(u.load[1].type).c_str(), rounded_health(u.load[1].health));
  }
  if (bigbuf == 0)
  {
    if (u.tilex - scroll_x > 5)
    {
      draw_trans_sprite(back_buffer, statbuf, 0, 445);
      create_dirty(BACK, 0, 445, 100, 35);
    }
    else
    {
      draw_trans_sprite(back_buffer, statbuf, 540, 445);
      create_dirty(BACK, 540, 445, 100, 35);
    }
  }
  else
  {
    if (u.tilex - scroll_x > 5)
    {
      draw_trans_sprite(back_buffer, statbuf, 0, 400);
      create_dirty(BACK, 0, 400, 100, 80);
    }
    else
    {
      draw_trans_sprite(back_buffer, statbuf, 540, 400);
      create_dirty(BACK, 540, 400, 100, 80);
    }
  }
  destroy_bitmap(statbuf);
}

string do_generalmenu(int moved)
{
  static _button items[5];
  static int first = 1;
  int i, j;
  if (first == 1)
  {
    i = 0;
    items[0].init(501, 1, 137, 29, "End Turn");
    items[1].init(501, 31, 137, 29, "Quit to Menu");
    if (player[pturn].power == 1000)
    {
      items[2].init(501, 61, 137, 29, "Power");
      i = 1;
    }
    items[2 + i].init(501, 61 + (30 * i), 137, 29, "Save Game");
    items[3 + i].init(501, 91 + (30 * i), 137, 29, "Cancel");
    rect(back_buffer, 500, 0, 639, 121 + (30 * i), ORANGE);
    rectfill(back_buffer, 501, 1, 638, 120 + (30 * i), LGREY);
    items[0].draw(back_buffer);
    items[1].draw(back_buffer);
    items[2].draw(back_buffer);
    items[3].draw(back_buffer);
    if (i == 1)
    {
      items[4].draw(back_buffer);
    }
    position_mouse(570, 15);
    rectfill(sprite_buffer, 500, 0, 640, 121 + (30 * i), TRANS);  //clear sprites here
    set_mouse_range(500, 1, 640, 121 + (30 * i));  //if mouse y == 0 the screen scrolls
    create_dirty(BACK, 500, 0, 140, 122 + (30 * i));
    first = 0;
  }
  if (player[pturn].power < 1000)
  {
    j = 4;
  }
  else
  {
    j = 5;
  }
  i = 0;
  while (i < j)
  {
    items[i].check(back_buffer, moved);
    if (items[i].clicked() == 1)
    {
      set_mouse_range(0, 0, 639, 479);
      first = 1;
      return items[i].text;
    }
    i++;
  }
  if (mouse_rclicked() == 1)
  {
    set_mouse_range(0, 0, 639, 479);
    first = 1;
    return "Cancel";
  }
  return "-";
}

string unit_name(int type)
{
  switch(type)
  {
    case ANTI_AIR:
      return "Anti-Air";
      break;
    case APC:
      return "APC";
      break;
    case ARTILLERY:
      return "Artillery";
      break;
    case B_COPTER:
      return "B-Copter";
      break;
    case B_SHIP:
      return "B-Ship";
      break;
    case BOMBER:
      return "Bomber";
      break;
    case CRUISER:
      return "Cruiser";
      break;
    case FIGHTER:
      return "Fighter";
      break;
    case INFANTRY:
      return "Infantry";
      break;
    case LANDER:
      return "Lander";
      break;
    case MD_TANK:
      return "Md-Tank";
      break;
    case MECH:
      return "Mech";
      break;
    case MISSILES:
      return "Missiles";
      break;
    case RECON:
      return "Recon";
      break;
    case ROCKETS:
      return "Rockets";
      break;
    case SUB:
      return "Sub";
      break;
    case T_COPTER:
      return "T-Copter";
      break;
    case TANK:
      return "Tank";
      break;
  }
  return "-";
}

int unit_type(string name)
{
  if (name == "Anti-Air")
  {
    return ANTI_AIR;
  }
  else if (name == "APC")
  {
    return APC;
  }
  else if (name == "Artillery")
  {
    return ARTILLERY;
  }
  else if (name == "B-Copter")
  {
    return B_COPTER;
  }
  else if (name == "B-Ship")
  {
    return B_SHIP;
  }
  else if (name == "Bomber")
  {
    return BOMBER;
  }
  else if (name == "Cruiser")
  {
    return CRUISER;
  }
  else if (name == "Fighter")
  {
    return FIGHTER;
  }
  else if (name == "Infantry")
  {
    return INFANTRY;
  }
  else if (name == "Lander")
  {
    return LANDER;
  }
  else if (name == "Md-Tank")
  {
    return MD_TANK;
  }
  else if (name == "Mech")
  {
    return MECH;
  }
  else if (name == "Missiles")
  {
    return MISSILES;
  }
  else if (name == "Recon")
  {
    return RECON;
  }
  else if (name == "Rockets")
  {
    return ROCKETS;
  }
  else if (name == "Sub")
  {
    return SUB;
  }
  else if (name == "T-Copter")
  {
    return T_COPTER;
  }
  else if (name == "Tank")
  {
    return TANK;
  }
  return -1;
}

int buildings_owned(int plyr)
{
  int temp1, temp2, z;
  int num = 0;
  temp1 = 0;
  while (temp1 < h)
  {
    temp2 = 0;
    while (temp2 < l)
    {
      z = building_here(temp2, temp1);
      if (z != -1)
      {
        if (z >= 4)  //if not a capital
        {
          z -= 4;
          if ((z % 5) - 1 == plyr)  //player owns the building
          {
            num++;
          }
        }
      }
      temp2++;
    }
    temp1++;
  }
  num++;  //the player will always control a capital, so add one to num
  return num;
}

int can_attack(_unit a, _unit d)
{
  int ta = a.type;
  int td = d.type;
  if (a.ammo > 0)
  {
    switch(d.basetype)
    {
      case LAND:
        if (a.basetype == LAND)
        {
          if (ta != MISSILES)
          {
            return 1;
          }
        }
        else
        {
          if ((ta == B_COPTER) || (ta == BOMBER) || (ta == B_SHIP))
          {
            return 1;
          }
        }
        break;
      case AIR:
        if (a.basetype == AIR)
        {
          if (ta != BOMBER)
          {
            if (ta == B_COPTER)
            {
              if ((td != BOMBER) && (td != FIGHTER))
              {
                return 1;
              }
            }
            else
            {
              return 1;
            }
          }
        }
        else if (a.basetype == LAND)
        {
          if ((td == BOMBER) || (td == FIGHTER))
          {
            if ((ta == MISSILES) || (ta == ANTI_AIR))
            {
              return 1;
            }
          }
          else
          {
            if (!((ta == ARTILLERY) || (ta == ROCKETS)))
            {
              return 1;
            }
          }
        }
        else if (ta == CRUISER)  //cruiser is the only sea unit w/ anti-air ability
        {
          return 1;
        }
        break;
      case SEA:
        if (a.basetype == SEA)
        {
          if (ta == CRUISER)
          {  //cruisers can only attack air units and subs
            if (td == SUB)
            {
              return 1;
            }
          }
          else
          {
            if ((td == SUB) && (d.submerged == 1))
            {  //battleships can't hit submerged subs
              if ((ta == SUB) || (ta == CRUISER))  //but subs and cruisers can
              {
                return 1;
              }
              else
              {
                return 0;
              }
            }
            return 1;
          }
        }
        else if (a.basetype == LAND)
        {
          if ((ta == TANK) || (ta == MD_TANK) || (ta == ARTILLERY) || (ta == ROCKETS))
          {
            if ((td == SUB) && (d.submerged == 1))
            {  //can't hit an underwater sub from land
              return 0;
            }
            else
            {
              return 1;
            }
          }
        }
        else
        {
          if ((ta == BOMBER) || (ta == B_COPTER))
          {
            if ((td == SUB) && (d.submerged == 1))
            {  //can't hit a submerged sub from air either
              return 0;
            }
            else
            {
              return 1;
            }
          }
        }
        break;
    }
  }
  return 0;
}

void draw_attackables(_unit u)
{
  _target t;
  _unit f;
  int t1, t2;  
  if (u.attacktype == DIRECT)
  {
    t = enemy_nearby(u.color, u.tilex, u.tiley);
    while (t.unit != -1)
    {
      f = player[t.player].unit[t.unit];
      if (can_attack(u, f) == 1)
      {
        t1 = (f.tilex - scroll_x) * 40;
        t2 = (f.tiley - scroll_y) * 40;
        rectfill(back_buffer, t1, t2, t1 + 40, t2 + 40, RED);
        create_dirty(BACK, t1, t2, 40, 40);
        f.draw(1);  //force the unit that's targeted to be drawn
      }
      t = enemy_nearby(u.color, u.tilex, u.tiley, t.player, t.unit + 1);
    }
  }
  else
  {  //enemy_in_range function only works correctly with range-attack units
    t = enemy_in_range(u.color, u.tilex, u.tiley, u.type);
    while (t.unit != -1)
    {  //what this does is cycle through all possible targets, drawing red as it goes
      f = player[t.player].unit[t.unit];
      if (can_attack(u, f) == 1)
      {
        t1 = (f.tilex - scroll_x) * 40;
        t2 = (f.tiley - scroll_y) * 40;
        rectfill(back_buffer, t1, t2, t1 + 40, t2 + 40, RED);
        create_dirty(BACK, t1, t2, 40, 40);
        f.draw(1);  //force the unit that's targeted to be drawn
      }
      t = enemy_in_range(u.color, u.tilex, u.tiley, u.type, t.player, t.unit + 1);
    }
  }
}

_target attackable(_unit attacker, int tx, int ty)
{
  _target t;
  int p = 0;
  int w;
  while (p < 4)
  {
    if ((player[p].playing == 1) && (p != attacker.color))
    {
      w = unit_here(p, tx, ty, LTILE);
      if (w != -1)
      {
        if (can_attack(attacker, player[p].unit[w]) == 1)
        {
          t.player = p;
          t.unit = w;
          return t;
        }
      }
    }
    p++;
  }
  t.player = -1;
  t.unit = -1;
  return t;
}

void draw_playerstats(int plyr)
{
  int z = plyr / 10;  //AI players send draw location information in the plyr int as well
  plyr %= 10;  //it is in the tens column, so regular player information is untouched
  if (player[plyr].controller == AI)
  {  //if it is an AI player, the stats are dimmer
    set_trans_blender(100, 100, 100, 100);
  }
  BITMAP *statbuf;
  int mx = mouse_x;
  int my = mouse_y;
  int col;
  switch(plyr)
  {
    case 0:
      col = RED;
      break;
    case 1:
      col = BLUE;
      break;
    case 2:
      col = DGREEN;
      break;
    case 3:
      col = DYELLOW;
      break;
  }
  statbuf = create_bitmap(130, 80);
  clear_to_color(statbuf, DGREY);
  draw_sprite(statbuf, character[player[plyr].number].picture, 25, 0);
  ellipsefill(statbuf, 65, 9, 65, 4, col);
  ellipsefill(statbuf, 65, 19, 65, 4, col);
  text_mode(-1);
  textprintf(statbuf, font, 5, 5, WHITE, "Player %-1d", plyr + 1);
  textprintf(statbuf, font, 5, 15, WHITE, "Funds: %-1d", player[plyr].cash);
  if (player[plyr].power == 1000)  //if the power gauge is full, make it stand out
  {
    rectfill(statbuf, 0, 24, 130, 34, WHITE);
    textprintf_centre(statbuf, font, 65, 27, col, "Power: %-1d", player[plyr].power);
  }
  else
  {
    rectfill(statbuf, 0, 24, (player[plyr].power * 130) / 1000, 34, col);
    textprintf_centre(statbuf, font, 65, 27, WHITE, "Power: %-1d", player[plyr].power);
  }
  text_mode(0);
  if (player[plyr].controller == AI)
  {  //for the AI, draw position was sent in 'plyr' in the tens column, and was sent to 'z'
    if (z == 1)
    {
      draw_trans_sprite(back_buffer, statbuf, 0, 0);
      create_dirty(BACK, 0, 0, 130, 80);
    }
    else
    {
      draw_trans_sprite(back_buffer, statbuf, 510, 0);
      create_dirty(BACK, 510, 0, 130, 80);    
    }
  }
  else
  {  //for a human, the draw position depends on the mouse location
    if (mx > 320)
    {
      draw_trans_sprite(back_buffer, statbuf, 0, 0);
      create_dirty(BACK, 0, 0, 130, 80);
    }
    else
    {
      draw_trans_sprite(back_buffer, statbuf, 510, 0);
      create_dirty(BACK, 510, 0, 130, 80);
    }
  }
  destroy_bitmap(statbuf);  
  if (player[plyr].controller == AI)
  {  //reset the transparency to what it was before
    set_trans_blender(192, 192, 192, 192);
  }
}

int unit_here_thorough(int plyr, int tx, int ty, int ignore_n)
{
  int i = 0;
  _unit u;
  while (i < 50)
  {
    if (i != ignore_n)
    {
      u = player[plyr].unit[i];
      if (u.exists == 1)
      {
        if ((u.tilex == tx) && (u.tiley == ty))
        {
          return i;
        }
      }
    }
    i++;
  }
  return -1;
}

void draw_unloadables(int tx, int ty, int type)
{
  DATAFILE *glb = (DATAFILE *)graphics[2].dat;
  int x, y;
  x = tx + 1;
  y = ty;
  if (unit_unloadable_here(x, y, type) == 1)
  {
    draw_trans_sprite(back_buffer, (BITMAP *)glb[3].dat, (x - scroll_x) * 40, (y - scroll_y) * 40);
    create_dirty(BACK, (x - scroll_x) * 40, (y - scroll_y) * 40, 40, 40);
  }
  x = tx - 1;
  if (unit_unloadable_here(x, y, type) == 1)
  {
    draw_trans_sprite(back_buffer, (BITMAP *)glb[3].dat, (x - scroll_x) * 40, (y - scroll_y) * 40);
    create_dirty(BACK, (x - scroll_x) * 40, (y - scroll_y) * 40, 40, 40);
  }
  x = tx;
  y = ty - 1;
  if (unit_unloadable_here(x, y, type) == 1)
  {
    draw_trans_sprite(back_buffer, (BITMAP *)glb[3].dat, (x - scroll_x) * 40, (y - scroll_y) * 40);
    create_dirty(BACK, (x - scroll_x) * 40, (y - scroll_y) * 40, 40, 40);
  }
  y = ty + 1;
  if (unit_unloadable_here(x, y, type) == 1)
  {
    draw_trans_sprite(back_buffer, (BITMAP *)glb[3].dat, (x - scroll_x) * 40, (y - scroll_y) * 40);
    create_dirty(BACK, (x - scroll_x) * 40, (y - scroll_y) * 40, 40, 40);
  }  
}

int unit_unloadable_here(int tx, int ty, int type)
{
  return unit_unloadable_here(tx - 1, ty, tx, ty, type);
}

int unit_unloadable_here(int ox, int oy, int tx, int ty, int type)
{
  int s = get_set(map[tx][ty]);
  int rivers = 0;
  int ok = 0;
  int z;
  if ((type == INFANTRY) || (type == MECH))
  {  //infantry and mech units can go in rivers
    rivers = 1;
  }
  if ((s == 0) || (s == 3) || (s == 4))
  {  //if the tile is land, shoal, or building
    ok = 1;
  }
  else if ((s == 1) && (rivers == 1))
  {  //if it is a river tile and the unit can go in rivers
    ok = 1;
  }
  if (unitmap[tx][ty] != -1)
  {  //can't unload if a unit is on the tile already
    ok = 0;
  }
  z = tile_distance(ox, oy, tx, ty);
  if (z != 1)
  {  //make sure the distance between unloader and unloadee is 1
    ok = 0;
  }
  return ok;
}

int do_unloadmenu(_unit u, int moved)
{
  static _button b[3];
  static int first = 1;
  static int oldmx, oldmy;
  if (first == 1)
  {
    oldmx = mouse_x;
    oldmy = mouse_y;
    if (u.load[0].loaded == 1)
    {
      b[0].init(501, 1, 137, 29, unit_name(u.load[0].type).c_str());
    }
    else
    {
      b[0].init(501, 1, 137, 29, "-");
    }
    if (u.load[1].loaded == 1)
    {
      b[1].init(501, 31, 137, 29, unit_name(u.load[1].type).c_str());
    }
    else
    {
      b[1].init(501, 31, 137, 29, "-");
    }
    b[2].init(501, 61, 137, 29, "Cancel");
    rect(back_buffer, 500, 0, 639, 91, ORANGE);
    rectfill(back_buffer, 501, 1, 638, 90, LGREY);
    b[0].draw(back_buffer);
    b[1].draw(back_buffer);
    b[2].draw(back_buffer);
    position_mouse(570, 15);
    rectfill(sprite_buffer, 500, 0, 640, 91, TRANS);  //get rid of any unit sprites
    set_mouse_range(500, 0, 640, 91);
    create_dirty(BACK, 500, 0, 140, 92);
    first = 0;
  }
  b[0].check(back_buffer, moved);
  b[1].check(back_buffer, moved);
  b[2].check(back_buffer, moved);
  if ((b[0].clicked() == 1) && (b[0].text != "-"))
  {
    draw_tiles(scroll_x, scroll_y, 0, 12, 0, 4, 3, 1);
    set_mouse_range(0, 0, 639, 479);
    position_mouse(oldmx, oldmy);
    first = 1;
    return 0;
  }
  if ((b[1].clicked() == 1) && (b[1].text != "-"))
  {
    draw_tiles(scroll_x, scroll_y, 0, 12, 0, 4, 3, 1);
    set_mouse_range(0, 0, 639, 479);
    position_mouse(oldmx, oldmy);
    first = 1;
    return 1;
  }
  if (b[2].clicked() == 1)
  {
    set_mouse_range(0, 0, 639, 479);
    position_mouse(oldmx, oldmy);
    first = 1;
    return 2;
  }
  return -1;
}

int do_cancelunload_menu(int moved)
{
  static _button b[2];
  static int first = 1;
  if (first == 1)
  {
    position_mouse(570, 15);
    set_mouse_range(501, 1, 639, 59);
    b[0].init(501, 1, 137, 29, "Continue Unload");
    b[1].init(501, 31, 137, 29, "Cancel Unload");
    rect(back_buffer, 500, 0, 639, 61, ORANGE);
    rectfill(back_buffer, 501, 1, 638, 60, LGREY);
    b[0].draw(back_buffer);
    b[1].draw(back_buffer);
    create_dirty(BACK, 500, 0, 141, 62);
    first = 0;
  }
  b[0].check(back_buffer, moved);
  b[1].check(back_buffer, moved);
  if (b[0].clicked() == 1)
  {
    set_mouse_range(0, 0, 639, 479);
    first = 1;
    draw_tiles(scroll_x, scroll_y, 0, 12, 0, 4, 3, 1);
    return 0;
  }
  if (b[1].clicked() == 1)
  {
    set_mouse_range(0, 0, 639, 479);
    first = 1;
    draw_tiles(scroll_x, scroll_y, 0, 12, 0, 4, 3, 1);
    return 2;
  }
  return 1;
}

int rounded_health(float h)
{
  int whole = int(h);
  int part = int((h - float(whole)) * 10);
  if ((whole == 0) && (h > 0))
  {
    return 1;
  }
  else if (whole == 10)
  {
    return 10;
  }
  else
  {
    if (part >= 5)
    {
      return whole + 1;
    }
    else
    {
      return whole;
    }
  }
}

int unit_exists(int plyr)
{
  int i = 0;
  while (i < 50)
  {
    if (player[plyr].unit[i].exists == 1)
    {
      return 1;
    }
    i++;
  }
  return 0;
}

void transform_buildings(int plyr, int plyr2)
{
  int i, j, z;
  i = 0;
  while (i < l)
  {
    j = 0;
    while (j < h)
    {
      z = get_set(map[i][j]);
      if (z == 4)
      {
        z = get_tilenum(map[i][j]);
        if (z < 4)
        {  //capital here
          if (z == plyr)
          {
            map[i][j] -= z;
            map[i][j] += 4 + (plyr2 + 1);
          }
        }
        else
        {  //building here
          z -= 4;
          if ((z % 5) - 1 == plyr)
          {
            map[i][j] -= z % 5;
            map[i][j] += plyr2 + 1;
          }
        }
      }
      j++;
    }
    i++;
  }
}

void repair_units(int plyr)
{
  int i = 0;
  int z;
  int rep;
  float oldh;
  _unit u;
  while (i < 50)
  {
    u = player[plyr].unit[i];
    if (u.exists == 1)
    {
      rep = 0;
      z = get_set(map[u.tilex][u.tiley]);
      if (z == 4)  //set 4 is the buildings set
      {
        z = get_tilenum(map[u.tilex][u.tiley]);
        if (z > 3)
        {
          z -= 4;
          if ((z % 5) - 1 == plyr)
          {
            rep = 1;
          }
        }
        else
        {
          if (z % 4 == plyr)
          {
            rep = 1;
          }
        }
      }
      if (rep == 1)  //if the unit is on a friendly base
      {
        player[plyr].unit[i].supply();  //resupply the unit
        if (u.health < 10)  //if the unit is damaged, add 2 health but take some cash
        {
          oldh = u.health;
          player[plyr].unit[i].health += 2;
          if (player[plyr].unit[i].health > 10)
          {
            player[plyr].unit[i].health = 10;
          }
          player[plyr].cash -= int((player[plyr].unit[i].health - oldh) / 20 * u.price);
          if (player[plyr].cash < 0)
          {
            player[plyr].cash = 0;
          }
        }
      }
    }
    i++;
  }
}

int do_savemenu(int moved)
{
  static int first = 1;
  static _button slot[10];
  int i, o, p;
  char path[10];
  char text[10];
  char name[15] = "";
  char t[35];
  sprintf(t, mapname);
  if (first == 1)
  {
    rectfill(sprite_buffer, 240, 100, 400, 390, TRANS);
    rect(back_buffer, 240, 100, 400, 390, ORANGE);
    rectfill(back_buffer, 241, 101, 399, 389, LGREY);
    position_mouse(320, 245);
    set_mouse_range(240, 100, 400, 390);
    i = 0;
    while (i < 9)
    {
      sprintf(path, "game%-1d.sav", i);
      ifstream n(path);
      if (n.bad())
      {
        slot[i].init(250, 110 + (i * 25), 140, 20, "Empty");
      }
      else
      {
        n >> text;
        slot[i].init(250, 110 + (i * 25), 140, 20, text);
      }
      slot[i].draw(back_buffer);
      i++;
    }
    slot[9].init(250, 360, 140, 20, "Cancel");
    slot[9].draw(back_buffer);
    first = 0;
    create_dirty(BACK, 240, 100, 161, 291);
  }
  i = 0;
  while (i < 10)
  {
    slot[i].check(back_buffer, moved);
    if (slot[i].clicked() == 1)
    {
      if (i == 9)  //Cancel was clicked
      {
        first = 1;
        set_mouse_range(0, 0, 639, 479);
        return 0;
      }
      else
      {
        if (slot[i].text != "Empty")
        {
          sprintf(name, slot[i].text.c_str());
        }
        text_box(240, 200, 160, 20, name, 15, 0);
        if (strcmp(name, "_CANCEL_") == 0)
        {  //if ESC was pressed in text_box, don't save
          first = 1;
          set_mouse_range(0, 0, 639, 479);
          return 0;
        }
        sprintf(path, "game%-1d.sav", i);
        ofstream savefile(path);
        if (!(savefile.bad()))
        {
          savefile << name << "\n" << l << "\n" << h << "\n";
          o = 0;
          while (o < h)
          {
            p = 0;
            while (p < l)
            {
              savefile << map[p][o];
              if (p != l - 1)
              {
                savefile << " ";
              }
              p++;
            }
            savefile << "\n";
            o++;
          }
          o = 0;
          while (o < 4)
          {
            savefile << "playing " << player[o].playing << "\n";
            if (player[o].playing == 1)
            {
              savefile << "number " << player[o].number << "\n";
              savefile << "cash " << player[o].cash << "\n";
              savefile << "power " << player[o].power << "\n";
              savefile << "controller " << player[o].controller << "\n";
              savefile << "powered " << player[o].powered << "\n";
              savefile << "units " << player[o].units_in_play() << "\n";
            }
            p = 0;
            if (player[o].playing != 1)
            {
              p = 50;
            }
            while (p < 50)
            {
              if (player[o].unit[p].exists == 1)
              {
                savefile << "unittype " << player[o].unit[p].type << "\n";
                savefile << "unittilex " << player[o].unit[p].tilex << "\n";
                savefile << "unittiley " << player[o].unit[p].tiley << "\n";
                savefile << "unithealth " << player[o].unit[p].health << "\n";
                savefile << "unitammo " << player[o].unit[p].ammo << "\n";
                savefile << "unitgas " << player[o].unit[p].gas << "\n";
                savefile << "unitready " << player[o].unit[p].ready << "\n";
                savefile << "unitcapturing " << player[o].unit[p].capturing << "\n";
                savefile << "unitload0loaded " << player[o].unit[p].load[0].loaded << "\n";
                savefile << "unitload0type " << player[o].unit[p].load[0].type << "\n";
                savefile << "unitload0health " << player[o].unit[p].load[0].health << "\n";
                savefile << "unitload0ammo " << player[o].unit[p].load[0].ammo << "\n";
                savefile << "unitload0gas " << player[o].unit[p].load[0].gas << "\n";
                savefile << "unitload0subloaded " << player[o].unit[p].load[0].subload.loaded << "\n";
                savefile << "unitload0subtype " << player[o].unit[p].load[0].subload.type << "\n";
                savefile << "unitload0subhealth " << player[o].unit[p].load[0].subload.health << "\n";
                savefile << "unitload0subammo " << player[o].unit[p].load[0].subload.ammo << "\n";
                savefile << "unitload0subgas " << player[o].unit[p].load[0].subload.gas << "\n";
                savefile << "unitload1loaded " << player[o].unit[p].load[1].loaded << "\n";
                savefile << "unitload1type " << player[o].unit[p].load[1].type << "\n";
                savefile << "unitload1health " << player[o].unit[p].load[1].health << "\n";
                savefile << "unitload1ammo " << player[o].unit[p].load[1].ammo << "\n";
                savefile << "unitload1gas " << player[o].unit[p].load[1].gas << "\n";
                savefile << "unitload1subloaded " << player[o].unit[p].load[1].subload.loaded << "\n";
                savefile << "unitload1subtype " << player[o].unit[p].load[1].subload.type << "\n";
                savefile << "unitload1subhealth " << player[o].unit[p].load[1].subload.health << "\n";
                savefile << "unitload1subammo " << player[o].unit[p].load[1].subload.ammo << "\n";
                savefile << "unitload1subgas " << player[o].unit[p].load[1].subload.gas << "\n";
                savefile << "unitmovingtowards " << player[o].unit[p].moving_towards << "\n";
              }
              p++;
            }
            o++;
          }
          savefile << "pturn " << pturn << "\n" << aiprofile << "\n" << t;
        }
        first = 1;
        set_mouse_range(0, 0, 639, 479);
        return 0;
      }
    }
    i++;
  }
  return 1;  //returns 1 if it isn't finished
}

void scroll_to_hq(int plyr)
{
  int x, y, z;
  y = 0;
  while (y < h)
  {
    x = 0;
    while (x < l)
    {
      z = building_here(x, y);
      if (z != -1)
      {
        if (z == plyr)
        {
          scroll_x = x - 8;  //center on the HQ
          scroll_y = y - 6;
          if (scroll_x < 0) scroll_x = 0;  //make sure it doesn't go past the map ends
          if (scroll_x + 16 > l) scroll_x = l - 16;
          if (scroll_y < 0) scroll_y = 0;
          if (scroll_y + 12 > h) scroll_y = h - 12;
          x = 5000;  //just to get out of the loop really fast
          y = 5000;
        }
      }
      x++;
    }
    y++;
  }
}

void scroll_to_location(int x, int y)
{
  scroll_x = x - 8;  //center on chosen tile
  scroll_y = y - 6;
  if (scroll_x < 0) scroll_x = 0;  //make sure it doesn't go past the map ends
  if (scroll_x + 16 > l) scroll_x = l - 16;
  if (scroll_y < 0) scroll_y = 0;
  if (scroll_y + 12 > h) scroll_y = h - 12;
}

void play_moving_sound(int utype)
{
  switch(utype)
  {
    case ANTI_AIR:
      play_sound(TANKMOVE);
      break;
    case APC:
      play_sound(ENGINE);
      break;
    case ARTILLERY:
      play_sound(TANKMOVE);
      break;
    case B_COPTER:
      play_sound(CHOPPER);
      break;
    case B_SHIP:
      play_sound(SEABOAT);
      break;
    case BOMBER:
      play_sound(JET);
      break;
    case CRUISER:
      play_sound(SEABOAT);
      break;
    case FIGHTER:
      play_sound(JET);
      break;
    case INFANTRY:
      play_sound(MARCH);
      break;
    case LANDER:
      play_sound(SEABOAT);
      break;
    case MD_TANK:
      play_sound(TANKMOVE);
      break;
    case MECH:
      play_sound(MARCH);
      break;
    case MISSILES:
      play_sound(ENGINE);
      break;
    case RECON:
      play_sound(ENGINE);
      break;
    case ROCKETS:
      play_sound(TANKMOVE);
      break;
    case SUB:
      play_sound(SEABOAT);
      break;
    case T_COPTER:
      play_sound(CHOPPER);
      break;
    case TANK:
      play_sound(TANKMOVE);
      break;
  }
}

int player_defeated(int plyr)
{
  int i, j, n, t, z;
  _target targ;
  if (player[plyr].units_in_play() == 0)
  {  //if this player has no units in play
    n = 0;
    i = 0;
    while (i < h)
    {
      j = 0;
      while (j < l)
      {
        z = map[j][i];
        if (get_set(z) == 4)
        {  //if there is a building here
          t = get_tilenum(z);
          if (t > 3)
          {  //if it is not a capital
            t -= 4;
            if ((t % 5) - 1 == plyr)
            {  //if it belongs to the player
              if (t / 5 >= 1)
              {  //if it is a building that can create units
                targ = any_unit_here(j, i, plyr);
                if (targ.unit == -1)  //if there is no unit on the bulding, which
                {                     //means the building can make more units
                  n++;
                }
              }
            }
          }
        }
        j++;
      }
      i++;
    }
    if (n == 0)  //if there are no buildings that can make more units
    {
      return 1;  //the player has been defeated
    }
    else
    {
      return 0;
    }
  }
  return 0;
}

int do_powerflash(int cnum)
{
  static int first = 1;
  static int x, col;
  BITMAP *temp;
  static BITMAP *thebmp;
  int i, h;
  DATAFILE *glb = (DATAFILE *)graphics[2].dat;
  if (first == 1)
  {
    position_mouse(650, 490);
    set_mouse_range(650, 490, 651, 491);
    x = 664;
    switch(pturn)
    {
      case 0:
        col = RED;
        break;
      case 1:
        col = BLUE;
        break;
      case 2:
        col = GREEN;
        break;
      case 3:
        col = YELLOW;
        break;
    }
    if (character[cnum].power == 3)
    {  //if the power is to damage all enemy units
      temp = create_bitmap(640, 480);
      clear_to_color(temp, col);  //shade the whole screen with that player's color
      set_trans_blender(90, 90, 90, 90);
      draw_trans_sprite(back_buffer, temp, 0, 0);
      set_trans_blender(192, 192, 192, 192);
      destroy_bitmap(temp);
    }
    rectfill(back_buffer, 0, 170, 640, 310, col);
    hline(back_buffer, 0, 168, 640, col);
    hline(back_buffer, 0, 312, 640, col);
    hline(back_buffer, 0, 165, 640, col);
    hline(back_buffer, 0, 315, 640, col);
    hline(back_buffer, 0, 161, 640, col);
    hline(back_buffer, 0, 319, 640, col);
    hline(back_buffer, 0, 156, 640, col);
    hline(back_buffer, 0, 324, 640, col);
    rectfill(sprite_buffer, 0, 0, 640, 480, TRANS);
    create_dirty(BACK, 0, 0, 640, 480);
    temp = create_bitmap(text_length((FONT *)glb[2].dat, character[cnum].powername.c_str()), 40);
    clear_to_color(temp, TRANS);
    text_mode(-1);
    textout(temp, (FONT *)glb[2].dat, character[cnum].powername.c_str(), 0, 0, WHITE);
    text_mode(0);
    thebmp = create_bitmap(temp->w * 3, temp->h * 3);
    clear_to_color(thebmp, TRANS);
    stretch_sprite(thebmp, temp, 0, 0, thebmp->w, thebmp->h);
    destroy_bitmap(temp);
    first = 0;
  }
  h = 240 - (thebmp->h / 2);
  if (x + thebmp->w > -300)
  {
    rectfill(back_buffer, x, h, x + thebmp->w, h + thebmp->h, col);
    x -= 12;
    draw_sprite(back_buffer, thebmp, x, h);
    create_dirty(BACK, x, h, thebmp->w + 12, thebmp->h);
    return 1;  //return something other than -1 to continue animation
  }
  else
  {
    destroy_bitmap(thebmp);
    first = 1;
    position_mouse(320, 240);
    set_mouse_range(0, 0, 639, 479);
    return -1;  //return -1 to end the animation
  }
}

void decrease_gas(int plyr)
{
  int i = 0;
  while (i < 50)
  {
    if (player[plyr].unit[i].exists == 1)
    {
      if ((player[plyr].unit[i].basetype == AIR) || (player[plyr].unit[i].basetype == SEA))
      {
        player[plyr].unit[i].gas -= 2;
        if (player[plyr].unit[i].submerged == 1)
        {  //submerged subs lose 4 gas per turn instead of 2
          player[plyr].unit[i].gas -= 2;
        }
        if (player[plyr].unit[i].gas <= 0)
        {
          player[plyr].unit[i].gas = 0;
          player[plyr].unit[i].kill();
        }
      }
    }
    i++;
  }
}

void init_explode(int x, int y)
{
  int i;
  boom.push_back();
  i = boom.size() - 1;
  boom[i].exists = 1;
  boom[i].x = x;
  boom[i].y = y;
  boom[i].frame = 0;
}

void do_explodes()
{
  DATAFILE *anim = (DATAFILE *)explosions[1].dat;
  int i = 0;
  int all_empty = 1;
  while (i < boom.size())
  {
    if (boom[i].exists == 1)
    {
      all_empty = 0;
      if (boom[i].frame == 0)  //if the explosion has just begun
      {
        play_sound(EXPLOSION);
      }
      boom[i].frame += 1.5;
      if (int(boom[i].frame) > 29)
      {
        boom[i].exists = 0;
        rectfill(sprite_buffer, boom[i].x, boom[i].y, boom[i].x + 40, boom[i].y + 40, TRANS);
        create_dirty(BACK, boom[i].x, boom[i].y, 40, 40);
      }
      else
      {
        blit(back_buffer, sprite_buffer, boom[i].x, boom[i].y, boom[i].x, boom[i].y, 40, 40);
        draw_sprite(sprite_buffer, (BITMAP *)anim[int(boom[i].frame)].dat, boom[i].x, boom[i].y);
        create_dirty(SPRITE, boom[i].x, boom[i].y, 40, 40);
      }
    }
    i++;
  }
  if ((all_empty == 1) && (boom.size() > 0))
  {  //if there are no explosions going on, but the vector has items in it
    boom.resize(0);  //remove those useless items
  }
}

void do_power()
{
  int i, j, r, t;
  switch(character[player[pturn].number].power)
  {
    case 0:  //+2 unit health
      i = 0;
      while (i < 50)
      {
        if (player[pturn].unit[i].exists == 1)
        {
          player[pturn].unit[i].health += 2;
          if (player[pturn].unit[i].health > 10)
          {
            player[pturn].unit[i].health = 10;
          }
        }
        i++;
      }
      break;
    case 3:  //-1 enemy unit health
      j = 0;
      while (j < 4)
      {
        if ((player[j].playing == 1) && (j != pturn))
        {
          i = 0;
          while (i < 50)
          {
            if (player[j].unit[i].exists == 1)
            {
              player[j].unit[i].health--;
              if (player[j].unit[i].health <= 0)
              {
                player[j].unit[i].health = 1;
              }
            }
            i++;
          }
        }
        j++;
      }
      break;
    case 4:  //refresh non-infantry units
      i = 0;
      while (i < 50)
      {
        if (player[pturn].unit[i].exists == 1)
        {
          if ((player[pturn].unit[i].type != INFANTRY) && (player[pturn].unit[i].type != MECH))
          {
            player[pturn].unit[i].ready = 1;
          }
        }
        i++;
      }
      break;
    case 5:  //kill random 1/5 enemy units
      i = 0;
      t = 0;
      r = 0;
      while (i < 4)
      {
        if ((player[i].playing == 1) && (i != pturn))
        {
          t += player[i].units_in_play();
        }
        i++;
      }
      r = t % 5;
      t /= 5;      //if there are < 5, 1 dies
      if (r != 0)  //if there are 5 exactly, 1 dies
      {            //if there are > 5 but <= 10, 2 die
        t++;
      }
      r = 0;
      while (r < t)
      {
        j = rand()%4;
        if (j != pturn)
        {
          i = rand()%50;
          if (player[j].unit[i].exists == 1)
          {
            player[j].unit[i].kill();
            r++;
          }
        }
      }
      break;
  }
}

int do_cancelattack_menu(int moved)
{
  static _button b[2];
  static int first = 1;
  if (first == 1)
  {
    position_mouse(570, 15);
    set_mouse_range(501, 1, 639, 59);
    b[0].init(501, 1, 137, 29, "Continue Attack");
    b[1].init(501, 31, 137, 29, "Cancel Attack");
    rect(back_buffer, 500, 0, 639, 61, ORANGE);
    rectfill(back_buffer, 501, 1, 638, 60, LGREY);
    b[0].draw(back_buffer);
    b[1].draw(back_buffer);
    create_dirty(BACK, 500, 0, 141, 62);
    first = 0;
  }
  b[0].check(back_buffer, moved);
  b[1].check(back_buffer, moved);
  if (b[0].clicked() == 1)
  {
    set_mouse_range(0, 0, 639, 479);
    first = 1;
    draw_tiles(scroll_x, scroll_y, 0, 12, 0, 4, 3, 1);
    return 0;
  }
  if (b[1].clicked() == 1)
  {
    set_mouse_range(0, 0, 639, 479);
    first = 1;
    draw_tiles(scroll_x, scroll_y, 0, 12, 0, 4, 3, 1);
    return 2;
  }
  return 1;
}

int secure_base(int plyr)
{
  int x, y, z, u;
  y = 0;
  while (y < h)
  {
    x = 0;
    while (x < l)
    {
      z = building_here(x, y);
      if (z > 9)
      {  //if it is not a city or HQ
        z -= 4;
        if (z % 5 == plyr + 1)
        {  //if it belongs to the player
          u = any_unit_here(x, y);
          if ((u == -1) || (u / 100 == plyr))
          {  //if there is no unit here or a unit that belongs to this player
            return 1;
          }
        }
      }
      x++;
    }
    y++;
  }
  return 0;
}

void capture_building(_unit* u)
{
  int temp1, temp2, z;
  if (u->capturing == -1)
  {  //just started a capture
    u->capturing = 20;
    u->capturing -= rounded_health(u->health);
  }
  else  //already in the process of capturing
  {
    u->capturing -= rounded_health(u->health);
    if (u->capturing <= 0)
    {  //if the building has been captured
      u->capturing = -1;
      temp1 = building_here(u->tilex, u->tiley);
      if (temp1 < 4)  //building is a capital
      {
        z = get_tilenum(map[u->tilex][u->tiley]);
        transform_buildings(z, u->color);      //captured player's buildings
        draw_tiles(scroll_x, scroll_y, 0, 1);  //go to the capturer
        player[z].clear_units();
        player[z].playing = 0;
      }
      else
      {
        temp2 = map[u->tilex][u->tiley];
        temp2 -= 3;  //get rid of capital tiles
        temp2 -= temp2 % 5;  //set to neutral
        temp2 += 4 + u->color + 1;  //put back capital tiles and add owner num + 1
        map[u->tilex][u->tiley] = temp2;
        draw_tiles(scroll_x, scroll_y, 0, u->tilex - scroll_x, u->tiley - scroll_y, 1, 1, 0);
      }
      u->draw(1);
    }
  }
}

void merge_units(_unit* merger, int tx, int ty)
{
  int u = unit_here_thorough(merger->color, tx, ty, merger->number);
  int h;
  _unit* mergee = &player[merger->color].unit[u];
  merger->gas += mergee->gas;
  if (merger->gas > 99)
  {
    merger->gas = 99;
  }
  merger->ammo += mergee->ammo;
  if (merger->ammo > 99)
  {
    merger->ammo = 99;
  }
  merger->health += float(rounded_health(mergee->health));
  if (merger->health > 10)
  {
    merger->health = 10;
  }
  merger->capturing = mergee->capturing;
  unitmap[tx][ty] = (merger->color * 100) + merger->number;
  mergee->exists = 0;
}
