/**
  * qty does not actually buy that qty, but checks that the AI has enough cash to buy that qty.
  *
  * @param type
  * @param location
  * @param qty
  * @param keep_reserve_cash
  * @return
  */
 private boolean buyUnit(int type, Point location, int qty, boolean keep_reserve_cash) {
   int cost = UnitStats.GetCost(type) * qty;
   if (keep_reserve_cash) {
     cost += this.player_attack_units_threat * 2;
   }
   if (main.game_data.pdata[side].getCash() >= cost) {
     if (main.game_data.map_data.map[location.x][location.y].owner == side) {
       if (main.isAreaClearForNewUnit(
           location.x * MapData.SQUARE_SIZE, location.y * MapData.SQUARE_SIZE, type)) {
         UnitStats.CreateUnit(main, type, location.x, location.y, side);
         main.game_data.pdata[side].addCash(-UnitStats.GetCost(type));
         if (Main.DEBUG_AI) {
           main.addLogEntry("AI bought " + UnitStats.GetName(type));
         }
         this.updateIntel();
         return true;
       } else {
         if (Main.DEBUG_AI) {
           main.addLogEntry("Area " + top_threat_location + " not clear");
         }
       }
     }
   }
   return false;
 }
  public void process() {
    if (ai_interval.hitInterval()) {

      if (update_intel_interval.hitInterval()) {
        this.updateIntel();
      }

      if (attack_type_to_build == -1) {
        SelectRandomUnitTypeAndQty(true);
      }
      if (defence_type_to_build == -1) {
        SelectRandomUnitTypeAndQty(false);
      }

      if (max_map_threat <= 1) {
        if (build_mine || max_map_target == 0) {
          if (best_mine_location.x >= 0) {
            if (buyUnit(UnitStats.MINE, best_mine_location, 1, true)) {
              this.build_mine = Functions.rnd(1, BUY_MINE_CHANCE) > 1;
            }
          } else {
            if (Main.DEBUG_AI) {
              main.addLogEntry("No potential mine location found.");
            }
          }
        } else if (max_map_target > 0) {
          if (buyUnit(
              attack_type_to_build, top_target_location, this.num_attackers_to_build, false)) {
            this.num_attackers_to_build--;
            if (this.num_attackers_to_build == 0) {
              this.build_mine = Functions.rnd(1, BUY_MINE_CHANCE) > 1;
              SelectRandomUnitTypeAndQty(true);
            } else {
              ai_interval.fireInterval(); // SO we buy again quickly!
            }
          }
        }
      } else { // Defend!
        if (buyUnit(defence_type_to_build, top_threat_location, num_defenders_to_build, false)) {
          num_defenders_to_build--;
          if (num_defenders_to_build == 0) {
            SelectRandomUnitTypeAndQty(false);
          } else {
            ai_interval.fireInterval(); // SO we buy again quickly!
          }
        }
      }
    }
  }
  private void updateIntel() {
    player_attack_units_threat = 0;

    // First, blank the intel rating
    for (int y = 0; y < map_height; y++) {
      for (int x = 0; x < map_width; x++) {
        threats_intel[x][y] = 0;
        targets_intel[x][y] = 0;
        allied_intel[x][y] = 0;
      }
    }

    // Now update the threat of each square
    ThreadSafeArrayList sprites = main.sprites;
    Sprite sprite;
    for (int i = 0; i < sprites.size(); i++) {
      sprite = (Sprite) sprites.get(i);
      if (sprite != null) {
        if (sprite instanceof GameUnit) {
          GameUnit gu = (GameUnit) sprite;
          if (gu.threat_value != 0) {
            if (gu.side != this.side) {
              if (gu instanceof UnitBomber || gu instanceof UnitTank) {
                player_attack_units_threat += gu.threat_value;
              }
            }

            int mapx = sprite.getMapX();
            int mapy = sprite.getMapY();

            // Update intel based on unit's view range
            int RANGE_SQ =
                (GameUnit.SHOT_RANGE
                    / MapData
                        .SQUARE_SIZE); // / 2; DONT HALVE IT SINCE THE AI WILL BULD MONES NEXT TO
            // SILOS!  // Halve it since it's the dist between our
            // enemies and squares owned by us

            for (int y2 = mapy - RANGE_SQ; y2 <= mapy + RANGE_SQ; y2++) {
              for (int x2 = mapx - RANGE_SQ; x2 <= mapx + RANGE_SQ; x2++) {
                double dist = Functions.distance(mapx, mapy, x2, y2);
                if (dist <= RANGE_SQ) {
                  try {
                    if (gu instanceof UnitMiningPlatform == false) {
                      if (gu.side != this.side) {
                        threats_intel[x2][y2] += gu.threat_value;
                      } else {
                        allied_intel[x2][y2] += gu.threat_value;
                      }
                    } else if (gu instanceof UnitMiningPlatform) {
                      if (gu.side != this.side) {
                        targets_intel[x2][y2] += gu.threat_value;
                      }
                    }
                  } catch (java.lang.ArrayIndexOutOfBoundsException ex) {
                    // Do nothing
                  }
                }
              }
            }

            // Update targets
            // Update intel based on unit's view range
            /*int TARGET_RANGE_SQ = (UnitStats.BOMBER_VIEW_RANGE / MapData.SQUARE_SIZE);

            for(int y2=mapy-TARGET_RANGE_SQ ; y2<=mapy+TARGET_RANGE_SQ ; y2++) {
            	for(int x2=mapx-TARGET_RANGE_SQ ; x2<=mapx+TARGET_RANGE_SQ ; x2++) {
            		double dist = Functions.distance(mapx, mapy, x2, y2);
            		if (dist <= TARGET_RANGE_SQ) {
            			try {
            				if (gu instanceof UnitMiningPlatform) {
            					if (gu.side != this.side) {
            						targets_intel[x2][y2] += gu.threat_value;
            					}
            				}
            			} catch (java.lang.ArrayIndexOutOfBoundsException ex) {
            				// Do nothing
            			}
            		}
            	}
            }*/
          }
        }
      }
    }

    // Get the top threat square
    int highest_threat = -1;
    int highest_target = -1;
    int highest_resources = -1;
    for (int y = 0; y < map_height; y++) {
      for (int x = 0; x < map_width; x++) {
        if (main.getMapData().map[x][y].owner
            == side) { // This is where we are going to build something, so it must be our square
          if (threats_intel[x][y] - allied_intel[x][y] > highest_threat) {
            if (main.isAreaClearForNewUnit(x * MapData.SQUARE_SIZE, y * MapData.SQUARE_SIZE, -1)) {
              highest_threat = threats_intel[x][y] - allied_intel[x][y];
              top_threat_location.x = x;
              top_threat_location.y = y;
            }
          }
          if (targets_intel[x][y] > highest_target) {
            if (main.isAreaClearForNewUnit(x * MapData.SQUARE_SIZE, y * MapData.SQUARE_SIZE, -1)) {
              highest_target = targets_intel[x][y];
              top_target_location.x = x;
              top_target_location.y = y;
            }
          }
          if (threats_intel[x][y] == 0) { // Don't build near an enemy!
            int minerals = (int) main.getMapData().map[x][y].minerals;
            if (minerals
                >= highest_resources) { // Needs to be ">=" otherwise the AI spreads itself all over
              // the map (was: Needs to be ">" so that if there's no
              // resources in starting squares, it moves up-left)
              // if (main.getMapData().map[x][y].owner == side) {
              if (main.isAreaClearForNewUnit(
                  x * MapData.SQUARE_SIZE, y * MapData.SQUARE_SIZE, -1)) {
                highest_resources = minerals;
                best_mine_location.x = x;
                best_mine_location.y = y;
              }
              // }
            }
          }
        }
      }
    }

    max_map_threat = 0;
    if (top_threat_location.x >= 0) {
      max_map_threat =
          this.threats_intel[top_threat_location.x][top_threat_location.y]
              - this.allied_intel[top_threat_location.x][top_threat_location.y];
    }

    max_map_target = 0;
    if (top_target_location.x >= 0) {
      max_map_target = this.targets_intel[top_target_location.x][top_target_location.y];
    }

    // Get the best mine location
    /*int highest_resources = -1;
    for (int y = 0 ; y<map_height ; y++) {
    	for (int x = 0 ; x<map_width ; x++) {
    		if (threats_intel[x][y] == 0) { // Don't build near an enemy!
    			int minerals = (int)main.getMapData().map[x][y].minerals;
    			if (minerals >= highest_resources) { // Needs to be ">=" otherwise the AI spreads itself all over the map (was: Needs to be ">" so that if there's no resources in starting squares, it moves up-left)
    				if (main.getMapData().map[x][y].owner == side) {
    					if (main.isAreaClearForNewUnit(x * MapData.SQUARE_SIZE, y * MapData.SQUARE_SIZE, -1)) {
    						highest_resources = minerals;
    						best_mine_location.x = x;
    						best_mine_location.y = y;
    					}
    				}
    			}
    		}
    	}
    }
    prev_highest_resources = highest_resources;*/
  }