package ai.general;
import java.util.ArrayList;
import rts.GameState;
import rts.units.UnitAction;
import rts.units.UnitDefinition;
/**
* \brief A task that needs to be produced
* @author Jeff Bernard
*
*/
public class GeneralAIProduction extends GeneralAIObject {
public UnitDefinition def; /**< unit definition */
public int id; /**< id in unit/building list */
public int x; /**< where to build this */
public int y; /**< where to build this */
public int priority; /**< how badly we want this unit. -1 is not all, 0 is most of all, > 0 sort of want */
public float cost_ratio; /**< cost of building this unit, with respect to it's fight utility */
public long builder; /**< id of the builder */
/**
* Makes a new thingy
* @param definition
* @param _id the index in unit/building list
* @param _x
* @param _y
*/
public GeneralAIProduction(UnitDefinition definition, int _id) {
def = definition;
id = _id;
priority = GeneralAI.DISTANCE_IGNORE;
//x = _x;
//y = _y;
builder = -1;
x = -1;
y = -1;
int total_cost = 0;
for (int i = 0; i < def.cost.size(); i++) {
total_cost += def.cost.get(i);
}
cost_ratio = GeneralAIUnit.evaluate(def)/total_cost;
}
/**
* A production that we want, along with where we want it!
* @param product
* @param _x
* @param _y
* @param _priority
*/
public GeneralAIProduction(GeneralAIProduction product, int _x, int _y, int _priority) {
def = product.def;
id = product.id;
priority = _priority;
cost_ratio = product.cost_ratio;
x = _x;
y = _y;
builder = -1;
}
@Override
public void order_unit(GeneralAIUnit unit, GeneralAI ai) {
if (def.is_building) {
// first make sure path to next to build spot
ArrayList<Integer> destination = new ArrayList<Integer>();
if (x > 0 && (ai.exploration_manager.map[x+y*ai.state.getMapWidth()-1]&(GameState.MAP_WALL|GameState.MAP_NEUTRAL|GameState.MAP_NONPLAYER)) == 0) {
destination.add(x+y*ai.state.getMapWidth()-1);
}
if (x < ai.state.getMapWidth()-1 && (ai.exploration_manager.map[x+y*ai.state.getMapWidth()+1]&(GameState.MAP_WALL|GameState.MAP_NEUTRAL|GameState.MAP_NONPLAYER)) == 0) {
destination.add(x+y*ai.state.getMapWidth()+1);
}
if (y > 0 && (ai.exploration_manager.map[x+(y-1)*ai.state.getMapWidth()]&(GameState.MAP_WALL|GameState.MAP_NEUTRAL|GameState.MAP_NONPLAYER)) == 0) {
destination.add(x+y*ai.state.getMapWidth()-ai.state.getMapWidth());
}
if (y < ai.state.getMapHeight()-1 && (ai.exploration_manager.map[x+(y+1)*ai.state.getMapWidth()]&(GameState.MAP_WALL|GameState.MAP_NEUTRAL|GameState.MAP_NONPLAYER)) == 0) {
destination.add(x+y*ai.state.getMapWidth()+ai.state.getMapWidth());
}
ArrayList<Integer[]> rpath = ai.get_path(unit.stats, unit.stats.getX()+unit.stats.getY()*ai.state.getMapWidth(), ai.current_turn, destination);
if (rpath != null) { // is possible to reach goal
// set order queue
//rpath.add(new Integer[]{unit.stats.getX()+unit.stats.getY()*ai.state.getMapWidth(), ai.current_turn});
for (int i = rpath.size()-1; i >= 0; i--) {
//unit.actions.add(new UnitAction(unit.stats, UnitAction.MOVE, rpath.get(i)%ai.state.getMapWidth(), rpath.get(i)/ai.state.getMapWidth(),-1));
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());
}
if (rpath.size() == 0) {
rpath.add(new Integer[]{unit.stats.getX()+unit.stats.getY()*ai.state.getMapWidth(), ai.current_turn});
}
unit.addAction(new UnitAction(unit.stats, UnitAction.BUILD, x, y, id), ai.traffic_map, rpath.get(0)[0], rpath.get(0)[1], -1);
} else {
//System.out.println("could not path to: "+(location%16)+"x"+(location/16));
}
} else {
// easy, just pick the adjacent spot
for (int i = 0; i < unit.stats.getActions().size(); i++) {
UnitAction action = unit.stats.getActions().get(i);
if (action.getBuild() == id && ai.traffic_map.valid(action.getTargetX()+action.getTargetY()*ai.state.getMapWidth(), ai.current_turn, ai.current_turn+def.produce_speed) /*&& action.getTargetX() == x && action.getTargetY() == y*/) {
//unit.actions.add(action);
unit.addAction(action, ai.traffic_map, action.getTargetX()+action.getTargetY()*ai.state.getMapWidth(), ai.current_turn, ai.current_turn+def.produce_speed);
break;
}
}
}
priority = GeneralAI.DISTANCE_IGNORE;
}
@Override
public int distance(GeneralAIUnit unit, GeneralAI ai) {
// ensure unit can build this guy
if (unit.stats.isBuilding() && !def.is_building) {
if (!unit.stats.getProduce().contains(id)) {
return GeneralAI.DISTANCE_IGNORE; // can't even build
}
} else if (!(unit.stats.isWorker() && def.is_building)){
return GeneralAI.DISTANCE_IGNORE;
}
for (int i = 0; i < def.cost.size(); i++) {
if (ai.money.get(i) < def.cost.get(i)) {
return GeneralAI.DISTANCE_IGNORE;
}
}
if (def.is_worker) {
return priority-GeneralAI.DISTANCE_IGNORE; // special priority for workers
} else if (priority == GeneralAI.DISTANCE_IGNORE) {
return GeneralAI.DISTANCE_IGNORE;
}
int distance = (unit.stats.getX()-x)*(unit.stats.getX()-x)+(unit.stats.getY()-y)*(unit.stats.getY()-y);
return (int)(priority*cost_ratio*def.produce_speed)+distance;
}
@Override
public void action_succeeded(GeneralAIUnit unit, GeneralAI ai, int type) {
if (type == UnitAction.BUILD){
unit.clearActions(ai.traffic_map);
unit.object = null;
}
}
@Override
public void remove(GeneralAIUnit unit, GeneralAI ai) {
if (def.is_building) {
builder = -1;
ai.production_manager.buildings_wanted.add(this);
}
unit.clearActions(ai.traffic_map);
}
/**
* evaluates this unit
* @return
*/
public float evaluate() {
return GeneralAIUnit.evaluate(def);
}
@Override
public void update_orders(GeneralAIUnit unit, GeneralAI ai) {
unit.clearActions(ai.traffic_map);
order_unit(unit, ai);
}
}