package ai.general; import java.util.ArrayList; import rts.units.Unit; import rts.units.UnitAction; /** * \brief Model of enemy units * @author Jeff Bernard */ public class GeneralAIEnemy extends GeneralAIObject { public Unit stats; /**< the last known unit object for this enemy */ public boolean dead; /**< whether or not this guy is dead */ public boolean seen; /**< whether or not this guy has been seen before */ public int priority; /**< additionaly priority to kill this unit */ /** * Constructs a new enemy knowledge thingy * @param unit */ public GeneralAIEnemy(Unit unit) { stats = unit; dead = false; seen = true; priority = 0; } @Override public void order_unit(GeneralAIUnit unit, GeneralAI ai) { if (dead) { unit.clearActions(ai.traffic_map); unit.object = null; } else if (seen) { // 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() == stats.getX() && action.getTargetY() == stats.getY()) { unit.addAction(new UnitAction(unit.stats, UnitAction.ATTACK, stats.getX(), stats.getY(), -1), ai.traffic_map, unit.stats.getX()+unit.stats.getY()*ai.state.getMapWidth(), ai.current_turn, -1); return; } } ArrayList<Integer> openings = new ArrayList<Integer>(); for (int j = stats.getY()-unit.stats.getAttackRange(); j <= stats.getY()+unit.stats.getVision(); j++) { if (j >= 0 && j < ai.state.getMapHeight()) { for (int k = stats.getX()-unit.stats.getAttackRange(); k <= stats.getX()+unit.stats.getAttackRange(); k++) { if (k >= 0 && k < ai.state.getMapWidth() && (j-stats.getY())*(j-stats.getY())+(k-stats.getX())*(k-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) { //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)); //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 ATTACK"); unit.addAction(new UnitAction(unit.stats, UnitAction.ATTACK, stats.getX(), stats.getY(), -1), ai.traffic_map, now_at, now_start, -1); } else { // oh no, can't reach this enemey!? remove(unit, ai); unit.dont_attack.add(stats.getID()); } } else { // can't reach this enemy remove(unit, ai); } } @Override public int distance(GeneralAIUnit unit, GeneralAI ai) { if (dead || !seen || unit.dont_attack.contains(stats.getID())) { return GeneralAI.DISTANCE_IGNORE; } int distance = (stats.getX()-unit.stats.getX())*(stats.getX()-unit.stats.getX())+(stats.getY()-unit.stats.getY())*(stats.getY()-unit.stats.getY()); if (distance < unit.stats.getVision()*unit.stats.getVision()) { // ensure this unit is actually on my unit list boolean found = false; for (int i = 0; i < ai.state.getOtherUnits().size(); i++) { if (ai.state.getOtherUnits().get(i).getID() == stats.getID()) { found = true; break; } } if (!found) { seen = false; return GeneralAI.DISTANCE_IGNORE; // this unit may very well be dead, but we missed the signal somehow } } distance -= priority; if (!stats.isBuilding()) { // I prefer to kill units before buildings if (distance < 0) { distance *= 2; } else { distance /= 2; } } return distance <= GeneralAI.DISTANCE_IGNORE ? distance-1 : distance; } @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; for (int i = 0; i < ai.attack_manager.units.size(); i++) { for (int j = 0; j < ai.attack_manager.units.get(i).dont_attack.size(); j++) { if (ai.attack_manager.units.get(i).dont_attack.get(j) == stats.getID()) { ai.attack_manager.units.get(i).dont_attack.remove(j); break; } } } } /** * Evaluates how good of a unit this is * @return */ public float evaluate() { if (stats.isBuilding()) { return 1; } return(((stats.getAttackMax()*stats.getAttackRange()+stats.getVision())*((float)stats.getHP()/(float)stats.getMaxHP())+(stats.isFlying()?1:0))/(float)(stats.getAttackSpeed()+stats.getMoveSpeed())); } @Override public void update_orders(GeneralAIUnit unit, GeneralAI ai) { // double check we are still next to the enemy //if (unit.actions.size() != 0 && unit.actions.get(0).getType() == UnitAction.ATTACK) { unit.clearActions(ai.traffic_map); order_unit(unit, ai); //} } }