From: <mp...@us...> - 2013-01-31 23:34:19
|
Revision: 10491 http://sourceforge.net/p/freecol/code/10491 Author: mpope Date: 2013-01-31 23:34:15 +0000 (Thu, 31 Jan 2013) Log Message: ----------- Merge git.bd1429a: Ensure directional tile improvements are correctly connected. Modified Paths: -------------- freecol/trunk/src/net/sf/freecol/client/gui/panel/MapEditorTransformPanel.java freecol/trunk/src/net/sf/freecol/common/model/Colony.java freecol/trunk/src/net/sf/freecol/common/model/Game.java freecol/trunk/src/net/sf/freecol/common/model/LostCityRumour.java freecol/trunk/src/net/sf/freecol/common/model/Map.java freecol/trunk/src/net/sf/freecol/common/model/Player.java freecol/trunk/src/net/sf/freecol/common/model/Resource.java freecol/trunk/src/net/sf/freecol/common/model/Tile.java freecol/trunk/src/net/sf/freecol/common/model/TileImprovement.java freecol/trunk/src/net/sf/freecol/common/model/TileImprovementStyle.java freecol/trunk/src/net/sf/freecol/common/model/TileImprovementType.java freecol/trunk/src/net/sf/freecol/common/model/TileItem.java freecol/trunk/src/net/sf/freecol/common/model/TileItemContainer.java freecol/trunk/src/net/sf/freecol/server/generator/River.java freecol/trunk/src/net/sf/freecol/server/generator/SimpleMapGenerator.java freecol/trunk/src/net/sf/freecol/server/model/ServerColony.java freecol/trunk/src/net/sf/freecol/server/model/ServerUnit.java freecol/trunk/test/src/net/sf/freecol/common/model/MovementTest.java freecol/trunk/test/src/net/sf/freecol/common/model/TileImprovementTest.java freecol/trunk/test/src/net/sf/freecol/common/model/TileItemContainerTest.java freecol/trunk/test/src/net/sf/freecol/common/model/TileTest.java freecol/trunk/test/src/net/sf/freecol/server/ai/mission/PioneeringMissionTest.java Modified: freecol/trunk/src/net/sf/freecol/client/gui/panel/MapEditorTransformPanel.java =================================================================== --- freecol/trunk/src/net/sf/freecol/client/gui/panel/MapEditorTransformPanel.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/client/gui/panel/MapEditorTransformPanel.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -274,13 +274,8 @@ tile.getSpecification().getTileImprovementType("model.improvement.river"); if (tile.getType().canHaveImprovement(riverType)) { - TileItemContainer tic = tile.getTileItemContainer(); - if (tic == null) { - tic = new TileItemContainer(tile.getGame(), tile); - tile.setTileItemContainer(tic); - } int oldMagnitude = TileImprovement.NO_RIVER; - TileImprovement river = tic.getRiver(); + TileImprovement river = tile.getRiver(); if (river == null) { river = new TileImprovement(tile.getGame(), tile, riverType); river.setStyle(TileImprovementStyle.getInstance("0000")); @@ -289,8 +284,8 @@ } if (magnitude != oldMagnitude) { - tic.addRiver(magnitude, river.getStyle()); - RiverSection mysection = new RiverSection(river.getStyle().getConnections()); + tile.addRiver(magnitude, river.getStyle().getString()); + RiverSection mysection = new RiverSection(river.getConnections()); // for each neighboring tile for (Direction direction : Direction.longSides) { Tile t = tile.getNeighbourOrNull(direction); @@ -308,7 +303,7 @@ // update the other tile river branch Direction otherDirection = direction.getReverseDirection(); RiverSection oppositesection = - new RiverSection(otherRiver.getStyle().getConnections()); + new RiverSection(otherRiver.getConnections()); oppositesection.setBranch(otherDirection, tile.getRiver().getMagnitude()); otherRiver.setStyle(TileImprovementStyle.getInstance(oppositesection.encodeStyle())); // update the current tile river branch Modified: freecol/trunk/src/net/sf/freecol/common/model/Colony.java =================================================================== --- freecol/trunk/src/net/sf/freecol/common/model/Colony.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/common/model/Colony.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -2222,7 +2222,7 @@ } TileImprovement road = getTile().getRoad(); if (road != null && road.isVirtual()) { - getTile().getTileItemContainer().removeTileItem(road); + getTile().removeRoad(); } objects.addAll(super.disposeList()); return objects; Modified: freecol/trunk/src/net/sf/freecol/common/model/Game.java =================================================================== --- freecol/trunk/src/net/sf/freecol/common/model/Game.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/common/model/Game.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -812,54 +812,40 @@ } /** - * Checks the integrity of this <code>Game</code - * by checking if there are any - * {@link FreeColGameObject#isUninitialized() uninitialized objects}. + * Checks the integrity of this <code>Game</code>. + * + * - Detects {@link FreeColGameObject#isUninitialized() uninitialized} + * <code>FreeColGameObject</code>s. + * - Detects and fixes map inconsistencies + * - Detects and fixes player inconsistencies * - * Detected problems gets written to the log. - * - * @return <code>true</code> if the <code>Game</code> has - * been loaded properly. + * @return True if there were no problems found. */ public boolean checkIntegrity() { - List<String> brokenObjects = new ArrayList<String>(); boolean ok = true; Iterator<FreeColGameObject> iterator = getFreeColGameObjectIterator(); while (iterator.hasNext()) { FreeColGameObject fgo = iterator.next(); if (fgo.isUninitialized()) { - brokenObjects.add(fgo.getId()); - logger.warning("Uninitialized object: " + fgo.getId() + " (" + fgo.getClass() + ")"); + logger.warning("Uninitialized object: " + fgo.getId() + + " (" + fgo.getClass() + ")"); ok = false; } } + Map map = getMap(); + if (map != null) ok &= map.fixIntegrity(); + for (Player player : getPlayers()) { + ok &= player.fixIntegrity(); + } if (ok) { logger.info("Game integrity ok."); } else { logger.warning("Game integrity test failed."); - fixIntegrity(brokenObjects); } return ok; } /** - * Try to fix integrity problems - */ - private boolean fixIntegrity(List<String> list){ - // try to update Units who may have missing info - for(Player player : this.getPlayers()){ - for(Unit unit : player.getUnits()){ - if(unit.getOwner() == null){ - logger.warning("Fixing " + unit.getId() + ": owner missing"); - unit.setOwner(player); - } - } - } - return false; - } - - - /** * Gets the <code>MapGeneratorOptions</code> that is associated with this * {@link Game}. * @return <code>OptionGroup</code> Modified: freecol/trunk/src/net/sf/freecol/common/model/LostCityRumour.java =================================================================== --- freecol/trunk/src/net/sf/freecol/common/model/LostCityRumour.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/common/model/LostCityRumour.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -142,10 +142,11 @@ this.name = newName; } + + // Interface TileItem + /** - * Get the <code>ZIndex</code> value. - * - * @return an <code>int</code> value + * {@inheritDoc} */ public final int getZIndex() { return RUMOUR_ZINDEX; Modified: freecol/trunk/src/net/sf/freecol/common/model/Map.java =================================================================== --- freecol/trunk/src/net/sf/freecol/common/model/Map.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/common/model/Map.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -2068,6 +2068,19 @@ } } + /** + * Fix any map integrity problems. + * + * @return True if there were no problems. + */ + public boolean fixIntegrity() { + boolean result = true; + for (Tile t : getAllTiles()) { + result &= t.fixIntegrity(); + } + return result; + } + // Location interface. // getId() inherited. Modified: freecol/trunk/src/net/sf/freecol/common/model/Player.java =================================================================== --- freecol/trunk/src/net/sf/freecol/common/model/Player.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/common/model/Player.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -1468,6 +1468,24 @@ } /** + * Try to fix integrity problems with units that have no owner. + * + * @return True if there were no problems, false if problems were found + * and corrected. + */ + public boolean fixIntegrity() { + boolean result = true; + for (Unit unit : getUnits()) { + if (unit.getOwner() == null) { + logger.warning("Fixing " + unit.getId() + ": owner missing"); + unit.setOwner(this); + result = false; + } + } + return result; + } + + /** * Gets the price to this player for a proposed unit. * * @param au The proposed <code>AbstractUnit</code>. Modified: freecol/trunk/src/net/sf/freecol/common/model/Resource.java =================================================================== --- freecol/trunk/src/net/sf/freecol/common/model/Resource.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/common/model/Resource.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -117,15 +117,6 @@ } /** - * Get the <code>ZIndex</code> value. - * - * @return an <code>int</code> value - */ - public final int getZIndex() { - return RESOURCE_ZINDEX; - } - - /** * Returns the best GoodsType */ public GoodsType getBestGoodsType() { @@ -179,20 +170,29 @@ return quantity; } + /* TODO: what was this for? Named resources, such as Lost Crazy Russian Gold Mine? + public void setName(String newName) { + // do nothing + } + */ + + // Interface TileItem + /** * {@inheritDoc} */ + public final int getZIndex() { + return RESOURCE_ZINDEX; + } + + /** + * {@inheritDoc} + */ public boolean isTileTypeAllowed(TileType tileType) { return tileType.canHaveResourceType(getType()); } - /* TODO: what was this for? Named resources, such as Lost Crazy Russian Gold Mine? - public void setName(String newName) { - // do nothing - } - */ - /** * This method writes an XML-representation of this object to the given * stream. Modified: freecol/trunk/src/net/sf/freecol/common/model/Tile.java =================================================================== --- freecol/trunk/src/net/sf/freecol/common/model/Tile.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/common/model/Tile.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -207,6 +207,19 @@ } } + /** + * Fix any tile integrity problems. + * + * @return True if there were no problems. + */ + public boolean fixIntegrity() { + boolean result = true; + for (TileImprovement ti : getTileImprovements()) { + result &= ti.fixIntegrity(); + } + return result; + } + // ------------------------------------------------------------ static methods /** * Creates a temporary copy of this tile for planning purposes. @@ -1177,7 +1190,65 @@ return this; } + /** + * Adds a river to this tile. + * + * @param magnitude The magnitude of the river to be created + * @param style The river style. + * @return The new river added, or the existing river TileImprovement. + */ + public TileImprovement addRiver(int magnitude, String style) { + if (magnitude == TileImprovement.NO_RIVER) return null; + TileImprovementType riverType = getSpecification() + .getTileImprovementType("model.improvement.river"); + TileImprovement river = new TileImprovement(getGame(), this, riverType); + river.setTurnsToComplete(0); + river.setMagnitude(magnitude); + river.setStyle(TileImprovementStyle.getInstance(style)); + if (!add(river)) return null; + river.updateConnections(); + return river; + } + + /** + * Removes a river from this tile. + * + * @return The removed river. + */ + public TileImprovement removeRiver() { + TileImprovement river = getRiver(); + return (river == null || !remove(river)) ? null : river; + } + + /** + * Adds a road to this tile. It is not necessarily complete. + * + * @return The new road added, or the existing one. + */ + public TileImprovement addRoad() { + TileImprovementType roadType = getSpecification() + .getTileImprovementType("model.improvement.road"); + TileImprovement road = new TileImprovement(getGame(), this, roadType); + road.setMagnitude(1); + if (!add(road)) return null; + road.setStyle(road.getRoadStyleFromMap()); + road.updateConnections(); + return road; + } + + /** + * Removes a road from this tile. + * + * @return The removed road. + */ + public TileImprovement removeRoad() { + TileImprovement road = getRoad(); + return (road == null || !remove(road)) ? null : road; + } + + + /** * Adds a <code>Locatable</code> to this Location. * * @param locatable The <code>Locatable</code> to add to this Location. @@ -1206,7 +1277,7 @@ public boolean remove(Locatable locatable) { if (locatable instanceof TileItem) { Player old = getOwner(); - tileItemContainer.addTileItem((TileItem) locatable); + tileItemContainer.removeTileItem((TileItem) locatable); updatePlayerExploredTiles(old); return true; } else { Modified: freecol/trunk/src/net/sf/freecol/common/model/TileImprovement.java =================================================================== --- freecol/trunk/src/net/sf/freecol/common/model/TileImprovement.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/common/model/TileImprovement.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -19,6 +19,8 @@ package net.sf.freecol.common.model; +import java.util.EnumMap; +import java.util.Map; import java.util.logging.Logger; import javax.xml.stream.XMLStreamException; @@ -35,15 +37,7 @@ private static Logger logger = Logger.getLogger(TileImprovement.class.getName()); - private TileImprovementType type; - private int turnsToComplete; - /** - * Default is type.getMagnitude(), but this will override. - */ - private int magnitude; - - /** * River magnitudes */ public static final int NO_RIVER = 0; @@ -51,13 +45,19 @@ public static final int LARGE_RIVER = 2; public static final int FJORD_RIVER = 3; + /** The type of this improvement. */ + private TileImprovementType type; + /** Turns remaining until the improvement is complete, if any. */ + private int turnsToComplete; + /** - * To store the style of multi-image TileImprovements (eg. rivers) - * Rivers have 4 directions {NE=1, SE=3, SW=9, NW=27}, and 3 levels (see above) - * @see Map - * @see net.sf.freecol.server.generator.River + * The improvement magnitude. Default is type.getMagnitude(), but + * this will override. */ + private int magnitude; + + /** Image and overlay style information for the improvement. */ private TileImprovementStyle style; /** @@ -67,8 +67,10 @@ */ private boolean virtual; - // ------------------------------------------------------------ constructor + /** Cached bitmap of connections by direction, derived from style. */ + private long connected = 0L; + /** * Creates a standard <code>TileImprovement</code>-instance. * @@ -88,6 +90,7 @@ this.turnsToComplete = tile.getType().getBasicWorkTurns() + type.getAddWorkTurns(); } this.magnitude = type.getMagnitude(); + this.connected = 0L; } public TileImprovement(Game game, XMLStreamReader in) throws XMLStreamException { @@ -96,229 +99,347 @@ } /** - * Initiates a new <code>TileImprovement</code> with the given ID. The object - * should later be initialized by calling either + * Instantiates a new <code>TileImprovement</code> with the given + * ID. The object should later be initialized by calling either * {@link #readFromXML(XMLStreamReader)} or * {@link #readFromXMLElement(Element)}. * - * @param game The <code>Game</code> in which this object belong. + * @param game The <code>Game</code> in which this object belongs. * @param id The unique identifier for this object. */ public TileImprovement(Game game, String id) { super(game, id); } - // ------------------------------------------------------------ retrieval methods - + /** + * Gets the type of this tile improvement. + * + * @return The type of this improvement. + */ public TileImprovementType getType() { return type; } - public int getMagnitude() { - return magnitude; + /** + * Gets a key for message routines. + * + * @return The name key. + */ + public String getNameKey() { + return type.getNameKey(); } - public void setMagnitude(int magnitude) { - this.magnitude = magnitude; + /** + * Is this <code>TileImprovement</code> a road? + * TODO: deprecate? + * + * @return True if this is a road improvement. + */ + public boolean isRoad() { + return "model.improvement.road".equals(type.getId()); } /** - * Get the <code>Virtual</code> value. + * Is this <code>TileImprovement</code> a river? + * TODO: deprecate? * - * @return a <code>boolean</code> value + * @return True if this is a river improvement. */ - public final boolean isVirtual() { - return virtual; + public boolean isRiver() { + return "model.improvement.river".equals(type.getId()); } /** - * Set the <code>Virtual</code> value. + * How many turns remain until this improvement is complete? * - * @param newVirtual The new Virtual value. + * @return The current turns to completion. */ - public final void setVirtual(final boolean newVirtual) { - this.virtual = newVirtual; + public int getTurnsToComplete() { + return turnsToComplete; } /** - * Is this <code>TileImprovement</code> a road? - * @return a <code>boolean</code> value + * Is this improvement complete? + * + * @return True if complete. */ - public boolean isRoad() { - return getType().getId().equals("model.improvement.road"); + public boolean isComplete() { + return turnsToComplete <= 0; } /** - * Is this <code>TileImprovement</code> a river? - * @return a <code>boolean</code> value + * Sets the turns required to complete the improvement. + * + * @param turns The new turns to completion. */ - public boolean isRiver() { - return getType().getId().equals("model.improvement.river"); + public void setTurnsToComplete(int turns) { + turnsToComplete = turns; } - public String getNameKey() { - return getType().getNameKey(); + /** + * Gets the magnitude of this improvement. + * + * @return The magnitude of this immprovement. + */ + public int getMagnitude() { + return magnitude; } /** - * Returns a textual representation of this object. - * @return A <code>String</code> of either: - * <ol> - * <li>NAME (#TURNS turns left) (eg. Road (2 turns left) ) if it is under construction - * <li>NAME (eg. Road) if it is complete - * </ol> + * Sets the magnitude of this improvement. + * + * @param magnitude The new magnitude. */ - public String toString() { - if (turnsToComplete > 0) { - return getType().getId() + " (" + Integer.toString(turnsToComplete) + " turns left)"; - } else { - return getType().getId(); - } + public void setMagnitude(int magnitude) { + this.magnitude = magnitude; } /** - * @return the current turns to completion. + * Gets the style of this improvement. + * + * @return The style */ - public int getTurnsToComplete() { - return turnsToComplete; + public TileImprovementStyle getStyle() { + return style; } /** - * Update the turns required to complete the improvement. + * Sets the style of this improvement. * - * @param turns an <code>int</code> value + * @param style The new style. */ - public void setTurnsToComplete(int turns) { - turnsToComplete = turns; + public void setStyle(TileImprovementStyle style) { + this.style = style; } /** - * Get the <code>ZIndex</code> value. + * Is this a virtual improvement? * - * @return an <code>int</code> value + * @return True if this is a virtual improvement. */ - public final int getZIndex() { - return type.getZIndex(); + public final boolean isVirtual() { + return virtual; } - public boolean isComplete() { - return turnsToComplete <= 0; + /** + * Set the virtual status of this improvement. + * Used for the roads in a colony center tile. + * + * @param virtual The new virtual value. + */ + public final void setVirtual(final boolean virtual) { + this.virtual = virtual; } - public EquipmentType getExpendedEquipmentType() { - return type.getExpendedEquipmentType(); + /** + * Is this TileImprovement connected to a similar TileImprovement + * on a neighbouring tile? + * + * @param direction The <code>Direction</code> to check. + * @return True if this improvement is connected. + */ + public boolean isConnectedTo(Direction direction) { + return (connected & (1 << direction.ordinal())) != 0; } - public int getExpendedAmount() { - return type.getExpendedAmount(); + /** + * Sets the connection status in a given direction. + * + * @param direction The <code>Direction</code> to set. + * @param value The new status for the connection. + */ + public void setConnected(Direction direction, boolean value) { + boolean now = isConnectedTo(direction); + if (now != value) { + if (value) { + connected |= 1 << direction.ordinal(); + } else { + connected &= ~(1 << direction.ordinal()); + } + } + style = TileImprovementStyle.getInstance(encodeConnections()); } /** - * Returns the bonus (if any). - * @param goodsType a <code>GoodsType</code> value - * @return an <code>int</code> value + * Encode a style string suitable for TileImprovementStyle.getInstance. */ - public int getBonus(GoodsType goodsType) { - if (!isComplete()) { - return 0; + private String encodeConnections() { + String s = new String(); + for (Direction d : Direction.values()) { + s = s.concat((isConnectedTo(d)) ? Integer.toString(magnitude) :"0"); } - return type.getBonus(goodsType); + return s; } /** - * Returns the bonus Modifier (if any). - * @param goodsType a <code>GoodsType</code> value - * @return a <code>Modifier</code> value + * Gets a map of connection-direction to magnitude. + * + * @return A map of the connections. */ - public Modifier getProductionModifier(GoodsType goodsType) { - if (!isComplete()) { - return null; + public Map<Direction, Integer> getConnections() { + Map<Direction, Integer> result + = new EnumMap<Direction, Integer>(Direction.class); + for (Direction d : Direction.values()) { + if (isConnectedTo(d)) result.put(d, magnitude); } - return type.getProductionModifier(goodsType); + return result; } /** + * Gets the production bonus this improvement provides for a given type + * of goods. + * + * @param goodsType The <code>GoodsType</code> to test. + * @return A production bonus, or zero if none applicable. + */ + public int getBonus(GoodsType goodsType) { + return (isComplete()) ? type.getBonus(goodsType) : 0; + } + + /** + * Gets a Modifier for the production bonus this improvement provides + * for a given type of goods. + * + * @param goodsType The <code>GoodsType</code> to test. + * @return A production <code>Modifier</code>, or null if none applicable. + */ + public Modifier getProductionModifier(GoodsType goodsType) { + return (isComplete()) ? type.getProductionModifier(goodsType) : null; + } + + + /** * Calculates the movement cost on the basis of connected tile * improvements. * - * @param fromTile a <code>Tile</code> value - * @param targetTile a <code>Tile</code> value - * @param moveCost Original movement cost - * @return The movement cost after any change + * @param direction The <code>Direction</code> to move. + * @param moveCost The original movement cost. + * @return The movement cost with this improvement. */ - public int getMoveCost(Tile fromTile, Tile targetTile, int moveCost) { - if (isComplete()) { - if (style == null) { - // implicitly connected to all neighbouring tiles - return type.getMoveCost(moveCost); - } else { - Direction direction = targetTile.getMap().getDirection(targetTile, fromTile); - // TODO: fix this properly, roads are getting bogus styles - boolean connected = (isRiver()) - ? style != null && style.isConnectedTo(direction) - : (isRoad()) - ? fromTile.hasRoad() && targetTile.hasRoad() - : false; - if (connected) return type.getMoveCost(moveCost); - } - } - return moveCost; + public int getMoveCost(Direction direction, int moveCost) { + return (isComplete() && isConnectedTo(direction)) + ? type.getMoveCost(moveCost) + : moveCost; } /** - * Returns any change of TileType - * @return The new TileType. + * What type of tile does this improvement change a given type to? + * + * @param tileType The original <code>TileType</code>. + * @return The <code>TileType</code> that results from completing this + * improvement, or null if nothing changes. */ public TileType getChange(TileType tileType) { - if (!isComplete()) { - return null; - } - return type.getChange(tileType); + return (isComplete()) ? type.getChange(tileType) : null; } /** - * Returns the Style of this Improvement - used for Rivers - * @return The style + * Can a unit build this improvement? + * + * @param unit A <code>Unit</code> to do the building. + * @return True if the supplied unit can build this improvement. */ - public TileImprovementStyle getStyle() { - return style; + public boolean isWorkerAllowed(Unit unit) { + return (unit == null || isComplete()) ? false + : type.isWorkerAllowed(unit); } + /** - * Sets the Style of this Improvement - used for Rivers - * @param style The style + * Fixes any tile improvement style discontinuities. + * + * We check only if this improvement is not connected to a neighbour + * that *is* connected to this one, and connect this one. + * + * TODO: drop this one day when we never have style discontinuities. + * This alas is not the case in 0.10.x. + * + * @return True if the style was coherent, false if a problem was + * found and corrected. */ - public void setStyle(TileImprovementStyle style) { - this.style = style; + public boolean fixIntegrity() { + final Tile tile = getTile(); + boolean result = true; + for (Tile t : tile.getSurroundingTiles(1)) { + Direction dForward = tile.getDirection(t); + Direction dReverse = dForward.getReverseDirection(); + for (TileImprovement ti : t.getTileImprovements()) { + if (getType() == ti.getType() + && !isConnectedTo(dForward) + && ti.isConnectedTo(dReverse)) { + setConnected(dForward, true); + result = false; + logger.warning("Connecting improvement " + this + + " at " + tile + " to " + t); + } + } + } + return result; } /** - * Returns <code>true</code> if this TileImprovement is connected - * to a similar TileImprovement on the given tile. + * Updates the connections from the current style. * - * @param direction a <code>Direction</code> value - * @return a <code>boolean</code> value + * Public for the test suite. */ - public boolean isConnectedTo(Direction direction) { - return style == null ? false : style.isConnectedTo(direction); + public void updateConnections() { + connected = 0L; + if (style != null) { + Direction[] directions = (isRoad()) ? Direction.values() + : Direction.longSides; + String mask = style.getMask(); + for (int i = 0; i < directions.length; i++) { + if (mask.charAt(i) != '0') { + connected |= 1L << directions[i].ordinal(); + } + } + } } /** - * Checks if a given worker can work at this Improvement + * Work out what the road style at this tile should be by checking + * neighbouring tiles for roads. + * + * @return A suitable TileImprovementStyle. */ - public boolean isWorkerAllowed(Unit unit) { - if (unit == null) { - return false; + public TileImprovementStyle getRoadStyleFromMap() { + if (!isRoad()) return null; + final Tile tile = getTile(); + String s = new String(); + for (Direction d : Direction.values()) { + Tile t = tile.getNeighbourOrNull(d); + s = s.concat((t != null && t.hasRoad()) ? "1" : "0"); } - if (isComplete()) { - return false; + return TileImprovementStyle.getInstance(s); + } + + /** + * Updates the connections from/to this road improvement. + * + * @param connect If true, add connections, otherwise remove them. + */ + public void updateRoadConnections(boolean connect) { + if (!isRoad() || !isComplete()) return; + final Tile tile = getTile(); + for (Tile t : tile.getSurroundingTiles(1)) { + if (t.hasRoad()) { + t.getRoad().setConnected(t.getDirection(tile), connect); + } } - return type.isWorkerAllowed(unit); } + // Interface TileItem + /** * {@inheritDoc} */ + public final int getZIndex() { + return type.getZIndex(); + } + + /** + * {@inheritDoc} + */ public boolean isTileTypeAllowed(TileType tileType) { return type.isTileTypeAllowed(tileType); } @@ -396,16 +517,44 @@ magnitude = Integer.parseInt(in.getAttributeValue(null, "magnitude")); - style = TileImprovementStyle.getInstance(in.getAttributeValue(null, "style")); + str = in.getAttributeValue(null, "style"); + if (str == null) { + style = null; + // @compat 0.10.5 + } else if (str.length() < 4) { + String old = TileImprovementStyle.decodeOldStyle(str, isRoad()); + if (old == null) { + logger.warning("Ignoring bogus old TileImprovementStyle: " + + str); + } else { + style = TileImprovementStyle.getInstance(old); + } + // end compatibility code + } else { + style = TileImprovementStyle.getInstance(str); + if (style == null) { + logger.warning("Ignoring bogus TileImprovementStyle: " + str); + } + } + updateConnections(); virtual = getAttribute(in, "virtual", false); + } + /** + * Gets a textual representation of this object. + * + * @return The id and turns to complete if any. + */ + public String toString() { + return getType().getId() + ((turnsToComplete <= 0) ? "" + : " (" + Integer.toString(turnsToComplete) + " turns left)"); } /** * Gets the tag name of the root element representing this object. * - * @return "tileImprovement". + * @return "tileimprovement". */ public static String getXMLElementTagName() { return "tileimprovement"; Modified: freecol/trunk/src/net/sf/freecol/common/model/TileImprovementStyle.java =================================================================== --- freecol/trunk/src/net/sf/freecol/common/model/TileImprovementStyle.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/common/model/TileImprovementStyle.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -19,7 +19,6 @@ package net.sf.freecol.common.model; -import java.util.EnumMap; import java.util.HashMap; import java.util.Map; @@ -46,125 +45,135 @@ */ public class TileImprovementStyle { - private String style; + /** Cache all TileImprovementStyles. */ + private static final Map<String, TileImprovementStyle> cache + = new HashMap<String, TileImprovementStyle>(); - private String mask; + /** A key for the tile improvement style. */ + private final String style; - private Map<Direction, Integer> connections = - new EnumMap<Direction, Integer>(Direction.class); + /** A key for the forest overlay, derived from the above. */ + private final String mask; - private static final Map<String, TileImprovementStyle> cache = - new HashMap<String, TileImprovementStyle>(); + /** + * Private constructor, only called in getInstance() below. + * + * @param style The (decoded) style. + */ + private TileImprovementStyle(String style) { + this.style = style; - private TileImprovementStyle(String input) { + String s = new String(); + for (int i = 0; i < style.length(); i++) { + char c = style.charAt(i); + if (Character.digit(c, Character.MAX_RADIX) < 0) break; + s = s.concat((c == '0') ? "0" : "1"); + } + this.mask = s; + } - Direction[] directions = (input.length() < 8) - ? Direction.longSides : Direction.values(); + // @compat 0.10.5 + /** + * Decode the old base-3 encoded style format. + * + * @param input An old style string. + * @param allDirections If true extend the string to contain a value for + * all directions, if not, extend the string only for the long sides. + * @return The style in the new format. + */ + public static String decodeOldStyle(String input, boolean allDirections) { + Direction[] directions = (allDirections) ? Direction.values() + : Direction.longSides; - // @compat 0.10.5 - if (input.length() < 4) { - // must be an old style - style = new String(); + String style = new String(); + try { int value = Integer.parseInt(input); for (int index = 0; index < 4; index++) { int magnitude = value % 3; - style = style.concat(Integer.toString(magnitude, Character.MAX_RADIX)); - connections.put(directions[index], magnitude); + style = style.concat(Integer.toString(magnitude, + Character.MAX_RADIX)); value /= 3; } - // end @compat - } else { - style = input; - char[] chars = new char[directions.length]; - for (int index = 0; index < directions.length; index++) { - int magnitude = Integer.parseInt(style.substring(index, index + 1), - Character.MAX_RADIX); - connections.put(directions[index], magnitude); - } + } catch (NumberFormatException nfe) { + return null; } - this.mask = new String(); - for (Direction direction : directions) { - mask = mask.concat((getConnection(direction) == 0) ? "0" : "1"); + while (style.length() < directions.length) { + style = style.concat("0"); } + return style; } + // @end compatibility code - /** - * Return the instance identified by the given string. + * Gets the style corresponding to the given string. * - * @param key a <code>String</code> value - * @return a <code>TileImprovementStyle</code> value + * @param key The key to look up. + * @return The corresponding <code>TileImprovementStyle</code>. */ public static TileImprovementStyle getInstance(String key) { - if (key == null || "".equals(key)) { - return null; - } else { - TileImprovementStyle result = cache.get(key); - if (result == null) { - result = new TileImprovementStyle(key); - cache.put(key, result); - if (result.getString() != key) { - cache.put(result.getString(), result); - } + if (key == null || "".equals(key)) return null; + + TileImprovementStyle result = cache.get(key); + if (result == null) { + result = new TileImprovementStyle(key); + cache.put(key, result); + if (result.getString() != key) { + cache.put(result.getString(), result); } - return result; } + return result; } + /** + * Gets a new style derived from a base version but with an added + * connection in a given direction. + * + * @param direction The new direction to connect to. + * @param base The base style (may be null). + * @param magnitude The magnitude of the new connection. + * @param allDirections The style must include all directions. + * @return A new style. + */ + public static TileImprovementStyle getConnectedStyle(Direction direction, + TileImprovementStyle base, int magnitude, boolean allDirections) { + String style = (base == null) ? decodeOldStyle("0", allDirections) + : base.getString(); + int index = direction.ordinal(); + if (style.length() < Direction.NUMBER_OF_DIRECTIONS) index /= 2; + String result = ((index == 0) ? "" : style.substring(0, index-1)) + + Integer.toString(magnitude) + + ((index+1 == style.length()) ? "" : style.substring(index+1)); + return getInstance(result); + } + + /** - * Return a string suitable for looking up an appropriate tile + * Gets the key suitable for looking up an appropriate tile * improvement image. * - * @return a <code>String</code> value + * @return The tile improvement lookup key. */ public String getString() { return style; } - public String toString() { - return style; - } - /** - * Return a string suitable for looking up an appropriate overlay + * Gets the key suitable for looking up an appropriate overlay * (forest) image. * - * @return a <code>String</code> value + * @return The overlay lookup key. */ public String getMask() { return mask; } - public Map<Direction, Integer> getConnections() { - return new EnumMap<Direction, Integer>(connections); - } - + /** - * Return the magnitude of the TileImprovement in the given - * direction. - * - * @param direction a <code>Direction</code> value - * @return an <code>int</code> value + * {@inheritDoc} */ - public int getConnection(Direction direction) { - if (connections.containsKey(direction)) { - return connections.get(direction); - } else { - return 0; - } + public String toString() { + return style; } - - /** - * Return <code>true</code> if the tile improvement is connected - * to a similar improvement on the given tile. - * - * @param direction a <code>Direction</code> value - * @return a <code>boolean</code> value - */ - public boolean isConnectedTo(Direction direction) { - return getConnection(direction) > 0; - } - -} \ No newline at end of file +} Modified: freecol/trunk/src/net/sf/freecol/common/model/TileImprovementType.java =================================================================== --- freecol/trunk/src/net/sf/freecol/common/model/TileImprovementType.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/common/model/TileImprovementType.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -58,8 +58,7 @@ private List<RandomChoice<Disaster>> disasters = new ArrayList<RandomChoice<Disaster>>(); - private int movementCost; - private float movementCostFactor; + private int movementCost = -1; /** * The layer a TileItem belongs to. Items with higher zIndex @@ -276,28 +275,20 @@ } /** - * Performs reduction of the movement-cost. - * @param moveCost Original movement cost - * @return The movement cost after any change + * Possibly reduces the cost of moving due to this tile + * improvement type. + * + * Only applies if movementCost is positive (see spec). Do not + * return zero from a movement costing routine or units get free + * moves! + * + * @param originalCost The original movement cost. + * @return The movement cost after any change. */ - public int getMoveCost(int moveCost) { - int cost = moveCost; - if (movementCostFactor >= 0) { - float cost2 = cost * movementCostFactor; - cost = (int)cost2; - if (cost < cost2) { - cost++; - } - } - if (movementCost > 0) { - // Only >0 values are meaningful (see spec). - // Do not return zero from a movement costing routine or - // units get free moves! - if (movementCost < cost) { - cost = movementCost; - } - } - return cost; + public int getMoveCost(int originalCost) { + return (movementCost > 0 && movementCost < originalCost) + ? movementCost + : originalCost; } /** @@ -444,7 +435,6 @@ natural = getAttribute(in, "natural", false); addWorkTurns = getAttribute(in, "add-work-turns", 0); movementCost = getAttribute(in, "movement-cost", 0); - movementCostFactor = -1; magnitude = getAttribute(in, "magnitude", 1); requiredImprovementType = getSpecification().getType(in, Modified: freecol/trunk/src/net/sf/freecol/common/model/TileItem.java =================================================================== --- freecol/trunk/src/net/sf/freecol/common/model/TileItem.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/common/model/TileItem.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -120,6 +120,7 @@ return 0; } + /** * Get the <code>ZIndex</code> value. * Modified: freecol/trunk/src/net/sf/freecol/common/model/TileItemContainer.java =================================================================== --- freecol/trunk/src/net/sf/freecol/common/model/TileItemContainer.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/common/model/TileItemContainer.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -349,7 +349,8 @@ for (TileItem item : tileItems) { if (item instanceof TileImprovement && ((TileImprovement) item).isComplete()) { - moveCost = Math.min(moveCost, ((TileImprovement) item).getMoveCost(fromTile, targetTile, moveCost)); + moveCost = Math.min(moveCost, + ((TileImprovement)item).getMoveCost(targetTile.getDirection(fromTile), moveCost)); } } return moveCost; @@ -505,45 +506,8 @@ // ------------------------------------------------------------ manipulation methods - /** - * Creates a river <code>TileImprovement</code> and adds to this Tile/Container. - * Checking for overwrite is done by {@link #addTileItem}. - * @param magnitude The Magnitude of the river to be created - * @param style an <code>int</code> value - * @return The new river added, or the existing river TileImprovement - */ - public TileImprovement addRiver(int magnitude, TileImprovementStyle style) { - if (magnitude == TileImprovement.NO_RIVER) { - return null; - } - TileImprovement river = new TileImprovement(getGame(), tile, getSpecification() - .getTileImprovementType("model.improvement.river")); - river = (TileImprovement) addTileItem(river); - river.setMagnitude(magnitude); - river.setStyle(style); - invalidateCache(); - return river; - } /** - * Removes the river <code>TileImprovement</code> from this Tile/Container. - */ - // Change neighbours' River Style with {@link #adjustNeighbourRiverStyle}. - public TileImprovement removeRiver() { - Iterator<TileItem> iterator = tileItems.iterator(); - while (iterator.hasNext()) { - TileItem item = iterator.next(); - if (item instanceof TileImprovement && ((TileImprovement) item).isRiver()) { - iterator.remove(); - invalidateCache(); - return (TileImprovement) item; - } - } - return null; - } - - - /** * This method writes an XML-representation of this object to * the given stream. * Modified: freecol/trunk/src/net/sf/freecol/server/generator/River.java =================================================================== --- freecol/trunk/src/net/sf/freecol/server/generator/River.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/server/generator/River.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -451,14 +451,12 @@ logger.fine("Added fjord (magnitude: " + section.getSize() + ") to tile at " + section.getPosition()); } else if (section.getSize() > TileImprovement.NO_RIVER) { - TileItemContainer container = tile.getTileItemContainer(); - if (container == null) { - container = new TileItemContainer(tile.getGame(), tile); - tile.setTileItemContainer(container); - } - container.addRiver(section.getSize(), TileImprovementStyle.getInstance(section.encodeStyle())); - logger.fine("Added river (magnitude: " + section.getSize() + - ") to tile at " + section.getPosition()); + String style = section.encodeStyle(); + tile.addRiver(section.getSize(), style); + logger.fine("Added river" + + "(magnitude: " + section.getSize() + + " style: " + style + + ") at " + section.getPosition()); } region.addTile(tile); oldSection = section; Modified: freecol/trunk/src/net/sf/freecol/server/generator/SimpleMapGenerator.java =================================================================== --- freecol/trunk/src/net/sf/freecol/server/generator/SimpleMapGenerator.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/server/generator/SimpleMapGenerator.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -997,15 +997,9 @@ ct.setType(t); TileImprovementType plowType = map.getSpecification() .getTileImprovementType("model.improvement.plow"); - TileImprovementType roadType = map.getSpecification() - .getTileImprovementType("model.improvement.road"); - TileImprovement road = new TileImprovement(game, ct, roadType); - road.setTurnsToComplete(0); TileImprovement plow = new TileImprovement(game, ct, plowType); plow.setTurnsToComplete(0); - ct.setTileItemContainer(new TileItemContainer(game, ct)); - ct.getTileItemContainer().addTileItem(road); - ct.getTileItemContainer().addTileItem(plow); + ct.add(plow); break; } } Modified: freecol/trunk/src/net/sf/freecol/server/model/ServerColony.java =================================================================== --- freecol/trunk/src/net/sf/freecol/server/model/ServerColony.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/server/model/ServerColony.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -88,12 +88,10 @@ established = game.getTurn(); tile.setOwner(owner); if (!tile.hasRoad()) { - TileImprovement road - = new TileImprovement(game, tile, - spec.getTileImprovementType("model.improvement.road")); + TileImprovement road = tile.addRoad(); road.setTurnsToComplete(0); road.setVirtual(true); - tile.add(road); + road.updateRoadConnections(true); } ColonyTile colonyTile = new ServerColonyTile(game, this, tile); Modified: freecol/trunk/src/net/sf/freecol/server/model/ServerUnit.java =================================================================== --- freecol/trunk/src/net/sf/freecol/server/model/ServerUnit.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/src/net/sf/freecol/server/model/ServerUnit.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -237,6 +237,7 @@ if (ti.isComplete()) { setState(UnitState.ACTIVE); setWorkLeft(-1); + if (ti.isRoad()) ti.updateRoadConnections(true); } else { // Otherwise do work int amount = (getType().hasAbility(Ability.EXPERT_PIONEER)) @@ -407,8 +408,8 @@ } // Expend equipment - EquipmentType type = ti.getExpendedEquipmentType(); - changeEquipment(type, -ti.getExpendedAmount()); + EquipmentType type = ti.getType().getExpendedEquipmentType(); + changeEquipment(type, -ti.getType().getExpendedAmount()); for (Unit unit : tile.getUnitList()) { if (unit.getWorkImprovement() != null && unit.getWorkImprovement().getType() == ti.getType() Modified: freecol/trunk/test/src/net/sf/freecol/common/model/MovementTest.java =================================================================== --- freecol/trunk/test/src/net/sf/freecol/common/model/MovementTest.java 2013-01-31 11:42:02 UTC (rev 10490) +++ freecol/trunk/test/src/net/sf/freecol/common/model/MovementTest.java 2013-01-31 23:34:15 UTC (rev 10491) @@ -25,19 +25,34 @@ public class MovementTest extends FreeColTestCase { + private static final TileType hills + = spec().getTileType("model.tile.hills"); + private static final TileType ocean + = spec().getTileType("model.tile.ocean"); + private static final TileType plains + = spec().getTileType("model.tile.plains"); - TileType plains = spec().getTileType("model.tile.plains"); - TileType hills = spec().getTileType("model.tile.hills"); - TileType ocean = spec().getTileType("model.tile.ocean"); + private static final UnitType braveType + = spec().getUnitType("model.unit.brave"); + private static final UnitType colonistType + = spec().getUnitType("model.unit.freeColonist"); + private static final UnitType galleonType + = spec().getUnitType("model.unit.galleon"); - UnitType galleonType = spec().getUnitType("model.unit.galleon"); - UnitType colonistType = spec().getUnitType("model.unit.freeColonist"); - UnitType braveType = spec().getUnitType("model.unit.brave"); + private static final EquipmentType horses + = spec().getEquipmentType("model.equipment.horses"); + private static final EquipmentType indianHorses + = spec().getEquipmentType("model.equipment.indian.horses"); + private static final EquipmentType indianMuskets + = spec().getEquipmentType("model.equipment.indian.muskets"); + private static final EquipmentType muskets + = spec().getEquipmentType("model.equipment.muskets"); + + private static final TileImprovementType riverType + = spec().getTileImprovementType("model.improvement.river"); + private static final TileImprovementType roadType + = spec().getTileImprovementType("model.improvement.road"); - EquipmentType horses = spec().getEquipmentType("model.equipment.horses"); - EquipmentType muskets = spec().getEquipmentType("model.equipment.muskets"); - EquipmentType indianHorses = spec().getEquipmentType("model.equipment.indian.horses"); - EquipmentType indianMuskets = spec().getEquipmentType("model.equipment.indian.muskets"); public void testMoveFromPlainsToPlains() throws Exception { @@ -61,8 +76,7 @@ assertTrue("No improvements", tile2.getTileImprovements().isEmpty()); TileImprovement ti = new TileImprovement(game, tile2, spec().getTileImprovementType("model.improvement.plow")); ti.setTurnsToComplete(0); - tile2.setTileItemContainer(new TileItemContainer(game, tile2)); - tile2.getTileItemContainer().addTileItem(ti); + tile2.add(ti); assertTrue("Plowed", tile2.getCompletedTileImprovements().size() == 1); assertEquals(moveCost, colonist.getMoveCost(tile2)); assertEquals(Math.min(moveCost, colonistType.getMovement()), @@ -101,30 +115,29 @@ tile1.setExploredBy(dutch, true); tile2.setExploredBy(dutch, true); - TileImprovementType roadType = spec().getTileImprovementType("model.improvement.road"); - TileImprovement road1 = new TileImprovement(game, tile1, roadType); + TileImprovement road1 = tile1.addRoad(); assertTrue(road1.isRoad()); assertFalse(road1.isComplete()); road1.setTurnsToComplete(0); assertTrue(road1.isComplete()); - tile1.setTileItemContainer(new TileItemContainer(game, tile1)); - tile1.getTileItemContainer().addTileItem(road1); - assertTrue(tile1.hasRoad()); + road1.updateRoadConnections(true); + assertEquals(road1, tile1.getRoad()); - TileImprovement road2 = new TileImprovement(game, tile2, roadType); + TileImprovement road2 = tile2.addRoad(); road2.setTurnsToComplete(0); - tile2.setTileItemContainer(new TileItemContainer(game, tile2)); - tile2.getTileItemContainer().addTileItem(road2); + road2.updateRoadConnections(true); assertTrue(road2.isComplete()); - assertTrue(tile2.hasRoad()); + assertEquals(road2, tile2.getRoad()); + + assertTrue(road1.isConnectedTo(tile1.getDirection(tile2))); + assertTrue(road2.isConnectedTo(tile2.getDirection(tile1))); +System.err.println("TMARoad " + tile1.getDirection(tile2)); Unit colonist = new ServerUnit(game, tile1, dutch, colonistType); - int moveCost = 1; assertEquals(moveCost, colonist.getMoveCost(tile2)); assertEquals(Math.min(moveCost, colonistType.getMovement()), colonist.getMoveCost(tile2)); - } public void testMoveAlongRiver() throws Exception { @@ -137,28 +150,32 @@ Tile tile2 = tile1.getAdjacentTile(Map.Direction.NE); tile1.setExploredBy(dutch, true); tile2.setExploredBy(dutch, true); + assertEquals(Map.Direction.NE, map.getDirection(tile1, tile2)); + assertEquals(Map.Direction.SW, map.getDirection(tile2, tile1)); - TileImprovementType riverType = spec().getTileImprovementType("model.improvement.river"); - TileImprovement river1 = new TileImprovement(game, tile1, riverType); + TileImprovement river1 = tile1.addRiver(1, "0101"); assertTrue(river1.isRiver()); assertTrue(river1.isComplete()); - tile1.setTileItemContainer(new TileItemContainer(game, tile1)); - tile1.getTileItemContainer().addTileItem(river1); assertTrue(tile1.hasRiver()); - TileImprovement river2 = new TileImprovement(game, tile2, riverType); - river2.setTurnsToComplete(0); - tile2.setTileItemContainer(new TileItemContainer(game, tile2)); - tile2.getTileItemContainer().addTileItem(river2); + TileImprovement river2 = tile2.addRiver(1, "0101"); + assertTrue(river2.isRiver()); assertTrue(river2.isComplete()); assertTrue(tile2.hasRiver()); + assertFalse(river1.isConnectedTo(Map.Direction.NE)); + assertTrue (river1.isConnectedTo(Map.Direction.SE)); + assertFalse(river1.isConnectedTo(Map.Direction.SW)); + assertTrue (river1.isConnectedTo(Map.Direction.NW)); + assertFalse(river2.isConnectedTo(Map.Direction.NE)); + assertTrue (river2.isConnectedTo(Map.Direction.SE)); + assertFalse(river2.isConnectedTo(Map.Direction.SW)); + assertTrue (river2.isConnectedTo(Map.Direction.NW)); + Unit colonist = new ServerUnit(game, tile1, dutch, colonistType); +System.err.println("TMAR"); - // rivers run parallel, no cost reduction - river1.setStyle(TileImprovementStyle.getInstance("0101")); - river2.setStyle(TileImprovementStyle.getInstance("0101")); - + // rivers start parallel, no cost reduction int moveCost = 3; assertEquals(moveCost, colonist.getMoveCost(tile2)); assertEquals(Math.min(moveCost, colonistType.getMovement()), @@ -166,17 +183,23 @@ // rivers are connected, cost reduction applies river1.setStyle(TileImprovementStyle.getInstance("1000")); - assertEquals(Map.Direction.NE, map.getDirection(tile1, tile2)); - assertTrue(tile1.getRiver().getStyle().isConnectedTo(Map.Direction.NE)); river2.setStyle(TileImprovementStyle.getInstance("0010")); - assertEquals(Map.Di... [truncated message content] |