package ai.general;
import java.util.ArrayList;
import rts.GameState;
import rts.units.Unit;
import rts.units.UnitAction;
/**
* \brief A farm is a place where one can gather resources it should define pathways for farmers to take
* @author Jeff Bernard
*
*/
public class GeneralAIFarm extends GeneralAIObject {
public static final int FARM_CLOSED = -1; /**< the farm is closed */
public static final int FARM_OPEN = -2; /**< the farm is open */
public static final int FARM_WALL_OPEN = -3; /**< the farm is open to fliers */
public static final int FARM_UNKNOWN = -4; /**< nobody knows what's going on at the farm !? */
public static final int FARMER_UP = 0; /**< the farmer in the up spot */
public static final int FARMER_DOWN = 1; /**< the farmer in the down spot */
public static final int FARMER_LEFT = 2; /**< the farmer in the left spot */
public static final int FARMER_RIGHT = 3; /**< the farmer in the right spot */
public Unit resources; /**< the resources unit */
public long[] farmers; /**< the guys farming */
public int[] _farmers; /**< the farmers original states */
/**
* Constructs a new farm
* @param rsrc the resources
* @param ai the ai
*/
public GeneralAIFarm(Unit rsrc, GeneralAI ai) {
resources = rsrc;
farmers = new long[4]; // assumption, square grid
_farmers = new int[4];
farmers[0] = FARM_UNKNOWN;
farmers[1] = FARM_UNKNOWN;
farmers[2] = FARM_UNKNOWN;
farmers[3] = FARM_UNKNOWN;
_farmers[0] = FARM_UNKNOWN;
_farmers[1] = FARM_UNKNOWN;
_farmers[2] = FARM_UNKNOWN;
_farmers[3] = FARM_UNKNOWN;
update_openings(ai);
}
/**
* Returns whether or not this farm has an opening
* @param unit the unit to check if the farm has an opening for
* @return whether or not this farm has an opening
*/
public boolean has_opening(GeneralAIUnit unit) {
if (farmers[FARMER_UP] == FARM_OPEN || (unit.stats.isFlying() && farmers[FARMER_UP] == FARM_WALL_OPEN)) {
return true;
}
if (farmers[FARMER_DOWN] == FARM_OPEN || (unit.stats.isFlying() && farmers[FARMER_DOWN] == FARM_WALL_OPEN)) {
return true;
}
if (farmers[FARMER_LEFT] == FARM_OPEN || (unit.stats.isFlying() && farmers[FARMER_LEFT] == FARM_WALL_OPEN)) {
return true;
}
if (farmers[FARMER_RIGHT] == FARM_OPEN || (unit.stats.isFlying() && farmers[FARMER_RIGHT] == FARM_WALL_OPEN)) {
return true;
}
return false;
}
/**
* Returns whether or not there are any openings that don't require flying
* @return whether or not there are any openings that don't require flying
*/
public boolean has_openings_strict() {
if (farmers[FARMER_UP] == FARM_OPEN || farmers[FARMER_DOWN] == FARM_OPEN || farmers[FARMER_LEFT] == FARM_OPEN || farmers[FARMER_RIGHT] == FARM_OPEN) {
return true;
}
return false;
}
@Override
/**
* Orders a unit to interact with this object
* @param unit the unit
*/
public void order_unit(GeneralAIUnit unit, GeneralAI ai) {
//System.out.println(unit.stats.getID()+" working at farm #"+resources.getID());
if (unit.stats.getResources() == 0) {
path_to_farm(unit, ai);
} else {
path_to_stockpile(unit, ai, unit.stats.getX()+unit.stats.getY()*ai.state.getMapWidth(), ai.current_turn);
}
}
/**
* Plans a path to the farm
* @param unit
* @param ai
*/
private void path_to_farm(GeneralAIUnit unit, GeneralAI ai) {
// check if we're already next to a farm
for (int i = 0; i < unit.stats.getActions().size(); i++) {
UnitAction action = unit.stats.getActions().get(i);
if (action.getType() == UnitAction.HARVEST) {
unit.addAction(action, ai.traffic_map, unit.stats.getX()+unit.stats.getY()*ai.state.getMapWidth(), ai.current_turn, ai.current_turn+resources.getHarvestSpeed());
return;
}
}
// find the path to nearest opening
ArrayList<Integer> openings = new ArrayList<Integer>();
int location = resources.getX()+resources.getY()*ai.state.getMapWidth();
// first check if this unit has already reserved a spot
if (farmers[FARMER_UP] == unit.stats.getID()) {
openings.add(location-ai.state.getMapWidth());
} else if (farmers[FARMER_DOWN] == unit.stats.getID()) {
openings.add(location+ai.state.getMapWidth());
} else if (farmers[FARMER_LEFT] == unit.stats.getID()) {
openings.add(location-1);
} else if (farmers[FARMER_RIGHT] == unit.stats.getID()) {
openings.add(location+1);
}
if (openings.size() == 0) {
if (farmers[FARMER_UP] == FARM_OPEN || (unit.stats.isFlying() && farmers[FARMER_UP] == FARM_WALL_OPEN)) {
openings.add(location-ai.state.getMapWidth());
}
if (farmers[FARMER_DOWN] == FARM_OPEN || (unit.stats.isFlying() && farmers[FARMER_DOWN] == FARM_WALL_OPEN)) {
openings.add(location+ai.state.getMapWidth());
}
if (farmers[FARMER_LEFT] == FARM_OPEN || (unit.stats.isFlying() && farmers[FARMER_LEFT] == FARM_WALL_OPEN)) {
openings.add(location-1);
}
if (farmers[FARMER_RIGHT] == FARM_OPEN || (unit.stats.isFlying() && farmers[FARMER_RIGHT] == FARM_WALL_OPEN)) {
openings.add(location+1);
}
}
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;
}
if (rpath.get(0)[0] == location-1) {
//System.out.println("farming left");
farmers[FARMER_LEFT] = unit.stats.getID();
} else if (rpath.get(0)[0] == location+1) {
//System.out.println("farming right");
farmers[FARMER_RIGHT] = unit.stats.getID();
} else if (rpath.get(0)[0] == location+ai.state.getMapWidth()) {
//System.out.println("farming down");
farmers[FARMER_DOWN] = unit.stats.getID();
} else {
//System.out.println("farming up");
farmers[FARMER_UP] = unit.stats.getID();
}
// set order queue
if (!there) {
for (int i = rpath.size()-1; i >= 0; i--) {
//System.out.println("adding MOVE");
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 HARVEST");
unit.addAction(new UnitAction(unit.stats, UnitAction.HARVEST, resources.getX(), resources.getY(), -1), ai.traffic_map, now_at, now_start, now_start+resources.getHarvestSpeed());
now_start += resources.getHarvestSpeed();
// after harvest, need to return to a stockpile
path_to_stockpile(unit, ai, now_at, now_start);
} else { // cannot reach this...
//unit.clearActions(ai.traffic_map);
//unit.object = null;
}
}
/**
* Plans a path to the nearest stockpile
* @param unit
* @param ai
* @param now_at
* @param now_start
*/
private void path_to_stockpile(GeneralAIUnit unit, GeneralAI ai, int now_at, int now_start) {
// after harvest, need to return to a stockpile
ArrayList<Integer> stockpiles = new ArrayList<Integer>();
for (int i = 0; i < ai.units.size(); i++) {
Unit u = ai.units.get(i).stats;
if (u.isStockpile()) {
stockpiles.add(u.getX()+u.getY()*ai.state.getMapWidth());
}
}
ArrayList<Integer[]> rpath = ai.get_path(unit.stats, now_at, now_start, stockpiles);
if (rpath != null) {
boolean there = false;
if (rpath.size() <= 1) {
there = true;
rpath.add(new Integer[]{now_at, now_start});
if (rpath.size() == 1) {
rpath.add(new Integer[]{now_at, now_start});
}
}
if (!there) {
for (int i = rpath.size()-1; i >= 1; i--) {
//unit.actions.add(new UnitAction(unit.stats, UnitAction.MOVE, rpath.get(i)[0]%ai.state.getMapWidth(), rpath.get(i)[0]/ai.state.getMapWidth(),-1));
//System.out.println("adding MOVE");
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());
}
now_start = rpath.get(1)[1];
now_at = rpath.get(1)[0];
}
//unit.actions.add(new UnitAction(unit.stats, UnitAction.RETURN, rpath.get(0)[0]%ai.state.getMapWidth(), rpath.get(0)[0]/ai.state.getMapWidth(), -1));
//System.out.println("adding RETURN");
unit.addAction(new UnitAction(unit.stats, UnitAction.RETURN, rpath.get(0)[0]%ai.state.getMapWidth(), rpath.get(0)[0]/ai.state.getMapWidth(),-1), ai.traffic_map, now_at, now_start, now_start+UnitAction.DEFAULT_COOLDOWN);
} else {
}
}
@Override
/**
* Calculates the distance from the unit to this object
* @param unit the unit
* @param ai the ai
* @return the distance
*/
public int distance(GeneralAIUnit unit, GeneralAI ai) {
if (has_opening(unit)) {
return((resources.getX()-unit.stats.getX())*(resources.getX()-unit.stats.getX())+(resources.getY()-unit.stats.getY())*(resources.getY()-unit.stats.getY()));
}
return GeneralAI.DISTANCE_IGNORE;
}
@Override
public void action_succeeded(GeneralAIUnit unit, GeneralAI ai, int type) {
if (type == UnitAction.RETURN) {
ai.money.set(resources.getResourcesType(), ai.money.get(resources.getResourcesType())+unit.resources_held);
}
}
@Override
public void remove(GeneralAIUnit unit, GeneralAI ai) {
// only remove this unit if it doesn't already have resources
if (unit.stats.getResources() == 0) {
//System.out.println(unit.stats.getID()+" was removed from farm #"+resources.getID());
if (farmers[FARMER_LEFT] == unit.stats.getID()) {
farmers[FARMER_LEFT] = _farmers[FARMER_LEFT];
} else if (farmers[FARMER_RIGHT] == unit.stats.getID()) {
farmers[FARMER_RIGHT] = _farmers[FARMER_RIGHT];
} else if (farmers[FARMER_DOWN] == unit.stats.getID()) {
farmers[FARMER_DOWN] = _farmers[FARMER_DOWN];
} else {
farmers[FARMER_UP] = _farmers[FARMER_UP];
}
//unit.actions.clear();
unit.clearActions(ai.traffic_map);
unit.object = null;
unit.remove_object = false;
} else {
//System.out.println(unit.stats.getID()+" should be removed from a farm #"+resources.getID());
unit.remove_object = true;
}
}
@Override
public void update_orders(GeneralAIUnit unit, GeneralAI ai) {
// check if the spot we originally wanted to visit is no longer possible....
boolean removed = false;
if (farmers[FARMER_UP] == unit.stats.getID()) {
if (_farmers[FARMER_UP] == FARM_CLOSED) {
removed = true;
}
} else if (farmers[FARMER_DOWN] == unit.stats.getID()) {
if (_farmers[FARMER_DOWN] == FARM_CLOSED) {
removed = true;
}
} else if (farmers[FARMER_LEFT] == unit.stats.getID()) {
if (_farmers[FARMER_LEFT] == FARM_CLOSED) {
removed = true;
}
} else if (farmers[FARMER_RIGHT] == unit.stats.getID()) {
if (_farmers[FARMER_RIGHT] == FARM_CLOSED) {
removed = true;
}
}
if (!removed) {
unit.clearActions(ai.traffic_map); // because we need to issue a new traffic map
order_unit(unit, ai);
} else {
remove(unit, ai);
}
}
/**
* Updates the openings at the farm
* @param ai
*/
public void update_openings(GeneralAI ai) {
// check if all spots are valid
if (resources.getY() > 0) { // up might be open
if ((ai.exploration_manager.map[(resources.getY()-1)*ai.state.getMapWidth()+resources.getX()]&(GameState.MAP_FOG|GameState.MAP_WALL|GameState.MAP_NEUTRAL)) != 0) { // up is a wall
if (farmers[FARMER_UP] < 0) {
farmers[FARMER_UP] = FARM_CLOSED;
}
_farmers[FARMER_UP] = FARM_CLOSED;
} else {
if (farmers[FARMER_UP] < 0) {
farmers[FARMER_UP] = FARM_OPEN;
}
_farmers[FARMER_UP] = FARM_OPEN;
}
} else { // up is closed
if (farmers[FARMER_UP] < 0) {
farmers[FARMER_UP] = FARM_CLOSED;
}
_farmers[FARMER_UP] = FARM_CLOSED;
}
if (resources.getY() < ai.state.getMapHeight()-1) { // down might be open
if ((ai.exploration_manager.map[(resources.getY()+1)*ai.state.getMapWidth()+resources.getX()]&(GameState.MAP_FOG|GameState.MAP_WALL|GameState.MAP_NEUTRAL)) != 0) { // up is a wall
if (farmers[FARMER_DOWN] < 0) {
farmers[FARMER_DOWN] = FARM_CLOSED;
}
_farmers[FARMER_DOWN] = FARM_CLOSED;
} else {
if (farmers[FARMER_DOWN] < 0) {
farmers[FARMER_DOWN] = FARM_OPEN;
}
_farmers[FARMER_DOWN] = FARM_OPEN;
}
} else { // up is closed
if (farmers[FARMER_DOWN] < 0) {
farmers[FARMER_DOWN] = FARM_CLOSED;
}
_farmers[FARMER_DOWN] = FARM_CLOSED;
}
if (resources.getX() > 0) { // left might be open
if ((ai.exploration_manager.map[resources.getY()*ai.state.getMapWidth()+resources.getX()-1]&(GameState.MAP_FOG|GameState.MAP_WALL|GameState.MAP_NEUTRAL)) != 0) { // up is a wall
if (farmers[FARMER_LEFT] < 0) {
farmers[FARMER_LEFT] = FARM_CLOSED;
}
_farmers[FARMER_LEFT] = FARM_CLOSED;
} else {
if (farmers[FARMER_LEFT] < 0) {
farmers[FARMER_LEFT] = FARM_OPEN;
}
_farmers[FARMER_LEFT] = FARM_OPEN;
}
} else { // up is closed
if (farmers[FARMER_LEFT] < 0) {
farmers[FARMER_LEFT] = FARM_CLOSED;
}
_farmers[FARMER_LEFT] = FARM_CLOSED;
}
if (resources.getX() < ai.state.getMapWidth()-1) { // right might be open
if ((ai.exploration_manager.map[resources.getY()*ai.state.getMapWidth()+resources.getX()+1]&(GameState.MAP_FOG|GameState.MAP_WALL|GameState.MAP_NEUTRAL)) != 0) { // up is a wall
if (farmers[FARMER_RIGHT] < 0) {
farmers[FARMER_RIGHT] = FARM_CLOSED;
}
_farmers[FARMER_RIGHT] = FARM_CLOSED;
} else {
if (farmers[FARMER_RIGHT] < 0) {
farmers[FARMER_RIGHT] = FARM_OPEN;
}
_farmers[FARMER_RIGHT] = FARM_OPEN;
}
} else { // up is closed
if (farmers[FARMER_RIGHT] < 0) {
farmers[FARMER_RIGHT] = FARM_CLOSED;
}
_farmers[FARMER_RIGHT] = FARM_CLOSED;
}
}
}