package ai.general;
import java.util.ArrayList;
import rts.GameState;
import rts.units.UnitAction;
/**
* \brief A group of buildings that are all together. Generally, towns are a stockpile, resources, and other buildings nearby
*
*/
public class GeneralAITown extends GeneralAIObject {
private static final int CITY_LIMIT2 = 25; /**< all structures should be within this many squares (root) of each other */
private static final int CITY_LIMIT = 5; /**< root CITY_LIMIT2 */
private static final int LOCATION_SCOUTING = 1000; /**< how many times to try and scout a location */
public static final int NO_VACANCY = -1; /**< could not find a place in this town to build */
public ArrayList<GeneralAIFarm> farms; /**< the farms belonging to this town */
public ArrayList<GeneralAIUnit> buildings; /**< the buildings belonging to this town */
public ArrayList<GeneralAIEnemy> enemy_buildings; /**< buildings belonging to the enemy */
public int owner; /**< id of whoever owns this town */
public int defenders;
public int defenders_wanted; /**< how many defenders this town wants */
private boolean[] building_requested; /**< whether or not we've requested a location for each building */
/**
* Constructs a new town around a building
* @param building
* @param building_count how many building types there are
*/
public GeneralAITown(GeneralAIUnit building, int building_count) {
farms = new ArrayList<GeneralAIFarm>();
buildings = new ArrayList<GeneralAIUnit>();
enemy_buildings = new ArrayList<GeneralAIEnemy>();
buildings.add(building);
owner = building.stats.getPlayer();
defenders_wanted = 2;
defenders = 0;
building_requested = new boolean[building_count];
for (int i = 0; i < building_count; i++) {
building_requested[i] = false;
}
}
/**
* Constructs a new town around a farm
* @param farm
* @param building_count how many building types there are
*/
public GeneralAITown(GeneralAIFarm farm, int building_count) {
farms = new ArrayList<GeneralAIFarm>();
buildings = new ArrayList<GeneralAIUnit>();
enemy_buildings = new ArrayList<GeneralAIEnemy>();
farms.add(farm);
owner = -1;
defenders_wanted = 0;
defenders = 0;
building_requested = new boolean[building_count];
for (int i = 0; i < building_count; i++) {
building_requested[i] = false;
}
}
/**
* Constructs a new town around an enemy building
* @param enemy
* @param building_count how many building types there are
*/
public GeneralAITown(GeneralAIEnemy enemy, int building_count) {
farms = new ArrayList<GeneralAIFarm>();
buildings = new ArrayList<GeneralAIUnit>();
enemy_buildings = new ArrayList<GeneralAIEnemy>();
enemy_buildings.add(enemy);
owner = enemy.stats.getPlayer();
defenders_wanted = 0;
defenders = 0;
building_requested = new boolean[building_count];
for (int i = 0; i < building_count; i++) {
building_requested[i] = false;
}
}
/**
* Adds an object to this town (maybe)
* @param obj
* @return true if the object was within city limits and added, otherwise false
*/
public boolean add(GeneralAIFarm farm) {
for (int i = 0; i < farms.size(); i++) {
if ((farms.get(i).resources.getX()-farm.resources.getX())*(farms.get(i).resources.getX()-farm.resources.getX())+(farms.get(i).resources.getY()-farm.resources.getY())*(farms.get(i).resources.getY()-farm.resources.getY()) <= CITY_LIMIT2) {
farms.add(farm);
return true;
}
}
for (int i = 0; i < buildings.size(); i++) {
if ((buildings.get(i).stats.getX()-farm.resources.getX())*(buildings.get(i).stats.getX()-farm.resources.getX())+(buildings.get(i).stats.getY()-farm.resources.getY())*(buildings.get(i).stats.getY()-farm.resources.getY()) <= CITY_LIMIT2) {
farms.add(farm);
return true;
}
}
for (int i = 0; i < enemy_buildings.size(); i++) {
if ((enemy_buildings.get(i).stats.getX()-farm.resources.getX())*(enemy_buildings.get(i).stats.getX()-farm.resources.getX())+(enemy_buildings.get(i).stats.getY()-farm.resources.getY())*(enemy_buildings.get(i).stats.getY()-farm.resources.getY()) <= CITY_LIMIT2) {
farms.add(farm);
return true;
}
}
return false;
}
/**
* Adds an object to this town (maybe)
* @param obj
* @return true if the object was within city limits and added, otherwise false
*/
public boolean add(GeneralAIUnit building) {
defenders_wanted += 1;
for (int i = 0; i < farms.size(); i++) {
if ((farms.get(i).resources.getX()-building.stats.getX())*(farms.get(i).resources.getX()-building.stats.getX())+(farms.get(i).resources.getY()-building.stats.getY())*(farms.get(i).resources.getY()-building.stats.getY()) <= CITY_LIMIT2) {
buildings.add(building);
if (buildings.size() > enemy_buildings.size()) {
owner = building.stats.getPlayer();
}
return true;
}
}
for (int i = 0; i < buildings.size(); i++) {
if ((buildings.get(i).stats.getX()-building.stats.getX())*(buildings.get(i).stats.getX()-building.stats.getX())+(buildings.get(i).stats.getY()-building.stats.getY())*(buildings.get(i).stats.getY()-building.stats.getY()) <= CITY_LIMIT2) {
buildings.add(building);
if (buildings.size() > enemy_buildings.size()) {
owner = building.stats.getPlayer();
}
return true;
}
}
for (int i = 0; i < enemy_buildings.size(); i++) {
if ((enemy_buildings.get(i).stats.getX()-building.stats.getX())*(enemy_buildings.get(i).stats.getX()-building.stats.getX())+(enemy_buildings.get(i).stats.getY()-building.stats.getY())*(enemy_buildings.get(i).stats.getY()-building.stats.getY()) <= CITY_LIMIT2) {
buildings.add(building);
if (buildings.size() > enemy_buildings.size()) {
owner = building.stats.getPlayer();
}
return true;
}
}
return false;
}
/**
* Adds an object to this town (maybe)
* @param obj
* @return true if the object was within city limits and added, otherwise false
*/
public boolean add(GeneralAIEnemy enemy) {
for (int i = 0; i < farms.size(); i++) {
if ((farms.get(i).resources.getX()-enemy.stats.getX())*(farms.get(i).resources.getX()-enemy.stats.getX())+(farms.get(i).resources.getY()-enemy.stats.getY())*(farms.get(i).resources.getY()-enemy.stats.getY()) <= CITY_LIMIT2) {
enemy_buildings.add(enemy);
if (buildings.size() < enemy_buildings.size()) {
owner = enemy.stats.getPlayer();
}
return true;
}
}
for (int i = 0; i < enemy_buildings.size(); i++) {
if ((enemy_buildings.get(i).stats.getX()-enemy.stats.getX())*(enemy_buildings.get(i).stats.getX()-enemy.stats.getX())+(enemy_buildings.get(i).stats.getY()-enemy.stats.getY())*(enemy_buildings.get(i).stats.getY()-enemy.stats.getY()) <= CITY_LIMIT2) {
enemy_buildings.add(enemy);
if (buildings.size() < enemy_buildings.size()) {
owner = enemy.stats.getPlayer();
}
return true;
}
}
for (int i = 0; i < buildings.size(); i++) {
if ((buildings.get(i).stats.getX()-enemy.stats.getX())*(buildings.get(i).stats.getX()-enemy.stats.getX())+(buildings.get(i).stats.getY()-enemy.stats.getY())*(buildings.get(i).stats.getY()-enemy.stats.getY()) <= CITY_LIMIT2) {
enemy_buildings.add(enemy);
if (buildings.size() < enemy_buildings.size()) {
owner = enemy.stats.getPlayer();
}
return true;
}
}
return false;
}
/**
* Removes a farm from this town
* @param farm
* @return true if this farm was in this town, otherwise false
*/
public boolean remove(GeneralAIFarm farm) {
for (int i = 0; i < farms.size(); i++) {
if (farms.get(i).resources.getID() == farm.resources.getID()) {
farms.remove(i);
return true;
}
}
return false;
}
/**
* Removes a building from this town
* @param building
* @return true if this building was in this town, otherwise false
*/
public boolean remove(GeneralAIUnit building) {
defenders_wanted -= 2;
for (int i = 0; i < buildings.size(); i++) {
if (buildings.get(i).stats.getID() == building.stats.getID()) {
buildings.remove(i);
building_requested[building.stats.getType()] = false;
if (buildings.size() < enemy_buildings.size()) {
owner = enemy_buildings.get(0).stats.getPlayer();
} else if (buildings.size() == 0 && enemy_buildings.size() == 0) {
owner = -1;
}
return true;
}
}
return false;
}
/**
* Removes a enemy building from this town
* @param building
* @return true if this building was in this town, otherwise false
*/
public boolean remove(GeneralAIEnemy enemy) {
for (int i = 0; i < enemy_buildings.size(); i++) {
if (enemy_buildings.get(i).stats.getID() == enemy.stats.getID()) {
enemy_buildings.remove(i);
if (buildings.size() > enemy_buildings.size()) {
owner = buildings.get(0).stats.getPlayer();
} else if (buildings.size() == 0 && enemy_buildings.size() == 0) {
owner = -1;
}
return true;
}
}
return false;
}
/**
* Returns the population of the town
* @return
*/
public int population() {
return farms.size()+buildings.size()+enemy_buildings.size();
}
/**
* Returns where we want to build a stock pile in this town
* @param product
* @param ai
* @return -1 if don't want a stockpile here (could be, already returned the wish location)
*/
public int get_location(GeneralAIProduction product, GeneralAI ai) {
if (!product.def.is_stockpile_building && !has_stockpile() && farms.size() > 0) {
return NO_VACANCY;
}
if (!building_requested[product.def.type]) {
building_requested[product.def.type] = true;
for (int i = 0; i < buildings.size(); i++) {
if (buildings.get(i).stats.getType() == product.def.type) {
return NO_VACANCY; // turns out we already have this building here
}
}
// pick a spot for this building
if (product.def.is_stockpile_building) {
// build near resources
int best_score = -1;
int best = NO_VACANCY;
if (farms.size() != 0) {
int farmX = farms.get(0).resources.getX();
int farmY = farms.get(0).resources.getY();
for (int i = farmY-CITY_LIMIT; i <= farmY+CITY_LIMIT; i++) {
if (i >= 0 && i < ai.state.getMapHeight()-1 && (i < farmY-1 || i > farmY+1)) {
for (int j = farmX-CITY_LIMIT; j <= farmX+CITY_LIMIT; j++) {
if (j >= 0 && j < ai.state.getMapWidth()-1 && (j < farmX-1 || j > farmX+1)) {
if ((ai.exploration_manager.map[j+i*ai.state.getMapWidth()]&(GameState.MAP_WALL|GameState.MAP_NEUTRAL|GameState.MAP_FOG)) != 0) {
continue; // can't build on a wall
}
if (((j > 0 && (ai.exploration_manager.map[j+i*ai.state.getMapWidth()-1]&GameState.MAP_WALL) != 0) || j == 0) &&
((j < ai.state.getMapWidth()-1 && (ai.exploration_manager.map[j+i*ai.state.getMapWidth()+1]&GameState.MAP_WALL) != 0) || j == ai.state.getMapWidth()-1) &&
((i > 0 && (ai.exploration_manager.map[j+(i-1)*ai.state.getMapWidth()]&GameState.MAP_WALL) != 0) || i == 0) &&
((i < ai.state.getMapHeight()-1 && (ai.exploration_manager.map[j+(i+1)*ai.state.getMapWidth()]&GameState.MAP_WALL) != 0) || i == ai.state.getMapHeight()-1)) {
continue; // there are no non-wall tiles adjacent to this spot
}
// check if there's already a building here
boolean building_here = false;
for (int k = 0; k < buildings.size(); k++) {
if (buildings.get(k).stats.getX() == j && buildings.get(k).stats.getY() == i) {
building_here = true;
break;
}
}
if (building_here) {
continue;
}
for (int k = 0; k < enemy_buildings.size(); k++) {
if (enemy_buildings.get(k).stats.getX() == j && enemy_buildings.get(k).stats.getY() == i) {
building_here = true;
break;
}
}
if (building_here) {
continue;
}
// finally, evaluate how good this location is
int score = (j-farmX)*(j-farmX)+(i-farmY)*(i-farmY);
for (int k = 1; k < farms.size(); k++) {
int farmKX = farms.get(k).resources.getX();
int farmKY = farms.get(k).resources.getY();
score += (j-farmKX)*(j-farmKX)+(i-farmKY)*(i-farmKY);
}
if (best == NO_VACANCY || score < best_score) {
best_score = score;
best = i*ai.state.getMapWidth()+j;
}
}
}
}
}
}
if (best != NO_VACANCY) {
return best;
}
}
// default rule, build practically anywhere
// pick a random spot within city limits
for (int i = 0; i < LOCATION_SCOUTING; i++) {
int location = (int)(Math.random()*ai.state.getMapWidth()*ai.state.getMapHeight());
int locationX = location%ai.state.getMapWidth();
int locationY = location/ai.state.getMapWidth();
// confirm this is a valid build location
if ((ai.exploration_manager.map[location]&(GameState.MAP_WALL|GameState.MAP_NEUTRAL|GameState.MAP_FOG)) != 0) {
continue; // can't build on a wall
}
if (((locationX > 0 && (ai.exploration_manager.map[location-1]&GameState.MAP_WALL) != 0) || locationX == 0) &&
((locationX < ai.state.getMapWidth()-1 && (ai.exploration_manager.map[location+1]&GameState.MAP_WALL) != 0) || locationX == ai.state.getMapWidth()-1) &&
((locationY > 0 && (ai.exploration_manager.map[location-ai.state.getMapWidth()]&GameState.MAP_WALL) != 0) || locationY == 0) &&
((locationY < ai.state.getMapHeight()-1 && (ai.exploration_manager.map[location+ai.state.getMapWidth()]&GameState.MAP_WALL) != 0) || locationY == ai.state.getMapHeight()-1)) {
continue; // there are no non-wall tiles adjacent to this spot
}
if ((locationX > 0 && (ai.exploration_manager.map[location-1]&GameState.MAP_NEUTRAL) != 0) ||
(locationX < ai.state.getMapWidth()-1 && (ai.exploration_manager.map[location+1]&GameState.MAP_NEUTRAL) != 0) ||
(locationY > 0 && (ai.exploration_manager.map[location-ai.state.getMapWidth()]&GameState.MAP_NEUTRAL) != 0) ||
(locationY < ai.state.getMapHeight()-1 && (ai.exploration_manager.map[location+ai.state.getMapWidth()]&GameState.MAP_NEUTRAL) != 0)) {
continue; // there are resources next to this spot
}
// confirm this location is within city limits
if (in_limits(location, ai.state.getMapWidth())) {
return location;
}
}
building_requested[product.def.type] = false;
}
return NO_VACANCY;
}
/**
* Checks if a location is within the city limits
* @param location the location to check
* @param map_w width of the map
* @return true or false
*/
public boolean in_limits(int location, int map_w) {
int locationX = location%map_w;
int locationY = location/map_w;
for (int j = 0; j < farms.size(); j++) {
if ((locationX-farms.get(j).resources.getX())*(locationX-farms.get(j).resources.getX())+(locationY-farms.get(j).resources.getY())*(locationY-farms.get(j).resources.getY()) < CITY_LIMIT2) {
return true;
}
}
for (int j = 0; j < buildings.size(); j++) {
if ((locationX-buildings.get(j).stats.getX())*(locationX-buildings.get(j).stats.getX())+(locationY-buildings.get(j).stats.getY())*(locationY-buildings.get(j).stats.getY()) < CITY_LIMIT2) {
return true;
}
}
for (int j = 0; j < enemy_buildings.size(); j++) {
if ((locationX-enemy_buildings.get(j).stats.getX())*(locationX-enemy_buildings.get(j).stats.getX())+(locationY-enemy_buildings.get(j).stats.getY())*(locationY-enemy_buildings.get(j).stats.getY()) < CITY_LIMIT2) {
return true;
}
}
return false;
}
/**
* Checks if there is a stockpile in this town
* @return
*/
public boolean has_stockpile() {
for (int i = 0; i < buildings.size(); i++) {
if (buildings.get(i).stats.isStockpile()) {
return true;
}
}
return false;
}
@Override
public void update_orders(GeneralAIUnit unit, GeneralAI ai) {
unit.clearActions(ai.traffic_map);
order_unit(unit, ai);
}
@Override
public void order_unit(GeneralAIUnit unit, GeneralAI ai) {
if (farms.size() == 0) { // nothing really to protect...
remove(unit, ai);
return;
}
// randomly patrol, or attack nearby enemies
boolean patrol = true;
// see if enemy is close by
int distance = GeneralAI.DISTANCE_IGNORE;
GeneralAIEnemy enemy = null;
for (int j = 0; j < ai.attack_manager.enemies.size(); j++) {
int d = ai.attack_manager.enemies.get(j).distance(unit, ai);
if (d != GeneralAI.DISTANCE_IGNORE && (distance == GeneralAI.DISTANCE_IGNORE || d < distance)) {
distance = d;
enemy = ai.attack_manager.enemies.get(j);
}
}
if (distance != GeneralAI.DISTANCE_IGNORE && distance < CITY_LIMIT2) {
patrol = false;
// attack this enemy!!!
// check if we can just attack...
for (int i = 0; i < unit.stats.getActions().size(); i++) {
UnitAction action = unit.stats.getActions().get(i);
if (action.getType() == UnitAction.ATTACK && action.getTargetX() == enemy.stats.getX() && action.getTargetY() == enemy.stats.getY()) {
unit.addAction(new UnitAction(unit.stats, UnitAction.ATTACK, enemy.stats.getX(), enemy.stats.getY(), -1), ai.traffic_map, unit.stats.getX()+unit.stats.getY()*ai.state.getMapWidth(), ai.current_turn, -1);
return;
}
}
// else try and path to enemy
ArrayList<Integer> openings = new ArrayList<Integer>();
for (int j = enemy.stats.getY()-unit.stats.getAttackRange(); j <= enemy.stats.getY()+unit.stats.getVision(); j++) {
if (j >= 0 && j < ai.state.getMapHeight()) {
for (int k = enemy.stats.getX()-unit.stats.getAttackRange(); k <= enemy.stats.getX()+unit.stats.getAttackRange(); k++) {
if (k >= 0 && k < ai.state.getMapWidth() && (j-enemy.stats.getY())*(j-enemy.stats.getY())+(k-enemy.stats.getX())*(k-enemy.stats.getX()) < unit.stats.getAttackRange()*unit.stats.getAttackRange()) {
openings.add(k+j*ai.state.getMapWidth());
}
}
}
}
ArrayList<Integer[]> rpath = ai.get_path(unit.stats, unit.stats.getX()+unit.stats.getY()*ai.state.getMapWidth(), ai.current_turn, openings);
if (rpath != null) { // is possible to reach goal
boolean there = false;
if (rpath.size() == 0) {
rpath.add(new Integer[]{unit.stats.getX()+unit.stats.getY()*ai.state.getMapWidth(), ai.current_turn});
there = true;
}
// set order queue
if (!there) {
for (int i = rpath.size()-1; i >= 0; i--) {
unit.addAction(new UnitAction(unit.stats, UnitAction.MOVE, rpath.get(i)[0]%ai.state.getMapWidth(), rpath.get(i)[0]/ai.state.getMapWidth(),-1), ai.traffic_map, rpath.get(i)[0], rpath.get(i)[1], rpath.get(i)[1]+unit.stats.getMoveSpeed());
}
}
int now_at = rpath.get(0)[0];
int now_start = rpath.get(0)[1];
//System.out.println("adding ATTACK");
unit.addAction(new UnitAction(unit.stats, UnitAction.ATTACK, enemy.stats.getX(), enemy.stats.getY(), -1), ai.traffic_map, now_at, now_start, -1);
} else {
// oh no, can't reach this enemey!?
// go back to patrol
patrol = true;
}
}
if (patrol && in_limits(unit.stats.getX()+unit.stats.getY()*ai.state.getMapWidth(), ai.state.getMapWidth())) { // patrol
// patrol the town
// pick a random point within city limits...
int[] dir = new int[]{0, 0, 0, 0};
int t = 0;
for (int i = 0; i < unit.stats.getActions().size(); i++) {
UnitAction action = unit.stats.getActions().get(i);
if (action.getType() == UnitAction.MOVE) {
if (action.getTargetX() < unit.stats.getX()) {
dir[0] += distance(unit, ai, 1, 0);
t += dir[0];
} else if (action.getTargetX() > unit.stats.getX()) {
dir[1] += distance(unit, ai, -1, 0);
t += dir[1];
} else if (action.getTargetY() < unit.stats.getY()) {
dir[2] += distance(unit, ai, 0, 1);
t += dir[2];
} else if (action.getTargetY() > unit.stats.getY()) {
dir[3] += distance(unit, ai, 0, -1);
t += dir[3];
}
}
}
int r = (int)(Math.random()*t);
for (int i = 0; i < dir.length; i++) {
r -= dir[i];
if (r < 0) {
switch (i) {
case 0:
unit.addAction(new UnitAction(unit.stats, UnitAction.MOVE, unit.stats.getX()-1, unit.stats.getY(), -1), ai.traffic_map, unit.stats.getX()-1+unit.stats.getY()*ai.state.getMapWidth(), ai.current_turn, ai.current_turn+unit.stats.getMoveSpeed());
break;
case 1:
unit.addAction(new UnitAction(unit.stats, UnitAction.MOVE, unit.stats.getX()+1, unit.stats.getY(), -1), ai.traffic_map, unit.stats.getX()+1+unit.stats.getY()*ai.state.getMapWidth(), ai.current_turn, ai.current_turn+unit.stats.getMoveSpeed());
break;
case 2:
unit.addAction(new UnitAction(unit.stats, UnitAction.MOVE, unit.stats.getX(), unit.stats.getY()-1, -1), ai.traffic_map, unit.stats.getX()+(unit.stats.getY()-1)*ai.state.getMapWidth(), ai.current_turn, ai.current_turn+unit.stats.getMoveSpeed());
break;
default:
unit.addAction(new UnitAction(unit.stats, UnitAction.MOVE, unit.stats.getX(), unit.stats.getY()+1, -1), ai.traffic_map, unit.stats.getX()+(unit.stats.getY()+1)*ai.state.getMapWidth(), ai.current_turn, ai.current_turn+unit.stats.getMoveSpeed());
break;
}
break;
}
}
} else if (patrol) {
// return to the city
int location = -1;
for (int i = 0; i < LOCATION_SCOUTING; i++) {
location = (int)(Math.random()*ai.state.getMapWidth()*ai.state.getMapHeight());
int locationX = location%ai.state.getMapWidth();
int locationY = location/ai.state.getMapWidth();
// confirm this is a valid build location
if ((ai.exploration_manager.map[location]&(GameState.MAP_WALL|GameState.MAP_NEUTRAL|GameState.MAP_FOG)) != 0) {
continue; // can't build on a wall
}
if (((locationX > 0 && (ai.exploration_manager.map[location-1]&GameState.MAP_WALL) != 0) || locationX == 0) &&
((locationX < ai.state.getMapWidth()-1 && (ai.exploration_manager.map[location+1]&GameState.MAP_WALL) != 0) || locationX == ai.state.getMapWidth()-1) &&
((locationY > 0 && (ai.exploration_manager.map[location-ai.state.getMapWidth()]&GameState.MAP_WALL) != 0) || locationY == 0) &&
((locationY < ai.state.getMapHeight()-1 && (ai.exploration_manager.map[location+ai.state.getMapWidth()]&GameState.MAP_WALL) != 0) || locationY == ai.state.getMapHeight()-1)) {
continue; // there are no non-wall tiles adjacent to this spot
}
if ((locationX > 0 && (ai.exploration_manager.map[location-1]&GameState.MAP_NEUTRAL) != 0) ||
(locationX < ai.state.getMapWidth()-1 && (ai.exploration_manager.map[location+1]&GameState.MAP_NEUTRAL) != 0) ||
(locationY > 0 && (ai.exploration_manager.map[location-ai.state.getMapWidth()]&GameState.MAP_NEUTRAL) != 0) ||
(locationY < ai.state.getMapHeight()-1 && (ai.exploration_manager.map[location+ai.state.getMapWidth()]&GameState.MAP_NEUTRAL) != 0)) {
continue; // there are resources next to this spot
}
// confirm this location is within city limits
if (in_limits(location, ai.state.getMapWidth())) {
break;
}
}
if (location != -1) {
ArrayList<Integer> openings = new ArrayList<Integer>();
openings.add(location);
ArrayList<Integer[]> rpath = ai.get_path(unit.stats, unit.stats.getX()+unit.stats.getY()*ai.state.getMapWidth(), ai.current_turn, openings);
if (rpath != null) { // is possible to reach goal
boolean there = false;
if (rpath.size() == 0) {
rpath.add(new Integer[]{unit.stats.getX()+unit.stats.getY()*ai.state.getMapWidth(), ai.current_turn});
there = true;
}
// set order queue
if (!there) {
for (int i = rpath.size()-1; i >= 0; i--) {
unit.addAction(new UnitAction(unit.stats, UnitAction.MOVE, rpath.get(i)[0]%ai.state.getMapWidth(), rpath.get(i)[0]/ai.state.getMapWidth(),-1), ai.traffic_map, rpath.get(i)[0], rpath.get(i)[1], rpath.get(i)[1]+unit.stats.getMoveSpeed());
}
}
} else {
// impossible to reach town !?
}
} else {
// impossible to reach town !?
}
}
}
public int distance(GeneralAIUnit unit, GeneralAI ai, int dx, int dy) {
if (ai.player_id != owner) {
return GeneralAI.DISTANCE_IGNORE;
}
if (buildings.size() > 0) {
return (unit.stats.getX()+dx-buildings.get(0).stats.getX())*(unit.stats.getX()+dx-buildings.get(0).stats.getX())+(unit.stats.getY()+dy-buildings.get(0).stats.getY())*(unit.stats.getY()+dy-buildings.get(0).stats.getY());
}
return 0; // erhmmm...???
}
@Override
public int distance(GeneralAIUnit unit, GeneralAI ai) {
if (ai.player_id != owner || defenders >= defenders_wanted || farms.size() == 0) {
return GeneralAI.DISTANCE_IGNORE;
}
if (buildings.size() > 0) {
return (unit.stats.getX()-buildings.get(0).stats.getX())*(unit.stats.getX()-buildings.get(0).stats.getX())+(unit.stats.getY()-buildings.get(0).stats.getY())*(unit.stats.getY()-buildings.get(0).stats.getY());
}
return 0; // erhmmm...???
}
@Override
public void action_succeeded(GeneralAIUnit unit, GeneralAI ai, int type) {
// NaN
}
@Override
public void remove(GeneralAIUnit unit, GeneralAI ai) {
unit.clearActions(ai.traffic_map);
unit.object = null;
defenders--;
}
public void add_defender() {
defenders++;
}
}