/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package rts; import java.util.ArrayList; import rts.units.*; import org.jdom.Element; /** * \brief Runs all of the logic of the game * @author santi, modified Jeff Bernard */ public class PhysicalGameState { @Deprecated public static final int TERRAIN_NONE = 0; @Deprecated public static final int TERRAIN_WALL = 1; public int width = 8; public int height = 8; public int terrain[] = null; public boolean fog; /**< whether or not we're playing with fog of war */ public ArrayList<ArrayList<Integer> > teams; /**< which teams have which players */ // last element is neutral army public ArrayList<ArrayList<Unit> > armies; /**< player x list of units */ public ArrayList<UnitStats> armyStats; /**< player x list of units */ private ArrayList<UnitStats> corpses; /**< dead people */ public ArrayList<ArrayList<Integer> > resources; /**< the resources for each player */ public ArrayList<Integer> scores; /**< how many points each player currently has */ // stats public ArrayList<Integer> kills; /**< how many kills each player has made */ public ArrayList<Integer> deaths; /**< how many deaths each player has suffered */ public UnitStats unit_map[]; public UnitStats reserved; public UnitDefinitionManager unitDefinitions; /**< the unit definitions manager */ private ArrayList<Long> timeLimits; public int current_player; /** * Returns the number of players (minus the neutral player) * @return armies.size()-1 */ public int numberOfPlayers() { return armies.size()-1; } /** * Returns the id of the winning team * @return the id of the winning team, or -1 on a draw */ public int winner() { int winner = -1; for (int i = 0; i < teams.size(); i++) { int men = 0; for (int j = 0; j < teams.get(i).size(); j++) { men += armies.get(teams.get(i).get(j)).size(); } if (men != 0) { if (winner == -1) { winner = i; } else { return -1; } } } return winner; } /** * Returns the team with the most points * @return -1 on a draw on score */ public int winnerByScore() { int winner = -1; int winningScore = -1; boolean draw = false; for (int i = 0; i < teams.size(); i++) { int score = 0; for (int j = 0; j < teams.get(i).size(); j++) { score += scores.get(teams.get(i).get(j)); } if (score == winningScore) { draw = true; } else if (score > winningScore) { winningScore = score; winner = i; draw = false; } } if (draw) { return -1; } return winner; } /** * Determines whether or not the game is over. *@retun true if yesm, otherwise false */ public boolean gameover() { boolean done = true; for (int i = 0; i < teams.size(); i++) { int men = 0; for (int j = 0; j < teams.get(i).size(); j++) { men += armies.get(teams.get(i).get(j)).size(); } if (men != 0) { done = false; break; } } if (done || winner() != -1) { return true; } return false; } /** * Cycles the game state * @return true if the game is over, otherwise false */ public boolean cycle() { for (int i = 0; i < armyStats.size(); i++) { current_player = armyStats.get(i).player; UnitAction action = armyStats.get(i).action; if (armyStats.get(i).player != -1 && action != null) { if (action.getTimestamp() <= timeLimits.get(armyStats.get(i).player) && action.validate(armyStats.get(i), this)) { // action must be issued in time if (action.ready()) { if (action.getType() == UnitAction.BUILD) { if (unit_map[action.getTargetX()+action.getTargetY()*width] == null && terrain[action.getTargetX()+action.getTargetY()*width] == TERRAIN_NONE) { unit_map[action.getTargetX()+action.getTargetY()*width] = reserved; } } else { action.execute(armyStats.get(i), this); } // prepare to accept another action //armyStats.get(i).action = null; } if (action.cooldown()) { if (action.getType() == UnitAction.BUILD){ /*if (action.getBuild() == 1 && !armyStats.get(i).definition.is_building) { System.out.println("built a soldier office: "); }*/ unit_map[action.getTargetX()+action.getTargetY()*width] = null; action.execute(armyStats.get(i), this); } armyStats.get(i).action = null; } } else { // action was issued too late //System.out.println("action too late for "+i); armyStats.get(i).action = null; } } } // check for dead units for (int i = 0; i < armyStats.size(); i++) { if (armyStats.get(i).definition.is_resources) { // resources are dead when they run out of resources if (armyStats.get(i).resources <= 0) { removeUnit(armyStats.get(i), i); i--; } } else { // other units are dead when they run out of hp if (armyStats.get(i).hp <= 0) { removeUnit(armyStats.get(i), i); i--; } } } for (int i = 0; i < corpses.size(); i++) { if (corpses.get(i).seen_dead) { int player = corpses.get(i).player%armies.size(); if (player == -1) { // Java implements mod incorrectly player = armies.size()-1; } for (int j = 0 ; j < armies.get(player).size(); j++) { if (armies.get(player).get(j).getID() == corpses.get(i).id) { armies.get(player).remove(j); break; } } corpses.remove(i--); } } // update legal actions for (int i = 0; i < armyStats.size(); i++) { determineLegalActions(armyStats.get(i)); } return gameover(); } public PhysicalGameState(int start_player, GameState gs, UnitDefinitionManager unitDefs) { width = gs.getMapWidth(); height = gs.getMapHeight(); fog = gs.isFog(); terrain = new int[width*height]; unit_map = new UnitStats[width*height]; for (int i = 0; i < terrain.length; i++) { unit_map[i] = null; terrain[i] = (gs.getMap()[i]&GameState.MAP_WALL)==0?0:1; } teams = new ArrayList<ArrayList<Integer> >(); for (int i = 0; i < gs.numberOfTeams(); i++) { teams.add(gs.getTeam(i)); } armies = new ArrayList<ArrayList<Unit> >(); armyStats = new ArrayList<UnitStats>(); corpses = new ArrayList<UnitStats>(); resources = new ArrayList<ArrayList<Integer> >(); timeLimits = new ArrayList<Long>(); scores = new ArrayList<Integer>(); kills = new ArrayList<Integer>(); deaths = new ArrayList<Integer>(); for (int i = 0; i < gs.getPlayers(); i++) { armies.add(new ArrayList<Unit>()); resources.add(new ArrayList<Integer>()); timeLimits.add(0L); scores.add(0); for (int j = 0; j < unitDefs.resourceTypes(); j++) { resources.get(i).add(0); } kills.add(0); deaths.add(0); } for (int i = 0; i < gs.getResourceTypes(); i++) { resources.get(start_player).set(i, gs.getResources(i)); } unitDefinitions = unitDefs.copy(); unitDefinitions.setPlayers(armies.size()); reserved = new UnitStats(-2, -1, -1, unitDefinitions.resource_defs.get(0).get(0)); // neutral army armies.add(new ArrayList<Unit>()); for (int i = 0; i < gs.getMyUnits().size(); i++) { Unit u = gs.getMyUnits().get(i); UnitStats stats = u.copyStats(); armyStats.add(stats); unit_map[stats.x+stats.y*width] = stats; armies.get(stats.player).add(new Unit(stats)); } for (int i = 0; i < gs.getOtherUnits().size(); i++) { Unit u = gs.getOtherUnits().get(i); UnitStats stats = u.copyStats(); armyStats.add(stats); unit_map[stats.x+stats.y*width] = stats; armies.get(stats.player).add(new Unit(stats)); } for (int i = 0; i < gs.getNeutralUnits().size(); i++) { Unit u = gs.getNeutralUnits().get(i); UnitStats stats = u.copyStats(); armyStats.add(stats); unit_map[stats.x+stats.y*width] = stats; armies.get(armies.size()-1).add(new Unit(stats)); } current_player = start_player; for (int i = 0; i < armyStats.size(); i++) { determineLegalActions(armyStats.get(i)); } } public PhysicalGameState(Element e, UnitDefinitionManager unitDefs) { Element terrain_e = e.getChild("terrain"); Element players_e = e.getChild("players"); Element units_e = e.getChild("units"); width = Integer.parseInt(e.getAttributeValue("width")); height = Integer.parseInt(e.getAttributeValue("height")); terrain = new int[width*height]; unit_map = new UnitStats[width*height]; String terrainString = terrain_e.getValue(); for(int i = 0;i<width*height;i++) { String c = terrainString.substring(i, i+1); terrain[i] = Integer.parseInt(c); unit_map[i] = null; } teams = new ArrayList<ArrayList<Integer> >(); armies = new ArrayList<ArrayList<Unit> >(); armyStats = new ArrayList<UnitStats>(); corpses = new ArrayList<UnitStats>(); resources = new ArrayList<ArrayList<Integer> >(); timeLimits = new ArrayList<Long>(); scores = new ArrayList<Integer>(); kills = new ArrayList<Integer>(); deaths = new ArrayList<Integer>(); for (int i = 0; i < players_e.getChildren().size(); i++) { Element child = (Element)players_e.getChildren().get(i); if (child.getName().equalsIgnoreCase("rts.Player")) { try { int team = Integer.parseInt(child.getAttributeValue("team")); if (team < 0) { team = 0; } else while (team >= teams.size()) { teams.add(new ArrayList<Integer>()); } teams.get(team).add(armies.size()); } catch (NumberFormatException ee) { teams.add(new ArrayList<Integer>()); teams.get(teams.size()-1).add(armies.size()); } armies.add(new ArrayList<Unit>()); resources.add(new ArrayList<Integer>()); timeLimits.add(0L); scores.add(0); for (int j = 0; j < unitDefs.resourceTypes(); j++) { resources.get(i).add(0); } for (int j = 0; j < child.getChildren().size(); j++) { Element start_resource = (Element)child.getChildren().get(j); if (start_resource.getName().equalsIgnoreCase("resource")) { resources.get(i).set(Integer.parseInt(start_resource.getAttributeValue("type")), Integer.parseInt(start_resource.getAttributeValue("amount"))); } } kills.add(0); deaths.add(0); } } unitDefinitions = unitDefs; unitDefinitions.setPlayers(armies.size()); reserved = new UnitStats(-2, -1, -1, unitDefinitions.resource_defs.get(0).get(0)); // neutral army armies.add(new ArrayList<Unit>()); for (int i = 0; i < units_e.getChildren().size(); i++) { Element child = (Element)units_e.getChildren().get(i); if (child.getName().equalsIgnoreCase("resource")) { int x = Integer.parseInt(child.getAttributeValue("x")); int y = Integer.parseInt(child.getAttributeValue("y")); if (unit_map[x+y*width] == null) { unitDefinitions.makeResource(armies.get(armies.size()-1), armyStats, Integer.parseInt(child.getAttributeValue("type")), -1, x, y, Integer.parseInt(child.getAttributeValue("amount"))); unit_map[x+y*width] = armyStats.get(armyStats.size()-1); } } else if (child.getName().equalsIgnoreCase("unit")) { int player = Integer.parseInt(child.getAttributeValue("player")); int x = Integer.parseInt(child.getAttributeValue("x")); int y = Integer.parseInt(child.getAttributeValue("y")); if (unit_map[x+y*width] == null) { unitDefinitions.makeUnit(armies.get(player), armyStats, Integer.parseInt(child.getAttributeValue("type")), Integer.parseInt(child.getAttributeValue("player")), x, y); unit_map[x+y*width] = armyStats.get(armyStats.size()-1); } } else if (child.getName().equalsIgnoreCase("building")) { int player = Integer.parseInt(child.getAttributeValue("player")); int x = Integer.parseInt(child.getAttributeValue("x")); int y = Integer.parseInt(child.getAttributeValue("y")); if (unit_map[x+y*width] == null) { unitDefinitions.makeBuilding(armies.get(player), armyStats, Integer.parseInt(child.getAttributeValue("type")), Integer.parseInt(child.getAttributeValue("player")), x, y); unit_map[x+y*width] = armyStats.get(armyStats.size()-1); } } } current_player = -1; for (int i = 0; i < armyStats.size(); i++) { determineLegalActions(armyStats.get(i)); } } /** * Gets the resources for the current player * @param type the type of resource to get * @return */ public int getResources(int type) { if (type >= 0 && type < resources.get(current_player).size()) { return resources.get(current_player).get(type); } return 0; } /** * Sets the time limit for the current player * @param timelimit */ public void setTimeLimit(long timelimit) { timeLimits.set(current_player, timelimit); } /** * Sets the current player * @param player */ public void setCurrentPlayer(int player) { if (current_player != -1) { for (int i = 0; i < unitDefinitions.resource_defs.get(current_player+1).size(); i++) { unitDefinitions.resource_defs.get(current_player+1).get(i).active_player = false; } for (int i = 0; i < unitDefinitions.unit_defs.get(current_player+1).size(); i++) { unitDefinitions.unit_defs.get(current_player+1).get(i).active_player = false; } for (int i = 0; i < unitDefinitions.building_defs.get(current_player+1).size(); i++) { unitDefinitions.building_defs.get(current_player+1).get(i).active_player = false; } } current_player = player; for (int i = 0; i < unitDefinitions.resource_defs.get(current_player+1).size(); i++) { unitDefinitions.resource_defs.get(current_player+1).get(i).active_player = true; } for (int i = 0; i < unitDefinitions.unit_defs.get(current_player+1).size(); i++) { unitDefinitions.unit_defs.get(current_player+1).get(i).active_player = true; } for (int i = 0; i < unitDefinitions.building_defs.get(current_player+1).size(); i++) { unitDefinitions.building_defs.get(current_player+1).get(i).active_player = true; } } /** * how long it'll take to harvest from this square * @param x * @param y * @return */ public int harvestTime(int x, int y) { if (x >= 0 && x < width && y >= 0 && y < height) { if (unit_map[x+y*width] != null && unit_map[x+y*width].definition.is_resources) { return unit_map[x+y*width].definition.harvest_speed; } } /*for (int i = 0; i < armies.get(numberOfPlayers()).size(); i++) { if (armies.get(numberOfPlayers()).get(i).isResources() && armies.get(numberOfPlayers()).get(i).getX() == x && armies.get(numberOfPlayers()).get(i).getY() == y) { return armies.get(numberOfPlayers()).get(i).getHarvestSpeed(); } }*/ return UnitAction.DEFAULT_COOLDOWN; } /** * Gets the build time for the thign you want to build * @param player the player that wants to build * @param is_building whether or not you want to build a building * @param build the thing you want to build * @return */ public int buildTime(int player, boolean is_building, int build) { if (is_building) { if (build >= 0 && build < unitDefinitions.building_defs.get(current_player).size()) { //System.out.println(current_player+" cooldown: "+unitDefinitions.building_defs.get(current_player).get(build).produce_speed); return unitDefinitions.building_defs.get(current_player).get(build).produce_speed; } } else { if (build >= 0 && build < unitDefinitions.unit_defs.get(current_player).size()) { return unitDefinitions.unit_defs.get(current_player).get(build).produce_speed; } } return UnitAction.DEFAULT_COOLDOWN; } /** * Reserves the resources to build something * @param player the player who is building * @param is_building whether or not the thing being built is a building * @param build the thing you want to build */ /*public void reserveResources(int player, boolean is_building, int build) { ArrayList<Integer> cost = null; if (is_building) { if (build >= 0 && build < unitDefinitions.building_defs.get(player).size()) { cost = unitDefinitions.building_defs.get(player).get(build).cost; } } else { if (build >= 0 && build < unitDefinitions.unit_defs.get(player).size()) { cost = unitDefinitions.unit_defs.get(player).get(build).cost; } } if (cost != null) { for (int i = 0; i < cost.size(); i++) { resources.get(player).set(i, resources.get(player).get(i)-cost.get(i)); } } }*/ /** * Restores the resources to build something because somethign went wrong * @param player the player who is building * @param is_building whether or not the thing being built is a building * @param build the thing you want to build */ /*public void restoreResources(int player, boolean is_building, int build) { ArrayList<Integer> cost = null; if (is_building) { if (build >= 0 && build < unitDefinitions.building_defs.get(player).size()) { cost = unitDefinitions.building_defs.get(player).get(build).cost; } } else { if (build >= 0 && build < unitDefinitions.unit_defs.get(player).size()) { cost = unitDefinitions.unit_defs.get(player).get(build).cost; } } if (cost != null) { for (int i = 0; i < cost.size(); i++) { resources.get(player).set(i, resources.get(player).get(i)+cost.get(i)); } } }*/ /** * Moves the unit to the new location * @param unit * @param x * @param y * @return whether or not the move was valid */ public boolean moveUnit(UnitStats unit, int x, int y) { if (!unit.definition.is_building && !unit.definition.is_resources) { if (x >= 0 && x < width && y >= 0 && y < height && ((x == unit.x && (y == unit.y-1 || y == unit.y+1)) || (y == unit.y && (x == unit.x-1 || x == unit.x+1)))) { // and must be empty if (unit_map[x+y*width] == null && (terrain[x+y*width] == TERRAIN_NONE || unit.definition.is_flying)) { unit_map[unit.x+unit.y*width] = null; unit_map[x+y*width] = unit; unit.x = x; unit.y = y; return true; } //else System.out.println("move target is occupied"); } //else System.out.println("move target is off map"); } //else System.out.println("building/resource can't move"); return false; } /** * A unit attacks a square * @param attacker * @param x * @param y * @return whether or not the attack was valid */ public boolean attackUnit(UnitStats attacker, int x, int y) { if (!attacker.definition.is_building && !attacker.definition.is_resources) { if (x >= 0 && x < width && y >= 0 && y < height) { // target needs to be within range of attacker if ((x-attacker.x)*(x-attacker.x)+(y-attacker.y)*(y-attacker.y) <= attacker.definition.attack_range*attacker.definition.attack_range) { UnitStats victim = unit_map[x+y*width]; if (victim != null && !victim.definition.is_resources) { victim.hp -= attacker.definition.getDamage(); if (victim.hp <= 0) { kills.set(attacker.player, kills.get(attacker.player)+1); victim.killed_by = attacker.player; deaths.set(victim.player, deaths.get(victim.player)+1); } return true; } //else System.out.println("no target to attack "+x+"x"+y); } //else System.out.println("target is too far away"); } //else System.out.println("target is off map"); } //else System.out.println("attacker is building or resources"); return false; } /** * A unit attempts to harvest from some location * @param unit * @param x * @param y * @return */ public boolean harvestUnit(UnitStats unit, int x, int y) { if (x >= 0 && x < width && y >= 0 && y < height && ((x == unit.x && (y == unit.y-1 || y == unit.y+1)) || (y == unit.y && (x == unit.x-1 || x == unit.x+1)))) { // can only harvest from resources UnitStats resource = unit_map[x+y*width]; if (resource != null && resource.definition.is_resources) { // can't be already holding resources either if (unit.resources == 0 && unit.definition.is_worker) { int harvestAmt = resource.definition.harvest_amt; if (harvestAmt > resource.resources) { harvestAmt = resource.resources; } resource.resources -= harvestAmt; unit.resources = harvestAmt; unit.resources_type = resource.resources_type; return true; } //else System.out.println("harvester is not worker or already has resources"); } //else System.out.println("harvest target is not resources"); } //else System.out.println("harvest target is off map"); return false; } /** * Attempts to return the harvest * @param unit * @param x * @param y * @return */ public boolean returnUnitHarvest(UnitStats unit, int x, int y) { if (unit.definition.is_worker) { if (x >= 0 && x < width && y >= 0 && y < height && ((x == unit.x && (y == unit.y-1 || y == unit.y+1)) || (y == unit.y && (x == unit.x-1 || x == unit.x+1)))) { UnitStats stockpile = unit_map[x+y*width]; if (stockpile != null && stockpile.definition.is_stockpile_building && unit.resources > 0) { resources.get(unit.player).set(unit.resources_type, resources.get(unit.player).get(unit.resources_type)+unit.resources); // add resources collected to score //System.out.println("a return occured"); scores.set(unit.player, scores.get(unit.player)+unit.resources); unit.resources = 0; return true; } //else System.out.println("return target is not stockpile"); } //else System.out.println("return target is off map"); } //else System.out.println("only workers can return"); return false; } /** * Attempts to build a unit somewhere * @param unit * @param x * @param y * @param build what to build * @return */ public boolean buildUnit(UnitStats unit, int x, int y, int build) { if (x >= 0 && x < width && y >= 0 && y < height && ((x == unit.x && (y == unit.y-1 || y == unit.y+1)) || (y == unit.y && (x == unit.x-1 || x == unit.x+1)))) { if (unit_map[x+y*width] == null) { if (unit.definition.is_worker) { if (build >= 0 && build < unitDefinitions.building_defs.get(unit.player).size()) { UnitDefinition def = unitDefinitions.building_defs.get(unit.player).get(build); for (int i = 0; i < def.cost.size(); i++) { if (resources.get(unit.player).get(i) < def.cost.get(i)) { //System.out.println("not enough resources to build: "+build); return false; } } // now that we have enough resources, decrement the cost for (int i = 0; i < def.cost.size(); i++) { resources.get(unit.player).set(i, resources.get(unit.player).get(i)-def.cost.get(i)); } unitDefinitions.makeBuilding(armies.get(unit.player), armyStats, build, unit.player, x, y); unit_map[x+y*width] = armyStats.get(armyStats.size()-1); // add score scores.set(unit.player, scores.get(unit.player)+unitDefinitions.getScore(armyStats.get(armyStats.size()-1))); return true; } //else System.out.println("invalid building id: "+build); } else if (unit.definition.is_building) { // ensure this building can build this unit for (int i = 0; i < unit.definition.produces.size(); i++) { if (build == unit.definition.produces.get(i)) { UnitDefinition def = unitDefinitions.unit_defs.get(unit.player).get(build); for (int j = 0; j < def.cost.size(); j++) { if (resources.get(unit.player).get(j) < def.cost.get(j)) { return false; } } // now that we have enough resources, decrement the cost for (int j = 0; j < def.cost.size(); j++) { resources.get(unit.player).set(j, resources.get(unit.player).get(j)-def.cost.get(j)); } unitDefinitions.makeUnit(armies.get(unit.player), armyStats, build, unit.player, x, y); unit_map[x+y*width] = armyStats.get(armyStats.size()-1); // add score scores.set(unit.player, scores.get(unit.player)+unitDefinitions.getScore(armyStats.get(armyStats.size()-1))); return true; } //else System.out.println(unit.id+" cannot build "+build); } } //else System.out.println("only buildings and workers can build"); } //else System.out.println("build target is already occupied"); } //else System.out.println("build target is off map"); return false; } /** * Builds a list of legal actions for the specified unit * @param unit */ private void determineLegalActions(UnitStats unit) { if (unit.player != -1) { unit.legalActions.clear(); if (unit.definition.is_building) { // consider UPGRADE for (int i = 0; i < unit.definition.unit_upgrades.size(); i++) { UnitUpgrade def = null; for (int j = 0; j < unitDefinitions.unit_upgrades.get(unit.player+1).size(); j++) { if (unit.definition.unit_upgrades.get(i) == unitDefinitions.unit_upgrades.get(unit.player+1).get(i).getID()) { def = unitDefinitions.unit_upgrades.get(unit.player+1).get(i); break; } } if (def != null) { boolean enoughMoney = true; for (int j = 0; j < resources.size(); j++) { if (resources.get(unit.player).get(j) < def.getCost(j)) { enoughMoney = false; break; } } if (enoughMoney) { unit.legalActions.add(new UnitAction(unit, UnitAction.UPGRADE, unit.x, unit.y, unit.definition.unit_upgrades.get(i))); } } } for (int i = 0; i < unit.definition.unit_upgrades.size(); i++) { UnitUpgrade def = null; for (int j = 0; j < unitDefinitions.building_upgrades.get(unit.player+1).size(); j++) { if (unit.definition.unit_upgrades.get(i) == unitDefinitions.building_upgrades.get(unit.player+1).get(i).getID()) { def = unitDefinitions.building_upgrades.get(unit.player+1).get(i); break; } } if (def != null) { boolean enoughMoney = true; for (int j = 0; j < resources.size(); j++) { if (resources.get(unit.player).get(j) < def.getCost(j)) { enoughMoney = false; break; } } if (enoughMoney) { unit.legalActions.add(new UnitAction(unit, UnitAction.UPGRADE, unit.x, unit.y, unit.definition.building_upgrades.get(i))); } } } // consider BUILD for (int i = 0; i < unit.definition.produces.size(); i++) { UnitDefinition def = unitDefinitions.unit_defs.get(unit.player+1).get(unit.definition.produces.get(i)); boolean enoughMoney = true; for (int j = 0; j < def.cost.size(); j++) { if (resources.get(unit.player).get(j) < def.cost.get(j)) { enoughMoney = false; break; } } if (enoughMoney) { // horizontal for (int x = unit.x-1; x < unit.x+2; x+=2) { if (x >= 0 && x < width && unit_map[x+unit.y*width] == null && (unitDefinitions.unit_defs.get(unit.player+1).get(unit.definition.produces.get(i)).is_flying || terrain[x+unit.y*width] == TERRAIN_NONE)) { unit.legalActions.add(new UnitAction(unit, UnitAction.BUILD, x, unit.y, unit.definition.produces.get(i))); } } // vertical for (int y = unit.y-1; y < unit.y+2; y+=2) { if (y >= 0 && y < height && unit_map[unit.x+y*width] == null && (unitDefinitions.unit_defs.get(unit.player+1).get(unit.definition.produces.get(i)).is_flying || terrain[unit.x+y*width] == TERRAIN_NONE)) { unit.legalActions.add(new UnitAction(unit, UnitAction.BUILD, unit.x, y, unit.definition.produces.get(i))); } } } } } else { if (unit.definition.is_worker) { // consider HARVEST // horizontal if (unit.resources == 0) { for (int x = unit.x-1; x < unit.x+2; x+=2) { if (x >= 0 && x < width) { UnitStats resource = unit_map[x+unit.y*width]; if (resource != null && resource.definition.is_resources && resource.resources > 0) { unit.legalActions.add(new UnitAction(unit, UnitAction.HARVEST, x, unit.y, -1)); } } } // vertical for (int y = unit.y-1; y < unit.y+2; y+=2) { if (y >= 0 && y < height) { UnitStats resource = unit_map[unit.x+y*width]; if (resource != null && resource.definition.is_resources && resource.resources > 0) { unit.legalActions.add(new UnitAction(unit, UnitAction.HARVEST, unit.x, y, -1)); } } } } // consider RETURN if (unit.resources > 0) { // horizontal for (int x = unit.x-1; x < unit.x+2; x+=2) { if (x >= 0 && x < width) { UnitStats stockpile = unit_map[x+unit.y*width]; if (stockpile != null && stockpile.definition.is_stockpile_building) { unit.legalActions.add(new UnitAction(unit, UnitAction.RETURN, x, unit.y, -1)); } } } // vertical for (int y = unit.y-1; y < unit.y+2; y+=2) { if (y >= 0 && y < height) { UnitStats stockpile = unit_map[unit.x+y*width]; if (stockpile != null && stockpile.definition.is_stockpile_building) { unit.legalActions.add(new UnitAction(unit, UnitAction.RETURN, unit.x, y, -1)); } } } } // consider BUILD for (int i = 0; i < unitDefinitions.building_defs.get(unit.player+1).size(); i++) { UnitDefinition def = unitDefinitions.building_defs.get(unit.player+1).get(i); boolean enoughMoney = true; for (int j = 0; j < def.cost.size(); j++) { if (resources.get(unit.player).get(j) < def.cost.get(j)) { enoughMoney = false; break; } } if (enoughMoney) { // horizontal for (int x = unit.x-1; x < unit.x+2; x+=2) { if (x >= 0 && x < width && unit_map[x+unit.y*width] == null && terrain[x+unit.y*width] == TERRAIN_NONE) { unit.legalActions.add(new UnitAction(unit, UnitAction.BUILD, x, unit.y, i)); } } // vertical for (int y = unit.y-1; y < unit.y+2; y+=2) { if (y >= 0 && y < height && unit_map[unit.x+y*width] == null && terrain[unit.x+y*width] == TERRAIN_NONE) { unit.legalActions.add(new UnitAction(unit, UnitAction.BUILD, unit.x, y, i)); } } } } } // consider MOVE // horizontal for (int x = unit.x-1; x < unit.x+2; x+=2) { if (x >= 0 && x < width && unit_map[x+unit.y*width] == null && (unit.definition.is_flying || terrain[x+unit.y*width] == TERRAIN_NONE)) { unit.legalActions.add(new UnitAction(unit, UnitAction.MOVE, x, unit.y, -1)); } } // vertical for (int y = unit.y-1; y < unit.y+2; y+=2) { if (y >= 0 && y < height && unit_map[unit.x+y*width] == null && (unit.definition.is_flying || terrain[unit.x+y*width] == TERRAIN_NONE)) { unit.legalActions.add(new UnitAction(unit, UnitAction.MOVE, unit.x, y, -1)); } } // consider ATTACK for (int y = unit.y-unit.definition.attack_range; y <= unit.y+unit.definition.attack_range; y++) { for (int x = unit.x-unit.definition.attack_range; x <= unit.x+unit.definition.attack_range; x++) { // ensure on map and in range int distance2 = (x-unit.x)*(x-unit.x)+(y-unit.y)*(y-unit.y); if (x >= 0 && x < width && y >= 0 && y < height && distance2 <= unit.definition.attack_range*unit.definition.attack_range && distance2 > 0) { UnitStats victim = unit_map[x+y*width]; if (victim != null && !victim.definition.is_resources) { unit.legalActions.add(new UnitAction(unit, UnitAction.ATTACK, x, y, -1)); } } } } } } } /** * Removes this unit because it is dead * @param unit * @param index */ private void removeUnit(UnitStats unit, int index) { // int player = unit.player%armies.size(); // if (player == -1) { // player = armies.size()-1; // } // for (int i = 0 ; i < armies.get(player).size(); i++) { // if (armies.get(player).get(i).getID() == unit.id) { // armies.get(player).remove(i); // break; // } // } // if this unit was building... if (unit.action != null && unit.action.getType() == UnitAction.BUILD) { unit_map[unit.action.getTargetX()+unit.action.getTargetY()*width] = null; } corpses.add(unit); // check score if (unit.killed_by != -1) { if (unit.player != unit.killed_by) { scores.set(unit.killed_by, scores.get(unit.killed_by)+unitDefinitions.getScore(unit)); } else { scores.set(unit.killed_by, scores.get(unit.killed_by)-unitDefinitions.getScore(unit)); } } unit_map[unit.x+unit.y*width] = null; armyStats.remove(index); } /** * Returns how long an upgrade is going to take * @param player * @param upgrade_id * @return */ public int upgradeTime(int player, int upgrade_id) { if (player >= 0 && player < numberOfPlayers()) { player++; for (int i = 0; i < unitDefinitions.unit_upgrades.get(player).size(); i++) { if (upgrade_id == unitDefinitions.unit_upgrades.get(player).get(i).getID()) { return unitDefinitions.unit_upgrades.get(player).get(i).getUpgradeTime(); } } for (int i = 0; i < unitDefinitions.building_upgrades.get(player).size(); i++) { if (upgrade_id == unitDefinitions.building_upgrades.get(player).get(i).getID()) { return unitDefinitions.building_upgrades.get(player).get(i).getUpgradeTime(); } } } return UnitAction.DEFAULT_COOLDOWN; } /** * Executes an upgrade * @param upgrade_id which upgrade to do * @return */ public boolean upgradeUnits(int player, int upgrade_id) { return unitDefinitions.upgrade(player, upgrade_id); } }